52 protected $mConn = null;
56 protected $mTrxIdleCallbacks = [];
58 protected $mTrxPreCommitCallbacks = [];
68 protected $mSessionVars = [];
82 protected $mTrxLevel = 0;
90 protected $mTrxShortId =
'';
100 private $mTrxTimestamp = null;
103 private $mTrxSlaveLag = null;
112 private $mTrxFname = null;
120 private $mTrxDoneWrites =
false;
128 private $mTrxAutomatic =
false;
135 private $mTrxAtomicLevels = [];
142 private $mTrxAutomaticAtomic =
false;
149 private $mTrxWriteCallers = [];
156 private $mTrxWriteDuration = 0.0;
159 private $mNamedLocksHeld = [];
168 protected $fileHandle = null;
174 protected $allViews = null;
232 return $this->mTrxLevel ? $this->mTrxTimestamp : null;
236 return wfSetVar( $this->mTablePrefix, $prefix );
240 return wfSetVar( $this->mSchema, $schema );
249 $this->fileHandle = $fh;
253 if ( is_null(
$name ) ) {
256 if ( array_key_exists(
$name, $this->mLBInfo ) ) {
257 return $this->mLBInfo[
$name];
265 if ( is_null(
$value ) ) {
266 $this->mLBInfo =
$name;
279 $this->lazyMasterHandle = $conn;
295 if ( !$this->trxProfiler ) {
307 $this->trxProfiler = $profiler;
383 return $this->mDoneWrites ?:
false;
391 return $this->mTrxLevel && (
397 return $this->mTrxLevel ? $this->mTrxWriteDuration :
false;
401 return $this->mTrxLevel ? $this->mTrxWriteCallers : [];
409 $this->mFlags |= $flag;
413 $this->mFlags &= ~$flag;
417 return !!( $this->mFlags & $flag );
425 if ( $this->mTablePrefix ) {
426 return "{$this->mDBname}-{$this->mTablePrefix}";
441 $dbmsSpecificFilePath =
"$IP/maintenance/" . $this->
getType() .
"/$filename";
442 if ( file_exists( $dbmsSpecificFilePath ) ) {
443 return $dbmsSpecificFilePath;
445 return "$IP/maintenance/$filename";
503 $server = $params[
'host'];
504 $user = $params[
'user'];
505 $password = $params[
'password'];
506 $dbName = $params[
'dbname'];
507 $flags = $params[
'flags'];
508 $tablePrefix = $params[
'tablePrefix'];
509 $schema = $params[
'schema'];
510 $foreign = $params[
'foreign'];
514 if ( $wgCommandLineMode ) {
521 $this->mSessionVars = $params[
'variables'];
524 if ( $tablePrefix ===
'get from global' ) {
527 $this->mTablePrefix = $tablePrefix;
531 if ( $schema ===
'get from global' ) {
534 $this->mSchema = $schema;
537 $this->mForeign = $foreign;
539 if ( isset( $params[
'trxProfiler'] ) ) {
540 $this->trxProfiler = $params[
'trxProfiler'];
544 $this->
open( $server,
$user, $password, $dbName );
554 throw new MWException(
'Database serialization may cause problems, since ' .
555 'the connection is not restored on wakeup.' );
580 final public static function factory( $dbType, $p = [] ) {
581 $canonicalDBTypes = [
582 'mysql' => [
'mysqli',
'mysql' ],
590 $dbType = strtolower( $dbType );
591 if ( isset( $canonicalDBTypes[$dbType] ) && $canonicalDBTypes[$dbType] ) {
592 $possibleDrivers = $canonicalDBTypes[$dbType];
593 if ( !empty( $p[
'driver'] ) ) {
594 if ( in_array( $p[
'driver'], $possibleDrivers ) ) {
595 $driver = $p[
'driver'];
598 " cannot construct Database with type '$dbType' and driver '{$p['driver']}'" );
601 foreach ( $possibleDrivers
as $posDriver ) {
602 if ( extension_loaded( $posDriver ) ) {
603 $driver = $posDriver;
611 if ( $driver ===
false ) {
613 " no viable database extension found for type '$dbType'" );
621 'mssql' =>
'get from global',
624 $class =
'Database' . ucfirst( $driver );
625 if ( class_exists( $class ) && is_subclass_of( $class,
'DatabaseBase' ) ) {
627 $p[
'host'] = isset( $p[
'host'] ) ? $p[
'host'] :
false;
628 $p[
'user'] = isset( $p[
'user'] ) ? $p[
'user'] :
false;
629 $p[
'password'] = isset( $p[
'password'] ) ? $p[
'password'] :
false;
630 $p[
'dbname'] = isset( $p[
'dbname'] ) ? $p[
'dbname'] :
false;
631 $p[
'flags'] = isset( $p[
'flags'] ) ? $p[
'flags'] : 0;
632 $p[
'variables'] = isset( $p[
'variables'] ) ? $p[
'variables'] : [];
633 $p[
'tablePrefix'] = isset( $p[
'tablePrefix'] ) ? $p[
'tablePrefix'] :
'get from global';
634 if ( !isset( $p[
'schema'] ) ) {
635 $p[
'schema'] = isset( $defaultSchemas[$dbType] ) ? $defaultSchemas[$dbType] : null;
637 $p[
'foreign'] = isset( $p[
'foreign'] ) ? $p[
'foreign'] :
false;
639 return new $class( $p );
646 $this->mPHPError =
false;
647 $this->htmlErrors = ini_set(
'html_errors',
'0' );
648 set_error_handler( [ $this,
'connectionErrorHandler' ] );
655 restore_error_handler();
656 if ( $this->htmlErrors !==
false ) {
657 ini_set(
'html_errors', $this->htmlErrors );
659 if ( $this->mPHPError ) {
660 $error = preg_replace(
'!\[<a.*</a>\]!',
'', $this->mPHPError );
661 $error = preg_replace(
'!^.*?:\s?(.*)$!',
'$1', $error );
674 $this->mPHPError = $errstr;
686 'db_server' => $this->mServer,
687 'db_name' => $this->mDBname,
688 'db_user' => $this->mUser,
695 if ( count( $this->mTrxIdleCallbacks ) ) {
696 throw new MWException(
"Transaction idle callbacks still pending." );
698 if ( $this->mConn ) {
700 if ( !$this->mTrxAutomatic ) {
701 wfWarn(
"Transaction still in progress (from {$this->mTrxFname}), " .
702 " performing implicit commit before closing connection!" );
705 $this->
commit( __METHOD__,
'flush' );
709 $this->mConn =
false;
713 $this->mOpened =
false;
753 abstract protected function doQuery( $sql );
763 return !preg_match(
'/^(?:SELECT|BEGIN|ROLLBACK|COMMIT|SET|SHOW|EXPLAIN|\(SELECT)\b/i', $sql );
776 $verb = substr( $sql, 0, strcspn( $sql,
" \t\r\n" ) );
777 return !in_array( $verb, [
'BEGIN',
'COMMIT',
'ROLLBACK',
'SHOW',
'SET' ] );
780 public function query( $sql,
$fname = __METHOD__, $tempIgnore =
false ) {
783 $this->mLastQuery = $sql;
786 if ( $isWriteQuery ) {
788 if ( $reason !==
false ) {
791 # Set a flag indicating that writes have been done
792 $this->mDoneWrites = microtime(
true );
795 # Add a comment for easy SHOW PROCESSLIST interpretation
796 if ( is_object( $wgUser ) && $wgUser->isItemLoaded(
'name' ) ) {
797 $userName = $wgUser->getName();
798 if ( mb_strlen( $userName ) > 15 ) {
799 $userName = mb_substr( $userName, 0, 15 ) .
'...';
801 $userName = str_replace(
'/',
'', $userName );
808 $commentedSql = preg_replace(
'/\s|$/',
" /* $fname $userName */ ", $sql, 1 );
811 $this->
begin( __METHOD__ .
" ($fname)" );
812 $this->mTrxAutomatic =
true;
815 # Keep track of whether the transaction has write queries pending
816 if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $isWriteQuery ) {
817 $this->mTrxDoneWrites =
true;
819 $this->mServer, $this->mDBname, $this->mTrxShortId );
822 $isMaster = !is_null( $this->
getLBInfo(
'master' ) );
823 # generalizeSQL will probably cut down the query to reasonable
824 # logging size most of the time. The substr is really just a sanity check.
827 $totalProf =
'DatabaseBase::query-master';
830 $totalProf =
'DatabaseBase::query';
832 # Include query transaction state
833 $queryProf .= $this->mTrxShortId ?
" [TRX#{$this->mTrxShortId}]" :
"";
837 $totalProfSection = $profiler->scopedProfileIn( $totalProf );
838 $queryProfSection = $profiler->scopedProfileIn( $queryProf );
841 if ( $this->
debug() ) {
842 wfDebugLog(
'queries', sprintf(
"%s: %s", $this->mDBname, $commentedSql ) );
847 # Avoid fatals if close() was called
850 # Do the query and handle errors
851 $startTime = microtime(
true );
853 $queryRuntime = microtime(
true ) - $startTime;
854 # Log the query time and feed it into the DB trx profiler
856 $queryProf, $startTime, $isWriteQuery, $this->
affectedRows() );
860 # Try reconnecting if the connection was lost
862 # Transaction is gone; this can mean lost writes or REPEATABLE-READ snapshots
864 # T127428: for non-write transactions, a disconnect and a COMMIT are similar:
865 # neither changed data and in both cases any read snapshots are reset anyway.
867 # Update state tracking to reflect transaction loss
868 $this->mTrxLevel = 0;
869 $this->mTrxIdleCallbacks = [];
870 $this->mTrxPreCommitCallbacks = [];
871 wfDebug(
"Connection lost, reconnecting...\n" );
872 # Stash the last error values since ping() might clear them
875 if ( $this->
ping() ) {
878 $msg = __METHOD__ .
": lost connection to $server; reconnected";
881 if ( ( $hadTrx && !$isNoopCommit ) || $this->mNamedLocksHeld ) {
882 # Leave $ret as false and let an error be reported.
883 # Callers may catch the exception and continue to use the DB.
886 # Should be safe to silently retry (no trx/callbacks/locks)
887 $startTime = microtime(
true );
889 $queryRuntime = microtime(
true ) - $startTime;
890 # Log the query time and feed it into the DB trx profiler
892 $queryProf, $startTime, $isWriteQuery, $this->
affectedRows() );
899 if (
false ===
$ret ) {
910 if ( $isWriteQuery && $this->mTrxLevel ) {
911 $this->mTrxWriteDuration += $queryRuntime;
912 $this->mTrxWriteCallers[] =
$fname;
920 wfDebug(
"SQL ERROR (ignored): $error\n" );
922 $sql1line = mb_substr( str_replace(
"\n",
"\\n", $sql ), 0, 5 * 1024 );
924 "{fname}\t{db_server}\t{errno}\t{error}\t{sql1line}",
926 'method' => __METHOD__,
929 'sql1line' => $sql1line,
933 wfDebug(
"SQL ERROR: " . $error .
"\n" );
952 protected function prepare( $sql, $func =
'DatabaseBase::prepare' ) {
957 return [
'query' => $sql,
'func' => $func ];
976 if ( !is_array(
$args ) ) {
978 $args = func_get_args();
979 array_shift(
$args );
984 return $this->
query( $sql, $prepared[
'func'] );
996 $this->preparedArgs =&
$args;
998 return preg_replace_callback(
'/(\\\\[?!&]|[?!&])/',
999 [ &$this,
'fillPreparedArg' ], $preparedQuery );
1021 list( , $arg ) = each( $this->preparedArgs );
1029 # return $this->addQuotes( file_get_contents( $arg ) );
1032 '& mode is not implemented. If it\'s really needed, uncomment the line above.'
1037 'Received invalid match. This should never happen!'
1048 if ( $var ===
'*' ) {
1065 if ( $row !==
false ) {
1066 return reset( $row );
1073 $table, $var, $cond =
'',
$fname = __METHOD__,
$options = [], $join_conds = []
1075 if ( $var ===
'*' ) {
1077 } elseif ( !is_string( $var ) ) {
1086 if (
$res ===
false ) {
1091 foreach (
$res as $row ) {
1092 $values[] = $row->$var;
1108 $preLimitTail = $postLimitTail =
'';
1114 if ( is_numeric(
$key ) ) {
1115 $noKeyOptions[$option] =
true;
1129 if ( isset( $noKeyOptions[
'FOR UPDATE'] ) ) {
1130 $postLimitTail .=
' FOR UPDATE';
1133 if ( isset( $noKeyOptions[
'LOCK IN SHARE MODE'] ) ) {
1134 $postLimitTail .=
' LOCK IN SHARE MODE';
1137 if ( isset( $noKeyOptions[
'DISTINCT'] ) || isset( $noKeyOptions[
'DISTINCTROW'] ) ) {
1138 $startOpts .=
'DISTINCT';
1141 # Various MySQL extensions
1142 if ( isset( $noKeyOptions[
'STRAIGHT_JOIN'] ) ) {
1143 $startOpts .=
' /*! STRAIGHT_JOIN */';
1146 if ( isset( $noKeyOptions[
'HIGH_PRIORITY'] ) ) {
1147 $startOpts .=
' HIGH_PRIORITY';
1150 if ( isset( $noKeyOptions[
'SQL_BIG_RESULT'] ) ) {
1151 $startOpts .=
' SQL_BIG_RESULT';
1154 if ( isset( $noKeyOptions[
'SQL_BUFFER_RESULT'] ) ) {
1155 $startOpts .=
' SQL_BUFFER_RESULT';
1158 if ( isset( $noKeyOptions[
'SQL_SMALL_RESULT'] ) ) {
1159 $startOpts .=
' SQL_SMALL_RESULT';
1162 if ( isset( $noKeyOptions[
'SQL_CALC_FOUND_ROWS'] ) ) {
1163 $startOpts .=
' SQL_CALC_FOUND_ROWS';
1166 if ( isset( $noKeyOptions[
'SQL_CACHE'] ) ) {
1167 $startOpts .=
' SQL_CACHE';
1170 if ( isset( $noKeyOptions[
'SQL_NO_CACHE'] ) ) {
1171 $startOpts .=
' SQL_NO_CACHE';
1174 if ( isset(
$options[
'USE INDEX'] ) && is_string(
$options[
'USE INDEX'] ) ) {
1180 return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail ];
1193 if ( isset(
$options[
'GROUP BY'] ) ) {
1194 $gb = is_array(
$options[
'GROUP BY'] )
1195 ? implode(
',',
$options[
'GROUP BY'] )
1197 $sql .=
' GROUP BY ' . $gb;
1199 if ( isset(
$options[
'HAVING'] ) ) {
1200 $having = is_array(
$options[
'HAVING'] )
1203 $sql .=
' HAVING ' . $having;
1218 if ( isset(
$options[
'ORDER BY'] ) ) {
1219 $ob = is_array(
$options[
'ORDER BY'] )
1220 ? implode(
',',
$options[
'ORDER BY'] )
1223 return ' ORDER BY ' . $ob;
1231 $options = [], $join_conds = [] ) {
1240 if ( is_array(
$vars ) ) {
1245 $useIndexes = ( isset(
$options[
'USE INDEX'] ) && is_array(
$options[
'USE INDEX'] ) )
1249 if ( is_array( $table ) ) {
1252 } elseif ( $table !=
'' ) {
1253 if ( $table[0] ==
' ' ) {
1254 $from =
' FROM ' . $table;
1263 list( $startOpts, $useIndex, $preLimitTail, $postLimitTail ) =
1266 if ( !empty( $conds ) ) {
1267 if ( is_array( $conds ) ) {
1270 $sql =
"SELECT $startOpts $vars $from $useIndex WHERE $conds $preLimitTail";
1272 $sql =
"SELECT $startOpts $vars $from $useIndex $preLimitTail";
1275 if ( isset(
$options[
'LIMIT'] ) ) {
1279 $sql =
"$sql $postLimitTail";
1281 if ( isset(
$options[
'EXPLAIN'] ) ) {
1282 $sql =
'EXPLAIN ' . $sql;
1295 if (
$res ===
false ) {
1316 $rows = ( isset( $row[
'rowcount'] ) ) ? (
int)$row[
'rowcount'] : 0;
1330 $res = $this->
query(
"SELECT COUNT(*) AS $rowCountCol FROM ($sql) $tableName",
$fname );
1334 $rows = ( isset( $row[
'rowcount'] ) ) ? (
int)$row[
'rowcount'] : 0;
1349 # This does the same as the regexp below would do, but in such a way
1350 # as to avoid crashing php on some large strings.
1351 # $sql = preg_replace( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql );
1353 $sql = str_replace(
"\\\\",
'', $sql );
1354 $sql = str_replace(
"\\'",
'', $sql );
1355 $sql = str_replace(
"\\\"",
'', $sql );
1356 $sql = preg_replace(
"/'.*'/s",
"'X'", $sql );
1357 $sql = preg_replace(
'/".*"/s',
"'X'", $sql );
1359 # All newlines, tabs, etc replaced by single space
1360 $sql = preg_replace(
'/\s+/',
' ', $sql );
1363 # except the ones surrounded by characters, e.g. l10n
1364 $sql = preg_replace(
'/-?\d+(,-?\d+)+/s',
'N,...,N', $sql );
1365 $sql = preg_replace(
'/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s',
'N', $sql );
1371 $info = $this->
fieldInfo( $table, $field );
1382 if ( is_null( $info ) ) {
1385 return $info !==
false;
1399 $indexInfo = $this->
indexInfo( $table, $index );
1401 if ( !$indexInfo ) {
1405 return !$indexInfo[0]->Non_unique;
1419 # No rows to insert, easy just return now
1420 if ( !count( $a ) ) {
1431 if ( isset(
$options[
'fileHandle'] ) ) {
1436 if ( isset( $a[0] ) && is_array( $a[0] ) ) {
1438 $keys = array_keys( $a[0] );
1441 $keys = array_keys( $a );
1445 " INTO $table (" . implode(
',',
$keys ) .
') VALUES ';
1449 foreach ( $a
as $row ) {
1455 $sql .=
'(' . $this->
makeList( $row ) .
')';
1458 $sql .=
'(' . $this->
makeList( $a ) .
')';
1461 if ( $fh !== null &&
false === fwrite( $fh, $sql ) ) {
1463 } elseif ( $fh !== null ) {
1483 if ( in_array(
'LOW_PRIORITY',
$options ) ) {
1487 if ( in_array(
'IGNORE',
$options ) ) {
1503 return implode(
' ', $opts );
1511 if ( $conds !== [] && $conds !==
'*' ) {
1519 if ( !is_array( $a ) ) {
1520 throw new DBUnexpectedError( $this,
'DatabaseBase::makeList called with incorrect parameters' );
1526 foreach ( $a
as $field =>
$value ) {
1530 } elseif ( $mode ==
LIST_OR ) {
1539 if ( ( $mode ==
LIST_AND || $mode ==
LIST_OR ) && is_numeric( $field ) ) {
1540 $list .=
"($value)";
1541 } elseif ( ( $mode ==
LIST_SET ) && is_numeric( $field ) ) {
1545 $includeNull =
false;
1546 foreach ( array_keys(
$value, null,
true )
as $nullKey ) {
1547 $includeNull =
true;
1548 unset(
$value[$nullKey] );
1550 if ( count(
$value ) == 0 && !$includeNull ) {
1551 throw new MWException( __METHOD__ .
": empty input for field $field" );
1552 } elseif ( count(
$value ) == 0 ) {
1554 $list .=
"$field IS NULL";
1557 if ( $includeNull ) {
1561 if ( count(
$value ) == 1 ) {
1571 if ( $includeNull ) {
1572 $list .=
" OR $field IS NULL)";
1575 } elseif (
$value === null ) {
1577 $list .=
"$field IS ";
1579 $list .=
"$field = ";
1584 $list .=
"$field = ";
1596 foreach ( $data
as $base => $sub ) {
1597 if ( count( $sub ) ) {
1599 [ $baseKey =>
$base, $subKey => array_keys( $sub ) ],
1628 public function bitAnd( $fieldLeft, $fieldRight ) {
1629 return "($fieldLeft & $fieldRight)";
1632 public function bitOr( $fieldLeft, $fieldRight ) {
1633 return "($fieldLeft | $fieldRight)";
1637 return 'CONCAT(' . implode(
',', $stringList ) .
')';
1641 $delim, $table, $field, $conds =
'', $join_conds = []
1643 $fld =
"GROUP_CONCAT($field SEPARATOR " . $this->
addQuotes( $delim ) .
')';
1645 return '(' . $this->
selectSQLText( $table, $fld, $conds, null, [], $join_conds ) .
')';
1649 # Stub. Shouldn't cause serious problems if it's not overridden, but
1650 # if your database engine supports a concept similar to MySQL's
1651 # databases you may as well.
1652 $this->mDBname = $db;
1686 # Skip the entire process when we have a string quoted on both ends.
1687 # Note that we check the end so that we will still quote any use of
1688 # use of `database`.table. But won't break things if someone wants
1689 # to query a database table with a dot in the name.
1694 # Lets test for any bits of text that should never show up in a table
1695 # name. Basically anything like JOIN or ON which are actually part of
1696 # SQL queries, but may end up inside of the table value to combine
1697 # sql. Such as how the API is doing.
1698 # Note that we use a whitespace test rather than a \b test to avoid
1699 # any remote case where a word like on may be inside of a table name
1700 # surrounded by symbols which may be considered word breaks.
1701 if ( preg_match(
'/(^|\s)(DISTINCT|JOIN|ON|AS)(\s|$)/i',
$name ) !== 0 ) {
1705 # Split database and table into proper variables.
1706 # We reverse the explode so that database.table and table both output
1707 # the correct table.
1708 $dbDetails = explode(
'.',
$name, 3 );
1709 if ( count( $dbDetails ) == 3 ) {
1710 list( $database, $schema, $table ) = $dbDetails;
1711 # We don't want any prefix added in this case
1713 } elseif ( count( $dbDetails ) == 2 ) {
1714 list( $database, $table ) = $dbDetails;
1715 # We don't want any prefix added in this case
1716 # In dbs that support it, $database may actually be the schema
1717 # but that doesn't affect any of the functionality here
1721 list( $table ) = $dbDetails;
1722 if ( $wgSharedDB !== null # We have a shared
database
1723 && $this->mForeign ==
false # We
're not working on a foreign database
1724 && !$this->isQuotedIdentifier( $table ) # Prevent shared tables listing '`
table`
'
1725 && in_array( $table, $wgSharedTables ) # A shared table is selected
1727 $database = $wgSharedDB;
1728 $schema = $wgSharedSchema === null ? $this->mSchema : $wgSharedSchema;
1729 $prefix = $wgSharedPrefix === null ? $this->mTablePrefix : $wgSharedPrefix;
1732 $schema = $this->mSchema; # Default schema
1733 $prefix = $this->mTablePrefix; # Default prefix
1737 # Quote $table and apply the prefix if not quoted.
1738 # $tableName might be empty if this is called from Database::replaceVars()
1739 $tableName = "{$prefix}{$table}";
1740 if ( $format == 'quoted
' && !$this->isQuotedIdentifier( $tableName ) && $tableName !== '' ) {
1741 $tableName = $this->addIdentifierQuotes( $tableName );
1744 # Quote $schema and merge it with the table name if needed
1745 if ( strlen( $schema ) ) {
1746 if ( $format == 'quoted
' && !$this->isQuotedIdentifier( $schema ) ) {
1747 $schema = $this->addIdentifierQuotes( $schema );
1749 $tableName = $schema . '.
' . $tableName;
1752 # Quote $database and merge it with the table name if needed
1753 if ( $database !== null ) {
1754 if ( $format == 'quoted
' && !$this->isQuotedIdentifier( $database ) ) {
1755 $database = $this->addIdentifierQuotes( $database );
1757 $tableName = $database . '.
' . $tableName;
1774 public function tableNames() {
1775 $inArray = func_get_args();
1778 foreach ( $inArray as $name ) {
1779 $retVal[$name] = $this->tableName( $name );
1796 public function tableNamesN() {
1797 $inArray = func_get_args();
1800 foreach ( $inArray as $name ) {
1801 $retVal[] = $this->tableName( $name );
1815 public function tableNameWithAlias( $name, $alias = false ) {
1816 if ( !$alias || $alias == $name ) {
1817 return $this->tableName( $name );
1819 return $this->tableName( $name ) . ' ' . $this->addIdentifierQuotes( $alias );
1829 public function tableNamesWithAlias( $tables ) {
1831 foreach ( $tables as $alias => $table ) {
1832 if ( is_numeric( $alias ) ) {
1835 $retval[] = $this->tableNameWithAlias( $table, $alias );
1849 public function fieldNameWithAlias( $name, $alias = false ) {
1850 if ( !$alias || (string)$alias === (string)$name ) {
1853 return $name . ' AS
' . $this->addIdentifierQuotes( $alias ); // PostgreSQL needs AS
1863 public function fieldNamesWithAlias( $fields ) {
1865 foreach ( $fields as $alias => $field ) {
1866 if ( is_numeric( $alias ) ) {
1869 $retval[] = $this->fieldNameWithAlias( $field, $alias );
1884 protected function tableNamesWithUseIndexOrJOIN(
1885 $tables, $use_index = [], $join_conds = []
1889 $use_index = (array)$use_index;
1890 $join_conds = (array)$join_conds;
1892 foreach ( $tables as $alias => $table ) {
1893 if ( !is_string( $alias ) ) {
1894 // No alias? Set it equal to the table name
1897 // Is there a JOIN clause for this table?
1898 if ( isset( $join_conds[$alias] ) ) {
1899 list( $joinType, $conds ) = $join_conds[$alias];
1900 $tableClause = $joinType;
1901 $tableClause .= ' ' . $this->tableNameWithAlias( $table, $alias );
1902 if ( isset( $use_index[$alias] ) ) { // has USE INDEX?
1903 $use = $this->useIndexClause( implode( ',
', (array)$use_index[$alias] ) );
1905 $tableClause .= ' ' . $use;
1908 $on = $this->makeList( (array)$conds, LIST_AND );
1910 $tableClause .= ' ON (
' . $on . ')
';
1913 $retJOIN[] = $tableClause;
1914 } elseif ( isset( $use_index[$alias] ) ) {
1915 // Is there an INDEX clause for this table?
1916 $tableClause = $this->tableNameWithAlias( $table, $alias );
1917 $tableClause .= ' ' . $this->useIndexClause(
1918 implode( ',
', (array)$use_index[$alias] )
1921 $ret[] = $tableClause;
1923 $tableClause = $this->tableNameWithAlias( $table, $alias );
1925 $ret[] = $tableClause;
1929 // We can't separate
explicit JOIN clauses with
',',
use ' ' for those
1930 $implicitJoins = !empty(
$ret ) ? implode(
',',
$ret ) :
"";
1931 $explicitJoins = !empty( $retJOIN ) ? implode(
' ', $retJOIN ) :
"";
1934 return implode(
' ', [ $implicitJoins, $explicitJoins ] );
1946 'ar_usertext_timestamp' =>
'usertext_timestamp',
1947 'un_user_id' =>
'user_id',
1948 'un_user_ip' =>
'user_ip',
1951 if ( isset( $renamed[$index] ) ) {
1952 return $renamed[$index];
1959 if (
$s instanceof
Blob ) {
1962 if (
$s === null ) {
1965 # This will also quote numeric values. This should be harmless,
1966 # and protects against weird problems that occur when they really
1967 # _are_ strings such as article titles and string->number->string
1968 # conversion is not 1:1.
1983 return '"' . str_replace(
'"',
'""',
$s ) .
'"';
1996 return $name[0] ==
'"' && substr(
$name, -1, 1 ) ==
'"';
2004 return addcslashes(
$s,
'\%_' );
2018 $s .= $value->toString();
2024 return " LIKE {$this->addQuotes( $s )} ";
2054 $quotedTable = $this->
tableName( $table );
2056 if ( count( $rows ) == 0 ) {
2061 if ( !is_array( reset( $rows ) ) ) {
2066 foreach ( $rows
as $row ) {
2067 # Delete rows which collide
2068 if ( $uniqueIndexes ) {
2069 $sql =
"DELETE FROM $quotedTable WHERE ";
2071 foreach ( $uniqueIndexes
as $index ) {
2078 if ( is_array( $index ) ) {
2080 foreach ( $index
as $col ) {
2086 $sql .= $col .
'=' . $this->
addQuotes( $row[$col] );
2089 $sql .= $index .
'=' . $this->
addQuotes( $row[$index] );
2096 # Now insert the row
2115 if ( !is_array( reset( $rows ) ) ) {
2119 $sql =
"REPLACE INTO $table (" . implode(
',', array_keys( $rows[0] ) ) .
') VALUES ';
2122 foreach ( $rows
as $row ) {
2129 $sql .=
'(' . $this->
makeList( $row ) .
')';
2138 if ( !count( $rows ) ) {
2142 if ( !is_array( reset( $rows ) ) ) {
2146 if ( count( $uniqueIndexes ) ) {
2148 foreach ( $rows
as $row ) {
2149 foreach ( $uniqueIndexes
as $index ) {
2150 $index = is_array( $index ) ? $index : [ $index ];
2152 foreach ( $index
as $column ) {
2153 $rowKey[$column] = $row[$column];
2168 # Update any existing conflicting row(s)
2169 if ( $where !==
false ) {
2174 # Now insert any non-conflicting row(s)
2175 $ok = $this->
insert( $table, $rows,
$fname, [
'IGNORE' ] ) && $ok;
2189 public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds,
2194 'DatabaseBase::deleteJoin() called with empty $conds' );
2197 $delTable = $this->
tableName( $delTable );
2198 $joinTable = $this->
tableName( $joinTable );
2199 $sql =
"DELETE FROM $delTable WHERE $delVar IN (SELECT $joinVar FROM $joinTable ";
2200 if ( $conds !=
'*' ) {
2217 $sql =
"SHOW COLUMNS FROM $table LIKE \"$field\";";
2218 $res = $this->
query( $sql,
'DatabaseBase::textFieldSize' );
2223 if ( preg_match(
'/\((.*)\)/', $row->Type, $m ) ) {
2244 public function delete( $table, $conds,
$fname = __METHOD__ ) {
2246 throw new DBUnexpectedError( $this,
'DatabaseBase::delete() called with no conditions' );
2250 $sql =
"DELETE FROM $table";
2252 if ( $conds !=
'*' ) {
2253 if ( is_array( $conds ) ) {
2256 $sql .=
' WHERE ' . $conds;
2259 return $this->
query( $sql, $fname );
2263 $fname = __METHOD__,
2264 $insertOptions = [], $selectOptions = []
2266 $destTable = $this->
tableName( $destTable );
2268 if ( !is_array( $insertOptions ) ) {
2269 $insertOptions = [ $insertOptions ];
2274 if ( !is_array( $selectOptions ) ) {
2275 $selectOptions = [ $selectOptions ];
2280 if ( is_array( $srcTable ) ) {
2281 $srcTable = implode(
',', array_map( [ &$this,
'tableName' ], $srcTable ) );
2283 $srcTable = $this->
tableName( $srcTable );
2286 $sql =
"INSERT $insertOptions INTO $destTable (" . implode(
',', array_keys( $varMap ) ) .
')' .
2287 " SELECT $startOpts " . implode(
',', $varMap ) .
2288 " FROM $srcTable $useIndex ";
2290 if ( $conds !=
'*' ) {
2291 if ( is_array( $conds ) ) {
2294 $sql .=
" WHERE $conds";
2297 $sql .=
" $tailOpts";
2299 return $this->
query( $sql, $fname );
2322 if ( !is_numeric(
$limit ) ) {
2323 throw new DBUnexpectedError( $this,
"Invalid non-numeric limit passed to limitResult()\n" );
2326 return "$sql LIMIT "
2327 . ( ( is_numeric( $offset ) && $offset != 0 ) ?
"{$offset}," :
"" )
2336 $glue = $all ?
') UNION ALL (' :
') UNION (';
2338 return '(' . implode( $glue, $sqls ) .
')';
2342 if ( is_array( $cond ) ) {
2346 return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
2350 return "REPLACE({$orig}, {$old}, {$new})";
2404 $args = func_get_args();
2405 $function = array_shift(
$args );
2406 $tries = self::DEADLOCK_TRIES;
2408 $this->
begin( __METHOD__ );
2415 $retVal = call_user_func_array( $function,
$args );
2420 usleep( mt_rand( self::DEADLOCK_DELAY_MIN, self::DEADLOCK_DELAY_MAX ) );
2426 }
while ( --$tries > 0 );
2428 if ( $tries <= 0 ) {
2433 $this->
commit( __METHOD__ );
2440 # Real waits are implemented in the subclass.
2455 $this->mTrxIdleCallbacks[] = [ $callback,
wfGetCaller() ];
2456 if ( !$this->mTrxLevel ) {
2462 if ( $this->mTrxLevel ) {
2463 $this->mTrxPreCommitCallbacks[] = [ $callback,
wfGetCaller() ];
2477 $e = $ePrior = null;
2480 $this->mTrxIdleCallbacks = [];
2481 foreach ( $callbacks
as $callback ) {
2483 list( $phpCallback ) = $callback;
2485 call_user_func( $phpCallback );
2503 }
while ( count( $this->mTrxIdleCallbacks ) );
2516 $e = $ePrior = null;
2519 $this->mTrxPreCommitCallbacks = [];
2520 foreach ( $callbacks
as $callback ) {
2522 list( $phpCallback ) = $callback;
2523 call_user_func( $phpCallback );
2531 }
while ( count( $this->mTrxPreCommitCallbacks ) );
2539 if ( !$this->mTrxLevel ) {
2540 $this->
begin( $fname );
2541 $this->mTrxAutomatic =
true;
2545 $this->mTrxAutomaticAtomic =
true;
2549 $this->mTrxAtomicLevels[] =
$fname;
2553 if ( !$this->mTrxLevel ) {
2556 if ( !$this->mTrxAtomicLevels ||
2557 array_pop( $this->mTrxAtomicLevels ) !== $fname
2562 if ( !$this->mTrxAtomicLevels && $this->mTrxAutomaticAtomic ) {
2563 $this->
commit( $fname,
'flush' );
2568 if ( !is_callable( $callback ) ) {
2574 call_user_func_array( $callback, [ $this, $fname ] );
2582 final public function begin( $fname = __METHOD__ ) {
2583 if ( $this->mTrxLevel ) {
2584 if ( $this->mTrxAtomicLevels ) {
2587 $levels = implode(
', ', $this->mTrxAtomicLevels );
2590 "Got explicit BEGIN from $fname while atomic section(s) $levels are open."
2592 } elseif ( !$this->mTrxAutomatic ) {
2595 $msg =
"$fname: Transaction already in progress (from {$this->mTrxFname}), " .
2596 " performing implicit commit!";
2600 'method' => __METHOD__,
2606 if ( $this->mTrxDoneWrites ) {
2607 wfDebug(
"$fname: Automatic transaction with writes in progress" .
2608 " (from {$this->mTrxFname}), performing implicit commit!\n"
2616 if ( $this->mTrxDoneWrites ) {
2617 $this->mDoneWrites = microtime(
true );
2619 $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
2624 # Avoid fatals if close() was called
2628 $this->mTrxTimestamp = microtime(
true );
2629 $this->mTrxFname =
$fname;
2630 $this->mTrxDoneWrites =
false;
2631 $this->mTrxAutomatic =
false;
2632 $this->mTrxAutomaticAtomic =
false;
2633 $this->mTrxAtomicLevels = [];
2634 $this->mTrxIdleCallbacks = [];
2635 $this->mTrxPreCommitCallbacks = [];
2637 $this->mTrxWriteDuration = 0.0;
2638 $this->mTrxWriteCallers = [];
2643 $this->mTrxSlaveLag =
$status[
'lag'] + ( microtime(
true ) -
$status[
'since'] );
2653 $this->
query(
'BEGIN', $fname );
2654 $this->mTrxLevel = 1;
2657 final public function commit( $fname = __METHOD__, $flush =
'' ) {
2658 if ( $this->mTrxLevel && $this->mTrxAtomicLevels ) {
2660 $levels = implode(
', ', $this->mTrxAtomicLevels );
2663 "Got COMMIT while atomic sections $levels are still open"
2667 if ( $flush ===
'flush' ) {
2668 if ( !$this->mTrxLevel ) {
2670 } elseif ( !$this->mTrxAutomatic ) {
2673 "$fname: Flushing an explicit transaction, getting out of sync!"
2677 if ( !$this->mTrxLevel ) {
2678 wfWarn(
"$fname: No transaction to commit, something got out of sync!" );
2680 } elseif ( $this->mTrxAutomatic ) {
2681 wfWarn(
"$fname: Explicit commit of implicit transaction. Something may be out of sync!" );
2685 # Avoid fatals if close() was called
2691 if ( $this->mTrxDoneWrites ) {
2692 $this->mDoneWrites = microtime(
true );
2694 $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
2706 if ( $this->mTrxLevel ) {
2707 $this->
query(
'COMMIT', $fname );
2708 $this->mTrxLevel = 0;
2712 final public function rollback( $fname = __METHOD__, $flush =
'' ) {
2713 if ( $flush !==
'flush' ) {
2714 if ( !$this->mTrxLevel ) {
2715 wfWarn(
"$fname: No transaction to rollback, something got out of sync!" );
2719 if ( !$this->mTrxLevel ) {
2724 # Avoid fatals if close() was called
2728 $this->mTrxIdleCallbacks = [];
2729 $this->mTrxPreCommitCallbacks = [];
2730 $this->mTrxAtomicLevels = [];
2731 if ( $this->mTrxDoneWrites ) {
2733 $this->mServer, $this->mDBname, $this->mTrxShortId );
2744 if ( $this->mTrxLevel ) {
2745 $this->
query(
'ROLLBACK', $fname,
true );
2746 $this->mTrxLevel = 0;
2769 'DatabaseBase::duplicateTableStructure is not implemented in descendant class' );
2773 throw new MWException(
'DatabaseBase::listTables is not implemented in descendant class' );
2781 $this->allViews = null;
2796 public function listViews( $prefix = null, $fname = __METHOD__ ) {
2797 throw new MWException(
'DatabaseBase::listViews is not implemented in descendant class' );
2809 throw new MWException(
'DatabaseBase::isView is not implemented in descendant class' );
2817 if ( is_null( $ts ) ) {
2842 } elseif (
$result ===
true ) {
2846 return new ResultWrapper( $this,
$result );
2851 # Stub. Not essential to override.
2871 return $this->mTrxLevel
2885 'since' => microtime(
true )
2908 $res = [
'lag' => 0,
'since' => INF,
'pending' =>
false ];
2909 foreach ( func_get_args()
as $db ) {
2911 $status = $db->getSessionLagStatus();
2912 if (
$status[
'lag'] ===
false ) {
2913 $res[
'lag'] =
false;
2914 } elseif (
$res[
'lag'] !==
false ) {
2918 $res[
'pending'] =
$res[
'pending'] ?: $db->writesPending();
2937 if ( $b instanceof
Blob ) {
2963 $filename, $lineCallback =
false, $resultCallback =
false, $fname =
false, $inputCallback =
false
2965 MediaWiki\suppressWarnings();
2966 $fp = fopen( $filename,
'r' );
2967 MediaWiki\restoreWarnings();
2969 if (
false === $fp ) {
2970 throw new MWException(
"Could not open \"{$filename}\".\n" );
2974 $fname = __METHOD__ .
"( $filename )";
2978 $error = $this->
sourceStream( $fp, $lineCallback, $resultCallback, $fname, $inputCallback );
3001 if ( file_exists(
"$IP/maintenance/$dbType/archives/$patch" ) ) {
3002 return "$IP/maintenance/$dbType/archives/$patch";
3004 return "$IP/maintenance/archives/$patch";
3009 $this->mSchemaVars =
$vars;
3025 public function sourceStream( $fp, $lineCallback =
false, $resultCallback =
false,
3026 $fname = __METHOD__, $inputCallback =
false
3030 while ( !feof( $fp ) ) {
3031 if ( $lineCallback ) {
3032 call_user_func( $lineCallback );
3035 $line = trim( fgets( $fp ) );
3037 if (
$line ==
'' ) {
3053 if ( $done || feof( $fp ) ) {
3056 if ( ( $inputCallback && call_user_func( $inputCallback, $cmd ) ) || !$inputCallback ) {
3059 if ( $resultCallback ) {
3060 call_user_func( $resultCallback,
$res, $this );
3063 if (
false ===
$res ) {
3066 return "Query \"{$cmd}\" failed with error code \"$err\".\n";
3084 if ( $this->delimiter ) {
3086 $newLine = preg_replace(
'/' . preg_quote( $this->delimiter,
'/' ) .
'$/',
'', $newLine );
3087 if ( $newLine != $prev ) {
3117 return preg_replace_callback(
3119 /\* (\$wgDBprefix|[_i]) \*/ (\w*) | # 1-2. tableName, indexName
3120 \'\{\$ (\w+) }\' | # 3. addQuotes
3121 `\{\$ (\w+) }` | # 4. addIdentifierQuotes
3122 /\*\$ (\w+) \*/ # 5. leave unencoded
3127 if ( isset( $m[1] ) && $m[1] !==
'' ) {
3128 if ( $m[1] ===
'i' ) {
3133 } elseif ( isset( $m[3] ) && $m[3] !==
'' && array_key_exists( $m[3],
$vars ) ) {
3135 } elseif ( isset( $m[4] ) && $m[4] !==
'' && array_key_exists( $m[4],
$vars ) ) {
3137 } elseif ( isset( $m[5] ) && $m[5] !==
'' && array_key_exists( $m[5],
$vars ) ) {
3138 return $vars[$m[5]];
3154 if ( $this->mSchemaVars ) {
3177 public function lock( $lockName, $method, $timeout = 5 ) {
3178 $this->mNamedLocksHeld[$lockName] = 1;
3183 public function unlock( $lockName, $method ) {
3184 unset( $this->mNamedLocksHeld[$lockName] );
3190 if ( !$this->
lock( $lockKey, $fname, $timeout ) ) {
3195 $this->
commit( __METHOD__,
'flush' );
3196 $this->
unlock( $lockKey, $fname );
3199 $this->
commit( __METHOD__,
'flush' );
3217 public function lockTables( $read, $write, $method, $lowPriority =
true ) {
3238 public function dropTable( $tableName, $fName = __METHOD__ ) {
3239 if ( !$this->
tableExists( $tableName, $fName ) ) {
3242 $sql =
"DROP TABLE " . $this->
tableName( $tableName );
3247 return $this->
query( $sql, $fName );
3257 return 'SearchEngineDummy';
3265 return ( $expiry ==
'' || $expiry ==
'infinity' || $expiry == $this->
getInfinity() )
3271 return ( $expiry ==
'' || $expiry ==
'infinity' || $expiry == $this->
getInfinity() )
3288 $reason = $this->
getLBInfo(
'readOnlyReason' );
3290 return is_string( $reason ) ? $reason :
false;
3305 if ( $this->mTrxLevel && $this->mTrxDoneWrites ) {
3306 trigger_error(
"Uncommitted DB writes (transaction from {$this->mTrxFname})." );
3308 if ( count( $this->mTrxIdleCallbacks ) || count( $this->mTrxPreCommitCallbacks ) ) {
3310 foreach ( $this->mTrxIdleCallbacks
as $callbackInfo ) {
3311 $callers[] = $callbackInfo[1];
3313 $callers = implode(
', ', $callers );
3314 trigger_error(
"DB transaction callbacks still pending (from $callers)." );
doneWrites()
Returns true if the connection may have been used for write queries.
select($table, $vars, $conds= '', $fname=__METHOD__, $options=[], $join_conds=[])
Execute a SELECT query constructed using the various parameters provided.
indexName($index)
Get the name of an index in a given table.
lowPriorityOption()
A string to insert into queries to show that they're low-priority, like MySQL's LOW_PRIORITY.
ping()
Ping the server and try to reconnect if it there is no connection.
setLBInfo($name, $value=null)
Set the LB info array, or a member of it.
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
TransactionProfiler $trxProfiler
const DEADLOCK_DELAY_MAX
Maximum time to wait before retry.
maxListLen()
Return the maximum number of items allowed in a list, or 0 for unlimited.
the array() calling protocol came about after MediaWiki 1.4rc1.
Utility classThis allows us to distinguish a blob from a normal string and an array of strings...
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the database
float $mTrxSlaveLag
Lag estimate at the time of BEGIN.
tableName($name, $format= 'quoted')
Format a table name ready for use in constructing an SQL query.
getScopedLockAndFlush($lockKey, $fname, $timeout)
Acquire a named lock, flush any transaction, and return an RAII style unlocker object.
bitOr($fieldLeft, $fieldRight)
aggregateValue($valuedata, $valuename= 'value')
Return aggregated value alias.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
patchPath($patch)
Get the full path of a patch file.
setSessionOptions(array $options)
Override database's default behavior.
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException'returning false will NOT prevent logging $e
encodeExpiry($expiry)
Encode an expiry time into the DBMS dependent format.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
__destruct()
Run a few simple sanity checks.
static instance()
Singleton.
decodeExpiry($expiry, $format=TS_MW)
Decode an expiry time into a DBMS independent format.
estimateRowCount($table, $vars= '*', $conds= '', $fname=__METHOD__, $options=[])
Estimate the number of rows in dataset.
clearFlag($flag)
Clear a flag for this connection.
makeOrderBy($options)
Returns an optional ORDER BY.
processing should stop and the error should be shown to the user * false
setTransactionProfiler(TransactionProfiler $profiler)
open($server, $user, $password, $dbName)
Open a connection to the database.
resource $mConn
Database connection.
listViews($prefix=null, $fname=__METHOD__)
Lists all the VIEWs in the database.
wfBacktrace($raw=null)
Get a debug backtrace as a string.
$wgDBmwschema
Mediawiki schema.
wfLogDBError($text, array $context=[])
Log for database errors.
getServerVersion()
A string describing the current software version, like from mysql_get_server_info().
Stub profiler that does nothing.
onTransactionIdle($callback)
Run an anonymous function as soon as there is no transaction pending.
it s the revision text itself In either if gzip is the revision text is gzipped $flags
makeList($a, $mode=LIST_COMMA)
Makes an encoded list of strings from an array.
lastError()
Get a description of the last error.
doRollback($fname)
Issues the ROLLBACK command to the database server.
getProperty($name)
General read-only accessor.
dropTable($tableName, $fName=__METHOD__)
Delete a table.
An object representing a master or slave position in a replicated setup.
functionalIndexes()
Returns true if this database can use functional indexes.
sourceFile($filename, $lineCallback=false, $resultCallback=false, $fname=false, $inputCallback=false)
Read and execute SQL commands from a file.
getDefaultSchemaVars()
Get schema variables to use if none have been set via setSchemaVars().
when a variable name is used in a it is silently declared as a new local masking the global
lockIsFree($lockName, $method)
Check to see if a named lock is available (non-blocking)
doQuery($sql)
The DBMS-dependent part of query()
fieldInfo($table, $field)
mysql_fetch_field() wrapper Returns false if the field doesn't exist
cleanupTriggers()
Returns true if this database supports (and uses) triggers (e.g.
getSchemaPath()
Return a path to the DBMS-specific schema file, otherwise default to tables.sql.
wasReadOnlyError()
Determines if the last failure was due to the database being read-only.
encodeBlob($b)
Some DBMSs have a special format for inserting into blob fields, they don't allow simple quoted strin...
duplicateTableStructure($oldName, $newName, $temporary=false, $fname=__METHOD__)
Creates a new table with structure copied from existing table Note that unlike most database abstract...
pendingWriteCallers()
Get the list of method names that did write queries for this transaction.
tableNamesWithUseIndexOrJOIN($tables, $use_index=[], $join_conds=[])
Get the aliased table name clause for a FROM clause which might have a JOIN and/or USE INDEX clause...
listTables($prefix=null, $fname=__METHOD__)
List all tables on the database.
selectFieldValues($table, $var, $cond= '', $fname=__METHOD__, $options=[], $join_conds=[])
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
lastErrno()
Get the last error number.
wfRandomString($length=32)
Get a random string containing a number of pseudo-random hex characters.
const DEADLOCK_TRIES
Number of times to re-try an operation in case of deadlock.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist & $tables
close()
Closes a database connection.
getSqlFilePath($filename)
Return a path to the DBMS-specific SQL file if it exists, otherwise default SQL file.
selectSQLText($table, $vars, $conds= '', $fname=__METHOD__, $options=[], $join_conds=[])
The equivalent of IDatabase::select() except that the constructed SQL is returned, instead of being immediately executed.
indexExists($table, $index, $fname=__METHOD__)
Determines whether an index exists Usually throws a DBQueryError on failure If errors are explicitly ...
wfDebug($text, $dest= 'all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
tablePrefix($prefix=null)
Get/set the table prefix.
runOnTransactionPreCommitCallbacks()
Actually any "on transaction pre-commit" callbacks.
useIndexClause($index)
USE INDEX clause.
update($table, $values, $conds, $fname=__METHOD__, $options=[])
UPDATE wrapper.
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
affectedRows()
Get the number of rows affected by the last write query.
strreplace($orig, $old, $new)
Returns a comand for str_replace function in SQL query.
trxTimestamp()
Get the UNIX timestamp of the time that the transaction was established.
wfTimestamp($outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Class for asserting that a callback happens when an dummy object leaves scope.
timestamp($ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
wfDebugLog($logGroup, $text, $dest= 'all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
getSlavePos()
Get the replication position of this slave.
global $wgCommandLineMode
implicitGroupby()
Returns true if this database does an implicit sort when doing GROUP BY.
bitAnd($fieldLeft, $fieldRight)
ignoreErrors($ignoreErrors=null)
Turns on (false) or off (true) the automatic generation and sending of a "we're sorry, but there has been a database error" page on database errors.
isQuotedIdentifier($name)
Returns if the given identifier looks quoted or not according to the database convention for quoting ...
anyString()
Returns a token for buildLike() that denotes a '' to be used in a LIKE query.
deadlockLoop()
Perform a deadlock-prone transaction.
fillPreparedArg($matches)
preg_callback func for fillPrepared() The arguments should be in $this->preparedArgs and must not be ...
wfSetBit(&$dest, $bit, $state=true)
As for wfSetVar except setting a bit.
doBegin($fname)
Issues the BEGIN command to the database server.
unlock($lockName, $method)
Release a lock.
doCommit($fname)
Issues the COMMIT command to the database server.
buildLike()
LIKE statement wrapper, receives a variable-length argument list with parts of pattern to match conta...
strictIPs()
Returns true if this database is strict about what can be put into an IP field.
tableExists($table, $fname=__METHOD__)
Query whether a given table exists.
unionSupportsOrderAndLimit()
Returns true if current database backend supports ORDER BY or LIMIT for separate subqueries within th...
bufferResults($buffer=null)
Turns buffering of SQL result sets on (true) or off (false).
makeUpdateOptionsArray($options)
Make UPDATE options array for DatabaseBase::makeUpdateOptions.
getSchemaVars()
Get schema variables.
trxLevel()
Gets the current transaction level.
wfWarn($msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
strencode($s)
Wrapper for addslashes()
Helper class that detects high-contention DB queries via profiling calls.
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
getUpdateKeysPath()
Return a path to the DBMS-specific update key file, otherwise default to update-keys.sql.
getDBname()
Get the current DB name.
fetchObject($res)
Fetch the next row from the given result object, in object form.
freePrepared($prepared)
Free a prepared query, generated by prepare().
unlockTables($method)
Unlock specific tables.
endAtomic($fname=__METHOD__)
Ends an atomic section of SQL statements.
namedLocksEnqueue()
Check to see if a named lock used by lock() use blocking queues.
implicitOrderby()
Returns true if this database does an implicit order by when the column has an index For example: SEL...
assertOpen()
Make sure isOpen() returns true as a sanity check.
setLazyMasterHandle(IDatabase $conn)
Set a lazy-connecting DB handle to the master DB (for replication status purposes) ...
getFlag($flag)
Returns a boolean whether the flag $flag is set for this connection.
isTransactableQuery($sql)
Determine whether a SQL statement is sensitive to isolation level.
insert($table, $a, $fname=__METHOD__, $options=[])
INSERT wrapper, inserts an array into a table.
static queryTime($id)
Calculates how long a query took.
$wgSharedDB
Shared database for multiple wikis.
static factory($dbType, $p=[])
Given a DB type, construct the name of the appropriate child class of DatabaseBase.
conditional($cond, $trueVal, $falseVal)
Returns an SQL expression for a simple conditional.
debug($debug=null)
Boolean, controls output of large amounts of debug information.
callable[] $mTrxPreCommitCallbacks
IDatabase null $lazyMasterHandle
Lazy handle to the master DB this server replicates from.
getSearchEngine()
Get search engine class.
addQuotes($s)
Adds quotes and backslashes.
addIdentifierQuotes($s)
Quotes an identifier using backticks or "double quotes" depending on the database type...
Used by DatabaseBase::buildLike() to represent characters that have special meaning in SQL LIKE claus...
searchableIPs()
Returns true if this database can do a native search on IP columns e.g.
onTransactionPreCommitOrIdle($callback)
Run an anonymous function before the current transaction commits or now if there is none...
freeResult($res)
Free a result object returned by query() or select().
static getCacheSetOptions(IDatabase $db1)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
lockTables($read, $write, $method, $lowPriority=true)
Lock specific tables.
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
getApproximateLagStatus()
Get a slave lag estimate for this server.
replaceVars($ins)
Database independent variable replacement.
fetchRow($res)
Fetch the next row from the given result object, in associative array form.
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
selectDB($db)
Change the current database.
selectRow($table, $vars, $conds, $fname=__METHOD__, $options=[], $join_conds=[])
Single row SELECT wrapper.
int $mTrxLevel
Either 1 if a transaction is active or 0 otherwise.
pendingWriteQueryDuration()
Get the time spend running write queries for this transaction.
numRows($res)
Get the number of rows in a result object.
setFlag($flag)
Set a flag for this connection.
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
wasErrorReissuable()
Determines if the last query error was something that should be dealt with by pinging the connection ...
buildGroupConcatField($delim, $table, $field, $conds= '', $join_conds=[])
Build a GROUP_CONCAT or equivalent statement for a query.
Database abstraction object.
indexUnique($table, $index)
Determines if a given index is unique.
wasConnectionError($errno)
Determines if the given query error was a connection drop STUB.
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
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
closeConnection()
Closes underlying database connection.
selectRowCount($tables, $vars= '*', $conds= '', $fname=__METHOD__, $options=[], $join_conds=[])
Get the number of rows in dataset.
cascadingDeletes()
Returns true if this database supports (and uses) cascading deletes.
runOnTransactionIdleCallbacks()
Actually any "on transaction idle" callbacks.
selectField($table, $var, $cond= '', $fname=__METHOD__, $options=[])
A SELECT wrapper which returns a single field from a single result row.
unionQueries($sqls, $all)
Construct a UNION query This is used for providing overload point for other DB abstractions not compa...
indexInfo($table, $index, $fname=__METHOD__)
Get information about an index into an object.
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined...
setBigSelects($value=true)
Allow or deny "big selects" for this session only.
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 then executing the whole list after the page is displayed We don t do anything smart like collating updates to the same table or such because the list is almost always going to have just one item on if so it s not worth the trouble Since there is a job queue in the jobs table
clearViewsCache()
Reset the views process cache set by listViews()
wasDeadlock()
Determines if the last failure was due to a deadlock STUB.
__sleep()
Called by serialize.
upsert($table, array $rows, array $uniqueIndexes, array $set, $fname=__METHOD__)
INSERT ON DUPLICATE KEY UPDATE wrapper, upserts an array into a table.
textFieldSize($table, $field)
Returns the size of a text field, or -1 for "unlimited".
fillPrepared($preparedQuery, $args)
For faking prepared SQL statements on DBs that don't support it directly.
getServer()
Get the server hostname or IP address.
static getLocalServerInstance($fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
begin($fname=__METHOD__)
Begin a transaction.
getServerInfo()
A string describing the current software version, and possibly other details in a user-friendly way...
anyChar()
Returns a token for buildLike() that denotes a '_' to be used in a LIKE query.
timestampOrNull($ts=null)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
reportQueryError($error, $errno, $sql, $fname, $tempIgnore=false)
Report a query error.
makeInsertOptions($options)
Helper for DatabaseBase::insert().
nextSequenceValue($seqName)
Returns an appropriately quoted sequence value for inserting a new row.
$wgDBprefix
Table name prefix.
getTransactionLagStatus()
Get the slave lag when the current transaction started.
query($sql, $fname=__METHOD__, $tempIgnore=false)
Run an SQL query and return the result.
static generalizeSQL($sql)
Removes most variables from an SQL query and replaces them with X or N for numbers.
static query($sql, $function, $isMaster)
Begins profiling on a database query.
lastDoneWrites()
Returns the last time the connection may have been used for write queries.
isWriteQuery($sql)
Determine whether a query writes to the DB.
lock($lockName, $method, $timeout=5)
Acquire a named lock.
makeUpdateOptions($options)
Make UPDATE options for the DatabaseBase::update function.
getServerUptime()
Determines how long the server has been up STUB.
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 the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers if desired 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 inclusive $limit
commit($fname=__METHOD__, $flush= '')
Commits a transaction previously started using begin().
masterPosWait(DBMasterPos $pos, $timeout)
Wait for the slave to catch up to a given master position.
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
getInfinity()
Find out when 'infinity' is.
startAtomic($fname=__METHOD__)
Begin an atomic section of statements.
static consume(ScopedCallback &$sc=null)
Trigger a scoped callback and destroy it.
bool $mTrxDoneWrites
Record if possible write queries were done in the last transaction started.
connectionErrorHandler($errno, $errstr)
getMasterPos()
Get the position of this master.
streamStatementEnd(&$sql, &$newLine)
Called by sourceStream() to check if we've reached a statement end.
rollback($fname=__METHOD__, $flush= '')
Rollback a transaction previously started using begin().
execute($prepared, $args=null)
Execute a prepared query with the various arguments.
makeWhereFrom2d($data, $baseKey, $subKey)
Build a partial where clause from a 2-d array such as used for LinkBatch.
makeGroupByWithHaving($options)
Returns an optional GROUP BY with an optional HAVING.
getLBInfo($name=null)
Get properties passed down from the server info array of the load balancer.
Result wrapper for grabbing data queried by someone else.
isView($name)
Differentiates between a TABLE and a VIEW.
deleteJoin($delTable, $joinTable, $delVar, $joinVar, $conds, $fname=__METHOD__)
DELETE where the condition is a join.
getLogContext(array $extras=[])
Create a log context to pass to wfLogDBError or other logging functions.
BagOStuff $srvCache
APC cache.
writesOrCallbacksPending()
Returns true if there is a transaction open with possible write queries or transaction pre-commit/idl...
prepare($sql, $func= 'DatabaseBase::prepare')
Intended to be compatible with the PEAR::DB wrapper functions.
setSchemaVars($vars)
Set variables to be used in sourceFile/sourceStream, in preference to the ones in $GLOBALS...
static logException($e)
Log an exception to the exception log (if enabled).
lastQuery()
Return the last query that went through IDatabase::query()
nativeReplace($table, $rows, $fname)
REPLACE query wrapper for MySQL and SQLite, which have a native REPLACE statement.
callable[] $mTrxIdleCallbacks
__construct(array $params)
Constructor.
resultObject($result)
Take the result from a query, and wrap it in a ResultWrapper if necessary.
replace($table, $uniqueIndexes, $rows, $fname=__METHOD__)
REPLACE query wrapper.
realTimestamps()
Returns true if this database uses timestamps rather than integers.
isOpen()
Is a connection to the database open?
decodeBlob($b)
Some DBMSs return a special placeholder object representing blob fields in result objects...
getSessionLagStatus()
Get the slave lag when the current transaction started or a general lag estimate if not transaction i...
makeSelectOptions($options)
Returns an optional USE INDEX clause to go after the table, and a string to go at the end of the quer...
insertSelect($destTable, $srcTable, $varMap, $conds, $fname=__METHOD__, $insertOptions=[], $selectOptions=[])
INSERT SELECT wrapper.
reportConnectionError($error= 'Unknown error')
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
buildConcat($stringList)
Build a concatenation list to feed into a SQL query.
doAtomicSection($fname, $callback)
Run a callback to do an atomic set of updates for this database.
sourceStream($fp, $lineCallback=false, $resultCallback=false, $fname=__METHOD__, $inputCallback=false)
Read and execute commands from an open file handle.
wfGetCaller($level=2)
Get the name of the function which called this function wfGetCaller( 1 ) is the function with the wfG...
limitResult($sql, $limit, $offset=false)
Construct a LIMIT query with optional offset.
fieldNamesWithAlias($fields)
Gets an array of aliased field names.
Basic database interface for live and lazy-loaded DB handles.
setFileHandle($fh)
Set the filehandle to copy write statements to.
const DEADLOCK_DELAY_MIN
Minimum time to wait before retry, in microseconds.
fieldExists($table, $field, $fname=__METHOD__)
Determines whether a field exists in a table.
dbSchema($schema=null)
Get/set the db schema.
wasLockTimeout()
Determines if the last failure was due to a lock timeout STUB.
Allows to change the fields on the form that will be generated $name