236 return $this->mTrxLevel ? $this->mTrxTimestamp : null;
240 return wfSetVar( $this->mTablePrefix, $prefix );
244 return wfSetVar( $this->mSchema, $schema );
253 $this->fileHandle = $fh;
257 if ( is_null(
$name ) ) {
260 if ( array_key_exists(
$name, $this->mLBInfo ) ) {
261 return $this->mLBInfo[
$name];
269 if ( is_null(
$value ) ) {
270 $this->mLBInfo =
$name;
283 $this->lazyMasterHandle = $conn;
299 if ( !$this->trxProfiler ) {
311 $this->trxProfiler = $profiler;
387 return $this->mDoneWrites ?:
false;
395 return $this->mTrxLevel && (
401 return $this->mTrxLevel ? $this->mTrxWriteDuration :
false;
405 return $this->mTrxLevel ? $this->mTrxWriteCallers : [];
413 $this->mFlags |= $flag;
417 $this->mFlags &= ~$flag;
421 return !!( $this->mFlags & $flag );
429 if ( $this->mTablePrefix ) {
430 return "{$this->mDBname}-{$this->mTablePrefix}";
445 $dbmsSpecificFilePath =
"$IP/maintenance/" . $this->
getType() .
"/$filename";
446 if ( file_exists( $dbmsSpecificFilePath ) ) {
447 return $dbmsSpecificFilePath;
449 return "$IP/maintenance/$filename";
507 $server = $params[
'host'];
508 $user = $params[
'user'];
509 $password = $params[
'password'];
510 $dbName = $params[
'dbname'];
511 $flags = $params[
'flags'];
512 $tablePrefix = $params[
'tablePrefix'];
513 $schema = $params[
'schema'];
514 $foreign = $params[
'foreign'];
518 if ( $wgCommandLineMode ) {
525 $this->mSessionVars = $params[
'variables'];
528 if ( $tablePrefix ===
'get from global' ) {
531 $this->mTablePrefix = $tablePrefix;
535 if ( $schema ===
'get from global' ) {
538 $this->mSchema = $schema;
541 $this->mForeign = $foreign;
543 if ( isset( $params[
'trxProfiler'] ) ) {
544 $this->trxProfiler = $params[
'trxProfiler'];
548 $this->
open( $server,
$user, $password, $dbName );
558 throw new MWException(
'Database serialization may cause problems, since ' .
559 'the connection is not restored on wakeup.' );
584 final public static function factory( $dbType, $p = [] ) {
585 $canonicalDBTypes = [
586 'mysql' => [
'mysqli',
'mysql' ],
594 $dbType = strtolower( $dbType );
595 if ( isset( $canonicalDBTypes[$dbType] ) && $canonicalDBTypes[$dbType] ) {
596 $possibleDrivers = $canonicalDBTypes[$dbType];
597 if ( !empty( $p[
'driver'] ) ) {
598 if ( in_array( $p[
'driver'], $possibleDrivers ) ) {
599 $driver = $p[
'driver'];
602 " cannot construct Database with type '$dbType' and driver '{$p['driver']}'" );
605 foreach ( $possibleDrivers
as $posDriver ) {
606 if ( extension_loaded( $posDriver ) ) {
607 $driver = $posDriver;
615 if ( $driver ===
false ) {
617 " no viable database extension found for type '$dbType'" );
625 'mssql' =>
'get from global',
628 $class =
'Database' . ucfirst( $driver );
629 if ( class_exists( $class ) && is_subclass_of( $class,
'DatabaseBase' ) ) {
631 $p[
'host'] = isset( $p[
'host'] ) ? $p[
'host'] :
false;
632 $p[
'user'] = isset( $p[
'user'] ) ? $p[
'user'] :
false;
633 $p[
'password'] = isset( $p[
'password'] ) ? $p[
'password'] :
false;
634 $p[
'dbname'] = isset( $p[
'dbname'] ) ? $p[
'dbname'] :
false;
635 $p[
'flags'] = isset( $p[
'flags'] ) ? $p[
'flags'] : 0;
636 $p[
'variables'] = isset( $p[
'variables'] ) ? $p[
'variables'] : [];
637 $p[
'tablePrefix'] = isset( $p[
'tablePrefix'] ) ? $p[
'tablePrefix'] :
'get from global';
638 if ( !isset( $p[
'schema'] ) ) {
639 $p[
'schema'] = isset( $defaultSchemas[$dbType] ) ? $defaultSchemas[$dbType] : null;
641 $p[
'foreign'] = isset( $p[
'foreign'] ) ? $p[
'foreign'] :
false;
643 return new $class( $p );
650 $this->mPHPError =
false;
651 $this->htmlErrors = ini_set(
'html_errors',
'0' );
652 set_error_handler( [ $this,
'connectionErrorHandler' ] );
659 restore_error_handler();
660 if ( $this->htmlErrors !==
false ) {
661 ini_set(
'html_errors', $this->htmlErrors );
663 if ( $this->mPHPError ) {
664 $error = preg_replace(
'!\[<a.*</a>\]!',
'', $this->mPHPError );
665 $error = preg_replace(
'!^.*?:\s?(.*)$!',
'$1', $error );
678 $this->mPHPError = $errstr;
690 'db_server' => $this->mServer,
691 'db_name' => $this->mDBname,
692 'db_user' => $this->mUser,
699 if ( $this->mConn ) {
701 if ( !$this->mTrxAutomatic ) {
702 wfWarn(
"Transaction still in progress (from {$this->mTrxFname}), " .
703 " performing implicit commit before closing connection!" );
706 $this->
commit( __METHOD__,
'flush' );
710 $this->mConn =
false;
711 } elseif ( $this->mTrxIdleCallbacks || $this->mTrxEndCallbacks ) {
712 throw new MWException(
"Transaction callbacks still pending." );
716 $this->mOpened =
false;
756 abstract protected function doQuery( $sql );
766 return !preg_match(
'/^(?:SELECT|BEGIN|ROLLBACK|COMMIT|SET|SHOW|EXPLAIN|\(SELECT)\b/i', $sql );
779 $verb = substr( $sql, 0, strcspn( $sql,
" \t\r\n" ) );
780 return !in_array( $verb, [
'BEGIN',
'COMMIT',
'ROLLBACK',
'SHOW',
'SET' ] );
783 public function query( $sql,
$fname = __METHOD__, $tempIgnore =
false ) {
786 $this->mLastQuery = $sql;
789 if ( $isWriteQuery ) {
791 if ( $reason !==
false ) {
794 # Set a flag indicating that writes have been done
795 $this->mDoneWrites = microtime(
true );
798 # Add a comment for easy SHOW PROCESSLIST interpretation
799 if ( is_object( $wgUser ) && $wgUser->isItemLoaded(
'name' ) ) {
800 $userName = $wgUser->getName();
801 if ( mb_strlen( $userName ) > 15 ) {
802 $userName = mb_substr( $userName, 0, 15 ) .
'...';
804 $userName = str_replace(
'/',
'', $userName );
811 $commentedSql = preg_replace(
'/\s|$/',
" /* $fname $userName */ ", $sql, 1 );
814 $this->
begin( __METHOD__ .
" ($fname)" );
815 $this->mTrxAutomatic =
true;
818 # Keep track of whether the transaction has write queries pending
819 if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $isWriteQuery ) {
820 $this->mTrxDoneWrites =
true;
822 $this->mServer, $this->mDBname, $this->mTrxShortId );
825 $isMaster = !is_null( $this->
getLBInfo(
'master' ) );
826 # generalizeSQL will probably cut down the query to reasonable
827 # logging size most of the time. The substr is really just a sanity check.
830 $totalProf =
'DatabaseBase::query-master';
833 $totalProf =
'DatabaseBase::query';
835 # Include query transaction state
836 $queryProf .= $this->mTrxShortId ?
" [TRX#{$this->mTrxShortId}]" :
"";
840 $totalProfSection = $profiler->scopedProfileIn( $totalProf );
841 $queryProfSection = $profiler->scopedProfileIn( $queryProf );
844 if ( $this->
debug() ) {
845 wfDebugLog(
'queries', sprintf(
"%s: %s", $this->mDBname, $commentedSql ) );
850 # Avoid fatals if close() was called
853 # Do the query and handle errors
854 $startTime = microtime(
true );
856 $queryRuntime = microtime(
true ) - $startTime;
857 # Log the query time and feed it into the DB trx profiler
859 $queryProf, $startTime, $isWriteQuery, $this->
affectedRows() );
863 # Try reconnecting if the connection was lost
865 # Transaction is gone; this can mean lost writes or REPEATABLE-READ snapshots
867 # T127428: for non-write transactions, a disconnect and a COMMIT are similar:
868 # neither changed data and in both cases any read snapshots are reset anyway.
870 # Update state tracking to reflect transaction loss
871 $this->mTrxLevel = 0;
872 $this->mTrxIdleCallbacks = [];
873 $this->mTrxPreCommitCallbacks = [];
874 wfDebug(
"Connection lost, reconnecting...\n" );
875 # Stash the last error values since ping() might clear them
878 if ( $this->
ping() ) {
881 $msg = __METHOD__ .
": lost connection to $server; reconnected";
884 if ( ( $hadTrx && !$isNoopCommit ) || $this->mNamedLocksHeld ) {
885 # Leave $ret as false and let an error be reported.
886 # Callers may catch the exception and continue to use the DB.
889 # Should be safe to silently retry (no trx/callbacks/locks)
890 $startTime = microtime(
true );
892 $queryRuntime = microtime(
true ) - $startTime;
893 # Log the query time and feed it into the DB trx profiler
895 $queryProf, $startTime, $isWriteQuery, $this->
affectedRows() );
902 if (
false ===
$ret ) {
913 if ( $isWriteQuery && $this->mTrxLevel ) {
914 $this->mTrxWriteDuration += $queryRuntime;
915 $this->mTrxWriteCallers[] =
$fname;
923 wfDebug(
"SQL ERROR (ignored): $error\n" );
925 $sql1line = mb_substr( str_replace(
"\n",
"\\n", $sql ), 0, 5 * 1024 );
927 "{fname}\t{db_server}\t{errno}\t{error}\t{sql1line}",
929 'method' => __METHOD__,
932 'sql1line' => $sql1line,
936 wfDebug(
"SQL ERROR: " . $error .
"\n" );
955 protected function prepare( $sql, $func =
'DatabaseBase::prepare' ) {
960 return [
'query' => $sql,
'func' => $func ];
979 if ( !is_array(
$args ) ) {
981 $args = func_get_args();
982 array_shift(
$args );
987 return $this->
query( $sql, $prepared[
'func'] );
999 $this->preparedArgs =&
$args;
1001 return preg_replace_callback(
'/(\\\\[?!&]|[?!&])/',
1002 [ &$this,
'fillPreparedArg' ], $preparedQuery );
1024 list( , $arg ) = each( $this->preparedArgs );
1032 # return $this->addQuotes( file_get_contents( $arg ) );
1035 '& mode is not implemented. If it\'s really needed, uncomment the line above.'
1040 'Received invalid match. This should never happen!'
1051 if ( $var ===
'*' ) {
1068 if ( $row !==
false ) {
1069 return reset( $row );
1076 $table, $var, $cond =
'',
$fname = __METHOD__,
$options = [], $join_conds = []
1078 if ( $var ===
'*' ) {
1080 } elseif ( !is_string( $var ) ) {
1089 if (
$res ===
false ) {
1094 foreach (
$res as $row ) {
1095 $values[] = $row->$var;
1111 $preLimitTail = $postLimitTail =
'';
1117 if ( is_numeric( $key ) ) {
1118 $noKeyOptions[$option] =
true;
1132 if ( isset( $noKeyOptions[
'FOR UPDATE'] ) ) {
1133 $postLimitTail .=
' FOR UPDATE';
1136 if ( isset( $noKeyOptions[
'LOCK IN SHARE MODE'] ) ) {
1137 $postLimitTail .=
' LOCK IN SHARE MODE';
1140 if ( isset( $noKeyOptions[
'DISTINCT'] ) || isset( $noKeyOptions[
'DISTINCTROW'] ) ) {
1141 $startOpts .=
'DISTINCT';
1144 # Various MySQL extensions
1145 if ( isset( $noKeyOptions[
'STRAIGHT_JOIN'] ) ) {
1146 $startOpts .=
' /*! STRAIGHT_JOIN */';
1149 if ( isset( $noKeyOptions[
'HIGH_PRIORITY'] ) ) {
1150 $startOpts .=
' HIGH_PRIORITY';
1153 if ( isset( $noKeyOptions[
'SQL_BIG_RESULT'] ) ) {
1154 $startOpts .=
' SQL_BIG_RESULT';
1157 if ( isset( $noKeyOptions[
'SQL_BUFFER_RESULT'] ) ) {
1158 $startOpts .=
' SQL_BUFFER_RESULT';
1161 if ( isset( $noKeyOptions[
'SQL_SMALL_RESULT'] ) ) {
1162 $startOpts .=
' SQL_SMALL_RESULT';
1165 if ( isset( $noKeyOptions[
'SQL_CALC_FOUND_ROWS'] ) ) {
1166 $startOpts .=
' SQL_CALC_FOUND_ROWS';
1169 if ( isset( $noKeyOptions[
'SQL_CACHE'] ) ) {
1170 $startOpts .=
' SQL_CACHE';
1173 if ( isset( $noKeyOptions[
'SQL_NO_CACHE'] ) ) {
1174 $startOpts .=
' SQL_NO_CACHE';
1177 if ( isset(
$options[
'USE INDEX'] ) && is_string(
$options[
'USE INDEX'] ) ) {
1183 return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail ];
1196 if ( isset(
$options[
'GROUP BY'] ) ) {
1197 $gb = is_array(
$options[
'GROUP BY'] )
1198 ? implode(
',',
$options[
'GROUP BY'] )
1200 $sql .=
' GROUP BY ' . $gb;
1202 if ( isset(
$options[
'HAVING'] ) ) {
1203 $having = is_array(
$options[
'HAVING'] )
1206 $sql .=
' HAVING ' . $having;
1221 if ( isset(
$options[
'ORDER BY'] ) ) {
1222 $ob = is_array(
$options[
'ORDER BY'] )
1223 ? implode(
',',
$options[
'ORDER BY'] )
1226 return ' ORDER BY ' . $ob;
1234 $options = [], $join_conds = [] ) {
1243 if ( is_array(
$vars ) ) {
1248 $useIndexes = ( isset(
$options[
'USE INDEX'] ) && is_array(
$options[
'USE INDEX'] ) )
1252 if ( is_array( $table ) ) {
1255 } elseif ( $table !=
'' ) {
1256 if ( $table[0] ==
' ' ) {
1257 $from =
' FROM ' . $table;
1266 list( $startOpts, $useIndex, $preLimitTail, $postLimitTail ) =
1269 if ( !empty( $conds ) ) {
1270 if ( is_array( $conds ) ) {
1273 $sql =
"SELECT $startOpts $vars $from $useIndex WHERE $conds $preLimitTail";
1275 $sql =
"SELECT $startOpts $vars $from $useIndex $preLimitTail";
1278 if ( isset(
$options[
'LIMIT'] ) ) {
1282 $sql =
"$sql $postLimitTail";
1284 if ( isset(
$options[
'EXPLAIN'] ) ) {
1285 $sql =
'EXPLAIN ' . $sql;
1298 if (
$res ===
false ) {
1319 $rows = ( isset( $row[
'rowcount'] ) ) ? (
int)$row[
'rowcount'] : 0;
1330 $res = $this->
query(
"SELECT COUNT(*) AS rowcount FROM ($sql) tmp_count",
$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;
2176 }
catch ( Exception
$e ) {
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})";
2409 $args = func_get_args();
2410 $function = array_shift(
$args );
2411 $tries = self::DEADLOCK_TRIES;
2413 $this->
begin( __METHOD__ );
2420 $retVal = call_user_func_array( $function,
$args );
2425 usleep( mt_rand( self::DEADLOCK_DELAY_MIN, self::DEADLOCK_DELAY_MAX ) );
2431 }
while ( --$tries > 0 );
2433 if ( $tries <= 0 ) {
2438 $this->
commit( __METHOD__ );
2445 # Real waits are implemented in the subclass.
2464 if ( !$this->mTrxLevel ) {
2467 $this->mTrxEndCallbacks[] = [ $callback,
wfGetCaller() ];
2471 $this->mTrxIdleCallbacks[] = [ $callback,
wfGetCaller() ];
2472 if ( !$this->mTrxLevel ) {
2478 if ( $this->mTrxLevel ) {
2479 $this->mTrxPreCommitCallbacks[] = [ $callback,
wfGetCaller() ];
2482 $this->
begin( __METHOD__ );
2484 call_user_func( $callback );
2485 $this->
commit( __METHOD__ );
2486 }
catch ( Exception
$e ) {
2502 $this->suppressPostCommitCallbacks = $suppress;
2514 if ( $this->suppressPostCommitCallbacks ) {
2520 $e = $ePrior = null;
2522 $callbacks = array_merge(
2523 $this->mTrxIdleCallbacks,
2524 $this->mTrxEndCallbacks
2526 $this->mTrxIdleCallbacks = [];
2527 $this->mTrxEndCallbacks = [];
2528 foreach ( $callbacks
as $callback ) {
2530 list( $phpCallback ) = $callback;
2532 call_user_func_array( $phpCallback, [ $trigger ] );
2538 }
catch ( Exception
$e ) {
2550 }
while ( count( $this->mTrxIdleCallbacks ) );
2552 if (
$e instanceof Exception ) {
2565 $e = $ePrior = null;
2568 $this->mTrxPreCommitCallbacks = [];
2569 foreach ( $callbacks
as $callback ) {
2571 list( $phpCallback ) = $callback;
2572 call_user_func( $phpCallback );
2573 }
catch ( Exception
$e ) {
2580 }
while ( count( $this->mTrxPreCommitCallbacks ) );
2582 if (
$e instanceof Exception ) {
2588 if ( !$this->mTrxLevel ) {
2589 $this->
begin( $fname );
2590 $this->mTrxAutomatic =
true;
2594 $this->mTrxAutomaticAtomic =
true;
2598 $this->mTrxAtomicLevels[] =
$fname;
2602 if ( !$this->mTrxLevel ) {
2603 throw new DBUnexpectedError( $this,
"No atomic transaction is open (got $fname)." );
2605 if ( !$this->mTrxAtomicLevels ||
2606 array_pop( $this->mTrxAtomicLevels ) !== $fname
2608 throw new DBUnexpectedError( $this,
"Invalid atomic section ended (got $fname)." );
2611 if ( !$this->mTrxAtomicLevels && $this->mTrxAutomaticAtomic ) {
2612 $this->
commit( $fname,
'flush' );
2619 call_user_func_array( $callback, [ $this, $fname ] );
2620 }
catch ( Exception
$e ) {
2627 final public function begin( $fname = __METHOD__ ) {
2628 if ( $this->mTrxLevel ) {
2629 if ( $this->mTrxAtomicLevels ) {
2632 $levels = implode(
', ', $this->mTrxAtomicLevels );
2635 "Got explicit BEGIN from $fname while atomic section(s) $levels are open."
2637 } elseif ( !$this->mTrxAutomatic ) {
2642 "$fname: Transaction already in progress (from {$this->mTrxFname}), " .
2643 " performing implicit commit!"
2647 if ( $this->mTrxDoneWrites ) {
2648 wfLogDBError(
"$fname: Automatic transaction with writes in progress" .
2649 " (from {$this->mTrxFname}), performing implicit commit!\n"
2657 if ( $this->mTrxDoneWrites ) {
2658 $this->mDoneWrites = microtime(
true );
2660 $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
2670 $this->mTrxTimestamp = microtime(
true );
2671 $this->mTrxFname =
$fname;
2672 $this->mTrxDoneWrites =
false;
2673 $this->mTrxAutomatic =
false;
2674 $this->mTrxAutomaticAtomic =
false;
2675 $this->mTrxAtomicLevels = [];
2677 $this->mTrxWriteDuration = 0.0;
2678 $this->mTrxWriteCallers = [];
2683 $this->mTrxSlaveLag =
$status[
'lag'] + ( microtime(
true ) -
$status[
'since'] );
2693 $this->
query(
'BEGIN', $fname );
2694 $this->mTrxLevel = 1;
2697 final public function commit( $fname = __METHOD__, $flush =
'' ) {
2698 if ( $this->mTrxLevel && $this->mTrxAtomicLevels ) {
2700 $levels = implode(
', ', $this->mTrxAtomicLevels );
2703 "Got COMMIT while atomic sections $levels are still open"
2707 if ( $flush ===
'flush' ) {
2708 if ( !$this->mTrxLevel ) {
2710 } elseif ( !$this->mTrxAutomatic ) {
2713 "$fname: Flushing an explicit transaction, getting out of sync!"
2717 if ( !$this->mTrxLevel ) {
2718 wfWarn(
"$fname: No transaction to commit, something got out of sync!" );
2720 } elseif ( $this->mTrxAutomatic ) {
2721 wfWarn(
"$fname: Explicit commit of implicit transaction. Something may be out of sync!" );
2731 if ( $this->mTrxDoneWrites ) {
2732 $this->mDoneWrites = microtime(
true );
2734 $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
2747 if ( $this->mTrxLevel ) {
2748 $this->
query(
'COMMIT', $fname );
2749 $this->mTrxLevel = 0;
2753 final public function rollback( $fname = __METHOD__, $flush =
'' ) {
2754 if ( $flush !==
'flush' ) {
2755 if ( !$this->mTrxLevel ) {
2756 wfWarn(
"$fname: No transaction to rollback, something got out of sync!" );
2760 if ( !$this->mTrxLevel ) {
2769 $this->mTrxAtomicLevels = [];
2770 if ( $this->mTrxDoneWrites ) {
2772 $this->mServer, $this->mDBname, $this->mTrxShortId );
2775 $this->mTrxIdleCallbacks = [];
2776 $this->mTrxPreCommitCallbacks = [];
2787 if ( $this->mTrxLevel ) {
2788 $this->
query(
'ROLLBACK', $fname,
true );
2789 $this->mTrxLevel = 0;
2812 'DatabaseBase::duplicateTableStructure is not implemented in descendant class' );
2816 throw new MWException(
'DatabaseBase::listTables is not implemented in descendant class' );
2824 $this->allViews = null;
2839 public function listViews( $prefix = null, $fname = __METHOD__ ) {
2840 throw new MWException(
'DatabaseBase::listViews is not implemented in descendant class' );
2852 throw new MWException(
'DatabaseBase::isView is not implemented in descendant class' );
2860 if ( is_null( $ts ) ) {
2885 } elseif (
$result ===
true ) {
2889 return new ResultWrapper( $this,
$result );
2894 # Stub. Not essential to override.
2914 return $this->mTrxLevel
2928 'since' => microtime(
true )
2951 $res = [
'lag' => 0,
'since' => INF,
'pending' =>
false ];
2952 foreach ( func_get_args()
as $db ) {
2954 $status = $db->getSessionLagStatus();
2955 if (
$status[
'lag'] ===
false ) {
2956 $res[
'lag'] =
false;
2957 } elseif (
$res[
'lag'] !==
false ) {
2961 $res[
'pending'] =
$res[
'pending'] ?: $db->writesPending();
2980 if ( $b instanceof
Blob ) {
3006 $filename, $lineCallback =
false, $resultCallback =
false, $fname =
false, $inputCallback =
false
3008 MediaWiki\suppressWarnings();
3009 $fp = fopen( $filename,
'r' );
3010 MediaWiki\restoreWarnings();
3012 if (
false === $fp ) {
3013 throw new MWException(
"Could not open \"{$filename}\".\n" );
3017 $fname = __METHOD__ .
"( $filename )";
3021 $error = $this->
sourceStream( $fp, $lineCallback, $resultCallback, $fname, $inputCallback );
3022 }
catch ( Exception
$e ) {
3044 if ( file_exists(
"$IP/maintenance/$dbType/archives/$patch" ) ) {
3045 return "$IP/maintenance/$dbType/archives/$patch";
3047 return "$IP/maintenance/archives/$patch";
3052 $this->mSchemaVars =
$vars;
3068 public function sourceStream( $fp, $lineCallback =
false, $resultCallback =
false,
3069 $fname = __METHOD__, $inputCallback =
false
3073 while ( !feof( $fp ) ) {
3074 if ( $lineCallback ) {
3075 call_user_func( $lineCallback );
3078 $line = trim( fgets( $fp ) );
3080 if (
$line ==
'' ) {
3096 if ( $done || feof( $fp ) ) {
3099 if ( ( $inputCallback && call_user_func( $inputCallback, $cmd ) ) || !$inputCallback ) {
3102 if ( $resultCallback ) {
3103 call_user_func( $resultCallback,
$res, $this );
3106 if (
false ===
$res ) {
3109 return "Query \"{$cmd}\" failed with error code \"$err\".\n";
3127 if ( $this->delimiter ) {
3129 $newLine = preg_replace(
'/' . preg_quote( $this->delimiter,
'/' ) .
'$/',
'', $newLine );
3130 if ( $newLine != $prev ) {
3160 return preg_replace_callback(
3162 /\* (\$wgDBprefix|[_i]) \*/ (\w*) | # 1-2. tableName, indexName
3163 \'\{\$ (\w+) }\' | # 3. addQuotes
3164 `\{\$ (\w+) }` | # 4. addIdentifierQuotes
3165 /\*\$ (\w+) \*/ # 5. leave unencoded
3170 if ( isset( $m[1] ) && $m[1] !==
'' ) {
3171 if ( $m[1] ===
'i' ) {
3176 } elseif ( isset( $m[3] ) && $m[3] !==
'' && array_key_exists( $m[3],
$vars ) ) {
3178 } elseif ( isset( $m[4] ) && $m[4] !==
'' && array_key_exists( $m[4],
$vars ) ) {
3180 } elseif ( isset( $m[5] ) && $m[5] !==
'' && array_key_exists( $m[5],
$vars ) ) {
3181 return $vars[$m[5]];
3197 if ( $this->mSchemaVars ) {
3220 public function lock( $lockName, $method, $timeout = 5 ) {
3221 $this->mNamedLocksHeld[$lockName] = 1;
3226 public function unlock( $lockName, $method ) {
3227 unset( $this->mNamedLocksHeld[$lockName] );
3233 if ( !$this->
lock( $lockKey, $fname, $timeout ) ) {
3238 $this->
commit( __METHOD__,
'flush' );
3239 $this->
unlock( $lockKey, $fname );
3242 $this->
commit( __METHOD__,
'flush' );
3260 public function lockTables( $read, $write, $method, $lowPriority =
true ) {
3281 public function dropTable( $tableName, $fName = __METHOD__ ) {
3282 if ( !$this->
tableExists( $tableName, $fName ) ) {
3285 $sql =
"DROP TABLE " . $this->
tableName( $tableName );
3290 return $this->
query( $sql, $fName );
3300 return 'SearchEngineDummy';
3308 return ( $expiry ==
'' || $expiry ==
'infinity' || $expiry == $this->
getInfinity() )
3314 return ( $expiry ==
'' || $expiry ==
'infinity' || $expiry == $this->
getInfinity() )
3331 $reason = $this->
getLBInfo(
'readOnlyReason' );
3333 return is_string( $reason ) ? $reason :
false;
3348 if ( $this->mTrxLevel && $this->mTrxDoneWrites ) {
3349 trigger_error(
"Uncommitted DB writes (transaction from {$this->mTrxFname})." );
3351 $danglingCallbacks = array_merge(
3352 $this->mTrxIdleCallbacks,
3353 $this->mTrxPreCommitCallbacks,
3354 $this->mTrxEndCallbacks
3356 if ( $danglingCallbacks ) {
3358 foreach ( $danglingCallbacks
as $callbackInfo ) {
3359 $callers[] = $callbackInfo[1];
3361 $callers = implode(
', ', $callers );
3362 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.
doAtomicSection($fname, callable $callback)
Run a callback to do an atomic set of updates for this database.
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.
bool $suppressPostCommitCallbacks
Whether to suppress triggering of post-commit callbacks.
the array() calling protocol came about after MediaWiki 1.4rc1.
array $mNamedLocksHeld
Map of (name => 1) for locks obtained via lock()
Utility classThis allows us to distinguish a blob from a normal string and an array of strings...
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
processing should stop and the error should be shown to the user * false
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.
array[] $mTrxEndCallbacks
List of (callable, method name)
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.
__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.
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.
runOnTransactionIdleCallbacks($trigger)
Actually run and consume any "on transaction idle/resolution" callbacks.
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.
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...
bool $mTrxAutomatic
Record if the current transaction was started implicitly due to DBO_TRX being set.
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 run and consume 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':DEPRECATED!Use HtmlPageLinkRendererBegin instead.Used when generating internal and interwiki links in Linker::link(), before processing starts.Return false to skip default processing and return $ret.See documentation for Linker::link() for details on the expected meanings of parameters.$skin:the Skin object $target:the Title that the link is pointing to &$html:the contents that the< a > tag should have(raw HTML) $result
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.
onTransactionPreCommitOrIdle(callable $callback)
Run a callback before the current transaction commits or now if there is none.
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.
string[] $mTrxWriteCallers
Track the write query callers of the current transaction.
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 t...
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.
array[] $mTrxPreCommitCallbacks
List of (callable, method name)
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.
bool $mTrxAutomaticAtomic
Record if the current transaction was started implicitly by DatabaseBase::startAtomic.
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.
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.
freeResult($res)
Free a result object returned by query() or select().
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
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.
string $mTrxShortId
Either a short hexidecimal string if a transaction is active or "".
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.
onTransactionResolution(callable $callback)
Run a callback as soon as the current transaction commits or rolls back.
cascadingDeletes()
Returns true if this database supports (and uses) cascading deletes.
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()
float null $mTrxTimestamp
The UNIX time that the transaction started.
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.
onTransactionIdle(callable $callback)
Run a callback as soon as there is no transaction pending.
getServer()
Get the server hostname or IP address.
static getLocalServerInstance($fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
array[] $mTrxIdleCallbacks
List of (callable, method name)
begin($fname=__METHOD__)
Begin a transaction.
getServerInfo()
A string describing the current software version, and possibly other details in a user-friendly way...
setPostCommitCallbackSupression($suppress)
Whether to disable running of post-commit callbacks.
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.
array $mTrxAtomicLevels
Array of levels of atomicity within transactions.
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.
float $mTrxWriteDuration
Track the seconds spent in write queries for the current transaction.
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.
__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.
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.
string $mTrxFname
Remembers the function name given for starting the most recent transaction via begin().
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