diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2013-01-18 16:46:04 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2013-01-18 16:46:04 +0100 |
commit | 63601400e476c6cf43d985f3e7b9864681695ed4 (patch) | |
tree | f7846203a952e38aaf66989d0a4702779f549962 /includes/db/Database.php | |
parent | 8ff01378c9e0207f9169b81966a51def645b6a51 (diff) |
Update to MediaWiki 1.20.2
this update includes:
* adjusted Arch Linux skin
* updated FluxBBAuthPlugin
* patch for https://bugzilla.wikimedia.org/show_bug.cgi?id=44024
Diffstat (limited to 'includes/db/Database.php')
-rw-r--r-- | includes/db/Database.php | 701 |
1 files changed, 387 insertions, 314 deletions
diff --git a/includes/db/Database.php b/includes/db/Database.php index f3e84675..5f10b97d 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -2,10 +2,26 @@ /** * @defgroup Database Database * + * This file deals with database interface functions + * and query specifics/optimisations. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Database - * This file deals with database interface functions - * and query specifics/optimisations */ /** Number of times to re-try an operation in case of deadlock */ @@ -209,12 +225,15 @@ abstract class DatabaseBase implements DatabaseType { protected $mServer, $mUser, $mPassword, $mDBname; - /** - * @var DatabaseBase - */ protected $mConn = null; protected $mOpened = false; + /** + * @since 1.20 + * @var array of Closure + */ + protected $mTrxIdleCallbacks = array(); + protected $mTablePrefix; protected $mFlags; protected $mTrxLevel = 0; @@ -253,9 +272,9 @@ abstract class DatabaseBase implements DatabaseType { * - false to disable debugging * - omitted or null to do nothing * - * @return The previous value of the flag + * @return bool|null previous value of the flag */ - function debug( $debug = null ) { + public function debug( $debug = null ) { return wfSetBit( $this->mFlags, DBO_DEBUG, $debug ); } @@ -279,9 +298,9 @@ abstract class DatabaseBase implements DatabaseType { * * @param $buffer null|bool * - * @return The previous value of the flag + * @return null|bool The previous value of the flag */ - function bufferResults( $buffer = null ) { + public function bufferResults( $buffer = null ) { if ( is_null( $buffer ) ) { return !(bool)( $this->mFlags & DBO_NOBUFFER ); } else { @@ -300,7 +319,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool The previous value of the flag. */ - function ignoreErrors( $ignoreErrors = null ) { + public function ignoreErrors( $ignoreErrors = null ) { return wfSetBit( $this->mFlags, DBO_IGNORE, $ignoreErrors ); } @@ -310,28 +329,28 @@ abstract class DatabaseBase implements DatabaseType { * Historically, transactions were allowed to be "nested". This is no * longer supported, so this function really only returns a boolean. * - * @param $level An integer (0 or 1), or omitted to leave it unchanged. - * @return The previous value + * @param $level int An integer (0 or 1), or omitted to leave it unchanged. + * @return int The previous value */ - function trxLevel( $level = null ) { + public function trxLevel( $level = null ) { return wfSetVar( $this->mTrxLevel, $level ); } /** * Get/set the number of errors logged. Only useful when errors are ignored - * @param $count The count to set, or omitted to leave it unchanged. - * @return The error count + * @param $count int The count to set, or omitted to leave it unchanged. + * @return int The error count */ - function errorCount( $count = null ) { + public function errorCount( $count = null ) { return wfSetVar( $this->mErrorCount, $count ); } /** * Get/set the table prefix. - * @param $prefix The table prefix to set, or omitted to leave it unchanged. - * @return The previous table prefix. + * @param $prefix string The table prefix to set, or omitted to leave it unchanged. + * @return string The previous table prefix. */ - function tablePrefix( $prefix = null ) { + public function tablePrefix( $prefix = null ) { return wfSetVar( $this->mTablePrefix, $prefix ); } @@ -344,7 +363,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return LoadBalancer|null */ - function getLBInfo( $name = null ) { + public function getLBInfo( $name = null ) { if ( is_null( $name ) ) { return $this->mLBInfo; } else { @@ -364,7 +383,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $name * @param $value */ - function setLBInfo( $name, $value = null ) { + public function setLBInfo( $name, $value = null ) { if ( is_null( $value ) ) { $this->mLBInfo = $name; } else { @@ -377,7 +396,7 @@ abstract class DatabaseBase implements DatabaseType { * * @param $lag int */ - function setFakeSlaveLag( $lag ) { + public function setFakeSlaveLag( $lag ) { $this->mFakeSlaveLag = $lag; } @@ -386,7 +405,7 @@ abstract class DatabaseBase implements DatabaseType { * * @param $enabled bool */ - function setFakeMaster( $enabled = true ) { + public function setFakeMaster( $enabled = true ) { $this->mFakeMaster = $enabled; } @@ -395,7 +414,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function cascadingDeletes() { + public function cascadingDeletes() { return false; } @@ -404,7 +423,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function cleanupTriggers() { + public function cleanupTriggers() { return false; } @@ -414,7 +433,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function strictIPs() { + public function strictIPs() { return false; } @@ -423,7 +442,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function realTimestamps() { + public function realTimestamps() { return false; } @@ -432,7 +451,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function implicitGroupby() { + public function implicitGroupby() { return true; } @@ -442,17 +461,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function implicitOrderby() { - return true; - } - - /** - * Returns true if this database requires that SELECT DISTINCT queries require that all - ORDER BY expressions occur in the SELECT list per the SQL92 standard - * - * @return bool - */ - function standardSelectDistinct() { + public function implicitOrderby() { return true; } @@ -462,7 +471,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function searchableIPs() { + public function searchableIPs() { return false; } @@ -471,7 +480,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function functionalIndexes() { + public function functionalIndexes() { return false; } @@ -479,7 +488,7 @@ abstract class DatabaseBase implements DatabaseType { * Return the last query that went through DatabaseBase::query() * @return String */ - function lastQuery() { + public function lastQuery() { return $this->mLastQuery; } @@ -489,15 +498,25 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function doneWrites() { + public function doneWrites() { return $this->mDoneWrites; } /** + * Returns true if there is a transaction open with possible write + * queries or transaction idle callbacks waiting on it to finish. + * + * @return bool + */ + public function writesOrCallbacksPending() { + return $this->mTrxLevel && ( $this->mDoneWrites || $this->mTrxIdleCallbacks ); + } + + /** * Is a connection to the database open? * @return Boolean */ - function isOpen() { + public function isOpen() { return $this->mOpened; } @@ -513,8 +532,12 @@ abstract class DatabaseBase implements DatabaseType { * and removes it in command line mode * - DBO_PERSISTENT: use persistant database connection */ - function setFlag( $flag ) { + public function setFlag( $flag ) { + global $wgDebugDBTransactions; $this->mFlags |= $flag; + if ( ( $flag & DBO_TRX) & $wgDebugDBTransactions ) { + wfDebug("Implicit transactions are now disabled.\n"); + } } /** @@ -522,8 +545,12 @@ abstract class DatabaseBase implements DatabaseType { * * @param $flag: same as setFlag()'s $flag param */ - function clearFlag( $flag ) { + public function clearFlag( $flag ) { + global $wgDebugDBTransactions; $this->mFlags &= ~$flag; + if ( ( $flag & DBO_TRX ) && $wgDebugDBTransactions ) { + wfDebug("Implicit transactions are now disabled.\n"); + } } /** @@ -532,7 +559,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $flag: same as setFlag()'s $flag param * @return Boolean */ - function getFlag( $flag ) { + public function getFlag( $flag ) { return !!( $this->mFlags & $flag ); } @@ -543,14 +570,14 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function getProperty( $name ) { + public function getProperty( $name ) { return $this->$name; } /** * @return string */ - function getWikiID() { + public function getWikiID() { if ( $this->mTablePrefix ) { return "{$this->mDBname}-{$this->mTablePrefix}"; } else { @@ -588,15 +615,21 @@ abstract class DatabaseBase implements DatabaseType { function __construct( $server = false, $user = false, $password = false, $dbName = false, $flags = 0, $tablePrefix = 'get from global' ) { - global $wgDBprefix, $wgCommandLineMode; + global $wgDBprefix, $wgCommandLineMode, $wgDebugDBTransactions; $this->mFlags = $flags; if ( $this->mFlags & DBO_DEFAULT ) { if ( $wgCommandLineMode ) { $this->mFlags &= ~DBO_TRX; + if ( $wgDebugDBTransactions ) { + wfDebug("Implicit transaction open disabled.\n"); + } } else { $this->mFlags |= DBO_TRX; + if ( $wgDebugDBTransactions ) { + wfDebug("Implicit transaction open enabled.\n"); + } } } @@ -622,35 +655,6 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Same as new DatabaseMysql( ... ), kept for backward compatibility - * @deprecated since 1.17 - * - * @param $server - * @param $user - * @param $password - * @param $dbName - * @param $flags int - * @return DatabaseMysql - */ - static function newFromParams( $server, $user, $password, $dbName, $flags = 0 ) { - wfDeprecated( __METHOD__, '1.17' ); - return new DatabaseMysql( $server, $user, $password, $dbName, $flags ); - } - - /** - * Same as new factory( ... ), kept for backward compatibility - * @deprecated since 1.18 - * @see Database::factory() - */ - public final static function newFromType( $dbType, $p = array() ) { - wfDeprecated( __METHOD__, '1.18' ); - if ( isset( $p['tableprefix'] ) ) { - $p['tablePrefix'] = $p['tableprefix']; - } - return self::factory( $dbType, $p ); - } - - /** * Given a DB type, construct the name of the appropriate child class of * DatabaseBase. This is designed to replace all of the manual stuff like: * $class = 'Database' . ucfirst( strtolower( $type ) ); @@ -665,6 +669,8 @@ abstract class DatabaseBase implements DatabaseType { * @see ForeignDBRepo::getMasterDB() * @see WebInstaller_DBConnect::execute() * + * @since 1.18 + * * @param $dbType String A possible DB type * @param $p Array An array of options to pass to the constructor. * Valid options are: host, user, password, dbname, flags, tablePrefix @@ -707,7 +713,7 @@ abstract class DatabaseBase implements DatabaseType { } if ( $this->mPHPError ) { $error = preg_replace( '!\[<a.*</a>\]!', '', $this->mPHPError ); - $error = preg_replace( '!^.*?:(.*)$!', '$1', $error ); + $error = preg_replace( '!^.*?:\s?(.*)$!', '$1', $error ); return $error; } else { return false; @@ -728,12 +734,31 @@ abstract class DatabaseBase implements DatabaseType { * * @return Bool operation success. true if already closed. */ - function close() { - # Stub, should probably be overridden - return true; + public function close() { + if ( count( $this->mTrxIdleCallbacks ) ) { // sanity + throw new MWException( "Transaction idle callbacks still pending." ); + } + $this->mOpened = false; + if ( $this->mConn ) { + if ( $this->trxLevel() ) { + $this->commit( __METHOD__ ); + } + $ret = $this->closeConnection(); + $this->mConn = false; + return $ret; + } else { + return true; + } } /** + * Closes underlying database connection + * @since 1.20 + * @return bool: Whether connection was closed successfully + */ + protected abstract function closeConnection(); + + /** * @param $error String: fallback error message, used if none is given by DB */ function reportConnectionError( $error = 'Unknown error' ) { @@ -762,8 +787,8 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function isWriteQuery( $sql ) { - return !preg_match( '/^(?:SELECT|BEGIN|COMMIT|SET|SHOW|\(SELECT)\b/i', $sql ); + public function isWriteQuery( $sql ) { + return !preg_match( '/^(?:SELECT|BEGIN|ROLLBACK|COMMIT|SET|SHOW|EXPLAIN|\(SELECT)\b/i', $sql ); } /** @@ -833,8 +858,13 @@ abstract class DatabaseBase implements DatabaseType { # that would delay transaction initializations to once connection # is really used by application $sqlstart = substr( $sql, 0, 10 ); // very much worth it, benchmark certified(tm) - if ( strpos( $sqlstart, "SHOW " ) !== 0 && strpos( $sqlstart, "SET " ) !== 0 ) + if ( strpos( $sqlstart, "SHOW " ) !== 0 && strpos( $sqlstart, "SET " ) !== 0 ) { + global $wgDebugDBTransactions; + if ( $wgDebugDBTransactions ) { + wfDebug("Implicit transaction start.\n"); + } $this->begin( __METHOD__ . " ($fname)" ); + } } if ( $this->debug() ) { @@ -863,6 +893,7 @@ abstract class DatabaseBase implements DatabaseType { if ( false === $ret && $this->wasErrorReissuable() ) { # Transaction is gone, like it or not $this->mTrxLevel = 0; + $this->mTrxIdleCallbacks = array(); // cancel wfDebug( "Connection lost, reconnecting...\n" ); if ( $this->ping() ) { @@ -903,7 +934,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $fname String * @param $tempIgnore Boolean */ - function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { + public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { # Ignore errors during error handling to avoid infinite recursion $ignore = $this->ignoreErrors( true ); ++$this->mErrorCount; @@ -928,16 +959,12 @@ abstract class DatabaseBase implements DatabaseType { * & = filename; reads the file and inserts as a blob * (we don't use this though...) * - * This function should not be used directly by new code outside of the - * database classes. The query wrapper functions (select() etc.) should be - * used instead. - * * @param $sql string * @param $func string * * @return array */ - function prepare( $sql, $func = 'DatabaseBase::prepare' ) { + protected function prepare( $sql, $func = 'DatabaseBase::prepare' ) { /* MySQL doesn't support prepared statements (yet), so just pack up the query for reference. We'll manually replace the bits later. */ @@ -948,7 +975,7 @@ abstract class DatabaseBase implements DatabaseType { * Free a prepared query, generated by prepare(). * @param $prepared */ - function freePrepared( $prepared ) { + protected function freePrepared( $prepared ) { /* No-op by default */ } @@ -959,7 +986,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return ResultWrapper */ - function execute( $prepared, $args = null ) { + public function execute( $prepared, $args = null ) { if ( !is_array( $args ) ) { # Pull the var args $args = func_get_args(); @@ -972,41 +999,13 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Prepare & execute an SQL statement, quoting and inserting arguments - * in the appropriate places. + * For faking prepared SQL statements on DBs that don't support it directly. * - * This function should not be used directly by new code outside of the - * database classes. The query wrapper functions (select() etc.) should be - * used instead. - * - * @param $query String - * @param $args ... - * - * @return ResultWrapper - */ - function safeQuery( $query, $args = null ) { - $prepared = $this->prepare( $query, 'DatabaseBase::safeQuery' ); - - if ( !is_array( $args ) ) { - # Pull the var args - $args = func_get_args(); - array_shift( $args ); - } - - $retval = $this->execute( $prepared, $args ); - $this->freePrepared( $prepared ); - - return $retval; - } - - /** - * For faking prepared SQL statements on DBs that don't support - * it directly. * @param $preparedQuery String: a 'preparable' SQL statement * @param $args Array of arguments to fill it with * @return string executable SQL */ - function fillPrepared( $preparedQuery, $args ) { + public function fillPrepared( $preparedQuery, $args ) { reset( $args ); $this->preparedArgs =& $args; @@ -1022,7 +1021,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $matches Array * @return String */ - function fillPreparedArg( $matches ) { + protected function fillPreparedArg( $matches ) { switch( $matches[1] ) { case '\\?': return '?'; case '\\!': return '!'; @@ -1049,32 +1048,7 @@ abstract class DatabaseBase implements DatabaseType { * * @param $res Mixed: A SQL result */ - function freeResult( $res ) { - } - - /** - * Simple UPDATE wrapper. - * Usually throws a DBQueryError on failure. - * If errors are explicitly ignored, returns success - * - * This function exists for historical reasons, DatabaseBase::update() has a more standard - * calling convention and feature set - * - * @param $table string - * @param $var - * @param $value - * @param $cond - * @param $fname string - * - * @return bool - */ - function set( $table, $var, $value, $cond, $fname = 'DatabaseBase::set' ) { - $table = $this->tableName( $table ); - $sql = "UPDATE $table SET $var = '" . - $this->strencode( $value ) . "' WHERE ($cond)"; - - return (bool)$this->query( $sql, $fname ); - } + public function freeResult( $res ) {} /** * A SELECT wrapper which returns a single field from a single result row. @@ -1091,9 +1065,9 @@ abstract class DatabaseBase implements DatabaseType { * @param $fname string The function name of the caller. * @param $options string|array The query options. See DatabaseBase::select() for details. * - * @return false|mixed The value from the field, or false on failure. + * @return bool|mixed The value from the field, or false on failure. */ - function selectField( $table, $var, $cond = '', $fname = 'DatabaseBase::selectField', + public function selectField( $table, $var, $cond = '', $fname = 'DatabaseBase::selectField', $options = array() ) { if ( !is_array( $options ) ) { @@ -1126,7 +1100,7 @@ abstract class DatabaseBase implements DatabaseType { * @return Array * @see DatabaseBase::select() */ - function makeSelectOptions( $options ) { + public function makeSelectOptions( $options ) { $preLimitTail = $postLimitTail = ''; $startOpts = ''; @@ -1146,7 +1120,10 @@ abstract class DatabaseBase implements DatabaseType { } if ( isset( $options['HAVING'] ) ) { - $preLimitTail .= " HAVING {$options['HAVING']}"; + $having = is_array( $options['HAVING'] ) + ? $this->makeList( $options['HAVING'], LIST_AND ) + : $options['HAVING']; + $preLimitTail .= " HAVING {$having}"; } if ( isset( $options['ORDER BY'] ) ) { @@ -1245,10 +1222,12 @@ abstract class DatabaseBase implements DatabaseType { * @param $vars string|array * * May be either a field name or an array of field names. The field names - * here are complete fragments of SQL, for direct inclusion into the SELECT - * query. Expressions and aliases may be specified as in SQL, for example: + * can be complete fragments of SQL, for direct inclusion into the SELECT + * query. If an array is given, field aliases can be specified, for example: + * + * array( 'maxrev' => 'MAX(rev_id)' ) * - * array( 'MAX(rev_id) AS maxrev' ) + * This includes an expression with the alias "maxrev" in the query. * * If an expression is given, care must be taken to ensure that it is * DBMS-independent. @@ -1305,7 +1284,9 @@ abstract class DatabaseBase implements DatabaseType { * - GROUP BY: May be either an SQL fragment string naming a field or * expression to group by, or an array of such SQL fragments. * - * - HAVING: A string containing a HAVING clause. + * - HAVING: May be either an string containing a HAVING clause or an array of + * conditions building the HAVING clause. If an array is given, the conditions + * constructed from each element are combined with AND. * * - ORDER BY: May be either an SQL fragment giving a field name or * expression to order by, or an array of such SQL fragments. @@ -1351,7 +1332,7 @@ abstract class DatabaseBase implements DatabaseType { * DBQueryError exception will be thrown, except if the "ignore errors" * option was set, in which case false will be returned. */ - function select( $table, $vars, $conds = '', $fname = 'DatabaseBase::select', + public function select( $table, $vars, $conds = '', $fname = 'DatabaseBase::select', $options = array(), $join_conds = array() ) { $sql = $this->selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds ); @@ -1360,7 +1341,9 @@ abstract class DatabaseBase implements DatabaseType { /** * The equivalent of DatabaseBase::select() except that the constructed SQL - * is returned, instead of being immediately executed. + * is returned, instead of being immediately executed. This can be useful for + * doing UNION queries, where the SQL text of each query is needed. In general, + * however, callers outside of Database classes should just use select(). * * @param $table string|array Table name * @param $vars string|array Field names @@ -1369,12 +1352,14 @@ abstract class DatabaseBase implements DatabaseType { * @param $options string|array Query options * @param $join_conds string|array Join conditions * - * @return SQL query string. + * @return string SQL query string. * @see DatabaseBase::select() */ - function selectSQLText( $table, $vars, $conds = '', $fname = 'DatabaseBase::select', $options = array(), $join_conds = array() ) { + public function selectSQLText( $table, $vars, $conds = '', $fname = 'DatabaseBase::select', + $options = array(), $join_conds = array() ) + { if ( is_array( $vars ) ) { - $vars = implode( ',', $vars ); + $vars = implode( ',', $this->fieldNamesWithAlias( $vars ) ); } $options = (array)$options; @@ -1435,9 +1420,9 @@ abstract class DatabaseBase implements DatabaseType { * @param $options string|array Query options * @param $join_conds array|string Join conditions * - * @return ResultWrapper|bool + * @return object|bool */ - function selectRow( $table, $vars, $conds, $fname = 'DatabaseBase::selectRow', + public function selectRow( $table, $vars, $conds, $fname = 'DatabaseBase::selectRow', $options = array(), $join_conds = array() ) { $options = (array)$options; @@ -1481,7 +1466,7 @@ abstract class DatabaseBase implements DatabaseType { $fname = 'DatabaseBase::estimateRowCount', $options = array() ) { $rows = 0; - $res = $this->select ( $table, 'COUNT(*) AS rowcount', $conds, $fname, $options ); + $res = $this->select( $table, array( 'rowcount' => 'COUNT(*)' ), $conds, $fname, $options ); if ( $res ) { $row = $this->fetchRow( $res ); @@ -1527,7 +1512,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $fname String: calling function name (optional) * @return Boolean: whether $table has filed $field */ - function fieldExists( $table, $field, $fname = 'DatabaseBase::fieldExists' ) { + public function fieldExists( $table, $field, $fname = 'DatabaseBase::fieldExists' ) { $info = $this->fieldInfo( $table, $field ); return (bool)$info; @@ -1544,7 +1529,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool|null */ - function indexExists( $table, $index, $fname = 'DatabaseBase::indexExists' ) { + public function indexExists( $table, $index, $fname = 'DatabaseBase::indexExists' ) { $info = $this->indexInfo( $table, $index, $fname ); if ( is_null( $info ) ) { return null; @@ -1561,7 +1546,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function tableExists( $table, $fname = __METHOD__ ) { + public function tableExists( $table, $fname = __METHOD__ ) { $table = $this->tableName( $table ); $old = $this->ignoreErrors( true ); $res = $this->query( "SELECT 1 FROM $table LIMIT 1", $fname ); @@ -1576,7 +1561,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $index * @return string */ - function fieldType( $res, $index ) { + public function fieldType( $res, $index ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -1592,7 +1577,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function indexUnique( $table, $index ) { + public function indexUnique( $table, $index ) { $indexInfo = $this->indexInfo( $table, $index ); if ( !$indexInfo ) { @@ -1608,7 +1593,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $options array * @return string */ - function makeInsertOptions( $options ) { + protected function makeInsertOptions( $options ) { return implode( ' ', $options ); } @@ -1645,7 +1630,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function insert( $table, $a, $fname = 'DatabaseBase::insert', $options = array() ) { + public function insert( $table, $a, $fname = 'DatabaseBase::insert', $options = array() ) { # No rows to insert, easy just return now if ( !count( $a ) ) { return true; @@ -1693,7 +1678,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $options Array: The options passed to DatabaseBase::update * @return string */ - function makeUpdateOptions( $options ) { + protected function makeUpdateOptions( $options ) { if ( !is_array( $options ) ) { $options = array( $options ); } @@ -1759,7 +1744,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function makeList( $a, $mode = LIST_COMMA ) { + public function makeList( $a, $mode = LIST_COMMA ) { if ( !is_array( $a ) ) { throw new DBUnexpectedError( $this, 'DatabaseBase::makeList called with incorrect parameters' ); } @@ -1819,12 +1804,12 @@ abstract class DatabaseBase implements DatabaseType { * The keys on each level may be either integers or strings. * * @param $data Array: organized as 2-d - * array(baseKeyVal => array(subKeyVal => <ignored>, ...), ...) + * array(baseKeyVal => array(subKeyVal => [ignored], ...), ...) * @param $baseKey String: field name to match the base-level keys to (eg 'pl_namespace') * @param $subKey String: field name to match the sub-level keys to (eg 'pl_title') * @return Mixed: string SQL fragment, or false if no items in array. */ - function makeWhereFrom2d( $data, $baseKey, $subKey ) { + public function makeWhereFrom2d( $data, $baseKey, $subKey ) { $conds = array(); foreach ( $data as $base => $sub ) { @@ -1844,14 +1829,22 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Bitwise operations + * Return aggregated value alias + * + * @param $valuedata + * @param $valuename string + * + * @return string */ + public function aggregateValue( $valuedata, $valuename = 'value' ) { + return $valuename; + } /** * @param $field * @return string */ - function bitNot( $field ) { + public function bitNot( $field ) { return "(~$field)"; } @@ -1860,7 +1853,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $fieldRight * @return string */ - function bitAnd( $fieldLeft, $fieldRight ) { + public function bitAnd( $fieldLeft, $fieldRight ) { return "($fieldLeft & $fieldRight)"; } @@ -1869,11 +1862,20 @@ abstract class DatabaseBase implements DatabaseType { * @param $fieldRight * @return string */ - function bitOr( $fieldLeft, $fieldRight ) { + public function bitOr( $fieldLeft, $fieldRight ) { return "($fieldLeft | $fieldRight)"; } /** + * Build a concatenation list to feed into a SQL query + * @param $stringList Array: list of raw SQL expressions; caller is responsible for any quoting + * @return String + */ + public function buildConcat( $stringList ) { + return 'CONCAT(' . implode( ',', $stringList ) . ')'; + } + + /** * Change the current database * * @todo Explain what exactly will fail if this is not overridden. @@ -1882,7 +1884,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool Success or failure */ - function selectDB( $db ) { + public function selectDB( $db ) { # Stub. Shouldn't cause serious problems if it's not overridden, but # if your database engine supports a concept similar to MySQL's # databases you may as well. @@ -1893,14 +1895,14 @@ abstract class DatabaseBase implements DatabaseType { /** * Get the current DB name */ - function getDBname() { + public function getDBname() { return $this->mDBname; } /** * Get the server hostname or IP address */ - function getServer() { + public function getServer() { return $this->mServer; } @@ -1921,7 +1923,7 @@ abstract class DatabaseBase implements DatabaseType { * raw - Do not add identifier quotes to the table name * @return String: full database name */ - function tableName( $name, $format = 'quoted' ) { + public function tableName( $name, $format = 'quoted' ) { global $wgSharedDB, $wgSharedPrefix, $wgSharedTables; # Skip the entire process when we have a string quoted on both ends. # Note that we check the end so that we will still quote any use of @@ -2067,6 +2069,39 @@ abstract class DatabaseBase implements DatabaseType { } /** + * Get an aliased field name + * e.g. fieldName AS newFieldName + * + * @param $name string Field name + * @param $alias string|bool Alias (optional) + * @return string SQL name for aliased field. Will not alias a field to its own name + */ + public function fieldNameWithAlias( $name, $alias = false ) { + if ( !$alias || (string)$alias === (string)$name ) { + return $name; + } else { + return $name . ' AS ' . $alias; //PostgreSQL needs AS + } + } + + /** + * Gets an array of aliased field names + * + * @param $fields array( [alias] => field ) + * @return array of strings, see fieldNameWithAlias() + */ + public function fieldNamesWithAlias( $fields ) { + $retval = array(); + foreach ( $fields as $alias => $field ) { + if ( is_numeric( $alias ) ) { + $alias = $field; + } + $retval[] = $this->fieldNameWithAlias( $field, $alias ); + } + return $retval; + } + + /** * Get the aliased table name clause for a FROM clause * which might have a JOIN and/or USE INDEX clause * @@ -2134,7 +2169,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function indexName( $index ) { + protected function indexName( $index ) { // Backwards-compatibility hack $renamed = array( 'ar_usertext_timestamp' => 'usertext_timestamp', @@ -2157,7 +2192,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function addQuotes( $s ) { + public function addQuotes( $s ) { if ( $s === null ) { return 'NULL'; } else { @@ -2196,36 +2231,6 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Backwards compatibility, identifier quoting originated in DatabasePostgres - * which used quote_ident which does not follow our naming conventions - * was renamed to addIdentifierQuotes. - * @deprecated since 1.18 use addIdentifierQuotes - * - * @param $s string - * - * @return string - */ - function quote_ident( $s ) { - wfDeprecated( __METHOD__, '1.18' ); - return $this->addIdentifierQuotes( $s ); - } - - /** - * Escape string for safe LIKE usage. - * WARNING: you should almost never use this function directly, - * instead use buildLike() that escapes everything automatically - * @deprecated since 1.17, warnings in 1.17, removed in ??? - * - * @param $s string - * - * @return string - */ - public function escapeLike( $s ) { - wfDeprecated( __METHOD__, '1.17' ); - return $this->escapeLikeInternal( $s ); - } - - /** * @param $s string * @return string */ @@ -2249,7 +2254,7 @@ abstract class DatabaseBase implements DatabaseType { * @since 1.16 * @return String: fully built LIKE statement */ - function buildLike() { + public function buildLike() { $params = func_get_args(); if ( count( $params ) > 0 && is_array( $params[0] ) ) { @@ -2274,7 +2279,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return LikeMatch */ - function anyChar() { + public function anyChar() { return new LikeMatch( '_' ); } @@ -2283,7 +2288,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return LikeMatch */ - function anyString() { + public function anyString() { return new LikeMatch( '%' ); } @@ -2298,7 +2303,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $seqName string * @return null */ - function nextSequenceValue( $seqName ) { + public function nextSequenceValue( $seqName ) { return null; } @@ -2312,7 +2317,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $index * @return string */ - function useIndexClause( $index ) { + public function useIndexClause( $index ) { return ''; } @@ -2338,7 +2343,7 @@ abstract class DatabaseBase implements DatabaseType { * a field name or an array of field names * @param $fname String: Calling function name (use __METHOD__) for logs/profiling */ - function replace( $table, $uniqueIndexes, $rows, $fname = 'DatabaseBase::replace' ) { + public function replace( $table, $uniqueIndexes, $rows, $fname = 'DatabaseBase::replace' ) { $quotedTable = $this->tableName( $table ); if ( count( $rows ) == 0 ) { @@ -2439,7 +2444,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $fname String: Calling function name (use __METHOD__) for * logs/profiling */ - function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, + public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = 'DatabaseBase::deleteJoin' ) { if ( !$conds ) { @@ -2466,7 +2471,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return int */ - function textFieldSize( $table, $field ) { + public function textFieldSize( $table, $field ) { $table = $this->tableName( $table ); $sql = "SHOW COLUMNS FROM $table LIKE \"$field\";"; $res = $this->query( $sql, 'DatabaseBase::textFieldSize' ); @@ -2491,7 +2496,7 @@ abstract class DatabaseBase implements DatabaseType { * @return string Returns the text of the low priority option if it is * supported, or a blank string otherwise */ - function lowPriorityOption() { + public function lowPriorityOption() { return ''; } @@ -2505,7 +2510,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function delete( $table, $conds, $fname = 'DatabaseBase::delete' ) { + public function delete( $table, $conds, $fname = 'DatabaseBase::delete' ) { if ( !$conds ) { throw new DBUnexpectedError( $this, 'DatabaseBase::delete() called with no conditions' ); } @@ -2546,7 +2551,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return ResultWrapper */ - function insertSelect( $destTable, $srcTable, $varMap, $conds, + public function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = 'DatabaseBase::insertSelect', $insertOptions = array(), $selectOptions = array() ) { @@ -2592,35 +2597,24 @@ abstract class DatabaseBase implements DatabaseType { * If the result of the query is not ordered, then the rows to be returned * are theoretically arbitrary. * - * $sql is expected to be a SELECT, if that makes a difference. For - * UPDATE, limitResultForUpdate should be used. + * $sql is expected to be a SELECT, if that makes a difference. * * The version provided by default works in MySQL and SQLite. It will very * likely need to be overridden for most other DBMSes. * * @param $sql String SQL query we will append the limit too * @param $limit Integer the SQL limit - * @param $offset Integer|false the SQL offset (default false) + * @param $offset Integer|bool the SQL offset (default false) * * @return string */ - function limitResult( $sql, $limit, $offset = false ) { + public function limitResult( $sql, $limit, $offset = false ) { if ( !is_numeric( $limit ) ) { throw new DBUnexpectedError( $this, "Invalid non-numeric limit passed to limitResult()\n" ); } - return "$sql LIMIT " - . ( ( is_numeric( $offset ) && $offset != 0 ) ? "{$offset}," : "" ) - . "{$limit} "; - } - - /** - * @param $sql - * @param $num - * @return string - */ - function limitResultForUpdate( $sql, $num ) { - return $this->limitResult( $sql, $num, 0 ); + . ( ( is_numeric( $offset ) && $offset != 0 ) ? "{$offset}," : "" ) + . "{$limit} "; } /** @@ -2628,7 +2622,7 @@ abstract class DatabaseBase implements DatabaseType { * within the UNION construct. * @return Boolean */ - function unionSupportsOrderAndLimit() { + public function unionSupportsOrderAndLimit() { return true; // True for almost every DB supported } @@ -2640,7 +2634,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $all Boolean: use UNION ALL * @return String: SQL fragment */ - function unionQueries( $sqls, $all ) { + public function unionQueries( $sqls, $all ) { $glue = $all ? ') UNION ALL (' : ') UNION ('; return '(' . implode( $glue, $sqls ) . ')'; } @@ -2649,12 +2643,15 @@ abstract class DatabaseBase implements DatabaseType { * Returns an SQL expression for a simple conditional. This doesn't need * to be overridden unless CASE isn't supported in your DBMS. * - * @param $cond String: SQL expression which will result in a boolean value + * @param $cond string|array SQL expression which will result in a boolean value * @param $trueVal String: SQL expression to return if true * @param $falseVal String: SQL expression to return if false * @return String: SQL fragment */ - function conditional( $cond, $trueVal, $falseVal ) { + public function conditional( $cond, $trueVal, $falseVal ) { + if ( is_array( $cond ) ) { + $cond = $this->makeList( $cond, LIST_AND ); + } return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) "; } @@ -2668,7 +2665,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function strreplace( $orig, $old, $new ) { + public function strreplace( $orig, $old, $new ) { return "REPLACE({$orig}, {$old}, {$new})"; } @@ -2678,7 +2675,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return int */ - function getServerUptime() { + public function getServerUptime() { return 0; } @@ -2688,7 +2685,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function wasDeadlock() { + public function wasDeadlock() { return false; } @@ -2698,7 +2695,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function wasLockTimeout() { + public function wasLockTimeout() { return false; } @@ -2709,7 +2706,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function wasErrorReissuable() { + public function wasErrorReissuable() { return false; } @@ -2719,7 +2716,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function wasReadOnlyError() { + public function wasReadOnlyError() { return false; } @@ -2741,8 +2738,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool */ - function deadlockLoop() { - + public function deadlockLoop() { $this->begin( __METHOD__ ); $args = func_get_args(); $function = array_shift( $args ); @@ -2790,11 +2786,11 @@ abstract class DatabaseBase implements DatabaseType { * @param $timeout Integer: the maximum number of seconds to wait for * synchronisation * - * @return An integer: zero if the slave was past that position already, + * @return integer: zero if the slave was past that position already, * greater than zero if we waited for some period of time, less than * zero if we timed out. */ - function masterPosWait( DBMasterPos $pos, $timeout ) { + public function masterPosWait( DBMasterPos $pos, $timeout ) { wfProfileIn( __METHOD__ ); if ( !is_null( $this->mFakeSlaveLag ) ) { @@ -2827,7 +2823,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return DBMasterPos, or false if this is not a slave. */ - function getSlavePos() { + public function getSlavePos() { if ( !is_null( $this->mFakeSlaveLag ) ) { $pos = new MySQLMasterPos( 'fake', microtime( true ) - $this->mFakeSlaveLag ); wfDebug( __METHOD__ . ": fake slave pos = $pos\n" ); @@ -2843,7 +2839,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return DBMasterPos, or false if this is not a master */ - function getMasterPos() { + public function getMasterPos() { if ( $this->mFakeMaster ) { return new MySQLMasterPos( 'fake', microtime( true ) ); } else { @@ -2852,11 +2848,65 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Begin a transaction, committing any previously open transaction + * Run an anonymous function as soon as there is no transaction pending. + * If there is a transaction and it is rolled back, then the callback is cancelled. + * Callbacks must commit any transactions that they begin. + * + * This is useful for updates to different systems or separate transactions are needed. + * + * @param Closure $callback + * @return void + */ + final public function onTransactionIdle( Closure $callback ) { + if ( $this->mTrxLevel ) { + $this->mTrxIdleCallbacks[] = $callback; + } else { + $callback(); + } + } + + /** + * Actually run the "on transaction idle" callbacks + */ + protected function runOnTransactionIdleCallbacks() { + $autoTrx = $this->getFlag( DBO_TRX ); // automatic begin() enabled? + + $e = null; // last exception + do { // callbacks may add callbacks :) + $callbacks = $this->mTrxIdleCallbacks; + $this->mTrxIdleCallbacks = array(); // recursion guard + foreach ( $callbacks as $callback ) { + try { + $this->clearFlag( DBO_TRX ); // make each query its own transaction + $callback(); + $this->setFlag( $autoTrx ? DBO_TRX : 0 ); // restore automatic begin() + } catch ( Exception $e ) {} + } + } while ( count( $this->mTrxIdleCallbacks ) ); + + if ( $e instanceof Exception ) { + throw $e; // re-throw any last exception + } + } + + /** + * Begin a transaction * * @param $fname string */ - function begin( $fname = 'DatabaseBase::begin' ) { + final public function begin( $fname = 'DatabaseBase::begin' ) { + if ( $this->mTrxLevel ) { // implicit commit + $this->doCommit( $fname ); + $this->runOnTransactionIdleCallbacks(); + } + $this->doBegin( $fname ); + } + + /** + * @see DatabaseBase::begin() + * @param type $fname + */ + protected function doBegin( $fname ) { $this->query( 'BEGIN', $fname ); $this->mTrxLevel = 1; } @@ -2866,7 +2916,16 @@ abstract class DatabaseBase implements DatabaseType { * * @param $fname string */ - function commit( $fname = 'DatabaseBase::commit' ) { + final public function commit( $fname = 'DatabaseBase::commit' ) { + $this->doCommit( $fname ); + $this->runOnTransactionIdleCallbacks(); + } + + /** + * @see DatabaseBase::commit() + * @param type $fname + */ + protected function doCommit( $fname ) { if ( $this->mTrxLevel ) { $this->query( 'COMMIT', $fname ); $this->mTrxLevel = 0; @@ -2879,7 +2938,16 @@ abstract class DatabaseBase implements DatabaseType { * * @param $fname string */ - function rollback( $fname = 'DatabaseBase::rollback' ) { + final public function rollback( $fname = 'DatabaseBase::rollback' ) { + $this->doRollback( $fname ); + $this->mTrxIdleCallbacks = array(); // cancel + } + + /** + * @see DatabaseBase::rollback() + * @param type $fname + */ + protected function doRollback( $fname ) { if ( $this->mTrxLevel ) { $this->query( 'ROLLBACK', $fname, true ); $this->mTrxLevel = 0; @@ -2900,7 +2968,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $fname String: calling function name * @return Boolean: true if operation was successful */ - function duplicateTableStructure( $oldName, $newName, $temporary = false, + public function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseBase::duplicateTableStructure' ) { throw new MWException( @@ -2910,7 +2978,7 @@ abstract class DatabaseBase implements DatabaseType { /** * List all tables on the database * - * @param $prefix Only show tables with this prefix, e.g. mw_ + * @param $prefix string Only show tables with this prefix, e.g. mw_ * @param $fname String: calling function name */ function listTables( $prefix = null, $fname = 'DatabaseBase::listTables' ) { @@ -2928,7 +2996,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function timestamp( $ts = 0 ) { + public function timestamp( $ts = 0 ) { return wfTimestamp( TS_MW, $ts ); } @@ -2945,7 +3013,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return string */ - function timestampOrNull( $ts = null ) { + public function timestampOrNull( $ts = null ) { if ( is_null( $ts ) ) { return null; } else { @@ -2968,7 +3036,7 @@ abstract class DatabaseBase implements DatabaseType { * * @return bool|ResultWrapper */ - function resultObject( $result ) { + public function resultObject( $result ) { if ( empty( $result ) ) { return false; } elseif ( $result instanceof ResultWrapper ) { @@ -2982,23 +3050,11 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Return aggregated value alias - * - * @param $valuedata - * @param $valuename string - * - * @return string - */ - function aggregateValue ( $valuedata, $valuename = 'value' ) { - return $valuename; - } - - /** * Ping the server and try to reconnect if it there is no connection * * @return bool Success or failure */ - function ping() { + public function ping() { # Stub. Not essential to override. return true; } @@ -3010,9 +3066,9 @@ abstract class DatabaseBase implements DatabaseType { * installations. Most callers should use LoadBalancer::safeGetLag() * instead. * - * @return Database replication lag in seconds + * @return int Database replication lag in seconds */ - function getLag() { + public function getLag() { return intval( $this->mFakeSlaveLag ); } @@ -3033,7 +3089,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $b string * @return string */ - function encodeBlob( $b ) { + public function encodeBlob( $b ) { return $b; } @@ -3044,23 +3100,11 @@ abstract class DatabaseBase implements DatabaseType { * @param $b string * @return string */ - function decodeBlob( $b ) { + public function decodeBlob( $b ) { return $b; } /** - * Override database's default connection timeout - * - * @param $timeout Integer in seconds - * @return void - * @deprecated since 1.19; use setSessionOptions() - */ - public function setTimeout( $timeout ) { - wfDeprecated( __METHOD__, '1.19' ); - $this->setSessionOptions( array( 'connTimeout' => $timeout ) ); - } - - /** * Override database's default behavior. $options include: * 'connTimeout' : Set the connection timeout value in seconds. * May be useful for very long batch queries such as @@ -3085,7 +3129,9 @@ abstract class DatabaseBase implements DatabaseType { * generated dynamically using $filename * @return bool|string */ - function sourceFile( $filename, $lineCallback = false, $resultCallback = false, $fname = false ) { + public function sourceFile( + $filename, $lineCallback = false, $resultCallback = false, $fname = false + ) { wfSuppressWarnings(); $fp = fopen( $filename, 'r' ); wfRestoreWarnings(); @@ -3135,9 +3181,9 @@ abstract class DatabaseBase implements DatabaseType { * ones in $GLOBALS. If an array is set here, $GLOBALS will not be used at * all. If it's set to false, $GLOBALS will be used. * - * @param $vars False, or array mapping variable name to value. + * @param $vars bool|array mapping variable name to value. */ - function setSchemaVars( $vars ) { + public function setSchemaVars( $vars ) { $this->mSchemaVars = $vars; } @@ -3323,12 +3369,15 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Build a concatenation list to feed into a SQL query - * @param $stringList Array: list of raw SQL expressions; caller is responsible for any quoting - * @return String + * Check to see if a named lock is available. This is non-blocking. + * + * @param $lockName String: name of lock to poll + * @param $method String: name of method calling us + * @return Boolean + * @since 1.20 */ - function buildConcat( $stringList ) { - return 'CONCAT(' . implode( ',', $stringList ) . ')'; + public function lockIsFree( $lockName, $method ) { + return true; } /** @@ -3352,7 +3401,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $lockName String: Name of lock to release * @param $method String: Name of method calling us * - * @return Returns 1 if the lock was released, 0 if the lock was not established + * @return int Returns 1 if the lock was released, 0 if the lock was not established * by this thread (in which case the lock is not released), and NULL if the named * lock did not exist */ @@ -3425,17 +3474,28 @@ abstract class DatabaseBase implements DatabaseType { } /** - * Encode an expiry time + * Encode an expiry time into the DBMS dependent format * * @param $expiry String: timestamp for expiry, or the 'infinity' string * @return String */ public function encodeExpiry( $expiry ) { - if ( $expiry == '' || $expiry == $this->getInfinity() ) { - return $this->getInfinity(); - } else { - return $this->timestamp( $expiry ); - } + return ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() ) + ? $this->getInfinity() + : $this->timestamp( $expiry ); + } + + /** + * Decode an expiry time into a DBMS independent format + * + * @param $expiry String: DB timestamp field value for expiry + * @param $format integer: TS_* constant, defaults to TS_MW + * @return String + */ + public function decodeExpiry( $expiry, $format = TS_MW ) { + return ( $expiry == '' || $expiry == $this->getInfinity() ) + ? 'infinity' + : wfTimestamp( $format, $expiry ); } /** @@ -3450,4 +3510,17 @@ abstract class DatabaseBase implements DatabaseType { public function setBigSelects( $value = true ) { // no-op } + + /** + * @since 1.19 + */ + public function __toString() { + return (string)$this->mConn; + } + + public function __destruct() { + if ( count( $this->mTrxIdleCallbacks ) ) { // sanity + trigger_error( "Transaction idle callbacks still pending." ); + } + } } |