MediaWiki  1.30.0
DatabaseMysqlBase.php
Go to the documentation of this file.
1 <?php
23 namespace Wikimedia\Rdbms;
24 
25 use DateTime;
26 use DateTimeZone;
28 use InvalidArgumentException;
29 use Exception;
30 use stdClass;
31 
40 abstract class DatabaseMysqlBase extends Database {
46  protected $lagDetectionOptions = [];
48  protected $useGTIDs = false;
50  protected $sslKeyPath;
52  protected $sslCertPath;
54  protected $sslCAFile;
56  protected $sslCAPath;
58  protected $sslCiphers;
60  protected $sqlMode;
62  protected $utf8Mode;
63 
65  private $serverVersion = null;
66 
85  function __construct( array $params ) {
86  $this->lagDetectionMethod = isset( $params['lagDetectionMethod'] )
87  ? $params['lagDetectionMethod']
88  : 'Seconds_Behind_Master';
89  $this->lagDetectionOptions = isset( $params['lagDetectionOptions'] )
90  ? $params['lagDetectionOptions']
91  : [];
92  $this->useGTIDs = !empty( $params['useGTIDs' ] );
93  foreach ( [ 'KeyPath', 'CertPath', 'CAFile', 'CAPath', 'Ciphers' ] as $name ) {
94  $var = "ssl{$name}";
95  if ( isset( $params[$var] ) ) {
96  $this->$var = $params[$var];
97  }
98  }
99  $this->sqlMode = isset( $params['sqlMode'] ) ? $params['sqlMode'] : '';
100  $this->utf8Mode = !empty( $params['utf8Mode'] );
101 
102  parent::__construct( $params );
103  }
104 
108  public function getType() {
109  return 'mysql';
110  }
111 
120  public function open( $server, $user, $password, $dbName ) {
121  # Close/unset connection handle
122  $this->close();
123 
124  $this->mServer = $server;
125  $this->mUser = $user;
126  $this->mPassword = $password;
127  $this->mDBname = $dbName;
128 
129  $this->installErrorHandler();
130  try {
131  $this->mConn = $this->mysqlConnect( $this->mServer );
132  } catch ( Exception $ex ) {
133  $this->restoreErrorHandler();
134  throw $ex;
135  }
136  $error = $this->restoreErrorHandler();
137 
138  # Always log connection errors
139  if ( !$this->mConn ) {
140  if ( !$error ) {
141  $error = $this->lastError();
142  }
143  $this->connLogger->error(
144  "Error connecting to {db_server}: {error}",
145  $this->getLogContext( [
146  'method' => __METHOD__,
147  'error' => $error,
148  ] )
149  );
150  $this->connLogger->debug( "DB connection error\n" .
151  "Server: $server, User: $user, Password: " .
152  substr( $password, 0, 3 ) . "..., error: " . $error . "\n" );
153 
154  $this->reportConnectionError( $error );
155  }
156 
157  if ( $dbName != '' ) {
158  MediaWiki\suppressWarnings();
159  $success = $this->selectDB( $dbName );
160  MediaWiki\restoreWarnings();
161  if ( !$success ) {
162  $this->queryLogger->error(
163  "Error selecting database {db_name} on server {db_server}",
164  $this->getLogContext( [
165  'method' => __METHOD__,
166  ] )
167  );
168  $this->queryLogger->debug(
169  "Error selecting database $dbName on server {$this->mServer}" );
170 
171  $this->reportConnectionError( "Error selecting database $dbName" );
172  }
173  }
174 
175  // Tell the server what we're communicating with
176  if ( !$this->connectInitCharset() ) {
177  $this->reportConnectionError( "Error setting character set" );
178  }
179 
180  // Abstract over any insane MySQL defaults
181  $set = [ 'group_concat_max_len = 262144' ];
182  // Set SQL mode, default is turning them all off, can be overridden or skipped with null
183  if ( is_string( $this->sqlMode ) ) {
184  $set[] = 'sql_mode = ' . $this->addQuotes( $this->sqlMode );
185  }
186  // Set any custom settings defined by site config
187  // (e.g. https://dev.mysql.com/doc/refman/4.1/en/innodb-parameters.html)
188  foreach ( $this->mSessionVars as $var => $val ) {
189  // Escape strings but not numbers to avoid MySQL complaining
190  if ( !is_int( $val ) && !is_float( $val ) ) {
191  $val = $this->addQuotes( $val );
192  }
193  $set[] = $this->addIdentifierQuotes( $var ) . ' = ' . $val;
194  }
195 
196  if ( $set ) {
197  // Use doQuery() to avoid opening implicit transactions (DBO_TRX)
198  $success = $this->doQuery( 'SET ' . implode( ', ', $set ) );
199  if ( !$success ) {
200  $this->queryLogger->error(
201  'Error setting MySQL variables on server {db_server} (check $wgSQLMode)',
202  $this->getLogContext( [
203  'method' => __METHOD__,
204  ] )
205  );
206  $this->reportConnectionError(
207  'Error setting MySQL variables on server {db_server} (check $wgSQLMode)' );
208  }
209  }
210 
211  $this->mOpened = true;
212 
213  return true;
214  }
215 
220  protected function connectInitCharset() {
221  if ( $this->utf8Mode ) {
222  // Tell the server we're communicating with it in UTF-8.
223  // This may engage various charset conversions.
224  return $this->mysqlSetCharset( 'utf8' );
225  } else {
226  return $this->mysqlSetCharset( 'binary' );
227  }
228  }
229 
237  abstract protected function mysqlConnect( $realServer );
238 
245  abstract protected function mysqlSetCharset( $charset );
246 
251  public function freeResult( $res ) {
252  if ( $res instanceof ResultWrapper ) {
253  $res = $res->result;
254  }
255  MediaWiki\suppressWarnings();
256  $ok = $this->mysqlFreeResult( $res );
257  MediaWiki\restoreWarnings();
258  if ( !$ok ) {
259  throw new DBUnexpectedError( $this, "Unable to free MySQL result" );
260  }
261  }
262 
269  abstract protected function mysqlFreeResult( $res );
270 
276  public function fetchObject( $res ) {
277  if ( $res instanceof ResultWrapper ) {
278  $res = $res->result;
279  }
280  MediaWiki\suppressWarnings();
281  $row = $this->mysqlFetchObject( $res );
282  MediaWiki\restoreWarnings();
283 
284  $errno = $this->lastErrno();
285  // Unfortunately, mysql_fetch_object does not reset the last errno.
286  // Only check for CR_SERVER_LOST and CR_UNKNOWN_ERROR, as
287  // these are the only errors mysql_fetch_object can cause.
288  // See https://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
289  if ( $errno == 2000 || $errno == 2013 ) {
290  throw new DBUnexpectedError(
291  $this,
292  'Error in fetchObject(): ' . htmlspecialchars( $this->lastError() )
293  );
294  }
295 
296  return $row;
297  }
298 
305  abstract protected function mysqlFetchObject( $res );
306 
312  public function fetchRow( $res ) {
313  if ( $res instanceof ResultWrapper ) {
314  $res = $res->result;
315  }
316  MediaWiki\suppressWarnings();
317  $row = $this->mysqlFetchArray( $res );
318  MediaWiki\restoreWarnings();
319 
320  $errno = $this->lastErrno();
321  // Unfortunately, mysql_fetch_array does not reset the last errno.
322  // Only check for CR_SERVER_LOST and CR_UNKNOWN_ERROR, as
323  // these are the only errors mysql_fetch_array can cause.
324  // See https://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
325  if ( $errno == 2000 || $errno == 2013 ) {
326  throw new DBUnexpectedError(
327  $this,
328  'Error in fetchRow(): ' . htmlspecialchars( $this->lastError() )
329  );
330  }
331 
332  return $row;
333  }
334 
341  abstract protected function mysqlFetchArray( $res );
342 
348  function numRows( $res ) {
349  if ( $res instanceof ResultWrapper ) {
350  $res = $res->result;
351  }
352  MediaWiki\suppressWarnings();
353  $n = $this->mysqlNumRows( $res );
354  MediaWiki\restoreWarnings();
355 
356  // Unfortunately, mysql_num_rows does not reset the last errno.
357  // We are not checking for any errors here, since
358  // these are no errors mysql_num_rows can cause.
359  // See https://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
360  // See https://phabricator.wikimedia.org/T44430
361  return $n;
362  }
363 
370  abstract protected function mysqlNumRows( $res );
371 
376  public function numFields( $res ) {
377  if ( $res instanceof ResultWrapper ) {
378  $res = $res->result;
379  }
380 
381  return $this->mysqlNumFields( $res );
382  }
383 
390  abstract protected function mysqlNumFields( $res );
391 
397  public function fieldName( $res, $n ) {
398  if ( $res instanceof ResultWrapper ) {
399  $res = $res->result;
400  }
401 
402  return $this->mysqlFieldName( $res, $n );
403  }
404 
412  abstract protected function mysqlFieldName( $res, $n );
413 
420  public function fieldType( $res, $n ) {
421  if ( $res instanceof ResultWrapper ) {
422  $res = $res->result;
423  }
424 
425  return $this->mysqlFieldType( $res, $n );
426  }
427 
435  abstract protected function mysqlFieldType( $res, $n );
436 
442  public function dataSeek( $res, $row ) {
443  if ( $res instanceof ResultWrapper ) {
444  $res = $res->result;
445  }
446 
447  return $this->mysqlDataSeek( $res, $row );
448  }
449 
457  abstract protected function mysqlDataSeek( $res, $row );
458 
462  public function lastError() {
463  if ( $this->mConn ) {
464  # Even if it's non-zero, it can still be invalid
465  MediaWiki\suppressWarnings();
466  $error = $this->mysqlError( $this->mConn );
467  if ( !$error ) {
468  $error = $this->mysqlError();
469  }
470  MediaWiki\restoreWarnings();
471  } else {
472  $error = $this->mysqlError();
473  }
474  if ( $error ) {
475  $error .= ' (' . $this->mServer . ')';
476  }
477 
478  return $error;
479  }
480 
487  abstract protected function mysqlError( $conn = null );
488 
496  public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
497  return $this->nativeReplace( $table, $rows, $fname );
498  }
499 
512  public function estimateRowCount( $table, $vars = '*', $conds = '',
513  $fname = __METHOD__, $options = []
514  ) {
515  $options['EXPLAIN'] = true;
516  $res = $this->select( $table, $vars, $conds, $fname, $options );
517  if ( $res === false ) {
518  return false;
519  }
520  if ( !$this->numRows( $res ) ) {
521  return 0;
522  }
523 
524  $rows = 1;
525  foreach ( $res as $plan ) {
526  $rows *= $plan->rows > 0 ? $plan->rows : 1; // avoid resetting to zero
527  }
528 
529  return (int)$rows;
530  }
531 
532  public function tableExists( $table, $fname = __METHOD__ ) {
533  // Split database and table into proper variables as Database::tableName() returns
534  // shared tables prefixed with their database, which do not work in SHOW TABLES statements
535  list( $database, , $prefix, $table ) = $this->qualifiedTableComponents( $table );
536  $tableName = "{$prefix}{$table}";
537 
538  if ( isset( $this->mSessionTempTables[$tableName] ) ) {
539  return true; // already known to exist and won't show in SHOW TABLES anyway
540  }
541 
542  // We can't use buildLike() here, because it specifies an escape character
543  // other than the backslash, which is the only one supported by SHOW TABLES
544  $encLike = $this->escapeLikeInternal( $tableName, '\\' );
545 
546  // If the database has been specified (such as for shared tables), use "FROM"
547  if ( $database !== '' ) {
548  $encDatabase = $this->addIdentifierQuotes( $database );
549  $query = "SHOW TABLES FROM $encDatabase LIKE '$encLike'";
550  } else {
551  $query = "SHOW TABLES LIKE '$encLike'";
552  }
553 
554  return $this->query( $query, $fname )->numRows() > 0;
555  }
556 
562  public function fieldInfo( $table, $field ) {
563  $table = $this->tableName( $table );
564  $res = $this->query( "SELECT * FROM $table LIMIT 1", __METHOD__, true );
565  if ( !$res ) {
566  return false;
567  }
568  $n = $this->mysqlNumFields( $res->result );
569  for ( $i = 0; $i < $n; $i++ ) {
570  $meta = $this->mysqlFetchField( $res->result, $i );
571  if ( $field == $meta->name ) {
572  return new MySQLField( $meta );
573  }
574  }
575 
576  return false;
577  }
578 
586  abstract protected function mysqlFetchField( $res, $n );
587 
597  public function indexInfo( $table, $index, $fname = __METHOD__ ) {
598  # SHOW INDEX works in MySQL 3.23.58, but SHOW INDEXES does not.
599  # SHOW INDEX should work for 3.x and up:
600  # https://dev.mysql.com/doc/mysql/en/SHOW_INDEX.html
601  $table = $this->tableName( $table );
602  $index = $this->indexName( $index );
603 
604  $sql = 'SHOW INDEX FROM ' . $table;
605  $res = $this->query( $sql, $fname );
606 
607  if ( !$res ) {
608  return null;
609  }
610 
611  $result = [];
612 
613  foreach ( $res as $row ) {
614  if ( $row->Key_name == $index ) {
615  $result[] = $row;
616  }
617  }
618 
619  return empty( $result ) ? false : $result;
620  }
621 
626  public function strencode( $s ) {
627  return $this->mysqlRealEscapeString( $s );
628  }
629 
634  abstract protected function mysqlRealEscapeString( $s );
635 
636  public function addQuotes( $s ) {
637  if ( is_bool( $s ) ) {
638  // Parent would transform to int, which does not play nice with MySQL type juggling.
639  // When searching for an int in a string column, the strings are cast to int, which
640  // means false would match any string not starting with a number.
641  $s = (string)(int)$s;
642  }
643  return parent::addQuotes( $s );
644  }
645 
652  public function addIdentifierQuotes( $s ) {
653  // Characters in the range \u0001-\uFFFF are valid in a quoted identifier
654  // Remove NUL bytes and escape backticks by doubling
655  return '`' . str_replace( [ "\0", '`' ], [ '', '``' ], $s ) . '`';
656  }
657 
662  public function isQuotedIdentifier( $name ) {
663  return strlen( $name ) && $name[0] == '`' && substr( $name, -1, 1 ) == '`';
664  }
665 
666  public function getLag() {
667  if ( $this->getLagDetectionMethod() === 'pt-heartbeat' ) {
668  return $this->getLagFromPtHeartbeat();
669  } else {
670  return $this->getLagFromSlaveStatus();
671  }
672  }
673 
677  protected function getLagDetectionMethod() {
679  }
680 
684  protected function getLagFromSlaveStatus() {
685  $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ );
686  $row = $res ? $res->fetchObject() : false;
687  if ( $row && strval( $row->Seconds_Behind_Master ) !== '' ) {
688  return intval( $row->Seconds_Behind_Master );
689  }
690 
691  return false;
692  }
693 
697  protected function getLagFromPtHeartbeat() {
699 
700  if ( isset( $options['conds'] ) ) {
701  // Best method for multi-DC setups: use logical channel names
702  $data = $this->getHeartbeatData( $options['conds'] );
703  } else {
704  // Standard method: use master server ID (works with stock pt-heartbeat)
705  $masterInfo = $this->getMasterServerInfo();
706  if ( !$masterInfo ) {
707  $this->queryLogger->error(
708  "Unable to query master of {db_server} for server ID",
709  $this->getLogContext( [
710  'method' => __METHOD__
711  ] )
712  );
713 
714  return false; // could not get master server ID
715  }
716 
717  $conds = [ 'server_id' => intval( $masterInfo['serverId'] ) ];
718  $data = $this->getHeartbeatData( $conds );
719  }
720 
721  list( $time, $nowUnix ) = $data;
722  if ( $time !== null ) {
723  // @time is in ISO format like "2015-09-25T16:48:10.000510"
724  $dateTime = new DateTime( $time, new DateTimeZone( 'UTC' ) );
725  $timeUnix = (int)$dateTime->format( 'U' ) + $dateTime->format( 'u' ) / 1e6;
726 
727  return max( $nowUnix - $timeUnix, 0.0 );
728  }
729 
730  $this->queryLogger->error(
731  "Unable to find pt-heartbeat row for {db_server}",
732  $this->getLogContext( [
733  'method' => __METHOD__
734  ] )
735  );
736 
737  return false;
738  }
739 
740  protected function getMasterServerInfo() {
742  $key = $cache->makeGlobalKey(
743  'mysql',
744  'master-info',
745  // Using one key for all cluster replica DBs is preferable
746  $this->getLBInfo( 'clusterMasterHost' ) ?: $this->getServer()
747  );
748 
749  return $cache->getWithSetCallback(
750  $key,
751  $cache::TTL_INDEFINITE,
752  function () use ( $cache, $key ) {
753  // Get and leave a lock key in place for a short period
754  if ( !$cache->lock( $key, 0, 10 ) ) {
755  return false; // avoid master connection spike slams
756  }
757 
758  $conn = $this->getLazyMasterHandle();
759  if ( !$conn ) {
760  return false; // something is misconfigured
761  }
762 
763  // Connect to and query the master; catch errors to avoid outages
764  try {
765  $res = $conn->query( 'SELECT @@server_id AS id', __METHOD__ );
766  $row = $res ? $res->fetchObject() : false;
767  $id = $row ? (int)$row->id : 0;
768  } catch ( DBError $e ) {
769  $id = 0;
770  }
771 
772  // Cache the ID if it was retrieved
773  return $id ? [ 'serverId' => $id, 'asOf' => time() ] : false;
774  }
775  );
776  }
777 
783  protected function getHeartbeatData( array $conds ) {
784  // Query time and trip time are not counted
785  $nowUnix = microtime( true );
786  // Do not bother starting implicit transactions here
787  $this->clearFlag( self::DBO_TRX, self::REMEMBER_PRIOR );
788  try {
789  $whereSQL = $this->makeList( $conds, self::LIST_AND );
790  // Use ORDER BY for channel based queries since that field might not be UNIQUE.
791  // Note: this would use "TIMESTAMPDIFF(MICROSECOND,ts,UTC_TIMESTAMP(6))" but the
792  // percision field is not supported in MySQL <= 5.5.
793  $res = $this->query(
794  "SELECT ts FROM heartbeat.heartbeat WHERE $whereSQL ORDER BY ts DESC LIMIT 1"
795  );
796  $row = $res ? $res->fetchObject() : false;
797  } finally {
798  $this->restoreFlags();
799  }
800 
801  return [ $row ? $row->ts : null, $nowUnix ];
802  }
803 
804  protected function getApproximateLagStatus() {
805  if ( $this->getLagDetectionMethod() === 'pt-heartbeat' ) {
806  // Disable caching since this is fast enough and we don't wan't
807  // to be *too* pessimistic by having both the cache TTL and the
808  // pt-heartbeat interval count as lag in getSessionLagStatus()
809  return parent::getApproximateLagStatus();
810  }
811 
812  $key = $this->srvCache->makeGlobalKey( 'mysql-lag', $this->getServer() );
813  $approxLag = $this->srvCache->get( $key );
814  if ( !$approxLag ) {
815  $approxLag = parent::getApproximateLagStatus();
816  $this->srvCache->set( $key, $approxLag, 1 );
817  }
818 
819  return $approxLag;
820  }
821 
822  public function masterPosWait( DBMasterPos $pos, $timeout ) {
823  if ( !( $pos instanceof MySQLMasterPos ) ) {
824  throw new InvalidArgumentException( "Position not an instance of MySQLMasterPos" );
825  }
826 
827  if ( $this->getLBInfo( 'is static' ) === true ) {
828  return 0; // this is a copy of a read-only dataset with no master DB
829  } elseif ( $this->lastKnownReplicaPos && $this->lastKnownReplicaPos->hasReached( $pos ) ) {
830  return 0; // already reached this point for sure
831  }
832 
833  // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
834  if ( $this->useGTIDs && $pos->gtids ) {
835  // Wait on the GTID set (MariaDB only)
836  $gtidArg = $this->addQuotes( implode( ',', $pos->gtids ) );
837  $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
838  } else {
839  // Wait on the binlog coordinates
840  $encFile = $this->addQuotes( $pos->file );
841  $encPos = intval( $pos->pos );
842  $res = $this->doQuery( "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)" );
843  }
844 
845  $row = $res ? $this->fetchRow( $res ) : false;
846  if ( !$row ) {
847  throw new DBExpectedError( $this,
848  "MASTER_POS_WAIT() or MASTER_GTID_WAIT() failed: {$this->lastError()}" );
849  }
850 
851  // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
852  $status = ( $row[0] !== null ) ? intval( $row[0] ) : null;
853  if ( $status === null ) {
854  // T126436: jobs programmed to wait on master positions might be referencing binlogs
855  // with an old master hostname. Such calls make MASTER_POS_WAIT() return null. Try
856  // to detect this and treat the replica DB as having reached the position; a proper master
857  // switchover already requires that the new master be caught up before the switch.
858  $replicationPos = $this->getReplicaPos();
859  if ( $replicationPos && !$replicationPos->channelsMatch( $pos ) ) {
860  $this->lastKnownReplicaPos = $replicationPos;
861  $status = 0;
862  }
863  } elseif ( $status >= 0 ) {
864  // Remember that this position was reached to save queries next time
865  $this->lastKnownReplicaPos = $pos;
866  }
867 
868  return $status;
869  }
870 
876  public function getReplicaPos() {
877  $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ );
878  $row = $this->fetchObject( $res );
879 
880  if ( $row ) {
881  $pos = isset( $row->Exec_master_log_pos )
882  ? $row->Exec_master_log_pos
883  : $row->Exec_Master_Log_Pos;
884  // Also fetch the last-applied GTID set (MariaDB)
885  if ( $this->useGTIDs ) {
886  $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'gtid_slave_pos'", __METHOD__ );
887  $gtidRow = $this->fetchObject( $res );
888  $gtidSet = $gtidRow ? $gtidRow->Value : '';
889  } else {
890  $gtidSet = '';
891  }
892 
893  return new MySQLMasterPos( $row->Relay_Master_Log_File, $pos, $gtidSet );
894  } else {
895  return false;
896  }
897  }
898 
904  public function getMasterPos() {
905  $res = $this->query( 'SHOW MASTER STATUS', __METHOD__ );
906  $row = $this->fetchObject( $res );
907 
908  if ( $row ) {
909  // Also fetch the last-written GTID set (MariaDB)
910  if ( $this->useGTIDs ) {
911  $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_pos'", __METHOD__ );
912  $gtidRow = $this->fetchObject( $res );
913  $gtidSet = $gtidRow ? $gtidRow->Value : '';
914  } else {
915  $gtidSet = '';
916  }
917 
918  return new MySQLMasterPos( $row->File, $row->Position, $gtidSet );
919  } else {
920  return false;
921  }
922  }
923 
924  public function serverIsReadOnly() {
925  $res = $this->query( "SHOW GLOBAL VARIABLES LIKE 'read_only'", __METHOD__ );
926  $row = $this->fetchObject( $res );
927 
928  return $row ? ( strtolower( $row->Value ) === 'on' ) : false;
929  }
930 
935  function useIndexClause( $index ) {
936  return "FORCE INDEX (" . $this->indexName( $index ) . ")";
937  }
938 
943  function ignoreIndexClause( $index ) {
944  return "IGNORE INDEX (" . $this->indexName( $index ) . ")";
945  }
946 
950  function lowPriorityOption() {
951  return 'LOW_PRIORITY';
952  }
953 
957  public function getSoftwareLink() {
958  // MariaDB includes its name in its version string; this is how MariaDB's version of
959  // the mysql command-line client identifies MariaDB servers (see mariadb_connection()
960  // in libmysql/libmysql.c).
961  $version = $this->getServerVersion();
962  if ( strpos( $version, 'MariaDB' ) !== false || strpos( $version, '-maria-' ) !== false ) {
963  return '[{{int:version-db-mariadb-url}} MariaDB]';
964  }
965 
966  // Percona Server's version suffix is not very distinctive, and @@version_comment
967  // doesn't give the necessary info for source builds, so assume the server is MySQL.
968  // (Even Percona's version of mysql doesn't try to make the distinction.)
969  return '[{{int:version-db-mysql-url}} MySQL]';
970  }
971 
975  public function getServerVersion() {
976  // Not using mysql_get_server_info() or similar for consistency: in the handshake,
977  // MariaDB 10 adds the prefix "5.5.5-", and only some newer client libraries strip
978  // it off (see RPL_VERSION_HACK in include/mysql_com.h).
979  if ( $this->serverVersion === null ) {
980  $this->serverVersion = $this->selectField( '', 'VERSION()', '', __METHOD__ );
981  }
982  return $this->serverVersion;
983  }
984 
988  public function setSessionOptions( array $options ) {
989  if ( isset( $options['connTimeout'] ) ) {
990  $timeout = (int)$options['connTimeout'];
991  $this->query( "SET net_read_timeout=$timeout" );
992  $this->query( "SET net_write_timeout=$timeout" );
993  }
994  }
995 
1001  public function streamStatementEnd( &$sql, &$newLine ) {
1002  if ( strtoupper( substr( $newLine, 0, 9 ) ) == 'DELIMITER' ) {
1003  preg_match( '/^DELIMITER\s+(\S+)/', $newLine, $m );
1004  $this->delimiter = $m[1];
1005  $newLine = '';
1006  }
1007 
1008  return parent::streamStatementEnd( $sql, $newLine );
1009  }
1010 
1019  public function lockIsFree( $lockName, $method ) {
1020  $encName = $this->addQuotes( $this->makeLockName( $lockName ) );
1021  $result = $this->query( "SELECT IS_FREE_LOCK($encName) AS lockstatus", $method );
1022  $row = $this->fetchObject( $result );
1023 
1024  return ( $row->lockstatus == 1 );
1025  }
1026 
1033  public function lock( $lockName, $method, $timeout = 5 ) {
1034  $encName = $this->addQuotes( $this->makeLockName( $lockName ) );
1035  $result = $this->query( "SELECT GET_LOCK($encName, $timeout) AS lockstatus", $method );
1036  $row = $this->fetchObject( $result );
1037 
1038  if ( $row->lockstatus == 1 ) {
1039  parent::lock( $lockName, $method, $timeout ); // record
1040  return true;
1041  }
1042 
1043  $this->queryLogger->warning( __METHOD__ . " failed to acquire lock '$lockName'\n" );
1044 
1045  return false;
1046  }
1047 
1055  public function unlock( $lockName, $method ) {
1056  $encName = $this->addQuotes( $this->makeLockName( $lockName ) );
1057  $result = $this->query( "SELECT RELEASE_LOCK($encName) as lockstatus", $method );
1058  $row = $this->fetchObject( $result );
1059 
1060  if ( $row->lockstatus == 1 ) {
1061  parent::unlock( $lockName, $method ); // record
1062  return true;
1063  }
1064 
1065  $this->queryLogger->warning( __METHOD__ . " failed to release lock '$lockName'\n" );
1066 
1067  return false;
1068  }
1069 
1070  private function makeLockName( $lockName ) {
1071  // https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock
1072  // Newer version enforce a 64 char length limit.
1073  return ( strlen( $lockName ) > 64 ) ? sha1( $lockName ) : $lockName;
1074  }
1075 
1076  public function namedLocksEnqueue() {
1077  return true;
1078  }
1079 
1081  return false; // tied to TCP connection
1082  }
1083 
1084  protected function doLockTables( array $read, array $write, $method ) {
1085  $items = [];
1086  foreach ( $write as $table ) {
1087  $items[] = $this->tableName( $table ) . ' WRITE';
1088  }
1089  foreach ( $read as $table ) {
1090  $items[] = $this->tableName( $table ) . ' READ';
1091  }
1092 
1093  $sql = "LOCK TABLES " . implode( ',', $items );
1094  $this->query( $sql, $method );
1095 
1096  return true;
1097  }
1098 
1099  protected function doUnlockTables( $method ) {
1100  $this->query( "UNLOCK TABLES", $method );
1101 
1102  return true;
1103  }
1104 
1108  public function setBigSelects( $value = true ) {
1109  if ( $value === 'default' ) {
1110  if ( $this->mDefaultBigSelects === null ) {
1111  # Function hasn't been called before so it must already be set to the default
1112  return;
1113  } else {
1115  }
1116  } elseif ( $this->mDefaultBigSelects === null ) {
1117  $this->mDefaultBigSelects =
1118  (bool)$this->selectField( false, '@@sql_big_selects', '', __METHOD__ );
1119  }
1120  $encValue = $value ? '1' : '0';
1121  $this->query( "SET sql_big_selects=$encValue", __METHOD__ );
1122  }
1123 
1135  public function deleteJoin(
1136  $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = __METHOD__
1137  ) {
1138  if ( !$conds ) {
1139  throw new DBUnexpectedError( $this, __METHOD__ . ' called with empty $conds' );
1140  }
1141 
1142  $delTable = $this->tableName( $delTable );
1143  $joinTable = $this->tableName( $joinTable );
1144  $sql = "DELETE $delTable FROM $delTable, $joinTable WHERE $delVar=$joinVar ";
1145 
1146  if ( $conds != '*' ) {
1147  $sql .= ' AND ' . $this->makeList( $conds, self::LIST_AND );
1148  }
1149 
1150  return $this->query( $sql, $fname );
1151  }
1152 
1161  public function upsert( $table, array $rows, array $uniqueIndexes,
1162  array $set, $fname = __METHOD__
1163  ) {
1164  if ( !count( $rows ) ) {
1165  return true; // nothing to do
1166  }
1167 
1168  if ( !is_array( reset( $rows ) ) ) {
1169  $rows = [ $rows ];
1170  }
1171 
1172  $table = $this->tableName( $table );
1173  $columns = array_keys( $rows[0] );
1174 
1175  $sql = "INSERT INTO $table (" . implode( ',', $columns ) . ') VALUES ';
1176  $rowTuples = [];
1177  foreach ( $rows as $row ) {
1178  $rowTuples[] = '(' . $this->makeList( $row ) . ')';
1179  }
1180  $sql .= implode( ',', $rowTuples );
1181  $sql .= " ON DUPLICATE KEY UPDATE " . $this->makeList( $set, self::LIST_SET );
1182 
1183  return (bool)$this->query( $sql, $fname );
1184  }
1185 
1191  public function getServerUptime() {
1192  $vars = $this->getMysqlStatus( 'Uptime' );
1193 
1194  return (int)$vars['Uptime'];
1195  }
1196 
1202  public function wasDeadlock() {
1203  return $this->lastErrno() == 1213;
1204  }
1205 
1211  public function wasLockTimeout() {
1212  return $this->lastErrno() == 1205;
1213  }
1214 
1215  public function wasErrorReissuable() {
1216  return $this->lastErrno() == 2013 || $this->lastErrno() == 2006;
1217  }
1218 
1224  public function wasReadOnlyError() {
1225  return $this->lastErrno() == 1223 ||
1226  ( $this->lastErrno() == 1290 && strpos( $this->lastError(), '--read-only' ) !== false );
1227  }
1228 
1229  public function wasConnectionError( $errno ) {
1230  return $errno == 2013 || $errno == 2006;
1231  }
1232 
1240  public function duplicateTableStructure(
1241  $oldName, $newName, $temporary = false, $fname = __METHOD__
1242  ) {
1243  $tmp = $temporary ? 'TEMPORARY ' : '';
1244  $newName = $this->addIdentifierQuotes( $newName );
1245  $oldName = $this->addIdentifierQuotes( $oldName );
1246  $query = "CREATE $tmp TABLE $newName (LIKE $oldName)";
1247 
1248  return $this->query( $query, $fname );
1249  }
1250 
1258  public function listTables( $prefix = null, $fname = __METHOD__ ) {
1259  $result = $this->query( "SHOW TABLES", $fname );
1260 
1261  $endArray = [];
1262 
1263  foreach ( $result as $table ) {
1264  $vars = get_object_vars( $table );
1265  $table = array_pop( $vars );
1266 
1267  if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
1268  $endArray[] = $table;
1269  }
1270  }
1271 
1272  return $endArray;
1273  }
1274 
1280  public function dropTable( $tableName, $fName = __METHOD__ ) {
1281  if ( !$this->tableExists( $tableName, $fName ) ) {
1282  return false;
1283  }
1284 
1285  return $this->query( "DROP TABLE IF EXISTS " . $this->tableName( $tableName ), $fName );
1286  }
1287 
1294  private function getMysqlStatus( $which = "%" ) {
1295  $res = $this->query( "SHOW STATUS LIKE '{$which}'" );
1296  $status = [];
1297 
1298  foreach ( $res as $row ) {
1299  $status[$row->Variable_name] = $row->Value;
1300  }
1301 
1302  return $status;
1303  }
1304 
1314  public function listViews( $prefix = null, $fname = __METHOD__ ) {
1315  // The name of the column containing the name of the VIEW
1316  $propertyName = 'Tables_in_' . $this->mDBname;
1317 
1318  // Query for the VIEWS
1319  $res = $this->query( 'SHOW FULL TABLES WHERE TABLE_TYPE = "VIEW"' );
1320  $allViews = [];
1321  foreach ( $res as $row ) {
1322  array_push( $allViews, $row->$propertyName );
1323  }
1324 
1325  if ( is_null( $prefix ) || $prefix === '' ) {
1326  return $allViews;
1327  }
1328 
1329  $filteredViews = [];
1330  foreach ( $allViews as $viewName ) {
1331  // Does the name of this VIEW start with the table-prefix?
1332  if ( strpos( $viewName, $prefix ) === 0 ) {
1333  array_push( $filteredViews, $viewName );
1334  }
1335  }
1336 
1337  return $filteredViews;
1338  }
1339 
1348  public function isView( $name, $prefix = null ) {
1349  return in_array( $name, $this->listViews( $prefix ) );
1350  }
1351 
1358  protected function indexName( $index ) {
1373  $renamed = [
1374  'ar_usertext_timestamp' => 'usertext_timestamp',
1375  'un_user_id' => 'user_id',
1376  'un_user_ip' => 'user_ip',
1377  ];
1378 
1379  if ( isset( $renamed[$index] ) ) {
1380  return $renamed[$index];
1381  } else {
1382  return $index;
1383  }
1384  }
1385 }
1386 
1387 class_alias( DatabaseMysqlBase::class, 'DatabaseMysqlBase' );
Wikimedia\Rdbms\DatabaseMysqlBase\doLockTables
doLockTables(array $read, array $write, $method)
Helper function for lockTables() that handles the actual table locking.
Definition: DatabaseMysqlBase.php:1084
Wikimedia\Rdbms\DatabaseMysqlBase\addIdentifierQuotes
addIdentifierQuotes( $s)
MySQL uses backticks for identifier quoting instead of the sql standard "double quotes".
Definition: DatabaseMysqlBase.php:652
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:45
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:244
Wikimedia\Rdbms\DatabaseMysqlBase\masterPosWait
masterPosWait(DBMasterPos $pos, $timeout)
Wait for the replica DB to catch up to a given master position.
Definition: DatabaseMysqlBase.php:822
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
Wikimedia\Rdbms\DatabaseMysqlBase\$sslKeyPath
string null $sslKeyPath
Definition: DatabaseMysqlBase.php:50
Wikimedia\Rdbms\DatabaseMysqlBase\getLagDetectionMethod
getLagDetectionMethod()
Definition: DatabaseMysqlBase.php:677
Wikimedia\Rdbms\DatabaseMysqlBase\indexInfo
indexInfo( $table, $index, $fname=__METHOD__)
Get information about an index into an object Returns false if the index does not exist.
Definition: DatabaseMysqlBase.php:597
Wikimedia\Rdbms\DatabaseMysqlBase\setSessionOptions
setSessionOptions(array $options)
Definition: DatabaseMysqlBase.php:988
Wikimedia\Rdbms\DatabaseMysqlBase\getServerUptime
getServerUptime()
Determines how long the server has been up.
Definition: DatabaseMysqlBase.php:1191
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlRealEscapeString
mysqlRealEscapeString( $s)
Wikimedia\Rdbms\DatabaseMysqlBase\$sslCAPath
string null $sslCAPath
Definition: DatabaseMysqlBase.php:56
captcha-old.count
count
Definition: captcha-old.py:249
Wikimedia\Rdbms\DatabaseMysqlBase\getApproximateLagStatus
getApproximateLagStatus()
Get a replica DB lag estimate for this server.
Definition: DatabaseMysqlBase.php:804
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlFieldName
mysqlFieldName( $res, $n)
Get the name of the specified field in a result.
Wikimedia\Rdbms\DatabaseMysqlBase\numRows
numRows( $res)
Definition: DatabaseMysqlBase.php:348
Wikimedia\Rdbms\DatabaseMysqlBase\lowPriorityOption
lowPriorityOption()
Definition: DatabaseMysqlBase.php:950
Wikimedia\Rdbms\Database\nativeReplace
nativeReplace( $table, $rows, $fname)
REPLACE query wrapper for MySQL and SQLite, which have a native REPLACE statement.
Definition: Database.php:2242
$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. '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 '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! 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! 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:1963
Wikimedia\Rdbms\DatabaseMysqlBase\wasLockTimeout
wasLockTimeout()
Determines if the last failure was due to a lock timeout.
Definition: DatabaseMysqlBase.php:1211
$status
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action or null $user:User who performed the tagging when the tagging is subsequent to the action or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1245
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\DatabaseMysqlBase\upsert
upsert( $table, array $rows, array $uniqueIndexes, array $set, $fname=__METHOD__)
Definition: DatabaseMysqlBase.php:1161
Wikimedia\Rdbms\DatabaseMysqlBase\$sslCertPath
string null $sslCertPath
Definition: DatabaseMysqlBase.php:52
Wikimedia\Rdbms\DatabaseMysqlBase\$useGTIDs
bool $useGTIDs
bool Whether to use GTID methods
Definition: DatabaseMysqlBase.php:48
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlNumRows
mysqlNumRows( $res)
Get number of rows in result.
Wikimedia\Rdbms\DatabaseMysqlBase\getHeartbeatData
getHeartbeatData(array $conds)
Definition: DatabaseMysqlBase.php:783
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
$fname
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition: Setup.php:36
Wikimedia\Rdbms\DBMasterPos
An object representing a master or replica DB position in a replicated setup.
Definition: DBMasterPos.php:10
$params
$params
Definition: styleTest.css.php:40
$s
$s
Definition: mergeMessageFileList.php:188
Wikimedia\Rdbms\DatabaseMysqlBase\ignoreIndexClause
ignoreIndexClause( $index)
Definition: DatabaseMysqlBase.php:943
$res
$res
Definition: database.txt:21
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
Wikimedia\Rdbms\ResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: ResultWrapper.php:24
$success
$success
Definition: NoLocalSettings.php:44
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlFreeResult
mysqlFreeResult( $res)
Free result memory.
Wikimedia\Rdbms\DatabaseMysqlBase\fieldInfo
fieldInfo( $table, $field)
Definition: DatabaseMysqlBase.php:562
Wikimedia\Rdbms\DBError
Database error base class.
Definition: DBError.php:30
Wikimedia\Rdbms\DatabaseMysqlBase\setBigSelects
setBigSelects( $value=true)
Definition: DatabaseMysqlBase.php:1108
DBO_TRX
const DBO_TRX
Definition: defines.php:12
Wikimedia\Rdbms\DatabaseMysqlBase\__construct
__construct(array $params)
Additional $params include:
Definition: DatabaseMysqlBase.php:85
Wikimedia\Rdbms\DatabaseMysqlBase\wasDeadlock
wasDeadlock()
Determines if the last failure was due to a deadlock.
Definition: DatabaseMysqlBase.php:1202
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
LIST_AND
const LIST_AND
Definition: Defines.php:44
Wikimedia\Rdbms\DatabaseMysqlBase\connectInitCharset
connectInitCharset()
Set the character set information right after connection.
Definition: DatabaseMysqlBase.php:220
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlNumFields
mysqlNumFields( $res)
Get number of fields in result.
Wikimedia\Rdbms\Database\clearFlag
clearFlag( $flag, $remember=self::REMEMBER_NOTHING)
Clear a flag for this connection.
Definition: Database.php:630
Wikimedia\Rdbms\Database\doQuery
doQuery( $sql)
The DBMS-dependent part of query()
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlFetchObject
mysqlFetchObject( $res)
Fetch a result row as an object.
$query
null for the wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1581
Wikimedia\Rdbms\DatabaseMysqlBase\doUnlockTables
doUnlockTables( $method)
Helper function for unlockTables() that handles the actual table unlocking.
Definition: DatabaseMysqlBase.php:1099
Wikimedia\Rdbms\DatabaseMysqlBase\duplicateTableStructure
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Definition: DatabaseMysqlBase.php:1240
Wikimedia\Rdbms\DatabaseMysqlBase\fieldName
fieldName( $res, $n)
Definition: DatabaseMysqlBase.php:397
Wikimedia\Rdbms\Database\escapeLikeInternal
escapeLikeInternal( $s, $escapeChar='`')
Definition: Database.php:2112
Wikimedia\Rdbms\DatabaseMysqlBase\getLagFromPtHeartbeat
getLagFromPtHeartbeat()
Definition: DatabaseMysqlBase.php:697
LIST_SET
const LIST_SET
Definition: Defines.php:45
Wikimedia\Rdbms\DatabaseMysqlBase\getSoftwareLink
getSoftwareLink()
Definition: DatabaseMysqlBase.php:957
Wikimedia\Rdbms\MySQLMasterPos
DBMasterPos class for MySQL/MariaDB.
Definition: MySQLMasterPos.php:15
Wikimedia\Rdbms\DatabaseMysqlBase\numFields
numFields( $res)
Definition: DatabaseMysqlBase.php:376
Wikimedia\Rdbms\DatabaseMysqlBase\listTables
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
Definition: DatabaseMysqlBase.php:1258
Wikimedia\Rdbms\DatabaseMysqlBase\lastError
lastError()
Definition: DatabaseMysqlBase.php:462
Wikimedia\Rdbms\DatabaseMysqlBase\getType
getType()
Definition: DatabaseMysqlBase.php:108
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlSetCharset
mysqlSetCharset( $charset)
Set the character set of the MySQL link.
MediaWiki
This document describes the state of Postgres support in MediaWiki
Definition: postgres.txt:4
Wikimedia\Rdbms\Database\selectDB
selectDB( $db)
Change the current database.
Definition: Database.php:1771
Wikimedia\Rdbms\DatabaseMysqlBase\getLag
getLag()
Get replica DB lag.
Definition: DatabaseMysqlBase.php:666
Wikimedia\Rdbms\Database\reportConnectionError
reportConnectionError( $error='Unknown error')
Definition: Database.php:793
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1778
$vars
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
Definition: hooks.txt:2198
Wikimedia\Rdbms\DatabaseMysqlBase\fieldType
fieldType( $res, $n)
mysql_field_type() wrapper
Definition: DatabaseMysqlBase.php:420
Wikimedia\Rdbms\DatabaseMysqlBase\$sslCAFile
string null $sslCAFile
Definition: DatabaseMysqlBase.php:54
Wikimedia\Rdbms\DatabaseMysqlBase\fetchObject
fetchObject( $res)
Definition: DatabaseMysqlBase.php:276
Wikimedia\Rdbms\Database\restoreFlags
restoreFlags( $state=self::RESTORE_PRIOR)
Restore the flags to their prior state before the last setFlag/clearFlag call.
Definition: Database.php:637
Wikimedia\Rdbms\MySQLField
Definition: MySQLField.php:5
Wikimedia\Rdbms\DatabaseMysqlBase\streamStatementEnd
streamStatementEnd(&$sql, &$newLine)
Definition: DatabaseMysqlBase.php:1001
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:175
Wikimedia\Rdbms\Database\getLBInfo
getLBInfo( $name=null)
Get properties passed down from the server info array of the load balancer.
Definition: Database.php:501
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlFieldType
mysqlFieldType( $res, $n)
Get the type of the specified field in a result.
Wikimedia\Rdbms\DatabaseMysqlBase\dataSeek
dataSeek( $res, $row)
Definition: DatabaseMysqlBase.php:442
Wikimedia\Rdbms\Database\installErrorHandler
installErrorHandler()
Set a custom error handler for logging errors during database connection.
Definition: Database.php:691
Wikimedia\Rdbms\DatabaseMysqlBase\indexName
indexName( $index)
Allows for index remapping in queries where this is not consistent across DBMS.
Definition: DatabaseMysqlBase.php:1358
Wikimedia\Rdbms\Database\restoreErrorHandler
restoreErrorHandler()
Restore the previous error handler and return the last PHP error for this DB.
Definition: Database.php:702
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlFetchField
mysqlFetchField( $res, $n)
Get column information from a result.
Wikimedia\Rdbms\DatabaseMysqlBase\unlock
unlock( $lockName, $method)
FROM MYSQL DOCS: https://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_releas...
Definition: DatabaseMysqlBase.php:1055
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2141
$value
$value
Definition: styleTest.css.php:45
Wikimedia\Rdbms\DatabaseMysqlBase\wasReadOnlyError
wasReadOnlyError()
Determines if the last failure was due to the database being read-only.
Definition: DatabaseMysqlBase.php:1224
Wikimedia\Rdbms\Database\$mDBname
string $mDBname
Definition: Database.php:74
Wikimedia\Rdbms\Database\getLogContext
getLogContext(array $extras=[])
Create a log context to pass to PSR-3 logger functions.
Definition: Database.php:742
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlFetchArray
mysqlFetchArray( $res)
Fetch a result row as an associative and numeric array.
Wikimedia\Rdbms\DatabaseMysqlBase\freeResult
freeResult( $res)
Definition: DatabaseMysqlBase.php:251
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlDataSeek
mysqlDataSeek( $res, $row)
Move internal result pointer.
Wikimedia\Rdbms\DatabaseMysqlBase\open
open( $server, $user, $password, $dbName)
Definition: DatabaseMysqlBase.php:120
Wikimedia\Rdbms\DatabaseMysqlBase\getMasterPos
getMasterPos()
Get the position of the master from SHOW MASTER STATUS.
Definition: DatabaseMysqlBase.php:904
Wikimedia\Rdbms\Database\tableName
tableName( $name, $format='quoted')
Format a table name ready for use in constructing an SQL query.
Definition: Database.php:1788
Wikimedia\Rdbms\DatabaseMysqlBase\getReplicaPos
getReplicaPos()
Get the position of the master from SHOW SLAVE STATUS.
Definition: DatabaseMysqlBase.php:876
Wikimedia\Rdbms\DatabaseMysqlBase\$serverVersion
string null $serverVersion
Definition: DatabaseMysqlBase.php:65
Wikimedia\Rdbms\DatabaseMysqlBase\getLagFromSlaveStatus
getLagFromSlaveStatus()
Definition: DatabaseMysqlBase.php:684
Wikimedia\Rdbms\DatabaseMysqlBase\$sslCiphers
string[] null $sslCiphers
Definition: DatabaseMysqlBase.php:58
Wikimedia\Rdbms\Database\query
query( $sql, $fname=__METHOD__, $tempIgnore=false)
Run an SQL query and return the result.
Definition: Database.php:888
Wikimedia\Rdbms\DatabaseMysqlBase\$utf8Mode
bool $utf8Mode
Use experimental UTF-8 transmission encoding.
Definition: DatabaseMysqlBase.php:62
Wikimedia\Rdbms\Database\getServer
getServer()
Get the server hostname or IP address.
Definition: Database.php:1784
Wikimedia\Rdbms\DBUnexpectedError
Definition: DBUnexpectedError.php:27
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:1156
Wikimedia\Rdbms\Database\makeList
makeList( $a, $mode=self::LIST_COMMA)
Makes an encoded list of strings from an array.
Definition: Database.php:1636
Wikimedia\Rdbms\DatabaseMysqlBase\serverIsReadOnly
serverIsReadOnly()
Definition: DatabaseMysqlBase.php:924
Wikimedia\Rdbms\Database\getLazyMasterHandle
getLazyMasterHandle()
Definition: Database.php:530
Wikimedia\Rdbms\DatabaseMysqlBase\$sqlMode
string $sqlMode
sql_mode value to send on connection
Definition: DatabaseMysqlBase.php:60
Wikimedia\Rdbms\Database\close
close()
Closes a database connection.
Definition: Database.php:753
Wikimedia\Rdbms\IDatabase\lastErrno
lastErrno()
Get the last error number.
Wikimedia\Rdbms\DatabaseMysqlBase\makeLockName
makeLockName( $lockName)
Definition: DatabaseMysqlBase.php:1070
$cache
$cache
Definition: mcc.php:33
$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:2581
Wikimedia\Rdbms\Database\$srvCache
BagOStuff $srvCache
APC cache.
Definition: Database.php:83
$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:1965
Wikimedia\Rdbms\DatabaseMysqlBase\strencode
strencode( $s)
Definition: DatabaseMysqlBase.php:626
Wikimedia\Rdbms\DBExpectedError
Base class for the more common types of database errors.
Definition: DBExpectedError.php:35
Wikimedia\Rdbms\DatabaseMysqlBase\deleteJoin
deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname=__METHOD__)
DELETE where the condition is a join.
Definition: DatabaseMysqlBase.php:1135
Wikimedia\Rdbms\DatabaseMysqlBase\estimateRowCount
estimateRowCount( $table, $vars=' *', $conds='', $fname=__METHOD__, $options=[])
Estimate rows in dataset Returns estimated count, based on EXPLAIN output Takes same arguments as Dat...
Definition: DatabaseMysqlBase.php:512
Wikimedia\Rdbms\DatabaseMysqlBase\useIndexClause
useIndexClause( $index)
Definition: DatabaseMysqlBase.php:935
Wikimedia\Rdbms\Database\$mDefaultBigSelects
bool null $mDefaultBigSelects
Definition: Database.php:116
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\DatabaseMysqlBase\mysqlConnect
mysqlConnect( $realServer)
Open a connection to a MySQL server.
Wikimedia\Rdbms\DatabaseMysqlBase\tableLocksHaveTransactionScope
tableLocksHaveTransactionScope()
Checks if table locks acquired by lockTables() are transaction-bound in their scope.
Definition: DatabaseMysqlBase.php:1080
Wikimedia\Rdbms\DatabaseMysqlBase\listViews
listViews( $prefix=null, $fname=__METHOD__)
Lists VIEWs in the database.
Definition: DatabaseMysqlBase.php:1314
Wikimedia\Rdbms\DatabaseMysqlBase\wasErrorReissuable
wasErrorReissuable()
Determines if the last query error was due to a dropped connection and should be dealt with by pingin...
Definition: DatabaseMysqlBase.php:1215
Wikimedia\Rdbms\DatabaseMysqlBase\replace
replace( $table, $uniqueIndexes, $rows, $fname=__METHOD__)
Definition: DatabaseMysqlBase.php:496
Wikimedia\Rdbms\DatabaseMysqlBase\$lastKnownReplicaPos
MysqlMasterPos $lastKnownReplicaPos
Definition: DatabaseMysqlBase.php:42
Wikimedia\Rdbms\DatabaseMysqlBase\isView
isView( $name, $prefix=null)
Differentiates between a TABLE and a VIEW.
Definition: DatabaseMysqlBase.php:1348
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:1339
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\DatabaseMysqlBase\$lagDetectionOptions
array $lagDetectionOptions
Method to detect replica DB lag.
Definition: DatabaseMysqlBase.php:46
Wikimedia\Rdbms\Database\qualifiedTableComponents
qualifiedTableComponents( $name)
Get the table components needed for a query given the currently selected database.
Definition: Database.php:1834
Wikimedia\Rdbms\DatabaseMysqlBase\lock
lock( $lockName, $method, $timeout=5)
Definition: DatabaseMysqlBase.php:1033
Wikimedia\Rdbms\DatabaseMysqlBase\wasConnectionError
wasConnectionError( $errno)
Do not use this method outside of Database/DBError classes.
Definition: DatabaseMysqlBase.php:1229
Wikimedia\Rdbms\DatabaseMysqlBase\fetchRow
fetchRow( $res)
Definition: DatabaseMysqlBase.php:312
Wikimedia\Rdbms\DatabaseMysqlBase\getMysqlStatus
getMysqlStatus( $which="%")
Get status information from SHOW STATUS in an associative array.
Definition: DatabaseMysqlBase.php:1294
Wikimedia\Rdbms\DatabaseMysqlBase\getServerVersion
getServerVersion()
Definition: DatabaseMysqlBase.php:975
Wikimedia\Rdbms\DatabaseMysqlBase\mysqlError
mysqlError( $conn=null)
Returns the text of the error message from previous MySQL operation.
Wikimedia\Rdbms\DatabaseMysqlBase\getMasterServerInfo
getMasterServerInfo()
Definition: DatabaseMysqlBase.php:740
array
the array() calling protocol came about after MediaWiki 1.4rc1.
Wikimedia\Rdbms\DatabaseMysqlBase\addQuotes
addQuotes( $s)
Adds quotes and backslashes.
Definition: DatabaseMysqlBase.php:636
Wikimedia\Rdbms\DatabaseMysqlBase
Database abstraction object for MySQL.
Definition: DatabaseMysqlBase.php:40
Wikimedia\Rdbms\DatabaseMysqlBase\isQuotedIdentifier
isQuotedIdentifier( $name)
Definition: DatabaseMysqlBase.php:662
Wikimedia\Rdbms\DatabaseMysqlBase\namedLocksEnqueue
namedLocksEnqueue()
Check to see if a named lock used by lock() use blocking queues.
Definition: DatabaseMysqlBase.php:1076
Wikimedia\Rdbms\DatabaseMysqlBase\tableExists
tableExists( $table, $fname=__METHOD__)
Query whether a given table exists.
Definition: DatabaseMysqlBase.php:532
Wikimedia\Rdbms\DatabaseMysqlBase\$lagDetectionMethod
string $lagDetectionMethod
Method to detect replica DB lag.
Definition: DatabaseMysqlBase.php:44
Wikimedia\Rdbms\DatabaseMysqlBase\lockIsFree
lockIsFree( $lockName, $method)
Check to see if a named lock is available.
Definition: DatabaseMysqlBase.php:1019
Wikimedia\Rdbms\DatabaseMysqlBase\dropTable
dropTable( $tableName, $fName=__METHOD__)
Definition: DatabaseMysqlBase.php:1280