MediaWiki REL1_27
DatabaseMysqlBase.php
Go to the documentation of this file.
1<?php
32abstract class DatabaseMysqlBase extends Database {
38 protected $lagDetectionOptions = [];
39
41 private $serverVersion = null;
42
56 parent::__construct( $params );
57
58 $this->lagDetectionMethod = isset( $params['lagDetectionMethod'] )
59 ? $params['lagDetectionMethod']
60 : 'Seconds_Behind_Master';
61 $this->lagDetectionOptions = isset( $params['lagDetectionOptions'] )
62 ? $params['lagDetectionOptions']
63 : [];
64 }
65
69 function getType() {
70 return 'mysql';
71 }
72
81 function open( $server, $user, $password, $dbName ) {
83
84 # Close/unset connection handle
85 $this->close();
86
87 # Debugging hack -- fake cluster
88 $realServer = $wgAllDBsAreLocalhost ? 'localhost' : $server;
89 $this->mServer = $server;
90 $this->mUser = $user;
91 $this->mPassword = $password;
92 $this->mDBname = $dbName;
93
94 $this->installErrorHandler();
95 try {
96 $this->mConn = $this->mysqlConnect( $realServer );
97 } catch ( Exception $ex ) {
98 $this->restoreErrorHandler();
99 throw $ex;
100 }
101 $error = $this->restoreErrorHandler();
102
103 # Always log connection errors
104 if ( !$this->mConn ) {
105 if ( !$error ) {
106 $error = $this->lastError();
107 }
109 "Error connecting to {db_server}: {error}",
110 $this->getLogContext( [
111 'method' => __METHOD__,
112 'error' => $error,
113 ] )
114 );
115 wfDebug( "DB connection error\n" .
116 "Server: $server, User: $user, Password: " .
117 substr( $password, 0, 3 ) . "..., error: " . $error . "\n" );
118
119 $this->reportConnectionError( $error );
120 }
121
122 if ( $dbName != '' ) {
123 MediaWiki\suppressWarnings();
124 $success = $this->selectDB( $dbName );
125 MediaWiki\restoreWarnings();
126 if ( !$success ) {
128 "Error selecting database {db_name} on server {db_server}",
129 $this->getLogContext( [
130 'method' => __METHOD__,
131 ] )
132 );
133 wfDebug( "Error selecting database $dbName on server {$this->mServer} " .
134 "from client host " . wfHostname() . "\n" );
135
136 $this->reportConnectionError( "Error selecting database $dbName" );
137 }
138 }
139
140 // Tell the server what we're communicating with
141 if ( !$this->connectInitCharset() ) {
142 $this->reportConnectionError( "Error setting character set" );
143 }
144
145 // Abstract over any insane MySQL defaults
146 $set = [ 'group_concat_max_len = 262144' ];
147 // Set SQL mode, default is turning them all off, can be overridden or skipped with null
148 if ( is_string( $wgSQLMode ) ) {
149 $set[] = 'sql_mode = ' . $this->addQuotes( $wgSQLMode );
150 }
151 // Set any custom settings defined by site config
152 // (e.g. https://dev.mysql.com/doc/refman/4.1/en/innodb-parameters.html)
153 foreach ( $this->mSessionVars as $var => $val ) {
154 // Escape strings but not numbers to avoid MySQL complaining
155 if ( !is_int( $val ) && !is_float( $val ) ) {
156 $val = $this->addQuotes( $val );
157 }
158 $set[] = $this->addIdentifierQuotes( $var ) . ' = ' . $val;
159 }
160
161 if ( $set ) {
162 // Use doQuery() to avoid opening implicit transactions (DBO_TRX)
163 $success = $this->doQuery( 'SET ' . implode( ', ', $set ) );
164 if ( !$success ) {
166 'Error setting MySQL variables on server {db_server} (check $wgSQLMode)',
167 $this->getLogContext( [
168 'method' => __METHOD__,
169 ] )
170 );
172 'Error setting MySQL variables on server {db_server} (check $wgSQLMode)' );
173 }
174 }
175
176 $this->mOpened = true;
177
178 return true;
179 }
180
185 protected function connectInitCharset() {
187
188 if ( $wgDBmysql5 ) {
189 // Tell the server we're communicating with it in UTF-8.
190 // This may engage various charset conversions.
191 return $this->mysqlSetCharset( 'utf8' );
192 } else {
193 return $this->mysqlSetCharset( 'binary' );
194 }
195 }
196
204 abstract protected function mysqlConnect( $realServer );
205
212 abstract protected function mysqlSetCharset( $charset );
213
218 function freeResult( $res ) {
219 if ( $res instanceof ResultWrapper ) {
220 $res = $res->result;
221 }
222 MediaWiki\suppressWarnings();
223 $ok = $this->mysqlFreeResult( $res );
224 MediaWiki\restoreWarnings();
225 if ( !$ok ) {
226 throw new DBUnexpectedError( $this, "Unable to free MySQL result" );
227 }
228 }
229
236 abstract protected function mysqlFreeResult( $res );
237
243 function fetchObject( $res ) {
244 if ( $res instanceof ResultWrapper ) {
245 $res = $res->result;
246 }
247 MediaWiki\suppressWarnings();
248 $row = $this->mysqlFetchObject( $res );
249 MediaWiki\restoreWarnings();
250
251 $errno = $this->lastErrno();
252 // Unfortunately, mysql_fetch_object does not reset the last errno.
253 // Only check for CR_SERVER_LOST and CR_UNKNOWN_ERROR, as
254 // these are the only errors mysql_fetch_object can cause.
255 // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
256 if ( $errno == 2000 || $errno == 2013 ) {
257 throw new DBUnexpectedError(
258 $this,
259 'Error in fetchObject(): ' . htmlspecialchars( $this->lastError() )
260 );
261 }
262
263 return $row;
264 }
265
272 abstract protected function mysqlFetchObject( $res );
273
279 function fetchRow( $res ) {
280 if ( $res instanceof ResultWrapper ) {
281 $res = $res->result;
282 }
283 MediaWiki\suppressWarnings();
284 $row = $this->mysqlFetchArray( $res );
285 MediaWiki\restoreWarnings();
286
287 $errno = $this->lastErrno();
288 // Unfortunately, mysql_fetch_array does not reset the last errno.
289 // Only check for CR_SERVER_LOST and CR_UNKNOWN_ERROR, as
290 // these are the only errors mysql_fetch_array can cause.
291 // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
292 if ( $errno == 2000 || $errno == 2013 ) {
293 throw new DBUnexpectedError(
294 $this,
295 'Error in fetchRow(): ' . htmlspecialchars( $this->lastError() )
296 );
297 }
298
299 return $row;
300 }
301
308 abstract protected function mysqlFetchArray( $res );
309
315 function numRows( $res ) {
316 if ( $res instanceof ResultWrapper ) {
317 $res = $res->result;
318 }
319 MediaWiki\suppressWarnings();
320 $n = $this->mysqlNumRows( $res );
321 MediaWiki\restoreWarnings();
322
323 // Unfortunately, mysql_num_rows does not reset the last errno.
324 // We are not checking for any errors here, since
325 // these are no errors mysql_num_rows can cause.
326 // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html.
327 // See https://phabricator.wikimedia.org/T44430
328 return $n;
329 }
330
337 abstract protected function mysqlNumRows( $res );
338
343 function numFields( $res ) {
344 if ( $res instanceof ResultWrapper ) {
345 $res = $res->result;
346 }
347
348 return $this->mysqlNumFields( $res );
349 }
350
357 abstract protected function mysqlNumFields( $res );
358
364 function fieldName( $res, $n ) {
365 if ( $res instanceof ResultWrapper ) {
366 $res = $res->result;
367 }
368
369 return $this->mysqlFieldName( $res, $n );
370 }
371
379 abstract protected function mysqlFieldName( $res, $n );
380
387 public function fieldType( $res, $n ) {
388 if ( $res instanceof ResultWrapper ) {
389 $res = $res->result;
390 }
391
392 return $this->mysqlFieldType( $res, $n );
393 }
394
402 abstract protected function mysqlFieldType( $res, $n );
403
409 function dataSeek( $res, $row ) {
410 if ( $res instanceof ResultWrapper ) {
411 $res = $res->result;
412 }
413
414 return $this->mysqlDataSeek( $res, $row );
415 }
416
424 abstract protected function mysqlDataSeek( $res, $row );
425
429 function lastError() {
430 if ( $this->mConn ) {
431 # Even if it's non-zero, it can still be invalid
432 MediaWiki\suppressWarnings();
433 $error = $this->mysqlError( $this->mConn );
434 if ( !$error ) {
435 $error = $this->mysqlError();
436 }
437 MediaWiki\restoreWarnings();
438 } else {
439 $error = $this->mysqlError();
440 }
441 if ( $error ) {
442 $error .= ' (' . $this->mServer . ')';
443 }
444
445 return $error;
446 }
447
454 abstract protected function mysqlError( $conn = null );
455
463 function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
464 return $this->nativeReplace( $table, $rows, $fname );
465 }
466
479 public function estimateRowCount( $table, $vars = '*', $conds = '',
480 $fname = __METHOD__, $options = []
481 ) {
482 $options['EXPLAIN'] = true;
483 $res = $this->select( $table, $vars, $conds, $fname, $options );
484 if ( $res === false ) {
485 return false;
486 }
487 if ( !$this->numRows( $res ) ) {
488 return 0;
489 }
490
491 $rows = 1;
492 foreach ( $res as $plan ) {
493 $rows *= $plan->rows > 0 ? $plan->rows : 1; // avoid resetting to zero
494 }
495
496 return (int)$rows;
497 }
498
504 function fieldInfo( $table, $field ) {
505 $table = $this->tableName( $table );
506 $res = $this->query( "SELECT * FROM $table LIMIT 1", __METHOD__, true );
507 if ( !$res ) {
508 return false;
509 }
510 $n = $this->mysqlNumFields( $res->result );
511 for ( $i = 0; $i < $n; $i++ ) {
512 $meta = $this->mysqlFetchField( $res->result, $i );
513 if ( $field == $meta->name ) {
514 return new MySQLField( $meta );
515 }
516 }
517
518 return false;
519 }
520
528 abstract protected function mysqlFetchField( $res, $n );
529
539 function indexInfo( $table, $index, $fname = __METHOD__ ) {
540 # SHOW INDEX works in MySQL 3.23.58, but SHOW INDEXES does not.
541 # SHOW INDEX should work for 3.x and up:
542 # http://dev.mysql.com/doc/mysql/en/SHOW_INDEX.html
543 $table = $this->tableName( $table );
544 $index = $this->indexName( $index );
545
546 $sql = 'SHOW INDEX FROM ' . $table;
547 $res = $this->query( $sql, $fname );
548
549 if ( !$res ) {
550 return null;
551 }
552
553 $result = [];
554
555 foreach ( $res as $row ) {
556 if ( $row->Key_name == $index ) {
557 $result[] = $row;
558 }
559 }
560
561 return empty( $result ) ? false : $result;
562 }
563
568 function strencode( $s ) {
569 $sQuoted = $this->mysqlRealEscapeString( $s );
570
571 if ( $sQuoted === false ) {
572 $this->ping();
573 $sQuoted = $this->mysqlRealEscapeString( $s );
574 }
575
576 return $sQuoted;
577 }
578
583 abstract protected function mysqlRealEscapeString( $s );
584
591 public function addIdentifierQuotes( $s ) {
592 // Characters in the range \u0001-\uFFFF are valid in a quoted identifier
593 // Remove NUL bytes and escape backticks by doubling
594 return '`' . str_replace( [ "\0", '`' ], [ '', '``' ], $s ) . '`';
595 }
596
601 public function isQuotedIdentifier( $name ) {
602 return strlen( $name ) && $name[0] == '`' && substr( $name, -1, 1 ) == '`';
603 }
604
608 function ping() {
609 $ping = $this->mysqlPing();
610 if ( $ping ) {
611 // Connection was good or lost but reconnected...
612 // @note: mysqlnd (php 5.6+) does not support this (PHP bug 52561)
613 return true;
614 }
615
616 // Try a full disconnect/reconnect cycle if ping() failed
617 $this->closeConnection();
618 $this->mOpened = false;
619 $this->mConn = false;
620 $this->open( $this->mServer, $this->mUser, $this->mPassword, $this->mDBname );
621
622 return true;
623 }
624
630 abstract protected function mysqlPing();
631
632 function getLag() {
633 if ( $this->getLagDetectionMethod() === 'pt-heartbeat' ) {
634 return $this->getLagFromPtHeartbeat();
635 } else {
636 return $this->getLagFromSlaveStatus();
637 }
638 }
639
643 protected function getLagDetectionMethod() {
645 }
646
650 protected function getLagFromSlaveStatus() {
651 $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ );
652 $row = $res ? $res->fetchObject() : false;
653 if ( $row && strval( $row->Seconds_Behind_Master ) !== '' ) {
654 return intval( $row->Seconds_Behind_Master );
655 }
656
657 return false;
658 }
659
663 protected function getLagFromPtHeartbeat() {
665
666 if ( isset( $options['conds'] ) ) {
667 // Best method for multi-DC setups: use logical channel names
668 $data = $this->getHeartbeatData( $options['conds'] );
669 } else {
670 // Standard method: use master server ID (works with stock pt-heartbeat)
671 $masterInfo = $this->getMasterServerInfo();
672 if ( !$masterInfo ) {
674 "Unable to query master of {db_server} for server ID",
675 $this->getLogContext( [
676 'method' => __METHOD__
677 ] )
678 );
679
680 return false; // could not get master server ID
681 }
682
683 $conds = [ 'server_id' => intval( $masterInfo['serverId'] ) ];
684 $data = $this->getHeartbeatData( $conds );
685 }
686
687 list( $time, $nowUnix ) = $data;
688 if ( $time !== null ) {
689 // @time is in ISO format like "2015-09-25T16:48:10.000510"
690 $dateTime = new DateTime( $time, new DateTimeZone( 'UTC' ) );
691 $timeUnix = (int)$dateTime->format( 'U' ) + $dateTime->format( 'u' ) / 1e6;
692
693 return max( $nowUnix - $timeUnix, 0.0 );
694 }
695
697 "Unable to find pt-heartbeat row for {db_server}",
698 $this->getLogContext( [
699 'method' => __METHOD__
700 ] )
701 );
702
703 return false;
704 }
705
706 protected function getMasterServerInfo() {
708 $key = $cache->makeGlobalKey(
709 'mysql',
710 'master-info',
711 // Using one key for all cluster slaves is preferable
712 $this->getLBInfo( 'clusterMasterHost' ) ?: $this->getServer()
713 );
714
715 return $cache->getWithSetCallback(
716 $key,
717 $cache::TTL_INDEFINITE,
718 function () use ( $cache, $key ) {
719 // Get and leave a lock key in place for a short period
720 if ( !$cache->lock( $key, 0, 10 ) ) {
721 return false; // avoid master connection spike slams
722 }
723
724 $conn = $this->getLazyMasterHandle();
725 if ( !$conn ) {
726 return false; // something is misconfigured
727 }
728
729 // Connect to and query the master; catch errors to avoid outages
730 try {
731 $res = $conn->query( 'SELECT @@server_id AS id', __METHOD__ );
732 $row = $res ? $res->fetchObject() : false;
733 $id = $row ? (int)$row->id : 0;
734 } catch ( DBError $e ) {
735 $id = 0;
736 }
737
738 // Cache the ID if it was retrieved
739 return $id ? [ 'serverId' => $id, 'asOf' => time() ] : false;
740 }
741 );
742 }
743
749 protected function getHeartbeatData( array $conds ) {
750 $whereSQL = $this->makeList( $conds, LIST_AND );
751 // Use ORDER BY for channel based queries since that field might not be UNIQUE.
752 // Note: this would use "TIMESTAMPDIFF(MICROSECOND,ts,UTC_TIMESTAMP(6))" but the
753 // percision field is not supported in MySQL <= 5.5.
754 $res = $this->query(
755 "SELECT ts FROM heartbeat.heartbeat WHERE $whereSQL ORDER BY ts DESC LIMIT 1"
756 );
757 $row = $res ? $res->fetchObject() : false;
758
759 return [ $row ? $row->ts : null, microtime( true ) ];
760 }
761
762 public function getApproximateLagStatus() {
763 if ( $this->getLagDetectionMethod() === 'pt-heartbeat' ) {
764 // Disable caching since this is fast enough and we don't wan't
765 // to be *too* pessimistic by having both the cache TTL and the
766 // pt-heartbeat interval count as lag in getSessionLagStatus()
767 return parent::getApproximateLagStatus();
768 }
769
770 $key = $this->srvCache->makeGlobalKey( 'mysql-lag', $this->getServer() );
771 $approxLag = $this->srvCache->get( $key );
772 if ( !$approxLag ) {
773 $approxLag = parent::getApproximateLagStatus();
774 $this->srvCache->set( $key, $approxLag, 1 );
775 }
776
777 return $approxLag;
778 }
779
780 function masterPosWait( DBMasterPos $pos, $timeout ) {
781 if ( !( $pos instanceof MySQLMasterPos ) ) {
782 throw new InvalidArgumentException( "Position not an instance of MySQLMasterPos" );
783 }
784
785 if ( $this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached( $pos ) ) {
786 return 0;
787 }
788
789 # Commit any open transactions
790 $this->commit( __METHOD__, 'flush' );
791
792 # Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
793 $encFile = $this->addQuotes( $pos->file );
794 $encPos = intval( $pos->pos );
795 $res = $this->doQuery( "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)" );
796
797 $row = $res ? $this->fetchRow( $res ) : false;
798 if ( !$row ) {
799 throw new DBExpectedError( $this, "Failed to query MASTER_POS_WAIT()" );
800 }
801
802 // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
803 $status = ( $row[0] !== null ) ? intval( $row[0] ) : null;
804 if ( $status === null ) {
805 // T126436: jobs programmed to wait on master positions might be referencing binlogs
806 // with an old master hostname. Such calls make MASTER_POS_WAIT() return null. Try
807 // to detect this and treat the slave as having reached the position; a proper master
808 // switchover already requires that the new master be caught up before the switch.
809 $slavePos = $this->getSlavePos();
810 if ( $slavePos && !$slavePos->channelsMatch( $pos ) ) {
811 $this->lastKnownSlavePos = $slavePos;
812 $status = 0;
813 }
814 } elseif ( $status >= 0 ) {
815 // Remember that this position was reached to save queries next time
816 $this->lastKnownSlavePos = $pos;
817 }
818
819 return $status;
820 }
821
827 function getSlavePos() {
828 $res = $this->query( 'SHOW SLAVE STATUS', 'DatabaseBase::getSlavePos' );
829 $row = $this->fetchObject( $res );
830
831 if ( $row ) {
832 $pos = isset( $row->Exec_master_log_pos )
833 ? $row->Exec_master_log_pos
834 : $row->Exec_Master_Log_Pos;
835
836 return new MySQLMasterPos( $row->Relay_Master_Log_File, $pos );
837 } else {
838 return false;
839 }
840 }
841
847 function getMasterPos() {
848 $res = $this->query( 'SHOW MASTER STATUS', 'DatabaseBase::getMasterPos' );
849 $row = $this->fetchObject( $res );
850
851 if ( $row ) {
852 return new MySQLMasterPos( $row->File, $row->Position );
853 } else {
854 return false;
855 }
856 }
857
862 function useIndexClause( $index ) {
863 return "FORCE INDEX (" . $this->indexName( $index ) . ")";
864 }
865
869 function lowPriorityOption() {
870 return 'LOW_PRIORITY';
871 }
872
876 public function getSoftwareLink() {
877 // MariaDB includes its name in its version string; this is how MariaDB's version of
878 // the mysql command-line client identifies MariaDB servers (see mariadb_connection()
879 // in libmysql/libmysql.c).
880 $version = $this->getServerVersion();
881 if ( strpos( $version, 'MariaDB' ) !== false || strpos( $version, '-maria-' ) !== false ) {
882 return '[{{int:version-db-mariadb-url}} MariaDB]';
883 }
884
885 // Percona Server's version suffix is not very distinctive, and @@version_comment
886 // doesn't give the necessary info for source builds, so assume the server is MySQL.
887 // (Even Percona's version of mysql doesn't try to make the distinction.)
888 return '[{{int:version-db-mysql-url}} MySQL]';
889 }
890
894 public function getServerVersion() {
895 // Not using mysql_get_server_info() or similar for consistency: in the handshake,
896 // MariaDB 10 adds the prefix "5.5.5-", and only some newer client libraries strip
897 // it off (see RPL_VERSION_HACK in include/mysql_com.h).
898 if ( $this->serverVersion === null ) {
899 $this->serverVersion = $this->selectField( '', 'VERSION()', '', __METHOD__ );
900 }
902 }
903
907 public function setSessionOptions( array $options ) {
908 if ( isset( $options['connTimeout'] ) ) {
909 $timeout = (int)$options['connTimeout'];
910 $this->query( "SET net_read_timeout=$timeout" );
911 $this->query( "SET net_write_timeout=$timeout" );
912 }
913 }
914
920 public function streamStatementEnd( &$sql, &$newLine ) {
921 if ( strtoupper( substr( $newLine, 0, 9 ) ) == 'DELIMITER' ) {
922 preg_match( '/^DELIMITER\s+(\S+)/', $newLine, $m );
923 $this->delimiter = $m[1];
924 $newLine = '';
925 }
926
927 return parent::streamStatementEnd( $sql, $newLine );
928 }
929
938 public function lockIsFree( $lockName, $method ) {
939 $lockName = $this->addQuotes( $this->makeLockName( $lockName ) );
940 $result = $this->query( "SELECT IS_FREE_LOCK($lockName) AS lockstatus", $method );
941 $row = $this->fetchObject( $result );
942
943 return ( $row->lockstatus == 1 );
944 }
945
952 public function lock( $lockName, $method, $timeout = 5 ) {
953 $lockName = $this->addQuotes( $this->makeLockName( $lockName ) );
954 $result = $this->query( "SELECT GET_LOCK($lockName, $timeout) AS lockstatus", $method );
955 $row = $this->fetchObject( $result );
956
957 if ( $row->lockstatus == 1 ) {
958 parent::lock( $lockName, $method, $timeout ); // record
959 return true;
960 }
961
962 wfDebug( __METHOD__ . " failed to acquire lock\n" );
963
964 return false;
965 }
966
974 public function unlock( $lockName, $method ) {
975 $lockName = $this->addQuotes( $this->makeLockName( $lockName ) );
976 $result = $this->query( "SELECT RELEASE_LOCK($lockName) as lockstatus", $method );
977 $row = $this->fetchObject( $result );
978
979 if ( $row->lockstatus == 1 ) {
980 parent::unlock( $lockName, $method ); // record
981 return true;
982 }
983
984 wfDebug( __METHOD__ . " failed to release lock\n" );
985
986 return false;
987 }
988
989 private function makeLockName( $lockName ) {
990 // http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock
991 // Newer version enforce a 64 char length limit.
992 return ( strlen( $lockName ) > 64 ) ? sha1( $lockName ) : $lockName;
993 }
994
995 public function namedLocksEnqueue() {
996 return true;
997 }
998
1006 public function lockTables( $read, $write, $method, $lowPriority = true ) {
1007 $items = [];
1008
1009 foreach ( $write as $table ) {
1010 $tbl = $this->tableName( $table ) .
1011 ( $lowPriority ? ' LOW_PRIORITY' : '' ) .
1012 ' WRITE';
1013 $items[] = $tbl;
1014 }
1015 foreach ( $read as $table ) {
1016 $items[] = $this->tableName( $table ) . ' READ';
1017 }
1018 $sql = "LOCK TABLES " . implode( ',', $items );
1019 $this->query( $sql, $method );
1020
1021 return true;
1022 }
1023
1028 public function unlockTables( $method ) {
1029 $this->query( "UNLOCK TABLES", $method );
1030
1031 return true;
1032 }
1033
1040 public function getSearchEngine() {
1041 return 'SearchMySQL';
1042 }
1043
1047 public function setBigSelects( $value = true ) {
1048 if ( $value === 'default' ) {
1049 if ( $this->mDefaultBigSelects === null ) {
1050 # Function hasn't been called before so it must already be set to the default
1051 return;
1052 } else {
1054 }
1055 } elseif ( $this->mDefaultBigSelects === null ) {
1056 $this->mDefaultBigSelects =
1057 (bool)$this->selectField( false, '@@sql_big_selects', '', __METHOD__ );
1058 }
1059 $encValue = $value ? '1' : '0';
1060 $this->query( "SET sql_big_selects=$encValue", __METHOD__ );
1061 }
1062
1074 function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = __METHOD__ ) {
1075 if ( !$conds ) {
1076 throw new DBUnexpectedError( $this, 'DatabaseBase::deleteJoin() called with empty $conds' );
1077 }
1078
1079 $delTable = $this->tableName( $delTable );
1080 $joinTable = $this->tableName( $joinTable );
1081 $sql = "DELETE $delTable FROM $delTable, $joinTable WHERE $delVar=$joinVar ";
1082
1083 if ( $conds != '*' ) {
1084 $sql .= ' AND ' . $this->makeList( $conds, LIST_AND );
1085 }
1086
1087 return $this->query( $sql, $fname );
1088 }
1089
1098 public function upsert( $table, array $rows, array $uniqueIndexes,
1099 array $set, $fname = __METHOD__
1100 ) {
1101 if ( !count( $rows ) ) {
1102 return true; // nothing to do
1103 }
1104
1105 if ( !is_array( reset( $rows ) ) ) {
1106 $rows = [ $rows ];
1107 }
1108
1109 $table = $this->tableName( $table );
1110 $columns = array_keys( $rows[0] );
1111
1112 $sql = "INSERT INTO $table (" . implode( ',', $columns ) . ') VALUES ';
1113 $rowTuples = [];
1114 foreach ( $rows as $row ) {
1115 $rowTuples[] = '(' . $this->makeList( $row ) . ')';
1116 }
1117 $sql .= implode( ',', $rowTuples );
1118 $sql .= " ON DUPLICATE KEY UPDATE " . $this->makeList( $set, LIST_SET );
1119
1120 return (bool)$this->query( $sql, $fname );
1121 }
1122
1128 function getServerUptime() {
1129 $vars = $this->getMysqlStatus( 'Uptime' );
1130
1131 return (int)$vars['Uptime'];
1132 }
1133
1139 function wasDeadlock() {
1140 return $this->lastErrno() == 1213;
1141 }
1142
1148 function wasLockTimeout() {
1149 return $this->lastErrno() == 1205;
1150 }
1151
1159 return $this->lastErrno() == 2013 || $this->lastErrno() == 2006;
1160 }
1161
1167 function wasReadOnlyError() {
1168 return $this->lastErrno() == 1223 ||
1169 ( $this->lastErrno() == 1290 && strpos( $this->lastError(), '--read-only' ) !== false );
1170 }
1171
1172 function wasConnectionError( $errno ) {
1173 return $errno == 2013 || $errno == 2006;
1174 }
1175
1187 protected function getBindingHandle() {
1188 if ( !$this->mConn ) {
1189 throw new DBUnexpectedError(
1190 $this,
1191 'DB connection was already closed or the connection dropped.'
1192 );
1193 }
1194
1195 return $this->mConn;
1196 }
1197
1205 function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = __METHOD__ ) {
1206 $tmp = $temporary ? 'TEMPORARY ' : '';
1207 $newName = $this->addIdentifierQuotes( $newName );
1208 $oldName = $this->addIdentifierQuotes( $oldName );
1209 $query = "CREATE $tmp TABLE $newName (LIKE $oldName)";
1210
1211 return $this->query( $query, $fname );
1212 }
1213
1221 function listTables( $prefix = null, $fname = __METHOD__ ) {
1222 $result = $this->query( "SHOW TABLES", $fname );
1223
1224 $endArray = [];
1225
1226 foreach ( $result as $table ) {
1227 $vars = get_object_vars( $table );
1228 $table = array_pop( $vars );
1229
1230 if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
1231 $endArray[] = $table;
1232 }
1233 }
1234
1235 return $endArray;
1236 }
1237
1243 public function dropTable( $tableName, $fName = __METHOD__ ) {
1244 if ( !$this->tableExists( $tableName, $fName ) ) {
1245 return false;
1246 }
1247
1248 return $this->query( "DROP TABLE IF EXISTS " . $this->tableName( $tableName ), $fName );
1249 }
1250
1254 protected function getDefaultSchemaVars() {
1255 $vars = parent::getDefaultSchemaVars();
1256 $vars['wgDBTableOptions'] = str_replace( 'TYPE', 'ENGINE', $GLOBALS['wgDBTableOptions'] );
1257 $vars['wgDBTableOptions'] = str_replace(
1258 'CHARSET=mysql4',
1259 'CHARSET=binary',
1260 $vars['wgDBTableOptions']
1261 );
1262
1263 return $vars;
1264 }
1265
1272 function getMysqlStatus( $which = "%" ) {
1273 $res = $this->query( "SHOW STATUS LIKE '{$which}'" );
1274 $status = [];
1275
1276 foreach ( $res as $row ) {
1277 $status[$row->Variable_name] = $row->Value;
1278 }
1279
1280 return $status;
1281 }
1282
1292 public function listViews( $prefix = null, $fname = __METHOD__ ) {
1293
1294 if ( !isset( $this->allViews ) ) {
1295
1296 // The name of the column containing the name of the VIEW
1297 $propertyName = 'Tables_in_' . $this->mDBname;
1298
1299 // Query for the VIEWS
1300 $result = $this->query( 'SHOW FULL TABLES WHERE TABLE_TYPE = "VIEW"' );
1301 $this->allViews = [];
1302 while ( ( $row = $this->fetchRow( $result ) ) !== false ) {
1303 array_push( $this->allViews, $row[$propertyName] );
1304 }
1305 }
1306
1307 if ( is_null( $prefix ) || $prefix === '' ) {
1308 return $this->allViews;
1309 }
1310
1311 $filteredViews = [];
1312 foreach ( $this->allViews as $viewName ) {
1313 // Does the name of this VIEW start with the table-prefix?
1314 if ( strpos( $viewName, $prefix ) === 0 ) {
1315 array_push( $filteredViews, $viewName );
1316 }
1317 }
1318
1319 return $filteredViews;
1320 }
1321
1330 public function isView( $name, $prefix = null ) {
1331 return in_array( $name, $this->listViews( $prefix ) );
1332 }
1333}
1334
1339class MySQLField implements Field {
1343
1344 function __construct( $info ) {
1345 $this->name = $info->name;
1346 $this->tablename = $info->table;
1347 $this->default = $info->def;
1348 $this->max_length = $info->max_length;
1349 $this->nullable = !$info->not_null;
1350 $this->is_pk = $info->primary_key;
1351 $this->is_unique = $info->unique_key;
1352 $this->is_multiple = $info->multiple_key;
1353 $this->is_key = ( $this->is_pk || $this->is_unique || $this->is_multiple );
1354 $this->type = $info->type;
1355 $this->binary = isset( $info->binary ) ? $info->binary : false;
1356 $this->is_numeric = isset( $info->numeric ) ? $info->numeric : false;
1357 $this->is_blob = isset( $info->blob ) ? $info->blob : false;
1358 $this->is_unsigned = isset( $info->unsigned ) ? $info->unsigned : false;
1359 $this->is_zerofill = isset( $info->zerofill ) ? $info->zerofill : false;
1360 }
1361
1365 function name() {
1366 return $this->name;
1367 }
1368
1372 function tableName() {
1373 return $this->tablename;
1374 }
1375
1379 function type() {
1380 return $this->type;
1381 }
1382
1386 function isNullable() {
1387 return $this->nullable;
1388 }
1389
1390 function defaultValue() {
1391 return $this->default;
1392 }
1393
1397 function isKey() {
1398 return $this->is_key;
1399 }
1400
1404 function isMultipleKey() {
1405 return $this->is_multiple;
1406 }
1407
1411 function isBinary() {
1412 return $this->binary;
1413 }
1414
1418 function isNumeric() {
1419 return $this->is_numeric;
1420 }
1421
1425 function isBlob() {
1426 return $this->is_blob;
1427 }
1428
1432 function isUnsigned() {
1433 return $this->is_unsigned;
1434 }
1435
1439 function isZerofill() {
1440 return $this->is_zerofill;
1441 }
1442}
1443
1444class MySQLMasterPos implements DBMasterPos {
1446 public $file;
1448 public $pos;
1450 public $asOfTime = 0.0;
1451
1452 function __construct( $file, $pos ) {
1453 $this->file = $file;
1454 $this->pos = $pos;
1455 $this->asOfTime = microtime( true );
1456 }
1457
1458 function asOfTime() {
1459 return $this->asOfTime;
1460 }
1461
1463 if ( !( $pos instanceof self ) ) {
1464 throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ );
1465 }
1466
1467 $thisPos = $this->getCoordinates();
1468 $thatPos = $pos->getCoordinates();
1469
1470 return ( $thisPos && $thatPos && $thisPos >= $thatPos );
1471 }
1472
1474 if ( !( $pos instanceof self ) ) {
1475 throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ );
1476 }
1477
1478 $thisBinlog = $this->getBinlogName();
1479 $thatBinlog = $pos->getBinlogName();
1480
1481 return ( $thisBinlog !== false && $thisBinlog === $thatBinlog );
1482 }
1483
1484 function __toString() {
1485 // e.g db1034-bin.000976/843431247
1486 return "{$this->file}/{$this->pos}";
1487 }
1488
1492 protected function getBinlogName() {
1493 $m = [];
1494 if ( preg_match( '!^(.+)\.(\d+)/(\d+)$!', (string)$this, $m ) ) {
1495 return $m[1];
1496 }
1497
1498 return false;
1499 }
1500
1504 protected function getCoordinates() {
1505 $m = [];
1506 if ( preg_match( '!\.(\d+)/(\d+)$!', (string)$this, $m ) ) {
1507 return [ (int)$m[1], (int)$m[2] ];
1508 }
1509
1510 return false;
1511 }
1512}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
$GLOBALS['IP']
$wgAllDBsAreLocalhost
Make all database connections secretly go to localhost.
$wgSQLMode
SQL Mode - default is turning off all modes, including strict, if set.
$wgDBmysql5
Set to true to engage MySQL 4.1/5.0 charset-related features; for now will just cause sending of 'SET...
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfLogDBError( $text, array $context=[])
Log for database errors.
wfHostname()
Fetch server name for use in error reporting etc.
$i
Definition Parser.php:1694
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition Setup.php:35
makeGlobalKey()
Make a global cache key.
Database error base class.
Base class for the more common types of database errors.
string[] $allViews
Definition Database.php:174
selectDB( $db)
Change the current database.
resource $mConn
Database connection.
Definition Database.php:52
close()
Closes a database connection.
Definition Database.php:694
getServer()
Get the server hostname or IP address.
nativeReplace( $table, $rows, $fname)
REPLACE query wrapper for MySQL and SQLite, which have a native REPLACE statement.
getLogContext(array $extras=[])
Create a log context to pass to wfLogDBError or other logging functions.
Definition Database.php:683
reportConnectionError( $error='Unknown error')
Definition Database.php:736
addQuotes( $s)
Adds quotes and backslashes.
indexName( $index)
Get the name of an index in a given table.
query( $sql, $fname=__METHOD__, $tempIgnore=false)
Run an SQL query and return the result.
Definition Database.php:780
commit( $fname=__METHOD__, $flush='')
Commits a transaction previously started using begin().
getLBInfo( $name=null)
Get properties passed down from the server info array of the load balancer.
Definition Database.php:252
selectField( $table, $var, $cond='', $fname=__METHOD__, $options=[])
A SELECT wrapper which returns a single field from a single result row.
restoreErrorHandler()
Definition Database.php:654
getLazyMasterHandle()
Definition Database.php:287
makeList( $a, $mode=LIST_COMMA)
Makes an encoded list of strings from an array.
doQuery( $sql)
The DBMS-dependent part of query()
tableExists( $table, $fname=__METHOD__)
Query whether a given table exists.
BagOStuff $srvCache
APC cache.
Definition Database.php:49
installErrorHandler()
Definition Database.php:645
closeConnection()
Closes underlying database connection.
Database abstraction object for MySQL.
indexInfo( $table, $index, $fname=__METHOD__)
Get information about an index into an object Returns false if the index does not exist.
lockTables( $read, $write, $method, $lowPriority=true)
estimateRowCount( $table, $vars=' *', $conds='', $fname=__METHOD__, $options=[])
Estimate rows in dataset Returns estimated count, based on EXPLAIN output Takes same arguments as Dat...
deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname=__METHOD__)
DELETE where the condition is a join.
wasReadOnlyError()
Determines if the last failure was due to the database being read-only.
upsert( $table, array $rows, array $uniqueIndexes, array $set, $fname=__METHOD__)
lock( $lockName, $method, $timeout=5)
wasConnectionError( $errno)
Determines if the given query error was a connection drop STUB.
getMysqlStatus( $which="%")
Get status information from SHOW STATUS in an associative array.
namedLocksEnqueue()
Check to see if a named lock used by lock() use blocking queues.
wasErrorReissuable()
Determines if the last query error was something that should be dealt with by pinging the connection ...
listViews( $prefix=null, $fname=__METHOD__)
Lists VIEWs in the database.
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
isView( $name, $prefix=null)
Differentiates between a TABLE and a VIEW.
mysqlDataSeek( $res, $row)
Move internal result pointer.
__construct(array $params)
Additional $params include:
unlock( $lockName, $method)
FROM MYSQL DOCS: http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release...
mysqlSetCharset( $charset)
Set the character set of the MySQL link.
getMasterPos()
Get the position of the master from SHOW MASTER STATUS.
getBindingHandle()
Get the underlying binding handle, mConn.
mysqlNumRows( $res)
Get number of rows in result.
mysqlFieldType( $res, $n)
Get the type of the specified field in a result.
streamStatementEnd(&$sql, &$newLine)
connectInitCharset()
Set the character set information right after connection.
fieldType( $res, $n)
mysql_field_type() wrapper
wasLockTimeout()
Determines if the last failure was due to a lock timeout.
open( $server, $user, $password, $dbName)
fieldInfo( $table, $field)
mysqlPing()
Ping a server connection or reconnect if there is no connection.
addIdentifierQuotes( $s)
MySQL uses backticks for identifier quoting instead of the sql standard "double quotes".
string $lagDetectionMethod
Method to detect slave lag.
mysqlNumFields( $res)
Get number of fields in result.
replace( $table, $uniqueIndexes, $rows, $fname=__METHOD__)
getServerUptime()
Determines how long the server has been up.
MysqlMasterPos $lastKnownSlavePos
mysqlFetchArray( $res)
Fetch a result row as an associative and numeric array.
getLag()
Get slave lag.
mysqlFetchField( $res, $n)
Get column information from a result.
getSlavePos()
Get the position of the master from SHOW SLAVE STATUS.
mysqlFieldName( $res, $n)
Get the name of the specified field in a result.
mysqlFreeResult( $res)
Free result memory.
mysqlRealEscapeString( $s)
masterPosWait(DBMasterPos $pos, $timeout)
Wait for the slave to catch up to a given master position.
lockIsFree( $lockName, $method)
Check to see if a named lock is available.
mysqlConnect( $realServer)
Open a connection to a MySQL server.
mysqlFetchObject( $res)
Fetch a result row as an object.
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
array $lagDetectionOptions
Method to detect slave lag.
getApproximateLagStatus()
Get a slave lag estimate for this server.
setBigSelects( $value=true)
setSessionOptions(array $options)
mysqlError( $conn=null)
Returns the text of the error message from previous MySQL operation.
wasDeadlock()
Determines if the last failure was due to a deadlock.
getSearchEngine()
Get search engine class.
dropTable( $tableName, $fName=__METHOD__)
getHeartbeatData(array $conds)
Utility class.
float $asOfTime
UNIX timestamp.
channelsMatch(DBMasterPos $pos)
__construct( $file, $pos)
hasReached(DBMasterPos $pos)
Result wrapper for grabbing data queried by someone else.
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 select() and insert() are usually more convenient. They take care of things like table prefixes and escaping for you. If you really need to make your own SQL
$res
Definition database.txt:21
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
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
when a variable name is used in a it is silently declared as a new local masking the global
Definition design.txt:95
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
const LIST_SET
Definition Defines.php:195
const LIST_AND
Definition Defines.php:194
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition hooks.txt:1007
the array() calling protocol came about after MediaWiki 1.4rc1.
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
Definition hooks.txt:1999
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 local account $user
Definition hooks.txt:249
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:Associative array mapping language codes to prefixed links of the form "language:title". & $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':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:1799
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition hooks.txt:1042
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition hooks.txt:1615
We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going and make changes or fix bugs In we can take all the code that deals with the little used title reversing we can concentrate it all in an extension file
Definition hooks.txt:108
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:314
processing should stop and the error should be shown to the user * false
Definition hooks.txt:189
null for the local 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:1458
returning false will NOT prevent logging $e
Definition hooks.txt:1940
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:37
An object representing a master or slave position in a replicated setup.
Base for all database-specific classes representing information about database fields.
lastErrno()
Get the last error number.
$cache
Definition mcc.php:33
$version
$params