MediaWiki  1.32.5
DatabasePostgres.php
Go to the documentation of this file.
1 <?php
23 namespace Wikimedia\Rdbms;
24 
25 use Wikimedia\Timestamp\ConvertibleTimestamp;
26 use Wikimedia\WaitConditionLoop;
28 use Exception;
29 
33 class DatabasePostgres extends Database {
35  protected $port;
36 
38  protected $lastResultHandle = null;
39 
41  private $numericVersion = null;
43  private $connectString;
45  private $coreSchema;
47  private $tempSchema;
49  private $keywordTableMap = [];
50 
56  public function __construct( array $params ) {
57  $this->port = $params['port'] ?? false;
58  $this->keywordTableMap = $params['keywordTableMap'] ?? [];
59 
60  parent::__construct( $params );
61  }
62 
63  public function getType() {
64  return 'postgres';
65  }
66 
67  public function implicitGroupby() {
68  return false;
69  }
70 
71  public function implicitOrderby() {
72  return false;
73  }
74 
75  public function hasConstraint( $name ) {
76  foreach ( $this->getCoreSchemas() as $schema ) {
77  $sql = "SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n " .
78  "WHERE c.connamespace = n.oid AND conname = " .
79  $this->addQuotes( $name ) . " AND n.nspname = " .
80  $this->addQuotes( $schema );
81  $res = $this->doQuery( $sql );
82  if ( $res && $this->numRows( $res ) ) {
83  return true;
84  }
85  }
86  return false;
87  }
88 
89  protected function open( $server, $user, $password, $dbName, $schema, $tablePrefix ) {
90  # Test for Postgres support, to avoid suppressed fatal error
91  if ( !function_exists( 'pg_connect' ) ) {
92  throw new DBConnectionError(
93  $this,
94  "Postgres functions missing, have you compiled PHP with the --with-pgsql\n" .
95  "option? (Note: if you recently installed PHP, you may need to restart your\n" .
96  "webserver and database)\n"
97  );
98  }
99 
100  $this->server = $server;
101  $this->user = $user;
102  $this->password = $password;
103 
104  $connectVars = [
105  // pg_connect() user $user as the default database. Since a database is *required*,
106  // at least pick a "don't care" database that is more likely to exist. This case
107  // arrises when LoadBalancer::getConnection( $i, [], '' ) is used.
108  'dbname' => strlen( $dbName ) ? $dbName : 'postgres',
109  'user' => $user,
110  'password' => $password
111  ];
112  if ( $server != false && $server != '' ) {
113  $connectVars['host'] = $server;
114  }
115  if ( (int)$this->port > 0 ) {
116  $connectVars['port'] = (int)$this->port;
117  }
118  if ( $this->flags & self::DBO_SSL ) {
119  $connectVars['sslmode'] = 1;
120  }
121 
122  $this->connectString = $this->makeConnectionString( $connectVars );
123  $this->close();
124  $this->installErrorHandler();
125 
126  try {
127  // Use new connections to let LoadBalancer/LBFactory handle reuse
128  $this->conn = pg_connect( $this->connectString, PGSQL_CONNECT_FORCE_NEW );
129  } catch ( Exception $ex ) {
130  $this->restoreErrorHandler();
131  throw $ex;
132  }
133 
134  $phpError = $this->restoreErrorHandler();
135 
136  if ( !$this->conn ) {
137  $this->queryLogger->debug(
138  "DB connection error\n" .
139  "Server: $server, Database: $dbName, User: $user, Password: " .
140  substr( $password, 0, 3 ) . "...\n"
141  );
142  $this->queryLogger->debug( $this->lastError() . "\n" );
143  throw new DBConnectionError( $this, str_replace( "\n", ' ', $phpError ) );
144  }
145 
146  $this->opened = true;
147 
148  # If called from the command-line (e.g. importDump), only show errors
149  if ( $this->cliMode ) {
150  $this->doQuery( "SET client_min_messages = 'ERROR'" );
151  }
152 
153  $this->query( "SET client_encoding='UTF8'", __METHOD__ );
154  $this->query( "SET datestyle = 'ISO, YMD'", __METHOD__ );
155  $this->query( "SET timezone = 'GMT'", __METHOD__ );
156  $this->query( "SET standard_conforming_strings = on", __METHOD__ );
157  $this->query( "SET bytea_output = 'escape'", __METHOD__ ); // PHP bug 53127
158 
159  $this->determineCoreSchema( $schema );
160  $this->currentDomain = new DatabaseDomain( $dbName, $schema, $tablePrefix );
161 
162  return (bool)$this->conn;
163  }
164 
165  protected function relationSchemaQualifier() {
166  if ( $this->coreSchema === $this->currentDomain->getSchema() ) {
167  // The schema to be used is now in the search path; no need for explicit qualification
168  return '';
169  }
170 
171  return parent::relationSchemaQualifier();
172  }
173 
174  public function databasesAreIndependent() {
175  return true;
176  }
177 
178  public function doSelectDomain( DatabaseDomain $domain ) {
179  if ( $this->getDBname() !== $domain->getDatabase() ) {
180  // Postgres doesn't support selectDB in the same way MySQL does.
181  // So if the DB name doesn't match the open connection, open a new one
182  $this->open(
183  $this->server,
184  $this->user,
185  $this->password,
186  $domain->getDatabase(),
187  $domain->getSchema(),
188  $domain->getTablePrefix()
189  );
190  } else {
191  $this->currentDomain = $domain;
192  }
193 
194  return true;
195  }
196 
201  private function makeConnectionString( $vars ) {
202  $s = '';
203  foreach ( $vars as $name => $value ) {
204  $s .= "$name='" . str_replace( "'", "\\'", $value ) . "' ";
205  }
206 
207  return $s;
208  }
209 
210  protected function closeConnection() {
211  return $this->conn ? pg_close( $this->conn ) : true;
212  }
213 
214  protected function isTransactableQuery( $sql ) {
215  return parent::isTransactableQuery( $sql ) &&
216  !preg_match( '/^SELECT\s+pg_(try_|)advisory_\w+\(/', $sql );
217  }
218 
219  public function doQuery( $sql ) {
220  $conn = $this->getBindingHandle();
221 
222  $sql = mb_convert_encoding( $sql, 'UTF-8' );
223  // Clear previously left over PQresult
224  while ( $res = pg_get_result( $conn ) ) {
225  pg_free_result( $res );
226  }
227  if ( pg_send_query( $conn, $sql ) === false ) {
228  throw new DBUnexpectedError( $this, "Unable to post new query to PostgreSQL\n" );
229  }
230  $this->lastResultHandle = pg_get_result( $conn );
231  if ( pg_result_error( $this->lastResultHandle ) ) {
232  return false;
233  }
234 
236  }
237 
238  protected function dumpError() {
239  $diags = [
240  PGSQL_DIAG_SEVERITY,
241  PGSQL_DIAG_SQLSTATE,
242  PGSQL_DIAG_MESSAGE_PRIMARY,
243  PGSQL_DIAG_MESSAGE_DETAIL,
244  PGSQL_DIAG_MESSAGE_HINT,
245  PGSQL_DIAG_STATEMENT_POSITION,
246  PGSQL_DIAG_INTERNAL_POSITION,
247  PGSQL_DIAG_INTERNAL_QUERY,
248  PGSQL_DIAG_CONTEXT,
249  PGSQL_DIAG_SOURCE_FILE,
250  PGSQL_DIAG_SOURCE_LINE,
251  PGSQL_DIAG_SOURCE_FUNCTION
252  ];
253  foreach ( $diags as $d ) {
254  $this->queryLogger->debug( sprintf( "PgSQL ERROR(%d): %s\n",
255  $d, pg_result_error_field( $this->lastResultHandle, $d ) ) );
256  }
257  }
258 
259  public function freeResult( $res ) {
260  if ( $res instanceof ResultWrapper ) {
261  $res = $res->result;
262  }
263  Wikimedia\suppressWarnings();
264  $ok = pg_free_result( $res );
265  Wikimedia\restoreWarnings();
266  if ( !$ok ) {
267  throw new DBUnexpectedError( $this, "Unable to free Postgres result\n" );
268  }
269  }
270 
271  public function fetchObject( $res ) {
272  if ( $res instanceof ResultWrapper ) {
273  $res = $res->result;
274  }
275  Wikimedia\suppressWarnings();
276  $row = pg_fetch_object( $res );
277  Wikimedia\restoreWarnings();
278  # @todo FIXME: HACK HACK HACK HACK debug
279 
280  # @todo hashar: not sure if the following test really trigger if the object
281  # fetching failed.
282  $conn = $this->getBindingHandle();
283  if ( pg_last_error( $conn ) ) {
284  throw new DBUnexpectedError(
285  $this,
286  'SQL error: ' . htmlspecialchars( pg_last_error( $conn ) )
287  );
288  }
289 
290  return $row;
291  }
292 
293  public function fetchRow( $res ) {
294  if ( $res instanceof ResultWrapper ) {
295  $res = $res->result;
296  }
297  Wikimedia\suppressWarnings();
298  $row = pg_fetch_array( $res );
299  Wikimedia\restoreWarnings();
300 
301  $conn = $this->getBindingHandle();
302  if ( pg_last_error( $conn ) ) {
303  throw new DBUnexpectedError(
304  $this,
305  'SQL error: ' . htmlspecialchars( pg_last_error( $conn ) )
306  );
307  }
308 
309  return $row;
310  }
311 
312  public function numRows( $res ) {
313  if ( $res === false ) {
314  return 0;
315  }
316 
317  if ( $res instanceof ResultWrapper ) {
318  $res = $res->result;
319  }
320  Wikimedia\suppressWarnings();
321  $n = pg_num_rows( $res );
322  Wikimedia\restoreWarnings();
323 
324  $conn = $this->getBindingHandle();
325  if ( pg_last_error( $conn ) ) {
326  throw new DBUnexpectedError(
327  $this,
328  'SQL error: ' . htmlspecialchars( pg_last_error( $conn ) )
329  );
330  }
331 
332  return $n;
333  }
334 
335  public function numFields( $res ) {
336  if ( $res instanceof ResultWrapper ) {
337  $res = $res->result;
338  }
339 
340  return pg_num_fields( $res );
341  }
342 
343  public function fieldName( $res, $n ) {
344  if ( $res instanceof ResultWrapper ) {
345  $res = $res->result;
346  }
347 
348  return pg_field_name( $res, $n );
349  }
350 
351  public function insertId() {
352  $res = $this->query( "SELECT lastval()" );
353  $row = $this->fetchRow( $res );
354  return is_null( $row[0] ) ? null : (int)$row[0];
355  }
356 
357  public function dataSeek( $res, $row ) {
358  if ( $res instanceof ResultWrapper ) {
359  $res = $res->result;
360  }
361 
362  return pg_result_seek( $res, $row );
363  }
364 
365  public function lastError() {
366  if ( $this->conn ) {
367  if ( $this->lastResultHandle ) {
368  return pg_result_error( $this->lastResultHandle );
369  } else {
370  return pg_last_error();
371  }
372  }
373 
374  return $this->getLastPHPError() ?: 'No database connection';
375  }
376 
377  public function lastErrno() {
378  if ( $this->lastResultHandle ) {
379  return pg_result_error_field( $this->lastResultHandle, PGSQL_DIAG_SQLSTATE );
380  } else {
381  return false;
382  }
383  }
384 
385  protected function fetchAffectedRowCount() {
386  if ( !$this->lastResultHandle ) {
387  return 0;
388  }
389 
390  return pg_affected_rows( $this->lastResultHandle );
391  }
392 
408  public function estimateRowCount( $table, $var = '*', $conds = '',
409  $fname = __METHOD__, $options = [], $join_conds = []
410  ) {
411  $conds = $this->normalizeConditions( $conds, $fname );
412  $column = $this->extractSingleFieldFromList( $var );
413  if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) {
414  $conds[] = "$column IS NOT NULL";
415  }
416 
417  $options['EXPLAIN'] = true;
418  $res = $this->select( $table, $var, $conds, $fname, $options, $join_conds );
419  $rows = -1;
420  if ( $res ) {
421  $row = $this->fetchRow( $res );
422  $count = [];
423  if ( preg_match( '/rows=(\d+)/', $row[0], $count ) ) {
424  $rows = (int)$count[1];
425  }
426  }
427 
428  return $rows;
429  }
430 
431  public function indexInfo( $table, $index, $fname = __METHOD__ ) {
432  $sql = "SELECT indexname FROM pg_indexes WHERE tablename='$table'";
433  $res = $this->query( $sql, $fname );
434  if ( !$res ) {
435  return null;
436  }
437  foreach ( $res as $row ) {
438  if ( $row->indexname == $this->indexName( $index ) ) {
439  return $row;
440  }
441  }
442 
443  return false;
444  }
445 
446  public function indexAttributes( $index, $schema = false ) {
447  if ( $schema === false ) {
448  $schemas = $this->getCoreSchemas();
449  } else {
450  $schemas = [ $schema ];
451  }
452 
453  $eindex = $this->addQuotes( $index );
454 
455  foreach ( $schemas as $schema ) {
456  $eschema = $this->addQuotes( $schema );
457  /*
458  * A subquery would be not needed if we didn't care about the order
459  * of attributes, but we do
460  */
461  $sql = <<<__INDEXATTR__
462 
463  SELECT opcname,
464  attname,
465  i.indoption[s.g] as option,
466  pg_am.amname
467  FROM
468  (SELECT generate_series(array_lower(isub.indkey,1), array_upper(isub.indkey,1)) AS g
469  FROM
470  pg_index isub
471  JOIN pg_class cis
472  ON cis.oid=isub.indexrelid
473  JOIN pg_namespace ns
474  ON cis.relnamespace = ns.oid
475  WHERE cis.relname=$eindex AND ns.nspname=$eschema) AS s,
476  pg_attribute,
477  pg_opclass opcls,
478  pg_am,
479  pg_class ci
480  JOIN pg_index i
481  ON ci.oid=i.indexrelid
482  JOIN pg_class ct
483  ON ct.oid = i.indrelid
484  JOIN pg_namespace n
485  ON ci.relnamespace = n.oid
486  WHERE
487  ci.relname=$eindex AND n.nspname=$eschema
488  AND attrelid = ct.oid
489  AND i.indkey[s.g] = attnum
490  AND i.indclass[s.g] = opcls.oid
491  AND pg_am.oid = opcls.opcmethod
492 __INDEXATTR__;
493  $res = $this->query( $sql, __METHOD__ );
494  $a = [];
495  if ( $res ) {
496  foreach ( $res as $row ) {
497  $a[] = [
498  $row->attname,
499  $row->opcname,
500  $row->amname,
501  $row->option ];
502  }
503  return $a;
504  }
505  }
506  return null;
507  }
508 
509  public function indexUnique( $table, $index, $fname = __METHOD__ ) {
510  $sql = "SELECT indexname FROM pg_indexes WHERE tablename='{$table}'" .
511  " AND indexdef LIKE 'CREATE UNIQUE%(" .
512  $this->strencode( $this->indexName( $index ) ) .
513  ")'";
514  $res = $this->query( $sql, $fname );
515  if ( !$res ) {
516  return null;
517  }
518 
519  return $res->numRows() > 0;
520  }
521 
522  public function selectSQLText(
523  $table, $vars, $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
524  ) {
525  if ( is_string( $options ) ) {
526  $options = [ $options ];
527  }
528 
529  // Change the FOR UPDATE option as necessary based on the join conditions. Then pass
530  // to the parent function to get the actual SQL text.
531  // In Postgres when using FOR UPDATE, only the main table and tables that are inner joined
532  // can be locked. That means tables in an outer join cannot be FOR UPDATE locked. Trying to
533  // do so causes a DB error. This wrapper checks which tables can be locked and adjusts it
534  // accordingly.
535  // MySQL uses "ORDER BY NULL" as an optimization hint, but that is illegal in PostgreSQL.
536  if ( is_array( $options ) ) {
537  $forUpdateKey = array_search( 'FOR UPDATE', $options, true );
538  if ( $forUpdateKey !== false && $join_conds ) {
539  unset( $options[$forUpdateKey] );
540  $options['FOR UPDATE'] = [];
541 
542  $toCheck = $table;
543  reset( $toCheck );
544  while ( $toCheck ) {
545  $alias = key( $toCheck );
546  $name = $toCheck[$alias];
547  unset( $toCheck[$alias] );
548 
549  $hasAlias = !is_numeric( $alias );
550  if ( !$hasAlias && is_string( $name ) ) {
551  $alias = $name;
552  }
553 
554  if ( !isset( $join_conds[$alias] ) ||
555  !preg_match( '/^(?:LEFT|RIGHT|FULL)(?: OUTER)? JOIN$/i', $join_conds[$alias][0] )
556  ) {
557  if ( is_array( $name ) ) {
558  // It's a parenthesized group, process all the tables inside the group.
559  $toCheck = array_merge( $toCheck, $name );
560  } else {
561  // Quote alias names so $this->tableName() won't mangle them
562  $options['FOR UPDATE'][] = $hasAlias ? $this->addIdentifierQuotes( $alias ) : $alias;
563  }
564  }
565  }
566  }
567 
568  if ( isset( $options['ORDER BY'] ) && $options['ORDER BY'] == 'NULL' ) {
569  unset( $options['ORDER BY'] );
570  }
571  }
572 
573  return parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
574  }
575 
577  public function insert( $table, $args, $fname = __METHOD__, $options = [] ) {
578  if ( !count( $args ) ) {
579  return true;
580  }
581 
582  $table = $this->tableName( $table );
583  if ( !isset( $this->numericVersion ) ) {
584  $this->getServerVersion();
585  }
586 
587  if ( !is_array( $options ) ) {
588  $options = [ $options ];
589  }
590 
591  if ( isset( $args[0] ) && is_array( $args[0] ) ) {
592  $rows = $args;
593  $keys = array_keys( $args[0] );
594  } else {
595  $rows = [ $args ];
596  $keys = array_keys( $args );
597  }
598 
599  $ignore = in_array( 'IGNORE', $options );
600 
601  $sql = "INSERT INTO $table (" . implode( ',', $keys ) . ') VALUES ';
602 
603  if ( $this->numericVersion >= 9.5 || !$ignore ) {
604  // No IGNORE or our PG has "ON CONFLICT DO NOTHING"
605  $first = true;
606  foreach ( $rows as $row ) {
607  if ( $first ) {
608  $first = false;
609  } else {
610  $sql .= ',';
611  }
612  $sql .= '(' . $this->makeList( $row ) . ')';
613  }
614  if ( $ignore ) {
615  $sql .= ' ON CONFLICT DO NOTHING';
616  }
617  $this->query( $sql, $fname );
618  } else {
619  // Emulate IGNORE by doing each row individually, with savepoints
620  // to roll back as necessary.
621  $numrowsinserted = 0;
622 
623  $tok = $this->startAtomic( "$fname (outer)", self::ATOMIC_CANCELABLE );
624  try {
625  foreach ( $rows as $row ) {
626  $tempsql = $sql;
627  $tempsql .= '(' . $this->makeList( $row ) . ')';
628 
629  $this->startAtomic( "$fname (inner)", self::ATOMIC_CANCELABLE );
630  try {
631  $this->query( $tempsql, $fname );
632  $this->endAtomic( "$fname (inner)" );
633  $numrowsinserted++;
634  } catch ( DBQueryError $e ) {
635  $this->cancelAtomic( "$fname (inner)" );
636  // Our IGNORE is supposed to ignore duplicate key errors, but not others.
637  // (even though MySQL's version apparently ignores all errors)
638  if ( $e->errno !== '23505' ) {
639  throw $e;
640  }
641  }
642  }
643  } catch ( Exception $e ) {
644  $this->cancelAtomic( "$fname (outer)", $tok );
645  throw $e;
646  }
647  $this->endAtomic( "$fname (outer)" );
648 
649  // Set the affected row count for the whole operation
650  $this->affectedRowCount = $numrowsinserted;
651  }
652 
653  return true;
654  }
655 
656  protected function makeUpdateOptionsArray( $options ) {
657  if ( !is_array( $options ) ) {
658  $options = [ $options ];
659  }
660 
661  // PostgreSQL doesn't support anything like "ignore" for
662  // UPDATE.
663  $options = array_diff( $options, [ 'IGNORE' ] );
664 
665  return parent::makeUpdateOptionsArray( $options );
666  }
667 
687  public function nativeInsertSelect(
688  $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
689  $insertOptions = [], $selectOptions = [], $selectJoinConds = []
690  ) {
691  if ( !is_array( $insertOptions ) ) {
692  $insertOptions = [ $insertOptions ];
693  }
694 
695  if ( in_array( 'IGNORE', $insertOptions ) ) {
696  if ( $this->getServerVersion() >= 9.5 ) {
697  // Use ON CONFLICT DO NOTHING if we have it for IGNORE
698  $destTable = $this->tableName( $destTable );
699 
700  $selectSql = $this->selectSQLText(
701  $srcTable,
702  array_values( $varMap ),
703  $conds,
704  $fname,
705  $selectOptions,
706  $selectJoinConds
707  );
708 
709  $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ') ' .
710  $selectSql . ' ON CONFLICT DO NOTHING';
711 
712  return $this->query( $sql, $fname );
713  } else {
714  // IGNORE and we don't have ON CONFLICT DO NOTHING, so just use the non-native version
715  return $this->nonNativeInsertSelect(
716  $destTable, $srcTable, $varMap, $conds, $fname,
717  $insertOptions, $selectOptions, $selectJoinConds
718  );
719  }
720  }
721 
722  return parent::nativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname,
723  $insertOptions, $selectOptions, $selectJoinConds );
724  }
725 
726  public function tableName( $name, $format = 'quoted' ) {
727  // Replace reserved words with better ones
728  $name = $this->remappedTableName( $name );
729 
730  return parent::tableName( $name, $format );
731  }
732 
737  public function remappedTableName( $name ) {
738  return $this->keywordTableMap[$name] ?? $name;
739  }
740 
746  public function realTableName( $name, $format = 'quoted' ) {
747  return parent::tableName( $name, $format );
748  }
749 
750  public function nextSequenceValue( $seqName ) {
751  return new NextSequenceValue;
752  }
753 
760  public function currentSequenceValue( $seqName ) {
761  $safeseq = str_replace( "'", "''", $seqName );
762  $res = $this->query( "SELECT currval('$safeseq')" );
763  $row = $this->fetchRow( $res );
764  $currval = $row[0];
765 
766  return $currval;
767  }
768 
769  public function textFieldSize( $table, $field ) {
770  $table = $this->tableName( $table );
771  $sql = "SELECT t.typname as ftype,a.atttypmod as size
772  FROM pg_class c, pg_attribute a, pg_type t
773  WHERE relname='$table' AND a.attrelid=c.oid AND
774  a.atttypid=t.oid and a.attname='$field'";
775  $res = $this->query( $sql );
776  $row = $this->fetchObject( $res );
777  if ( $row->ftype == 'varchar' ) {
778  $size = $row->size - 4;
779  } else {
780  $size = $row->size;
781  }
782 
783  return $size;
784  }
785 
786  public function limitResult( $sql, $limit, $offset = false ) {
787  return "$sql LIMIT $limit " . ( is_numeric( $offset ) ? " OFFSET {$offset} " : '' );
788  }
789 
790  public function wasDeadlock() {
791  // https://www.postgresql.org/docs/9.2/static/errcodes-appendix.html
792  return $this->lastErrno() === '40P01';
793  }
794 
795  public function wasLockTimeout() {
796  // https://www.postgresql.org/docs/9.2/static/errcodes-appendix.html
797  return $this->lastErrno() === '55P03';
798  }
799 
800  public function wasConnectionError( $errno ) {
801  // https://www.postgresql.org/docs/9.2/static/errcodes-appendix.html
802  static $codes = [ '08000', '08003', '08006', '08001', '08004', '57P01', '57P03', '53300' ];
803 
804  return in_array( $errno, $codes, true );
805  }
806 
807  protected function wasKnownStatementRollbackError() {
808  return false; // transaction has to be rolled-back from error state
809  }
810 
811  public function duplicateTableStructure(
812  $oldName, $newName, $temporary = false, $fname = __METHOD__
813  ) {
814  $newNameE = $this->addIdentifierQuotes( $newName );
815  $oldNameE = $this->addIdentifierQuotes( $oldName );
816 
817  $temporary = $temporary ? 'TEMPORARY' : '';
818 
819  $ret = $this->query( "CREATE $temporary TABLE $newNameE " .
820  "(LIKE $oldNameE INCLUDING DEFAULTS INCLUDING INDEXES)", $fname );
821  if ( !$ret ) {
822  return $ret;
823  }
824 
825  $res = $this->query( 'SELECT attname FROM pg_class c'
826  . ' JOIN pg_namespace n ON (n.oid = c.relnamespace)'
827  . ' JOIN pg_attribute a ON (a.attrelid = c.oid)'
828  . ' JOIN pg_attrdef d ON (c.oid=d.adrelid and a.attnum=d.adnum)'
829  . ' WHERE relkind = \'r\''
830  . ' AND nspname = ' . $this->addQuotes( $this->getCoreSchema() )
831  . ' AND relname = ' . $this->addQuotes( $oldName )
832  . ' AND adsrc LIKE \'nextval(%\'',
833  $fname
834  );
835  $row = $this->fetchObject( $res );
836  if ( $row ) {
837  $field = $row->attname;
838  $newSeq = "{$newName}_{$field}_seq";
839  $fieldE = $this->addIdentifierQuotes( $field );
840  $newSeqE = $this->addIdentifierQuotes( $newSeq );
841  $newSeqQ = $this->addQuotes( $newSeq );
842  $this->query( "CREATE $temporary SEQUENCE $newSeqE OWNED BY $newNameE.$fieldE", $fname );
843  $this->query(
844  "ALTER TABLE $newNameE ALTER COLUMN $fieldE SET DEFAULT nextval({$newSeqQ}::regclass)",
845  $fname
846  );
847  }
848 
849  return $ret;
850  }
851 
852  public function resetSequenceForTable( $table, $fname = __METHOD__ ) {
853  $table = $this->tableName( $table, 'raw' );
854  foreach ( $this->getCoreSchemas() as $schema ) {
855  $res = $this->query(
856  'SELECT c.oid FROM pg_class c JOIN pg_namespace n ON (n.oid = c.relnamespace)'
857  . ' WHERE relkind = \'r\''
858  . ' AND nspname = ' . $this->addQuotes( $schema )
859  . ' AND relname = ' . $this->addQuotes( $table ),
860  $fname
861  );
862  if ( !$res || !$this->numRows( $res ) ) {
863  continue;
864  }
865 
866  $oid = $this->fetchObject( $res )->oid;
867  $res = $this->query( 'SELECT adsrc FROM pg_attribute a'
868  . ' JOIN pg_attrdef d ON (a.attrelid=d.adrelid and a.attnum=d.adnum)'
869  . " WHERE a.attrelid = $oid"
870  . ' AND adsrc LIKE \'nextval(%\'',
871  $fname
872  );
873  $row = $this->fetchObject( $res );
874  if ( $row ) {
875  $this->query(
876  'SELECT ' . preg_replace( '/^nextval\((.+)\)$/', 'setval($1,1,false)', $row->adsrc ),
877  $fname
878  );
879  return true;
880  }
881  return false;
882  }
883 
884  return false;
885  }
886 
890  public function listTables( $prefix = null, $fname = __METHOD__ ) {
891  $eschemas = implode( ',', array_map( [ $this, 'addQuotes' ], $this->getCoreSchemas() ) );
892  $result = $this->query(
893  "SELECT DISTINCT tablename FROM pg_tables WHERE schemaname IN ($eschemas)", $fname );
894  $endArray = [];
895 
896  foreach ( $result as $table ) {
897  $vars = get_object_vars( $table );
898  $table = array_pop( $vars );
899  if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
900  $endArray[] = $table;
901  }
902  }
903 
904  return $endArray;
905  }
906 
907  public function timestamp( $ts = 0 ) {
908  $ct = new ConvertibleTimestamp( $ts );
909 
910  return $ct->getTimestamp( TS_POSTGRES );
911  }
912 
931  private function pg_array_parse( $text, &$output, $limit = false, $offset = 1 ) {
932  if ( false === $limit ) {
933  $limit = strlen( $text ) - 1;
934  $output = [];
935  }
936  if ( '{}' == $text ) {
937  return $output;
938  }
939  do {
940  if ( '{' != $text[$offset] ) {
941  preg_match( "/(\\{?\"([^\"\\\\]|\\\\.)*\"|[^,{}]+)+([,}]+)/",
942  $text, $match, 0, $offset );
943  $offset += strlen( $match[0] );
944  $output[] = ( '"' != $match[1][0]
945  ? $match[1]
946  : stripcslashes( substr( $match[1], 1, -1 ) ) );
947  if ( '},' == $match[3] ) {
948  return $output;
949  }
950  } else {
951  $offset = $this->pg_array_parse( $text, $output, $limit, $offset + 1 );
952  }
953  } while ( $limit > $offset );
954 
955  return $output;
956  }
957 
958  public function aggregateValue( $valuedata, $valuename = 'value' ) {
959  return $valuedata;
960  }
961 
962  public function getSoftwareLink() {
963  return '[{{int:version-db-postgres-url}} PostgreSQL]';
964  }
965 
973  public function getCurrentSchema() {
974  $res = $this->query( "SELECT current_schema()", __METHOD__ );
975  $row = $this->fetchRow( $res );
976 
977  return $row[0];
978  }
979 
990  public function getSchemas() {
991  $res = $this->query( "SELECT current_schemas(false)", __METHOD__ );
992  $row = $this->fetchRow( $res );
993  $schemas = [];
994 
995  /* PHP pgsql support does not support array type, "{a,b}" string is returned */
996 
997  return $this->pg_array_parse( $row[0], $schemas );
998  }
999 
1009  public function getSearchPath() {
1010  $res = $this->query( "SHOW search_path", __METHOD__ );
1011  $row = $this->fetchRow( $res );
1012 
1013  /* PostgreSQL returns SHOW values as strings */
1014 
1015  return explode( ",", $row[0] );
1016  }
1017 
1025  private function setSearchPath( $search_path ) {
1026  $this->query( "SET search_path = " . implode( ", ", $search_path ) );
1027  }
1028 
1043  public function determineCoreSchema( $desiredSchema ) {
1044  $this->begin( __METHOD__, self::TRANSACTION_INTERNAL );
1045  if ( $this->schemaExists( $desiredSchema ) ) {
1046  if ( in_array( $desiredSchema, $this->getSchemas() ) ) {
1047  $this->coreSchema = $desiredSchema;
1048  $this->queryLogger->debug(
1049  "Schema \"" . $desiredSchema . "\" already in the search path\n" );
1050  } else {
1056  $search_path = $this->getSearchPath();
1057  array_unshift( $search_path,
1058  $this->addIdentifierQuotes( $desiredSchema ) );
1059  $this->setSearchPath( $search_path );
1060  $this->coreSchema = $desiredSchema;
1061  $this->queryLogger->debug(
1062  "Schema \"" . $desiredSchema . "\" added to the search path\n" );
1063  }
1064  } else {
1065  $this->coreSchema = $this->getCurrentSchema();
1066  $this->queryLogger->debug(
1067  "Schema \"" . $desiredSchema . "\" not found, using current \"" .
1068  $this->coreSchema . "\"\n" );
1069  }
1070  /* Commit SET otherwise it will be rollbacked on error or IGNORE SELECT */
1071  $this->commit( __METHOD__, self::FLUSHING_INTERNAL );
1072  }
1073 
1080  public function getCoreSchema() {
1081  return $this->coreSchema;
1082  }
1083 
1090  public function getCoreSchemas() {
1091  if ( $this->tempSchema ) {
1092  return [ $this->tempSchema, $this->getCoreSchema() ];
1093  }
1094 
1095  $res = $this->query(
1096  "SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = pg_my_temp_schema()", __METHOD__
1097  );
1098  $row = $this->fetchObject( $res );
1099  if ( $row ) {
1100  $this->tempSchema = $row->nspname;
1101  return [ $this->tempSchema, $this->getCoreSchema() ];
1102  }
1103 
1104  return [ $this->getCoreSchema() ];
1105  }
1106 
1107  public function getServerVersion() {
1108  if ( !isset( $this->numericVersion ) ) {
1109  $conn = $this->getBindingHandle();
1110  $versionInfo = pg_version( $conn );
1111  if ( version_compare( $versionInfo['client'], '7.4.0', 'lt' ) ) {
1112  // Old client, abort install
1113  $this->numericVersion = '7.3 or earlier';
1114  } elseif ( isset( $versionInfo['server'] ) ) {
1115  // Normal client
1116  $this->numericVersion = $versionInfo['server'];
1117  } else {
1118  // T18937: broken pgsql extension from PHP<5.3
1119  $this->numericVersion = pg_parameter_status( $conn, 'server_version' );
1120  }
1121  }
1122 
1123  return $this->numericVersion;
1124  }
1125 
1134  private function relationExists( $table, $types, $schema = false ) {
1135  if ( !is_array( $types ) ) {
1136  $types = [ $types ];
1137  }
1138  if ( $schema === false ) {
1139  $schemas = $this->getCoreSchemas();
1140  } else {
1141  $schemas = [ $schema ];
1142  }
1143  $table = $this->realTableName( $table, 'raw' );
1144  $etable = $this->addQuotes( $table );
1145  foreach ( $schemas as $schema ) {
1146  $eschema = $this->addQuotes( $schema );
1147  $sql = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
1148  . "WHERE c.relnamespace = n.oid AND c.relname = $etable AND n.nspname = $eschema "
1149  . "AND c.relkind IN ('" . implode( "','", $types ) . "')";
1150  $res = $this->query( $sql );
1151  if ( $res && $res->numRows() ) {
1152  return true;
1153  }
1154  }
1155 
1156  return false;
1157  }
1158 
1166  public function tableExists( $table, $fname = __METHOD__, $schema = false ) {
1167  return $this->relationExists( $table, [ 'r', 'v' ], $schema );
1168  }
1169 
1170  public function sequenceExists( $sequence, $schema = false ) {
1171  return $this->relationExists( $sequence, 'S', $schema );
1172  }
1173 
1174  public function triggerExists( $table, $trigger ) {
1175  $q = <<<SQL
1176  SELECT 1 FROM pg_class, pg_namespace, pg_trigger
1177  WHERE relnamespace=pg_namespace.oid AND relkind='r'
1178  AND tgrelid=pg_class.oid
1179  AND nspname=%s AND relname=%s AND tgname=%s
1180 SQL;
1181  foreach ( $this->getCoreSchemas() as $schema ) {
1182  $res = $this->query(
1183  sprintf(
1184  $q,
1185  $this->addQuotes( $schema ),
1186  $this->addQuotes( $table ),
1187  $this->addQuotes( $trigger )
1188  )
1189  );
1190  if ( $res && $res->numRows() ) {
1191  return true;
1192  }
1193  }
1194 
1195  return false;
1196  }
1197 
1198  public function ruleExists( $table, $rule ) {
1199  $exists = $this->selectField( 'pg_rules', 'rulename',
1200  [
1201  'rulename' => $rule,
1202  'tablename' => $table,
1203  'schemaname' => $this->getCoreSchemas()
1204  ]
1205  );
1206 
1207  return $exists === $rule;
1208  }
1209 
1210  public function constraintExists( $table, $constraint ) {
1211  foreach ( $this->getCoreSchemas() as $schema ) {
1212  $sql = sprintf( "SELECT 1 FROM information_schema.table_constraints " .
1213  "WHERE constraint_schema = %s AND table_name = %s AND constraint_name = %s",
1214  $this->addQuotes( $schema ),
1215  $this->addQuotes( $table ),
1216  $this->addQuotes( $constraint )
1217  );
1218  $res = $this->query( $sql );
1219  if ( $res && $res->numRows() ) {
1220  return true;
1221  }
1222  }
1223  return false;
1224  }
1225 
1231  public function schemaExists( $schema ) {
1232  if ( !strlen( $schema ) ) {
1233  return false; // short-circuit
1234  }
1235 
1236  $exists = $this->selectField(
1237  '"pg_catalog"."pg_namespace"', 1, [ 'nspname' => $schema ], __METHOD__ );
1238 
1239  return (bool)$exists;
1240  }
1241 
1247  public function roleExists( $roleName ) {
1248  $exists = $this->selectField( '"pg_catalog"."pg_roles"', 1,
1249  [ 'rolname' => $roleName ], __METHOD__ );
1250 
1251  return (bool)$exists;
1252  }
1253 
1259  public function fieldInfo( $table, $field ) {
1260  return PostgresField::fromText( $this, $table, $field );
1261  }
1262 
1269  public function fieldType( $res, $index ) {
1270  if ( $res instanceof ResultWrapper ) {
1271  $res = $res->result;
1272  }
1273 
1274  return pg_field_type( $res, $index );
1275  }
1276 
1277  public function encodeBlob( $b ) {
1278  return new PostgresBlob( pg_escape_bytea( $b ) );
1279  }
1280 
1281  public function decodeBlob( $b ) {
1282  if ( $b instanceof PostgresBlob ) {
1283  $b = $b->fetch();
1284  } elseif ( $b instanceof Blob ) {
1285  return $b->fetch();
1286  }
1287 
1288  return pg_unescape_bytea( $b );
1289  }
1290 
1291  public function strencode( $s ) {
1292  // Should not be called by us
1293  return pg_escape_string( $this->getBindingHandle(), (string)$s );
1294  }
1295 
1296  public function addQuotes( $s ) {
1297  $conn = $this->getBindingHandle();
1298 
1299  if ( is_null( $s ) ) {
1300  return 'NULL';
1301  } elseif ( is_bool( $s ) ) {
1302  return intval( $s );
1303  } elseif ( $s instanceof Blob ) {
1304  if ( $s instanceof PostgresBlob ) {
1305  $s = $s->fetch();
1306  } else {
1307  $s = pg_escape_bytea( $conn, $s->fetch() );
1308  }
1309  return "'$s'";
1310  } elseif ( $s instanceof NextSequenceValue ) {
1311  return 'DEFAULT';
1312  }
1313 
1314  return "'" . pg_escape_string( $conn, (string)$s ) . "'";
1315  }
1316 
1317  public function makeSelectOptions( $options ) {
1318  $preLimitTail = $postLimitTail = '';
1319  $startOpts = $useIndex = $ignoreIndex = '';
1320 
1321  $noKeyOptions = [];
1322  foreach ( $options as $key => $option ) {
1323  if ( is_numeric( $key ) ) {
1324  $noKeyOptions[$option] = true;
1325  }
1326  }
1327 
1328  $preLimitTail .= $this->makeGroupByWithHaving( $options );
1329 
1330  $preLimitTail .= $this->makeOrderBy( $options );
1331 
1332  if ( isset( $options['FOR UPDATE'] ) ) {
1333  $postLimitTail .= ' FOR UPDATE OF ' .
1334  implode( ', ', array_map( [ $this, 'tableName' ], $options['FOR UPDATE'] ) );
1335  } elseif ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
1336  $postLimitTail .= ' FOR UPDATE';
1337  }
1338 
1339  if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) {
1340  $startOpts .= 'DISTINCT';
1341  }
1342 
1343  return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ];
1344  }
1345 
1346  public function getServer() {
1347  return $this->server;
1348  }
1349 
1350  public function buildConcat( $stringList ) {
1351  return implode( ' || ', $stringList );
1352  }
1353 
1354  public function buildGroupConcatField(
1355  $delimiter, $table, $field, $conds = '', $options = [], $join_conds = []
1356  ) {
1357  $fld = "array_to_string(array_agg($field)," . $this->addQuotes( $delimiter ) . ')';
1358 
1359  return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')';
1360  }
1361 
1362  public function buildStringCast( $field ) {
1363  return $field . '::text';
1364  }
1365 
1366  public function streamStatementEnd( &$sql, &$newLine ) {
1367  # Allow dollar quoting for function declarations
1368  if ( substr( $newLine, 0, 4 ) == '$mw$' ) {
1369  if ( $this->delimiter ) {
1370  $this->delimiter = false;
1371  } else {
1372  $this->delimiter = ';';
1373  }
1374  }
1375 
1376  return parent::streamStatementEnd( $sql, $newLine );
1377  }
1378 
1379  public function doLockTables( array $read, array $write, $method ) {
1380  $tablesWrite = [];
1381  foreach ( $write as $table ) {
1382  $tablesWrite[] = $this->tableName( $table );
1383  }
1384  $tablesRead = [];
1385  foreach ( $read as $table ) {
1386  $tablesRead[] = $this->tableName( $table );
1387  }
1388 
1389  // Acquire locks for the duration of the current transaction...
1390  if ( $tablesWrite ) {
1391  $this->query(
1392  'LOCK TABLE ONLY ' . implode( ',', $tablesWrite ) . ' IN EXCLUSIVE MODE',
1393  $method
1394  );
1395  }
1396  if ( $tablesRead ) {
1397  $this->query(
1398  'LOCK TABLE ONLY ' . implode( ',', $tablesRead ) . ' IN SHARE MODE',
1399  $method
1400  );
1401  }
1402 
1403  return true;
1404  }
1405 
1406  public function lockIsFree( $lockName, $method ) {
1407  if ( !parent::lockIsFree( $lockName, $method ) ) {
1408  return false; // already held
1409  }
1410  // http://www.postgresql.org/docs/9.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
1411  $key = $this->addQuotes( $this->bigintFromLockName( $lockName ) );
1412  $result = $this->query( "SELECT (CASE(pg_try_advisory_lock($key))
1413  WHEN 'f' THEN 'f' ELSE pg_advisory_unlock($key) END) AS lockstatus", $method );
1414  $row = $this->fetchObject( $result );
1415 
1416  return ( $row->lockstatus === 't' );
1417  }
1418 
1419  public function lock( $lockName, $method, $timeout = 5 ) {
1420  // http://www.postgresql.org/docs/9.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
1421  $key = $this->addQuotes( $this->bigintFromLockName( $lockName ) );
1422  $loop = new WaitConditionLoop(
1423  function () use ( $lockName, $key, $timeout, $method ) {
1424  $res = $this->query( "SELECT pg_try_advisory_lock($key) AS lockstatus", $method );
1425  $row = $this->fetchObject( $res );
1426  if ( $row->lockstatus === 't' ) {
1427  parent::lock( $lockName, $method, $timeout ); // record
1428  return true;
1429  }
1430 
1431  return WaitConditionLoop::CONDITION_CONTINUE;
1432  },
1433  $timeout
1434  );
1435 
1436  return ( $loop->invoke() === $loop::CONDITION_REACHED );
1437  }
1438 
1439  public function unlock( $lockName, $method ) {
1440  // http://www.postgresql.org/docs/9.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
1441  $key = $this->addQuotes( $this->bigintFromLockName( $lockName ) );
1442  $result = $this->query( "SELECT pg_advisory_unlock($key) as lockstatus", $method );
1443  $row = $this->fetchObject( $result );
1444 
1445  if ( $row->lockstatus === 't' ) {
1446  parent::unlock( $lockName, $method ); // record
1447  return true;
1448  }
1449 
1450  $this->queryLogger->debug( __METHOD__ . " failed to release lock\n" );
1451 
1452  return false;
1453  }
1454 
1455  public function serverIsReadOnly() {
1456  $res = $this->query( "SHOW default_transaction_read_only", __METHOD__ );
1457  $row = $this->fetchObject( $res );
1458 
1459  return $row ? ( strtolower( $row->default_transaction_read_only ) === 'on' ) : false;
1460  }
1461 
1466  private function bigintFromLockName( $lockName ) {
1467  return \Wikimedia\base_convert( substr( sha1( $lockName ), 0, 15 ), 16, 10 );
1468  }
1469 }
1470 
1474 class_alias( DatabasePostgres::class, 'DatabasePostgres' );
Wikimedia\Rdbms\DatabasePostgres\freeResult
freeResult( $res)
Free a result object returned by query() or select().
Definition: DatabasePostgres.php:259
Wikimedia\Rdbms\Database\getLastPHPError
getLastPHPError()
Definition: Database.php:886
Wikimedia\Rdbms\DatabasePostgres\resetSequenceForTable
resetSequenceForTable( $table, $fname=__METHOD__)
Definition: DatabasePostgres.php:852
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:48
Wikimedia\Rdbms\DatabasePostgres\doLockTables
doLockTables(array $read, array $write, $method)
Helper function for lockTables() that handles the actual table locking.
Definition: DatabasePostgres.php:1379
Wikimedia\Rdbms\DatabasePostgres\numFields
numFields( $res)
Get the number of fields in a result object.
Definition: DatabasePostgres.php:335
Wikimedia\Rdbms\DatabasePostgres\bigintFromLockName
bigintFromLockName( $lockName)
Definition: DatabasePostgres.php:1466
Wikimedia\Rdbms\Database\getBindingHandle
getBindingHandle()
Get the underlying binding connection handle.
Definition: Database.php:4657
Wikimedia\Rdbms\DatabasePostgres\tableName
tableName( $name, $format='quoted')
Format a table name ready for use in constructing an SQL query.
Definition: DatabasePostgres.php:726
Wikimedia\Rdbms\DatabasePostgres\getSoftwareLink
getSoftwareLink()
Returns a wikitext link to the DB's website, e.g., return "[https://www.mysql.com/ MySQL]"; Should at...
Definition: DatabasePostgres.php:962
Wikimedia\Rdbms\DatabasePostgres\closeConnection
closeConnection()
Closes underlying database connection.
Definition: DatabasePostgres.php:210
Wikimedia\Rdbms\DatabasePostgres\relationExists
relationExists( $table, $types, $schema=false)
Query whether a given relation exists (in the given schema, or the default mw one if not given)
Definition: DatabasePostgres.php:1134
Wikimedia\Rdbms\DatabasePostgres\makeUpdateOptionsArray
makeUpdateOptionsArray( $options)
Make UPDATE options array for Database::makeUpdateOptions.
Definition: DatabasePostgres.php:656
Wikimedia\Rdbms\DatabasePostgres\getSchemas
getSchemas()
Return list of schemas which are accessible without schema name This is list does not contain magic k...
Definition: DatabasePostgres.php:990
Wikimedia\Rdbms\DatabasePostgres\implicitGroupby
implicitGroupby()
Returns true if this database does an implicit sort when doing GROUP BY.
Definition: DatabasePostgres.php:67
Wikimedia\Rdbms\DatabasePostgres\remappedTableName
remappedTableName( $name)
Definition: DatabasePostgres.php:737
Wikimedia\Rdbms\DatabasePostgres\addQuotes
addQuotes( $s)
Adds quotes and backslashes.
Definition: DatabasePostgres.php:1296
Wikimedia\Rdbms\DatabasePostgres\$connectString
string $connectString
Connect string to open a PostgreSQL connection.
Definition: DatabasePostgres.php:43
Wikimedia\Rdbms\DatabasePostgres\fetchAffectedRowCount
fetchAffectedRowCount()
Definition: DatabasePostgres.php:385
Wikimedia\Rdbms\DatabasePostgres\getCoreSchemas
getCoreSchemas()
Return schema names for temporary tables and core application tables.
Definition: DatabasePostgres.php:1090
n
while(( $__line=Maintenance::readconsole()) !==false) print n
Definition: eval.php:64
Wikimedia\Rdbms\DatabasePostgres\fieldInfo
fieldInfo( $table, $field)
Definition: DatabasePostgres.php:1259
captcha-old.count
count
Definition: captcha-old.py:249
Wikimedia\Rdbms\Database\$password
string $password
Password used to establish the current connection.
Definition: Database.php:83
Wikimedia\Rdbms\DatabasePostgres\unlock
unlock( $lockName, $method)
Release a lock.
Definition: DatabasePostgres.php:1439
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImgAuthModifyHeaders':Executed just before a file is streamed to a user via img_auth.php, allowing headers to be modified beforehand. $title:LinkTarget object & $headers:HTTP headers(name=> value, names are case insensitive). Two headers get special handling:If-Modified-Since(value must be a valid HTTP date) and Range(must be of the form "bytes=(\d*-\d*)") will be honored when streaming the file. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED since 1.16! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:2042
Wikimedia\Rdbms\Database\$delimiter
string $delimiter
Definition: Database.php:134
Wikimedia\Rdbms\Database\endAtomic
endAtomic( $fname=__METHOD__)
Ends an atomic section of SQL statements.
Definition: Database.php:3703
Wikimedia\Rdbms\Database\indexName
indexName( $index)
Allows for index remapping in queries where this is not consistent across DBMS.
Definition: Database.php:2652
Wikimedia\Rdbms\DatabasePostgres\fieldType
fieldType( $res, $index)
pg_field_type() wrapper
Definition: DatabasePostgres.php:1269
Wikimedia\Rdbms\DatabaseDomain\getTablePrefix
getTablePrefix()
Definition: DatabaseDomain.php:172
Wikimedia\Rdbms\DatabasePostgres\$numericVersion
float string $numericVersion
Definition: DatabasePostgres.php:41
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
Wikimedia\Rdbms\Database\normalizeConditions
normalizeConditions( $conds, $fname)
Definition: Database.php:1903
$params
$params
Definition: styleTest.css.php:44
$s
$s
Definition: mergeMessageFileList.php:187
Wikimedia\Rdbms\Database\extractSingleFieldFromList
extractSingleFieldFromList( $var)
Definition: Database.php:1926
DBO_SSL
const DBO_SSL
Definition: defines.php:17
Wikimedia\Rdbms\DatabaseDomain\getDatabase
getDatabase()
Definition: DatabaseDomain.php:158
Wikimedia\Rdbms\DatabasePostgres
Definition: DatabasePostgres.php:33
$res
$res
Definition: database.txt:21
Wikimedia\Rdbms\ResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: ResultWrapper.php:24
Wikimedia\Rdbms\DatabasePostgres\makeSelectOptions
makeSelectOptions( $options)
Returns an optional USE INDEX clause to go after the table, and a string to go at the end of the quer...
Definition: DatabasePostgres.php:1317
Wikimedia\Rdbms\DatabasePostgres\textFieldSize
textFieldSize( $table, $field)
Returns the size of a text field, or -1 for "unlimited".
Definition: DatabasePostgres.php:769
Wikimedia\Rdbms\Database\cancelAtomic
cancelAtomic( $fname=__METHOD__, AtomicSectionIdentifier $sectionId=null)
Cancel an atomic section of SQL statements.
Definition: Database.php:3737
Wikimedia\Rdbms\DatabasePostgres\indexUnique
indexUnique( $table, $index, $fname=__METHOD__)
Definition: DatabasePostgres.php:509
Wikimedia\Rdbms\DatabasePostgres\insertId
insertId()
Get the inserted value of an auto-increment row.
Definition: DatabasePostgres.php:351
Wikimedia\Rdbms\DatabasePostgres\fetchObject
fetchObject( $res)
Fetch the next row from the given result object, in object form.
Definition: DatabasePostgres.php:271
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Wikimedia\Rdbms\DatabasePostgres\aggregateValue
aggregateValue( $valuedata, $valuename='value')
Return aggregated value alias.
Definition: DatabasePostgres.php:958
Wikimedia\Rdbms\DatabasePostgres\open
open( $server, $user, $password, $dbName, $schema, $tablePrefix)
Open a new connection to the database (closing any existing one)
Definition: DatabasePostgres.php:89
Wikimedia\Rdbms\DatabasePostgres\roleExists
roleExists( $roleName)
Returns true if a given role (i.e.
Definition: DatabasePostgres.php:1247
Wikimedia\Rdbms\DatabasePostgres\nativeInsertSelect
nativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname=__METHOD__, $insertOptions=[], $selectOptions=[], $selectJoinConds=[])
INSERT SELECT wrapper $varMap must be an associative array of the form [ 'dest1' => 'source1',...
Definition: DatabasePostgres.php:687
Wikimedia\Rdbms\DatabasePostgres\insert
insert( $table, $args, $fname=__METHOD__, $options=[])
@inheritDoc
Definition: DatabasePostgres.php:577
Wikimedia\Rdbms\Database\begin
begin( $fname=__METHOD__, $mode=self::TRANSACTION_EXPLICIT)
Begin a transaction.
Definition: Database.php:3826
Wikimedia\Rdbms\DatabasePostgres\$coreSchema
string $coreSchema
Definition: DatabasePostgres.php:45
FROM
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to and or sell copies of the and to permit persons to whom the Software is furnished to do subject to the following WITHOUT WARRANTY OF ANY EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR ARISING FROM
Definition: MIT-LICENSE.txt:10
Wikimedia\Rdbms\DatabasePostgres\encodeBlob
encodeBlob( $b)
Some DBMSs have a special format for inserting into blob fields, they don't allow simple quoted strin...
Definition: DatabasePostgres.php:1277
Wikimedia\Rdbms\DatabasePostgres\makeConnectionString
makeConnectionString( $vars)
Definition: DatabasePostgres.php:201
Wikimedia\Rdbms\DatabasePostgres\lockIsFree
lockIsFree( $lockName, $method)
Check to see if a named lock is not locked by any thread (non-blocking)
Definition: DatabasePostgres.php:1406
user
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such and we might be restricted by PHP settings such as safe mode or open_basedir We cannot assume that the software even has read access anywhere useful Many shared hosts run all users web applications under the same user
Definition: distributors.txt:9
Wikimedia\Rdbms\DatabasePostgres\isTransactableQuery
isTransactableQuery( $sql)
Determine whether a SQL statement is sensitive to isolation level.
Definition: DatabasePostgres.php:214
Wikimedia\Rdbms\Database\nonNativeInsertSelect
nonNativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname=__METHOD__, $insertOptions=[], $selectOptions=[], $selectJoinConds=[])
Implementation of insertSelect() based on select() and insert()
Definition: Database.php:3028
Wikimedia\Rdbms\DatabasePostgres\schemaExists
schemaExists( $schema)
Query whether a given schema exists.
Definition: DatabasePostgres.php:1231
Wikimedia\Rdbms\DatabasePostgres\implicitOrderby
implicitOrderby()
Returns true if this database does an implicit order by when the column has an index For example: SEL...
Definition: DatabasePostgres.php:71
Wikimedia\Rdbms\Database\startAtomic
startAtomic( $fname=__METHOD__, $cancelable=self::ATOMIC_NOT_CANCELABLE)
Begin an atomic section of SQL statements.
Definition: Database.php:3673
Wikimedia\Rdbms\DatabasePostgres\limitResult
limitResult( $sql, $limit, $offset=false)
Construct a LIMIT query with optional offset.
Definition: DatabasePostgres.php:786
tableName
We use the convention $dbr for read and $dbw for write to help you keep track of whether the database object is a the world will explode Or to be a subsequent write query which succeeded on the master may fail when replicated to the slave due to a unique key collision Replication on the slave will stop and it may take hours to repair the database and get it back online Setting read_only in my cnf on the slave will avoid this but given the dire we prefer to have as many checks as possible We provide a but the wrapper functions like please read the documentation for tableName() and addQuotes(). You will need both of them. ------------------------------------------------------------------------ Basic query optimisation ------------------------------------------------------------------------ MediaWiki developers who need to write DB queries should have some understanding of databases and the performance issues associated with them. Patches containing unacceptably slow features will not be accepted. Unindexed queries are generally not welcome in MediaWiki
Wikimedia\Rdbms\DatabasePostgres\duplicateTableStructure
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Creates a new table with structure copied from existing table.
Definition: DatabasePostgres.php:811
Wikimedia\Rdbms\PostgresField\fromText
static fromText(DatabasePostgres $db, $table, $field)
Definition: PostgresField.php:15
Wikimedia\Rdbms\DatabasePostgres\doQuery
doQuery( $sql)
Run a query and return a DBMS-dependent wrapper (that has all IResultWrapper methods)
Definition: DatabasePostgres.php:219
Wikimedia\Rdbms\DatabasePostgres\buildStringCast
buildStringCast( $field)
Definition: DatabasePostgres.php:1362
Wikimedia\Rdbms\DatabasePostgres\pg_array_parse
pg_array_parse( $text, &$output, $limit=false, $offset=1)
Posted by cc[plus]php[at]c2se[dot]com on 25-Mar-2009 09:12 to https://secure.php.net/manual/en/ref....
Definition: DatabasePostgres.php:931
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Wikimedia\Rdbms\DatabasePostgres\lastErrno
lastErrno()
Get the last error number.
Definition: DatabasePostgres.php:377
Wikimedia\Rdbms\Database\$phpError
string bool $phpError
Definition: Database.php:77
Wikimedia\Rdbms\Database\$user
string $user
User that this instance is currently connected under the name of.
Definition: Database.php:81
Wikimedia\Rdbms\DatabasePostgres\$lastResultHandle
resource $lastResultHandle
Definition: DatabasePostgres.php:38
$output
$output
Definition: SyntaxHighlight.php:334
$vars
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
Definition: hooks.txt:2278
Wikimedia\Rdbms\DatabasePostgres\selectSQLText
selectSQLText( $table, $vars, $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
The equivalent of IDatabase::select() except that the constructed SQL is returned,...
Definition: DatabasePostgres.php:522
Wikimedia\Rdbms\Database\commit
commit( $fname=__METHOD__, $flush=self::FLUSHING_ONE)
Commits a transaction previously started using begin().
Definition: Database.php:3890
Wikimedia\Rdbms\DatabasePostgres\numRows
numRows( $res)
Get the number of rows in a query result.
Definition: DatabasePostgres.php:312
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
port
storage can be distributed across multiple and multiple web servers can use the same cache cluster *********************W A R N I N G ***********************Memcached has no security or authentication Please ensure that your server is appropriately and that the port(s) used for memcached servers are not publicly accessible. Otherwise
Wikimedia\Rdbms\NextSequenceValue
Used by Database::nextSequenceValue() so Database::insert() can detect values coming from the depreca...
Definition: NextSequenceValue.php:11
Wikimedia\Rdbms\DatabasePostgres\strencode
strencode( $s)
Wrapper for addslashes()
Definition: DatabasePostgres.php:1291
Wikimedia\Rdbms\DBQueryError
Definition: DBQueryError.php:27
Wikimedia\Rdbms\DatabasePostgres\wasConnectionError
wasConnectionError( $errno)
Do not use this method outside of Database/DBError classes.
Definition: DatabasePostgres.php:800
$fname
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
Definition: Setup.php:121
Wikimedia\Rdbms\Database\installErrorHandler
installErrorHandler()
Set a custom error handler for logging errors during database connection.
Definition: Database.php:863
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
Wikimedia\Rdbms\Database\restoreErrorHandler
restoreErrorHandler()
Restore the previous error handler and return the last PHP error for this DB.
Definition: Database.php:874
key
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message key
Definition: hooks.txt:2213
Wikimedia\Rdbms\DatabasePostgres\serverIsReadOnly
serverIsReadOnly()
Definition: DatabasePostgres.php:1455
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2221
$value
$value
Definition: styleTest.css.php:49
Wikimedia\Rdbms\DatabasePostgres\timestamp
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
Definition: DatabasePostgres.php:907
Wikimedia\Rdbms\DatabasePostgres\relationSchemaQualifier
relationSchemaQualifier()
Definition: DatabasePostgres.php:165
Wikimedia\Rdbms\DatabasePostgres\getServer
getServer()
Get the server hostname or IP address.
Definition: DatabasePostgres.php:1346
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:2044
Wikimedia\Rdbms\Database\$conn
resource null $conn
Database connection.
Definition: Database.php:106
Wikimedia\Rdbms\DatabasePostgres\decodeBlob
decodeBlob( $b)
Some DBMSs return a special placeholder object representing blob fields in result objects.
Definition: DatabasePostgres.php:1281
Wikimedia\Rdbms\Database\query
query( $sql, $fname=__METHOD__, $tempIgnore=false)
Run an SQL query and return the result.
Definition: Database.php:1136
Wikimedia\Rdbms\DatabasePostgres\getCurrentSchema
getCurrentSchema()
Return current schema (executes SELECT current_schema()) Needs transaction.
Definition: DatabasePostgres.php:973
Wikimedia\Rdbms\DBUnexpectedError
Definition: DBUnexpectedError.php:27
Wikimedia\Rdbms\DatabasePostgres\realTableName
realTableName( $name, $format='quoted')
Definition: DatabasePostgres.php:746
Wikimedia\Rdbms\Database\selectField
selectField( $table, $var, $cond='', $fname=__METHOD__, $options=[], $join_conds=[])
A SELECT wrapper which returns a single field from a single result row.
Definition: Database.php:1515
Wikimedia\Rdbms\DatabasePostgres\nextSequenceValue
nextSequenceValue( $seqName)
Deprecated method, calls should be removed.
Definition: DatabasePostgres.php:750
Wikimedia\Rdbms\DatabasePostgres\buildConcat
buildConcat( $stringList)
Build a concatenation list to feed into a SQL query.
Definition: DatabasePostgres.php:1350
Wikimedia\Rdbms\Database\makeList
makeList( $a, $mode=self::LIST_COMMA)
Makes an encoded list of strings from an array.
Definition: Database.php:2125
Wikimedia\Rdbms\DatabasePostgres\getType
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
Definition: DatabasePostgres.php:63
Wikimedia\Rdbms\Database\addIdentifierQuotes
addIdentifierQuotes( $s)
Quotes an identifier using backticks or "double quotes" depending on the database type.
Definition: Database.php:2682
Wikimedia\Rdbms\DatabasePostgres\getServerVersion
getServerVersion()
A string describing the current software version, like from mysql_get_server_info().
Definition: DatabasePostgres.php:1107
$args
if( $line===false) $args
Definition: cdb.php:64
Wikimedia\Rdbms\Database\close
close()
Close the database connection.
Definition: Database.php:925
Wikimedia\Rdbms\DatabasePostgres\lastError
lastError()
Get a description of the last error.
Definition: DatabasePostgres.php:365
$rows
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction $rows
Definition: hooks.txt:2683
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:2044
Wikimedia\Rdbms\DatabasePostgres\__construct
__construct(array $params)
Definition: DatabasePostgres.php:56
Wikimedia\Rdbms\DatabasePostgres\constraintExists
constraintExists( $table, $constraint)
Definition: DatabasePostgres.php:1210
Wikimedia\Rdbms\DatabasePostgres\wasLockTimeout
wasLockTimeout()
Determines if the last failure was due to a lock timeout.
Definition: DatabasePostgres.php:795
Wikimedia\Rdbms\DatabasePostgres\streamStatementEnd
streamStatementEnd(&$sql, &$newLine)
Called by sourceStream() to check if we've reached a statement end.
Definition: DatabasePostgres.php:1366
Wikimedia\Rdbms\Database\makeGroupByWithHaving
makeGroupByWithHaving( $options)
Returns an optional GROUP BY with an optional HAVING.
Definition: Database.php:1660
Wikimedia\Rdbms\DatabaseDomain\getSchema
getSchema()
Definition: DatabaseDomain.php:165
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Wikimedia\Rdbms\DBConnectionError
Definition: DBConnectionError.php:26
Wikimedia
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
Wikimedia\Rdbms\DatabasePostgres\sequenceExists
sequenceExists( $sequence, $schema=false)
Definition: DatabasePostgres.php:1170
Wikimedia\Rdbms\Database\$server
string $server
Server that this instance is currently connected to.
Definition: Database.php:79
$keys
$keys
Definition: testCompression.php:67
Wikimedia\Rdbms\DatabasePostgres\tableExists
tableExists( $table, $fname=__METHOD__, $schema=false)
For backward compatibility, this function checks both tables and views.
Definition: DatabasePostgres.php:1166
Wikimedia\Rdbms\DatabasePostgres\$keywordTableMap
string[] $keywordTableMap
Map of (reserved table name => alternate table name)
Definition: DatabasePostgres.php:49
Wikimedia\Rdbms\DatabasePostgres\buildGroupConcatField
buildGroupConcatField( $delimiter, $table, $field, $conds='', $options=[], $join_conds=[])
Definition: DatabasePostgres.php:1354
Wikimedia\Rdbms\Database\makeOrderBy
makeOrderBy( $options)
Returns an optional ORDER BY.
Definition: Database.php:1686
Wikimedia\Rdbms\DatabasePostgres\dataSeek
dataSeek( $res, $row)
Change the position of the cursor in a result object.
Definition: DatabasePostgres.php:357
Wikimedia\Rdbms\DatabasePostgres\ruleExists
ruleExists( $table, $rule)
Definition: DatabasePostgres.php:1198
Wikimedia\Rdbms\Database\select
select( $table, $vars, $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
Execute a SELECT query constructed using the various parameters provided.
Definition: Database.php:1698
Wikimedia\Rdbms\DatabasePostgres\wasKnownStatementRollbackError
wasKnownStatementRollbackError()
Definition: DatabasePostgres.php:807
Wikimedia\Rdbms\DatabasePostgres\fetchRow
fetchRow( $res)
Fetch the next row from the given result object, in associative array form.
Definition: DatabasePostgres.php:293
Wikimedia\Rdbms\DatabasePostgres\fieldName
fieldName( $res, $n)
Get a field name in a result object.
Definition: DatabasePostgres.php:343
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
Wikimedia\Rdbms\DatabasePostgres\dumpError
dumpError()
Definition: DatabasePostgres.php:238
Wikimedia\Rdbms\DatabasePostgres\determineCoreSchema
determineCoreSchema( $desiredSchema)
Determine default schema for the current application Adjust this session schema search path if desire...
Definition: DatabasePostgres.php:1043
Wikimedia\Rdbms\DatabasePostgres\getSearchPath
getSearchPath()
Return search patch for schemas This is different from getSchemas() since it contain magic keywords (...
Definition: DatabasePostgres.php:1009
Wikimedia\Rdbms\DatabasePostgres\getCoreSchema
getCoreSchema()
Return schema name for core application tables.
Definition: DatabasePostgres.php:1080
Wikimedia\Rdbms\DatabaseDomain
Class to handle database/prefix specification for IDatabase domains.
Definition: DatabaseDomain.php:28
Wikimedia\Rdbms\DatabasePostgres\indexInfo
indexInfo( $table, $index, $fname=__METHOD__)
Get information about an index into an object.
Definition: DatabasePostgres.php:431
Wikimedia\Rdbms\DatabasePostgres\$tempSchema
string $tempSchema
Definition: DatabasePostgres.php:47
Wikimedia\Rdbms\DatabasePostgres\triggerExists
triggerExists( $table, $trigger)
Definition: DatabasePostgres.php:1174
Wikimedia\Rdbms\DatabasePostgres\currentSequenceValue
currentSequenceValue( $seqName)
Return the current value of a sequence.
Definition: DatabasePostgres.php:760
Wikimedia\Rdbms\DatabasePostgres\setSearchPath
setSearchPath( $search_path)
Update search_path, values should already be sanitized Values may contain magic keywords like "$user"...
Definition: DatabasePostgres.php:1025
server
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such and we might be restricted by PHP settings such as safe mode or open_basedir We cannot assume that the software even has read access anywhere useful Many shared hosts run all users web applications under the same so they can t rely on Unix and must forbid reads to even standard directories like tmp lest users read each others files We cannot assume that the user has the ability to install or run any programs not written as web accessible PHP scripts Since anything that works on cheap shared hosting will work if you have shell or root access MediaWiki s design is based around catering to the lowest common denominator Although we support higher end setups as the way many things work by default is tailored toward shared hosting These defaults are unconventional from the point of view of and they certainly aren t ideal for someone who s installing MediaWiki as MediaWiki does not conform to normal Unix filesystem layout Hopefully we ll offer direct support for standard layouts in the but for now *any change to the location of files is unsupported *Moving things and leaving symlinks will *probably *not break but it is *strongly *advised not to try any more intrusive changes to get MediaWiki to conform more closely to your filesystem hierarchy Any such attempt will almost certainly result in unnecessary bugs The standard recommended location to install relative to the web is it should be possible to enable the appropriate rewrite rules by if you can reconfigure the web server
Definition: distributors.txt:53
Wikimedia\Rdbms\DatabasePostgres\wasDeadlock
wasDeadlock()
Determines if the last failure was due to a deadlock.
Definition: DatabasePostgres.php:790
Wikimedia\Rdbms\DatabasePostgres\doSelectDomain
doSelectDomain(DatabaseDomain $domain)
Definition: DatabasePostgres.php:178
Wikimedia\Rdbms\PostgresBlob
Definition: PostgresBlob.php:5
Wikimedia\Rdbms\DatabasePostgres\lock
lock( $lockName, $method, $timeout=5)
Acquire a named lock.
Definition: DatabasePostgres.php:1419
Wikimedia\Rdbms\DatabasePostgres\estimateRowCount
estimateRowCount( $table, $var=' *', $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
Estimate rows in dataset Returns estimated count, based on EXPLAIN output This is not necessarily an ...
Definition: DatabasePostgres.php:408
Wikimedia\Rdbms\DatabasePostgres\hasConstraint
hasConstraint( $name)
Definition: DatabasePostgres.php:75
Wikimedia\Rdbms\DatabasePostgres\listTables
listTables( $prefix=null, $fname=__METHOD__)
@suppress SecurityCheck-SQLInjection array_map not recognized T204911
Definition: DatabasePostgres.php:890
Wikimedia\Rdbms\DatabasePostgres\databasesAreIndependent
databasesAreIndependent()
Returns true if DBs are assumed to be on potentially different servers.
Definition: DatabasePostgres.php:174
Wikimedia\Rdbms\DatabasePostgres\$port
int bool $port
Definition: DatabasePostgres.php:35
Wikimedia\Rdbms\Database\getDBname
getDBname()
Get the current DB name.
Definition: Database.php:2325
Wikimedia\Rdbms\DatabasePostgres\indexAttributes
indexAttributes( $index, $schema=false)
Definition: DatabasePostgres.php:446
Wikimedia\Rdbms\Blob
Definition: Blob.php:5