summaryrefslogtreecommitdiff
path: root/includes/db/Database.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/db/Database.php')
-rw-r--r--includes/db/Database.php1325
1 files changed, 823 insertions, 502 deletions
diff --git a/includes/db/Database.php b/includes/db/Database.php
index 10645608..9b783a99 100644
--- a/includes/db/Database.php
+++ b/includes/db/Database.php
@@ -1,4 +1,5 @@
<?php
+
/**
* @defgroup Database Database
*
@@ -42,10 +43,10 @@ interface DatabaseType {
/**
* Open a connection to the database. Usually aborts on failure
*
- * @param string $server database server host
- * @param string $user database user name
- * @param string $password database user password
- * @param string $dbName database name
+ * @param string $server Database server host
+ * @param string $user Database user name
+ * @param string $password Database user password
+ * @param string $dbName Database name
* @return bool
* @throws DBConnectionError
*/
@@ -57,18 +58,18 @@ interface DatabaseType {
* member variables.
* If no more rows are available, false is returned.
*
- * @param $res ResultWrapper|object as returned from DatabaseBase::query(), etc.
- * @return object|bool
+ * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc.
+ * @return stdClass|bool
* @throws DBUnexpectedError Thrown if the database returns an error
*/
function fetchObject( $res );
/**
* Fetch the next row from the given result object, in associative array
- * form. Fields are retrieved with $row['fieldname'].
+ * form. Fields are retrieved with $row['fieldname'].
* If no more rows are available, false is returned.
*
- * @param $res ResultWrapper result object as returned from DatabaseBase::query(), etc.
+ * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc.
* @return array|bool
* @throws DBUnexpectedError Thrown if the database returns an error
*/
@@ -77,7 +78,7 @@ interface DatabaseType {
/**
* Get the number of rows in a result object
*
- * @param $res Mixed: A SQL result
+ * @param mixed $res A SQL result
* @return int
*/
function numRows( $res );
@@ -86,7 +87,7 @@ interface DatabaseType {
* Get the number of fields in a result object
* @see http://www.php.net/mysql_num_fields
*
- * @param $res Mixed: A SQL result
+ * @param mixed $res A SQL result
* @return int
*/
function numFields( $res );
@@ -95,8 +96,8 @@ interface DatabaseType {
* Get a field name in a result object
* @see http://www.php.net/mysql_field_name
*
- * @param $res Mixed: A SQL result
- * @param $n Integer
+ * @param mixed $res A SQL result
+ * @param int $n
* @return string
*/
function fieldName( $res, $n );
@@ -119,8 +120,8 @@ interface DatabaseType {
* Change the position of the cursor in a result object
* @see http://www.php.net/mysql_data_seek
*
- * @param $res Mixed: A SQL result
- * @param $row Mixed: Either MySQL row or ResultWrapper
+ * @param mixed $res A SQL result
+ * @param int $row
*/
function dataSeek( $res, $row );
@@ -144,8 +145,8 @@ interface DatabaseType {
* mysql_fetch_field() wrapper
* Returns false if the field doesn't exist
*
- * @param string $table table name
- * @param string $field field name
+ * @param string $table Table name
+ * @param string $field Field name
*
* @return Field
*/
@@ -156,7 +157,7 @@ interface DatabaseType {
* @param string $table Table name
* @param string $index Index name
* @param string $fname Calling function name
- * @return Mixed: Database-specific index description class or false if the index does not exist
+ * @return mixed Database-specific index description class or false if the index does not exist
*/
function indexInfo( $table, $index, $fname = __METHOD__ );
@@ -171,18 +172,18 @@ interface DatabaseType {
/**
* Wrapper for addslashes()
*
- * @param string $s to be slashed.
- * @return string: slashed string.
+ * @param string $s String to be slashed.
+ * @return string Slashed string.
*/
function strencode( $s );
/**
* Returns a wikitext link to the DB's website, e.g.,
- * return "[http://www.mysql.com/ MySQL]";
+ * return "[http://www.mysql.com/ MySQL]";
* Should at least contain plain text, if for some reason
* your database has no website.
*
- * @return string: wikitext of a link to the server software's web site
+ * @return string Wikitext of a link to the server software's web site
*/
function getSoftwareLink();
@@ -190,16 +191,16 @@ interface DatabaseType {
* A string describing the current software version, like from
* mysql_get_server_info().
*
- * @return string: Version information from the database server.
+ * @return string Version information from the database server.
*/
function getServerVersion();
/**
* A string describing the current software version, and possibly
- * other details in a user-friendly way. Will be listed on Special:Version, etc.
+ * other details in a user-friendly way. Will be listed on Special:Version, etc.
* Use getServerVersion() to get machine-friendly information.
*
- * @return string: Version information from the database server
+ * @return string Version information from the database server
*/
function getServerInfo();
}
@@ -208,7 +209,8 @@ interface DatabaseType {
* Interface for classes that implement or wrap DatabaseBase
* @ingroup Database
*/
-interface IDatabase {}
+interface IDatabase {
+}
/**
* Database abstraction object
@@ -217,8 +219,10 @@ interface IDatabase {}
abstract class DatabaseBase implements IDatabase, DatabaseType {
/** Number of times to re-try an operation in case of deadlock */
const DEADLOCK_TRIES = 4;
+
/** Minimum time to wait before retry, in microseconds */
const DEADLOCK_DELAY_MIN = 500000;
+
/** Maximum time to wait before retry */
const DEADLOCK_DELAY_MAX = 1500000;
@@ -232,6 +236,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
protected $mServer, $mUser, $mPassword, $mDBname;
+ /** @var resource Database connection */
protected $mConn = null;
protected $mOpened = false;
@@ -241,12 +246,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
protected $mTrxPreCommitCallbacks = array();
protected $mTablePrefix;
+ protected $mSchema;
protected $mFlags;
protected $mForeign;
- protected $mTrxLevel = 0;
protected $mErrorCount = 0;
protected $mLBInfo = array();
- protected $mFakeSlaveLag = null, $mFakeMaster = false;
protected $mDefaultBigSelects = null;
protected $mSchemaVars = false;
@@ -257,10 +261,25 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
protected $delimiter = ';';
/**
+ * Either 1 if a transaction is active or 0 otherwise.
+ * The other Trx fields may not be meaningfull if this is 0.
+ *
+ * @var int
+ */
+ protected $mTrxLevel = 0;
+
+ /**
+ * Either a short hexidecimal string if a transaction is active or ""
+ *
+ * @var string
+ */
+ protected $mTrxShortId = '';
+
+ /**
* Remembers the function name given for starting the most recent transaction via begin().
* Used to provide additional context for error reporting.
*
- * @var String
+ * @var string
* @see DatabaseBase::mTrxLevel
*/
private $mTrxFname = null;
@@ -268,7 +287,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Record if possible write queries were done in the last transaction started
*
- * @var Bool
+ * @var bool
* @see DatabaseBase::mTrxLevel
*/
private $mTrxDoneWrites = false;
@@ -276,20 +295,34 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Record if the current transaction was started implicitly due to DBO_TRX being set.
*
- * @var Bool
+ * @var bool
* @see DatabaseBase::mTrxLevel
*/
private $mTrxAutomatic = false;
/**
+ * Array of levels of atomicity within transactions
+ *
+ * @var SplStack
+ */
+ private $mTrxAtomicLevels;
+
+ /**
+ * Record if the current transaction was started implicitly by DatabaseBase::startAtomic
+ *
+ * @var bool
+ */
+ private $mTrxAutomaticAtomic = false;
+
+ /**
* @since 1.21
- * @var file handle for upgrade
+ * @var resource File handle for upgrade
*/
protected $fileHandle = null;
/**
* @since 1.22
- * @var Process cache of VIEWs names in the database
+ * @var string[] Process cache of VIEWs names in the database
*/
protected $allViews = null;
@@ -300,17 +333,17 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* A string describing the current software version, and possibly
- * other details in a user-friendly way. Will be listed on Special:Version, etc.
+ * other details in a user-friendly way. Will be listed on Special:Version, etc.
* Use getServerVersion() to get machine-friendly information.
*
- * @return string: Version information from the database server
+ * @return string Version information from the database server
*/
public function getServerInfo() {
return $this->getServerVersion();
}
/**
- * @return string: command delimiter used by this database engine
+ * @return string Command delimiter used by this database engine
*/
public function getDelimiter() {
return $this->delimiter;
@@ -318,12 +351,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Boolean, controls output of large amounts of debug information.
- * @param $debug bool|null
+ * @param bool|null $debug
* - true to enable debugging
* - false to disable debugging
* - omitted or null to do nothing
*
- * @return bool|null previous value of the flag
+ * @return bool|null Previous value of the flag
*/
public function debug( $debug = null ) {
return wfSetBit( $this->mFlags, DBO_DEBUG, $debug );
@@ -347,8 +380,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* split up queries into batches using a LIMIT clause than to switch off
* buffering.
*
- * @param $buffer null|bool
- *
+ * @param null|bool $buffer
* @return null|bool The previous value of the flag
*/
public function bufferResults( $buffer = null ) {
@@ -368,8 +400,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* Do not use this function outside of the Database classes.
*
- * @param $ignoreErrors bool|null
- *
+ * @param null|bool $ignoreErrors
* @return bool The previous value of the flag.
*/
public function ignoreErrors( $ignoreErrors = null ) {
@@ -377,16 +408,15 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * Gets or sets the current transaction level.
+ * Gets the current transaction level.
*
* Historically, transactions were allowed to be "nested". This is no
* longer supported, so this function really only returns a boolean.
*
- * @param int $level An integer (0 or 1), or omitted to leave it unchanged.
* @return int The previous value
*/
- public function trxLevel( $level = null ) {
- return wfSetVar( $this->mTrxLevel, $level );
+ public function trxLevel() {
+ return $this->mTrxLevel;
}
/**
@@ -408,9 +438,18 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
+ * Get/set the db schema.
+ * @param string $schema The database schema to set, or omitted to leave it unchanged.
+ * @return string The previous db schema.
+ */
+ public function dbSchema( $schema = null ) {
+ return wfSetVar( $this->mSchema, $schema );
+ }
+
+ /**
* Set the filehandle to copy write statements to.
*
- * @param $fh filehandle
+ * @param resource $fh File handle
*/
public function setFileHandle( $fh ) {
$this->fileHandle = $fh;
@@ -423,7 +462,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @param string $name The entry of the info array to get, or null to get the
* whole array
*
- * @return LoadBalancer|null
+ * @return array|mixed|null
*/
public function getLBInfo( $name = null ) {
if ( is_null( $name ) ) {
@@ -442,8 +481,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* the LB info array is set to that parameter. If it is called with two
* parameters, the member with the given name is set to the given value.
*
- * @param $name
- * @param $value
+ * @param string $name
+ * @param array $value
*/
public function setLBInfo( $name, $value = null ) {
if ( is_null( $value ) ) {
@@ -456,19 +495,19 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Set lag time in seconds for a fake slave
*
- * @param $lag int
+ * @param mixed $lag Valid values for this parameter are determined by the
+ * subclass, but should be a PHP scalar or array that would be sensible
+ * as part of $wgLBFactoryConf.
*/
public function setFakeSlaveLag( $lag ) {
- $this->mFakeSlaveLag = $lag;
}
/**
* Make this connection a fake master
*
- * @param $enabled bool
+ * @param bool $enabled
*/
public function setFakeMaster( $enabled = true ) {
- $this->mFakeMaster = $enabled;
}
/**
@@ -548,7 +587,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Return the last query that went through DatabaseBase::query()
- * @return String
+ * @return string
*/
public function lastQuery() {
return $this->mLastQuery;
@@ -561,7 +600,18 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @return bool
*/
public function doneWrites() {
- return $this->mDoneWrites;
+ return (bool)$this->mDoneWrites;
+ }
+
+ /**
+ * Returns the last time the connection may have been used for write queries.
+ * Should return a timestamp if unsure.
+ *
+ * @return int|float UNIX timestamp or false
+ * @since 1.24
+ */
+ public function lastDoneWrites() {
+ return $this->mDoneWrites ?: false;
}
/**
@@ -578,7 +628,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Is a connection to the database open?
- * @return Boolean
+ * @return bool
*/
public function isOpen() {
return $this->mOpened;
@@ -587,7 +637,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Set a flag for this connection
*
- * @param $flag Integer: DBO_* constants from Defines.php:
+ * @param int $flag DBO_* constants from Defines.php:
* - DBO_DEBUG: output some debug info (same as debug())
* - DBO_NOBUFFER: don't buffer results (inverse of bufferResults())
* - DBO_TRX: automatically start transactions
@@ -598,15 +648,21 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
public function setFlag( $flag ) {
global $wgDebugDBTransactions;
$this->mFlags |= $flag;
- if ( ( $flag & DBO_TRX ) & $wgDebugDBTransactions ) {
- wfDebug( "Implicit transactions are now disabled.\n" );
+ if ( ( $flag & DBO_TRX ) && $wgDebugDBTransactions ) {
+ wfDebug( "Implicit transactions are now enabled.\n" );
}
}
/**
* Clear a flag for this connection
*
- * @param $flag: same as setFlag()'s $flag param
+ * @param int $flag DBO_* constants from Defines.php:
+ * - DBO_DEBUG: output some debug info (same as debug())
+ * - DBO_NOBUFFER: don't buffer results (inverse of bufferResults())
+ * - DBO_TRX: automatically start transactions
+ * - DBO_DEFAULT: automatically sets DBO_TRX if not in command line mode
+ * and removes it in command line mode
+ * - DBO_PERSISTENT: use persistant database connection
*/
public function clearFlag( $flag ) {
global $wgDebugDBTransactions;
@@ -619,8 +675,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Returns a boolean whether the flag $flag is set for this connection
*
- * @param $flag: same as setFlag()'s $flag param
- * @return Boolean
+ * @param int $flag DBO_* constants from Defines.php:
+ * - DBO_DEBUG: output some debug info (same as debug())
+ * - DBO_NOBUFFER: don't buffer results (inverse of bufferResults())
+ * - DBO_TRX: automatically start transactions
+ * - DBO_PERSISTENT: use persistant database connection
+ * @return bool
*/
public function getFlag( $flag ) {
return !!( $this->mFlags & $flag );
@@ -629,8 +689,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* General read-only accessor
*
- * @param $name string
- *
+ * @param string $name
* @return string
*/
public function getProperty( $name ) {
@@ -649,19 +708,42 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * Return a path to the DBMS-specific schema file, otherwise default to tables.sql
+ * Return a path to the DBMS-specific SQL file if it exists,
+ * otherwise default SQL file
*
+ * @param string $filename
* @return string
*/
- public function getSchemaPath() {
+ private function getSqlFilePath( $filename ) {
global $IP;
- if ( file_exists( "$IP/maintenance/" . $this->getType() . "/tables.sql" ) ) {
- return "$IP/maintenance/" . $this->getType() . "/tables.sql";
+ $dbmsSpecificFilePath = "$IP/maintenance/" . $this->getType() . "/$filename";
+ if ( file_exists( $dbmsSpecificFilePath ) ) {
+ return $dbmsSpecificFilePath;
} else {
- return "$IP/maintenance/tables.sql";
+ return "$IP/maintenance/$filename";
}
}
+ /**
+ * Return a path to the DBMS-specific schema file,
+ * otherwise default to tables.sql
+ *
+ * @return string
+ */
+ public function getSchemaPath() {
+ return $this->getSqlFilePath( 'tables.sql' );
+ }
+
+ /**
+ * Return a path to the DBMS-specific update key file,
+ * otherwise default to update-keys.sql
+ *
+ * @return string
+ */
+ public function getUpdateKeysPath() {
+ return $this->getSqlFilePath( 'update-keys.sql' );
+ }
+
# ------------------------------------------------------------------------------
# Other functions
# ------------------------------------------------------------------------------
@@ -673,28 +755,39 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* connection object, by specifying no parameters to __construct(). This
* feature is deprecated and should be removed.
*
- * FIXME: The long list of formal parameters here is not really appropriate
- * for MySQL, and not at all appropriate for any other DBMS. It should be
- * replaced by named parameters as in DatabaseBase::factory().
- *
* DatabaseBase subclasses should not be constructed directly in external
* code. DatabaseBase::factory() should be used instead.
*
- * @param string $server database server host
- * @param string $user database user name
- * @param string $password database user password
- * @param string $dbName database name
- * @param $flags
- * @param string $tablePrefix database table prefixes. By default use the prefix gave in LocalSettings.php
- * @param bool $foreign disable some operations specific to local databases
+ * @param array $params Parameters passed from DatabaseBase::factory()
*/
- function __construct( $server = false, $user = false, $password = false, $dbName = false,
- $flags = 0, $tablePrefix = 'get from global', $foreign = false
- ) {
- global $wgDBprefix, $wgCommandLineMode, $wgDebugDBTransactions;
+ function __construct( $params = null ) {
+ global $wgDBprefix, $wgDBmwschema, $wgCommandLineMode, $wgDebugDBTransactions;
- $this->mFlags = $flags;
+ $this->mTrxAtomicLevels = new SplStack;
+
+ if ( is_array( $params ) ) { // MW 1.22
+ $server = $params['host'];
+ $user = $params['user'];
+ $password = $params['password'];
+ $dbName = $params['dbname'];
+ $flags = $params['flags'];
+ $tablePrefix = $params['tablePrefix'];
+ $schema = $params['schema'];
+ $foreign = $params['foreign'];
+ } else { // legacy calling pattern
+ wfDeprecated( __METHOD__ . " method called without parameter array.", "1.23" );
+ $args = func_get_args();
+ $server = isset( $args[0] ) ? $args[0] : false;
+ $user = isset( $args[1] ) ? $args[1] : false;
+ $password = isset( $args[2] ) ? $args[2] : false;
+ $dbName = isset( $args[3] ) ? $args[3] : false;
+ $flags = isset( $args[4] ) ? $args[4] : 0;
+ $tablePrefix = isset( $args[5] ) ? $args[5] : 'get from global';
+ $schema = 'get from global';
+ $foreign = isset( $args[6] ) ? $args[6] : false;
+ }
+ $this->mFlags = $flags;
if ( $this->mFlags & DBO_DEFAULT ) {
if ( $wgCommandLineMode ) {
$this->mFlags &= ~DBO_TRX;
@@ -716,6 +809,13 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$this->mTablePrefix = $tablePrefix;
}
+ /** Get the database schema*/
+ if ( $schema == 'get from global' ) {
+ $this->mSchema = $wgDBmwschema;
+ } else {
+ $this->mSchema = $schema;
+ }
+
$this->mForeign = $foreign;
if ( $user ) {
@@ -729,13 +829,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* not restored on unserialize.
*/
public function __sleep() {
- throw new MWException( 'Database serialization may cause problems, since the connection is not restored on wakeup.' );
+ throw new MWException( 'Database serialization may cause problems, since ' .
+ 'the connection is not restored on wakeup.' );
}
/**
* 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( $dbType ) );
+ * $class = 'Database' . ucfirst( strtolower( $dbType ) );
* as well as validate against the canonical list of DB types we have
*
* This factory function is mostly useful for when you need to connect to a
@@ -744,22 +845,23 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* database. Example uses in core:
* @see LoadBalancer::reallyOpenConnection()
* @see ForeignDBRepo::getMasterDB()
- * @see WebInstaller_DBConnect::execute()
+ * @see WebInstallerDBConnect::execute()
*
* @since 1.18
*
* @param string $dbType A possible DB type
* @param array $p An array of options to pass to the constructor.
- * Valid options are: host, user, password, dbname, flags, tablePrefix, driver
- * @return DatabaseBase subclass or null
+ * Valid options are: host, user, password, dbname, flags, tablePrefix, schema, driver
+ * @throws MWException If the database driver or extension cannot be found
+ * @return DatabaseBase|null DatabaseBase subclass or null
*/
final public static function factory( $dbType, $p = array() ) {
$canonicalDBTypes = array(
- 'mysql' => array( 'mysqli', 'mysql' ),
+ 'mysql' => array( 'mysqli', 'mysql' ),
'postgres' => array(),
- 'sqlite' => array(),
- 'oracle' => array(),
- 'mssql' => array(),
+ 'sqlite' => array(),
+ 'oracle' => array(),
+ 'mssql' => array(),
);
$driver = false;
@@ -789,17 +891,32 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
" no viable database extension found for type '$dbType'" );
}
+ // Determine schema defaults. Currently Microsoft SQL Server uses $wgDBmwschema,
+ // and everything else doesn't use a schema (e.g. null)
+ // Although postgres and oracle support schemas, we don't use them (yet)
+ // to maintain backwards compatibility
+ $defaultSchemas = array(
+ 'mysql' => null,
+ 'postgres' => null,
+ 'sqlite' => null,
+ 'oracle' => null,
+ 'mssql' => 'get from global',
+ );
+
$class = 'Database' . ucfirst( $driver );
if ( class_exists( $class ) && is_subclass_of( $class, 'DatabaseBase' ) ) {
- return new $class(
- isset( $p['host'] ) ? $p['host'] : false,
- isset( $p['user'] ) ? $p['user'] : false,
- isset( $p['password'] ) ? $p['password'] : false,
- isset( $p['dbname'] ) ? $p['dbname'] : false,
- isset( $p['flags'] ) ? $p['flags'] : 0,
- isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global',
- isset( $p['foreign'] ) ? $p['foreign'] : false
+ $params = array(
+ 'host' => isset( $p['host'] ) ? $p['host'] : false,
+ 'user' => isset( $p['user'] ) ? $p['user'] : false,
+ 'password' => isset( $p['password'] ) ? $p['password'] : false,
+ 'dbname' => isset( $p['dbname'] ) ? $p['dbname'] : false,
+ 'flags' => isset( $p['flags'] ) ? $p['flags'] : 0,
+ 'tablePrefix' => isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global',
+ 'schema' => isset( $p['schema'] ) ? $p['schema'] : $defaultSchemas[$dbType],
+ 'foreign' => isset( $p['foreign'] ) ? $p['foreign'] : false
);
+
+ return new $class( $params );
} else {
return null;
}
@@ -822,6 +939,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
if ( $this->mPHPError ) {
$error = preg_replace( '!\[<a.*</a>\]!', '', $this->mPHPError );
$error = preg_replace( '!^.*?:\s?(.*)$!', '$1', $error );
+
return $error;
} else {
return false;
@@ -829,9 +947,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * @param $errno
- * @param $errstr
- * @access private
+ * @param int $errno
+ * @param string $errstr
*/
public function connectionErrorHandler( $errno, $errstr ) {
$this->mPHPError = $errstr;
@@ -842,13 +959,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* if it is open : commits any open transactions
*
* @throws MWException
- * @return Bool operation success. true if already closed.
+ * @return bool Operation success. true if already closed.
*/
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() ) {
if ( !$this->mTrxAutomatic ) {
@@ -859,23 +975,25 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$this->commit( __METHOD__, 'flush' );
}
- $ret = $this->closeConnection();
+ $closed = $this->closeConnection();
$this->mConn = false;
- return $ret;
} else {
- return true;
+ $closed = true;
}
+ $this->mOpened = false;
+
+ return $closed;
}
/**
* Closes underlying database connection
* @since 1.20
- * @return bool: Whether connection was closed successfully
+ * @return bool Whether connection was closed successfully
*/
abstract protected function closeConnection();
/**
- * @param string $error fallback error message, used if none is given by DB
+ * @param string $error Fallback error message, used if none is given by DB
* @throws DBConnectionError
*/
function reportConnectionError( $error = 'Unknown error' ) {
@@ -891,8 +1009,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* The DBMS-dependent part of query()
*
- * @param $sql String: SQL query.
- * @return ResultWrapper Result object to feed to fetchObject, fetchRow, ...; or false on failure
+ * @param string $sql SQL query.
+ * @return ResultWrapper|bool Result object to feed to fetchObject,
+ * fetchRow, ...; or false on failure
*/
abstract protected function doQuery( $sql );
@@ -900,8 +1019,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Determine whether a query writes to the DB.
* Should return true if unsure.
*
- * @param $sql string
- *
+ * @param string $sql
* @return bool
*/
public function isWriteQuery( $sql ) {
@@ -921,23 +1039,23 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* However, the query wrappers themselves should call this function.
*
- * @param $sql String: SQL query
- * @param $fname String: Name of the calling function, for profiling/SHOW PROCESSLIST
+ * @param string $sql SQL query
+ * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST
* comment (you can use __METHOD__ or add some extra info)
- * @param $tempIgnore Boolean: Whether to avoid throwing an exception on errors...
+ * @param bool $tempIgnore Whether to avoid throwing an exception on errors...
* maybe best to catch the exception instead?
* @throws MWException
- * @return boolean|ResultWrapper. true for a successful write query, ResultWrapper object
+ * @return bool|ResultWrapper True for a successful write query, ResultWrapper object
* for a successful read query, or false on failure if $tempIgnore set
*/
public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
- global $wgUser, $wgDebugDBTransactions;
+ global $wgUser, $wgDebugDBTransactions, $wgDebugDumpSqlLength;
$this->mLastQuery = $sql;
- if ( !$this->mDoneWrites && $this->isWriteQuery( $sql ) ) {
+ if ( $this->isWriteQuery( $sql ) ) {
# Set a flag indicating that writes have been done
- wfDebug( __METHOD__ . ": Writes done: $sql\n" );
- $this->mDoneWrites = true;
+ wfDebug( __METHOD__ . ': Writes done: ' . DatabaseBase::generalizeSQL( $sql ) . "\n" );
+ $this->mDoneWrites = microtime( true );
}
# Add a comment for easy SHOW PROCESSLIST interpretation
@@ -957,8 +1075,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
# If DBO_TRX is set, start a transaction
if ( ( $this->mFlags & DBO_TRX ) && !$this->mTrxLevel &&
- $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK' )
- {
+ $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK'
+ ) {
# Avoid establishing transactions for SHOW and SET statements too -
# that would delay transaction initializations to once connection
# is really used by application
@@ -975,10 +1093,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
# Keep track of whether the transaction has write queries pending
if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery( $sql ) ) {
$this->mTrxDoneWrites = true;
- Profiler::instance()->transactionWritingIn( $this->mServer, $this->mDBname );
+ Profiler::instance()->transactionWritingIn(
+ $this->mServer, $this->mDBname, $this->mTrxShortId );
}
+ $queryProf = '';
+ $totalProf = '';
$isMaster = !is_null( $this->getLBInfo( 'master' ) );
+
if ( !Profiler::instance()->isStub() ) {
# generalizeSQL will probably cut down the query to reasonable
# logging size most of the time. The substr is really just a sanity check.
@@ -989,6 +1111,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$queryProf = 'query: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
$totalProf = 'DatabaseBase::query';
}
+ # Include query transaction state
+ $queryProf .= $this->mTrxShortId ? " [TRX#{$this->mTrxShortId}]" : "";
+
+ $trx = $this->mTrxLevel ? 'TRX=yes' : 'TRX=no';
wfProfileIn( $totalProf );
wfProfileIn( $queryProf );
}
@@ -997,7 +1123,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
static $cnt = 0;
$cnt++;
- $sqlx = substr( $commentedSql, 0, 500 );
+ $sqlx = $wgDebugDumpSqlLength ? substr( $commentedSql, 0, $wgDebugDumpSqlLength )
+ : $commentedSql;
$sqlx = strtr( $sqlx, "\t\n", ' ' );
$master = $isMaster ? 'master' : 'slave';
@@ -1006,6 +1133,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$queryId = MWDebug::query( $sql, $fname, $isMaster );
+ # Avoid fatals if close() was called
+ if ( !$this->isOpen() ) {
+ throw new DBUnexpectedError( $this, "DB connection was already closed." );
+ }
+
# Do the query and handle errors
$ret = $this->doQuery( $commentedSql );
@@ -1014,22 +1146,33 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
# Try reconnecting if the connection was lost
if ( false === $ret && $this->wasErrorReissuable() ) {
# Transaction is gone, like it or not
+ $hadTrx = $this->mTrxLevel; // possible lost transaction
$this->mTrxLevel = 0;
- $this->mTrxIdleCallbacks = array(); // cancel
- $this->mTrxPreCommitCallbacks = array(); // cancel
+ $this->mTrxIdleCallbacks = array(); // bug 65263
+ $this->mTrxPreCommitCallbacks = array(); // bug 65263
wfDebug( "Connection lost, reconnecting...\n" );
-
+ # Stash the last error values since ping() might clear them
+ $lastError = $this->lastError();
+ $lastErrno = $this->lastErrno();
if ( $this->ping() ) {
+ global $wgRequestTime;
wfDebug( "Reconnected\n" );
- $sqlx = substr( $commentedSql, 0, 500 );
+ $sqlx = $wgDebugDumpSqlLength ? substr( $commentedSql, 0, $wgDebugDumpSqlLength )
+ : $commentedSql;
$sqlx = strtr( $sqlx, "\t\n", ' ' );
- global $wgRequestTime;
$elapsed = round( microtime( true ) - $wgRequestTime, 3 );
if ( $elapsed < 300 ) {
# Not a database error to lose a transaction after a minute or two
- wfLogDBError( "Connection lost and reconnected after {$elapsed}s, query: $sqlx\n" );
+ wfLogDBError( "Connection lost and reconnected after {$elapsed}s, query: $sqlx" );
+ }
+ if ( $hadTrx ) {
+ # Leave $ret as false and let an error be reported.
+ # Callers may catch the exception and continue to use the DB.
+ $this->reportQueryError( $lastError, $lastErrno, $sql, $fname, $tempIgnore );
+ } else {
+ # Should be safe to silently retry (no trx and thus no callbacks)
+ $ret = $this->doQuery( $commentedSql );
}
- $ret = $this->doQuery( $commentedSql );
} else {
wfDebug( "Failed\n" );
}
@@ -1051,11 +1194,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Report a query error. Log the error, and if neither the object ignore
* flag nor the $tempIgnore flag is set, throw a DBQueryError.
*
- * @param $error String
- * @param $errno Integer
- * @param $sql String
- * @param $fname String
- * @param $tempIgnore Boolean
+ * @param string $error
+ * @param int $errno
+ * @param string $sql
+ * @param string $fname
+ * @param bool $tempIgnore
* @throws DBQueryError
*/
public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
@@ -1067,8 +1210,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
wfDebug( "SQL ERROR (ignored): $error\n" );
$this->ignoreErrors( $ignore );
} else {
- $sql1line = str_replace( "\n", "\\n", $sql );
- wfLogDBError( "$fname\t{$this->mServer}\t$errno\t$error\t$sql1line\n" );
+ $sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
+ wfLogDBError( "$fname\t{$this->mServer}\t$errno\t$error\t$sql1line" );
wfDebug( "SQL ERROR: " . $error . "\n" );
throw new DBQueryError( $this, $error, $errno, $sql, $fname );
}
@@ -1083,21 +1226,22 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* & = filename; reads the file and inserts as a blob
* (we don't use this though...)
*
- * @param $sql string
- * @param $func string
+ * @param string $sql
+ * @param string $func
*
* @return array
*/
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. */
+ * pack up the query for reference. We'll manually replace
+ * the bits later.
+ */
return array( 'query' => $sql, 'func' => $func );
}
/**
* Free a prepared query, generated by prepare().
- * @param $prepared
+ * @param string $prepared
*/
protected function freePrepared( $prepared ) {
/* No-op by default */
@@ -1105,8 +1249,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Execute a prepared query with the various arguments
- * @param string $prepared the prepared sql
- * @param $args Mixed: Either an array here, or put scalars as varargs
+ * @param string $prepared The prepared sql
+ * @param mixed $args Either an array here, or put scalars as varargs
*
* @return ResultWrapper
*/
@@ -1125,9 +1269,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* For faking prepared SQL statements on DBs that don't support it directly.
*
- * @param string $preparedQuery a 'preparable' SQL statement
- * @param array $args of arguments to fill it with
- * @return string executable SQL
+ * @param string $preparedQuery A 'preparable' SQL statement
+ * @param array $args Array of Arguments to fill it with
+ * @return string Executable SQL
*/
public function fillPrepared( $preparedQuery, $args ) {
reset( $args );
@@ -1142,9 +1286,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* The arguments should be in $this->preparedArgs and must not be touched
* while we're doing this.
*
- * @param $matches Array
+ * @param array $matches
* @throws DBUnexpectedError
- * @return String
+ * @return string
*/
protected function fillPreparedArg( $matches ) {
switch ( $matches[1] ) {
@@ -1165,9 +1309,15 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
return $arg;
case '&':
# return $this->addQuotes( file_get_contents( $arg ) );
- throw new DBUnexpectedError( $this, '& mode is not implemented. If it\'s really needed, uncomment the line above.' );
+ throw new DBUnexpectedError(
+ $this,
+ '& mode is not implemented. If it\'s really needed, uncomment the line above.'
+ );
default:
- throw new DBUnexpectedError( $this, 'Received invalid match. This should never happen!' );
+ throw new DBUnexpectedError(
+ $this,
+ 'Received invalid match. This should never happen!'
+ );
}
}
@@ -1176,7 +1326,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* necessary to call this, just use unset() or let the variable holding
* the result object go out of scope.
*
- * @param $res Mixed: A SQL result
+ * @param mixed $res A SQL result
*/
public function freeResult( $res ) {
}
@@ -1226,9 +1376,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Returns an optional USE INDEX clause to go after the table, and a
* string to go at the end of the query.
*
- * @param array $options associative array of options to be turned into
- * an SQL query, valid keys are listed in the function.
- * @return Array
+ * @param array $options Associative array of options to be turned into
+ * an SQL query, valid keys are listed in the function.
+ * @return array
* @see DatabaseBase::select()
*/
public function makeSelectOptions( $options ) {
@@ -1310,7 +1460,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Returns an optional GROUP BY with an optional HAVING
*
- * @param array $options associative array of options
+ * @param array $options Associative array of options
* @return string
* @see DatabaseBase::select()
* @since 1.21
@@ -1329,13 +1479,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
: $options['HAVING'];
$sql .= ' HAVING ' . $having;
}
+
return $sql;
}
/**
* Returns an optional ORDER BY
*
- * @param array $options associative array of options
+ * @param array $options Associative array of options
* @return string
* @see DatabaseBase::select()
* @since 1.21
@@ -1345,8 +1496,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$ob = is_array( $options['ORDER BY'] )
? implode( ',', $options['ORDER BY'] )
: $options['ORDER BY'];
+
return ' ORDER BY ' . $ob;
}
+
return '';
}
@@ -1359,9 +1512,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @param string|array $conds Conditions
* @param string $fname Caller function name
* @param array $options Query options
- * @param $join_conds Array Join conditions
+ * @param array $join_conds Join conditions
*
- * @param $table string|array
+ *
+ * @param string|array $table
*
* May be either an array of table names, or a single string holding a table
* name. If an array is given, table aliases can be specified, for example:
@@ -1376,7 +1530,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* added, and various other table name mappings to be performed.
*
*
- * @param $vars string|array
+ * @param string|array $vars
*
* May be either a field name or an array of field names. The field names
* can be complete fragments of SQL, for direct inclusion into the SELECT
@@ -1390,7 +1544,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* DBMS-independent.
*
*
- * @param $conds string|array
+ * @param string|array $conds
*
* May be either a string containing a single condition, or an array of
* conditions. If an array is given, the conditions constructed from each
@@ -1415,7 +1569,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* - DatabaseBase::conditional()
*
*
- * @param $options string|array
+ * @param string|array $options
*
* Optional: Array of query options. Boolean options are specified by
* including them in the array as a string value with a numeric key, for
@@ -1471,7 +1625,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* - SQL_NO_CACHE
*
*
- * @param $join_conds string|array
+ * @param string|array $join_conds
*
* Optional associative array of table-specific join conditions. In the
* most common case, this is unnecessary, since the join condition can be
@@ -1484,7 +1638,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* array( 'page' => array( 'LEFT JOIN', 'page_latest=rev_id' ) )
*
- * @return ResultWrapper. If the query returned no rows, a ResultWrapper
+ * @return ResultWrapper|bool If the query returned no rows, a ResultWrapper
* with no rows in it will be returned. If there was a query error, a
* DBQueryError exception will be thrown, except if the "ignore errors"
* option was set, in which case false will be returned.
@@ -1507,14 +1661,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @param string|array $conds Conditions
* @param string $fname Caller function name
* @param string|array $options Query options
- * @param $join_conds string|array Join conditions
+ * @param string|array $join_conds Join conditions
*
* @return string SQL query string.
* @see DatabaseBase::select()
*/
public function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
- $options = array(), $join_conds = array() )
- {
+ $options = array(), $join_conds = array()
+ ) {
if ( is_array( $vars ) ) {
$vars = implode( ',', $this->fieldNamesWithAlias( $vars ) );
}
@@ -1573,13 +1727,13 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @param array $conds Conditions
* @param string $fname Caller function name
* @param string|array $options Query options
- * @param $join_conds array|string Join conditions
+ * @param array|string $join_conds Join conditions
*
- * @return object|bool
+ * @return stdClass|bool
*/
public function selectRow( $table, $vars, $conds, $fname = __METHOD__,
- $options = array(), $join_conds = array() )
- {
+ $options = array(), $join_conds = array()
+ ) {
$options = (array)$options;
$options['LIMIT'] = 1;
$res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
@@ -1598,7 +1752,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * Estimate rows in dataset.
+ * Estimate the number of rows in dataset
*
* MySQL allows you to estimate the number of rows that would be returned
* by a SELECT query, using EXPLAIN SELECT. The estimate is provided using
@@ -1610,16 +1764,16 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* Takes the same arguments as DatabaseBase::select().
*
- * @param string $table table name
- * @param array|string $vars : unused
- * @param array|string $conds : filters on the table
- * @param string $fname function name for profiling
- * @param array $options options for select
- * @return Integer: row count
- */
- public function estimateRowCount( $table, $vars = '*', $conds = '',
- $fname = __METHOD__, $options = array() )
- {
+ * @param string $table Table name
+ * @param string $vars Unused
+ * @param array|string $conds Filters on the table
+ * @param string $fname Function name for profiling
+ * @param array $options Options for select
+ * @return int Row count
+ */
+ public function estimateRowCount(
+ $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ ) {
$rows = 0;
$res = $this->select( $table, array( 'rowcount' => 'COUNT(*)' ), $conds, $fname, $options );
@@ -1632,6 +1786,36 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
+ * Get the number of rows in dataset
+ *
+ * This is useful when trying to do COUNT(*) but with a LIMIT for performance.
+ *
+ * Takes the same arguments as DatabaseBase::select().
+ *
+ * @param string $table Table name
+ * @param string $vars Unused
+ * @param array|string $conds Filters on the table
+ * @param string $fname Function name for profiling
+ * @param array $options Options for select
+ * @return int Row count
+ * @since 1.24
+ */
+ public function selectRowCount(
+ $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ ) {
+ $rows = 0;
+ $sql = $this->selectSQLText( $table, '1', $conds, $fname, $options );
+ $res = $this->query( "SELECT COUNT(*) AS rowcount FROM ($sql) tmp_count" );
+
+ if ( $res ) {
+ $row = $this->fetchRow( $res );
+ $rows = ( isset( $row['rowcount'] ) ) ? $row['rowcount'] : 0;
+ }
+
+ return $rows;
+ }
+
+ /**
* Removes most variables from an SQL query and replaces them with X or N for numbers.
* It's only slightly flawed. Don't use for anything important.
*
@@ -1653,9 +1837,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
# All newlines, tabs, etc replaced by single space
$sql = preg_replace( '/\s+/', ' ', $sql );
- # All numbers => N
+ # All numbers => N,
+ # except the ones surrounded by characters, e.g. l10n
$sql = preg_replace( '/-?\d+(,-?\d+)+/s', 'N,...,N', $sql );
- $sql = preg_replace( '/-?\d+/s', 'N', $sql );
+ $sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s', 'N', $sql );
return $sql;
}
@@ -1663,10 +1848,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Determines whether a field exists in a table
*
- * @param string $table table name
- * @param string $field filed to check on that table
- * @param string $fname calling function name (optional)
- * @return Boolean: whether $table has filed $field
+ * @param string $table Table name
+ * @param string $field Filed to check on that table
+ * @param string $fname Calling function name (optional)
+ * @return bool Whether $table has filed $field
*/
public function fieldExists( $table, $field, $fname = __METHOD__ ) {
$info = $this->fieldInfo( $table, $field );
@@ -1679,10 +1864,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Usually throws a DBQueryError on failure
* If errors are explicitly ignored, returns NULL on failure
*
- * @param $table
- * @param $index
- * @param $fname string
- *
+ * @param string $table
+ * @param string $index
+ * @param string $fname
* @return bool|null
*/
public function indexExists( $table, $index, $fname = __METHOD__ ) {
@@ -1701,9 +1885,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Query whether a given table exists
*
- * @param $table string
- * @param $fname string
- *
+ * @param string $table
+ * @param string $fname
* @return bool
*/
public function tableExists( $table, $fname = __METHOD__ ) {
@@ -1716,24 +1899,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * mysql_field_type() wrapper
- * @param $res
- * @param $index
- * @return string
- */
- public function fieldType( $res, $index ) {
- if ( $res instanceof ResultWrapper ) {
- $res = $res->result;
- }
-
- return mysql_field_type( $res, $index );
- }
-
- /**
* Determines if a given index is unique
*
- * @param $table string
- * @param $index string
+ * @param string $table
+ * @param string $index
*
* @return bool
*/
@@ -1750,7 +1919,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Helper for DatabaseBase::insert().
*
- * @param $options array
+ * @param array $options
* @return string
*/
protected function makeInsertOptions( $options ) {
@@ -1782,11 +1951,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* possible to determine how many rows were successfully inserted using
* DatabaseBase::affectedRows().
*
- * @param $table String Table name. This will be passed through
- * DatabaseBase::tableName().
- * @param $a Array of rows to insert
- * @param $fname String Calling function name (use __METHOD__) for logs/profiling
- * @param array $options of options
+ * @param string $table Table name. This will be passed through
+ * DatabaseBase::tableName().
+ * @param array $a Array of rows to insert
+ * @param string $fname Calling function name (use __METHOD__) for logs/profiling
+ * @param array $options Array of options
*
* @return bool
*/
@@ -1843,12 +2012,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * Make UPDATE options for the DatabaseBase::update function
+ * Make UPDATE options array for DatabaseBase::makeUpdateOptions
*
- * @param array $options The options passed to DatabaseBase::update
- * @return string
+ * @param array $options
+ * @return array
*/
- protected function makeUpdateOptions( $options ) {
+ protected function makeUpdateOptionsArray( $options ) {
if ( !is_array( $options ) ) {
$options = array( $options );
}
@@ -1863,31 +2032,38 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$opts[] = 'IGNORE';
}
+ return $opts;
+ }
+
+ /**
+ * Make UPDATE options for the DatabaseBase::update function
+ *
+ * @param array $options The options passed to DatabaseBase::update
+ * @return string
+ */
+ protected function makeUpdateOptions( $options ) {
+ $opts = $this->makeUpdateOptionsArray( $options );
+
return implode( ' ', $opts );
}
/**
* UPDATE wrapper. Takes a condition array and a SET array.
*
- * @param $table String name of the table to UPDATE. This will be passed through
- * DatabaseBase::tableName().
- *
- * @param array $values An array of values to SET. For each array element,
- * the key gives the field name, and the value gives the data
- * to set that field to. The data will be quoted by
- * DatabaseBase::addQuotes().
- *
- * @param $conds Array: An array of conditions (WHERE). See
- * DatabaseBase::select() for the details of the format of
- * condition arrays. Use '*' to update all rows.
- *
- * @param $fname String: The function name of the caller (from __METHOD__),
- * for logging and profiling.
- *
+ * @param string $table Name of the table to UPDATE. This will be passed through
+ * DatabaseBase::tableName().
+ * @param array $values An array of values to SET. For each array element,
+ * the key gives the field name, and the value gives the data to set
+ * that field to. The data will be quoted by DatabaseBase::addQuotes().
+ * @param array $conds An array of conditions (WHERE). See
+ * DatabaseBase::select() for the details of the format of condition
+ * arrays. Use '*' to update all rows.
+ * @param string $fname The function name of the caller (from __METHOD__),
+ * for logging and profiling.
* @param array $options An array of UPDATE options, can be:
- * - IGNORE: Ignore unique key conflicts
- * - LOW_PRIORITY: MySQL-specific, see MySQL manual.
- * @return Boolean
+ * - IGNORE: Ignore unique key conflicts
+ * - LOW_PRIORITY: MySQL-specific, see MySQL manual.
+ * @return bool
*/
function update( $table, $values, $conds, $fname = __METHOD__, $options = array() ) {
$table = $this->tableName( $table );
@@ -1903,15 +2079,15 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Makes an encoded list of strings from an array
- * @param array $a containing the data
- * @param int $mode Constant
- * - LIST_COMMA: comma separated, no field names
- * - LIST_AND: ANDed WHERE clause (without the WHERE). See
- * the documentation for $conds in DatabaseBase::select().
- * - LIST_OR: ORed WHERE clause (without the WHERE)
- * - LIST_SET: comma separated with field names, like a SET clause
- * - LIST_NAMES: comma separated field names
*
+ * @param array $a Containing the data
+ * @param int $mode Constant
+ * - LIST_COMMA: Comma separated, no field names
+ * - LIST_AND: ANDed WHERE clause (without the WHERE). See the
+ * documentation for $conds in DatabaseBase::select().
+ * - LIST_OR: ORed WHERE clause (without the WHERE)
+ * - LIST_SET: Comma separated with field names, like a SET clause
+ * - LIST_NAMES: Comma separated field names
* @throws MWException|DBUnexpectedError
* @return string
*/
@@ -1974,11 +2150,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Build a partial where clause from a 2-d array such as used for LinkBatch.
* The keys on each level may be either integers or strings.
*
- * @param array $data organized as 2-d
- * array(baseKeyVal => array(subKeyVal => [ignored], ...), ...)
- * @param string $baseKey field name to match the base-level keys to (eg 'pl_namespace')
- * @param string $subKey field name to match the sub-level keys to (eg 'pl_title')
- * @return Mixed: string SQL fragment, or false if no items in array.
+ * @param array $data Organized as 2-d
+ * array(baseKeyVal => array(subKeyVal => [ignored], ...), ...)
+ * @param string $baseKey Field name to match the base-level keys to (eg 'pl_namespace')
+ * @param string $subKey Field name to match the sub-level keys to (eg 'pl_title')
+ * @return string|bool SQL fragment, or false if no items in array
*/
public function makeWhereFrom2d( $data, $baseKey, $subKey ) {
$conds = array();
@@ -2002,8 +2178,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Return aggregated value alias
*
- * @param $valuedata
- * @param $valuename string
+ * @param array $valuedata
+ * @param string $valuename
*
* @return string
*/
@@ -2012,7 +2188,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * @param $field
+ * @param string $field
* @return string
*/
public function bitNot( $field ) {
@@ -2020,8 +2196,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * @param $fieldLeft
- * @param $fieldRight
+ * @param string $fieldLeft
+ * @param string $fieldRight
* @return string
*/
public function bitAnd( $fieldLeft, $fieldRight ) {
@@ -2029,8 +2205,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * @param $fieldLeft
- * @param $fieldRight
+ * @param string $fieldLeft
+ * @param string $fieldRight
* @return string
*/
public function bitOr( $fieldLeft, $fieldRight ) {
@@ -2039,32 +2215,59 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Build a concatenation list to feed into a SQL query
- * @param array $stringList list of raw SQL expressions; caller is responsible for any quoting
- * @return String
+ * @param array $stringList List of raw SQL expressions; caller is
+ * responsible for any quoting
+ * @return string
*/
public function buildConcat( $stringList ) {
return 'CONCAT(' . implode( ',', $stringList ) . ')';
}
/**
+ * Build a GROUP_CONCAT or equivalent statement for a query.
+ *
+ * This is useful for combining a field for several rows into a single string.
+ * NULL values will not appear in the output, duplicated values will appear,
+ * and the resulting delimiter-separated values have no defined sort order.
+ * Code using the results may need to use the PHP unique() or sort() methods.
+ *
+ * @param string $delim Glue to bind the results together
+ * @param string|array $table Table name
+ * @param string $field Field name
+ * @param string|array $conds Conditions
+ * @param string|array $join_conds Join conditions
+ * @return string SQL text
+ * @since 1.23
+ */
+ public function buildGroupConcatField(
+ $delim, $table, $field, $conds = '', $join_conds = array()
+ ) {
+ $fld = "GROUP_CONCAT($field SEPARATOR " . $this->addQuotes( $delim ) . ')';
+
+ return '(' . $this->selectSQLText( $table, $fld, $conds, null, array(), $join_conds ) . ')';
+ }
+
+ /**
* Change the current database
*
* @todo Explain what exactly will fail if this is not overridden.
*
- * @param $db
+ * @param string $db
*
* @return bool Success or failure
*/
public function selectDB( $db ) {
- # Stub. Shouldn't cause serious problems if it's not overridden, but
+ # 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.
$this->mDBname = $db;
+
return true;
}
/**
* Get the current DB name
+ * @return string
*/
public function getDBname() {
return $this->mDBname;
@@ -2072,6 +2275,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Get the server hostname or IP address
+ * @return string
*/
public function getServer() {
return $this->mServer;
@@ -2087,15 +2291,15 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* themselves. Pass the canonical name to such functions. This is only needed
* when calling query() directly.
*
- * @param string $name database table name
+ * @param string $name Database table name
* @param string $format One of:
* quoted - Automatically pass the table name through addIdentifierQuotes()
* so that it can be used in a query.
* raw - Do not add identifier quotes to the table name
- * @return String: full database name
+ * @return string Full database name
*/
public function tableName( $name, $format = 'quoted' ) {
- global $wgSharedDB, $wgSharedPrefix, $wgSharedTables;
+ global $wgSharedDB, $wgSharedPrefix, $wgSharedTables, $wgSharedSchema;
# 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
# use of `database`.table. But won't break things if someone wants
@@ -2119,31 +2323,49 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
# We reverse the explode so that database.table and table both output
# the correct table.
$dbDetails = explode( '.', $name, 2 );
- if ( count( $dbDetails ) == 2 ) {
+ if ( count( $dbDetails ) == 3 ) {
+ list( $database, $schema, $table ) = $dbDetails;
+ # We don't want any prefix added in this case
+ $prefix = '';
+ } elseif ( count( $dbDetails ) == 2 ) {
list( $database, $table ) = $dbDetails;
# We don't want any prefix added in this case
+ # In dbs that support it, $database may actually be the schema
+ # but that doesn't affect any of the functionality here
$prefix = '';
+ $schema = null;
} else {
list( $table ) = $dbDetails;
if ( $wgSharedDB !== null # We have a shared database
&& $this->mForeign == false # We're not working on a foreign database
- && !$this->isQuotedIdentifier( $table ) # Paranoia check to prevent shared tables listing '`table`'
+ && !$this->isQuotedIdentifier( $table ) # Prevent shared tables listing '`table`'
&& in_array( $table, $wgSharedTables ) # A shared table is selected
) {
$database = $wgSharedDB;
+ $schema = $wgSharedSchema === null ? $this->mSchema : $wgSharedSchema;
$prefix = $wgSharedPrefix === null ? $this->mTablePrefix : $wgSharedPrefix;
} else {
$database = null;
+ $schema = $this->mSchema; # Default schema
$prefix = $this->mTablePrefix; # Default prefix
}
}
# Quote $table and apply the prefix if not quoted.
+ # $tableName might be empty if this is called from Database::replaceVars()
$tableName = "{$prefix}{$table}";
- if ( $format == 'quoted' && !$this->isQuotedIdentifier( $tableName ) ) {
+ if ( $format == 'quoted' && !$this->isQuotedIdentifier( $tableName ) && $tableName !== '' ) {
$tableName = $this->addIdentifierQuotes( $tableName );
}
+ # Quote $schema and merge it with the table name if needed
+ if ( $schema !== null ) {
+ if ( $format == 'quoted' && !$this->isQuotedIdentifier( $schema ) ) {
+ $schema = $this->addIdentifierQuotes( $schema );
+ }
+ $tableName = $schema . '.' . $tableName;
+ }
+
# Quote $database and merge it with the table name if needed
if ( $database !== null ) {
if ( $format == 'quoted' && !$this->isQuotedIdentifier( $database ) ) {
@@ -2218,8 +2440,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Gets an array of aliased table names
*
- * @param $tables array( [alias] => table )
- * @return array of strings, see tableNameWithAlias()
+ * @param array $tables Array( [alias] => table )
+ * @return string[] See tableNameWithAlias()
*/
public function tableNamesWithAlias( $tables ) {
$retval = array();
@@ -2229,6 +2451,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
$retval[] = $this->tableNameWithAlias( $table, $alias );
}
+
return $retval;
}
@@ -2251,8 +2474,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Gets an array of aliased field names
*
- * @param $fields array( [alias] => field )
- * @return array of strings, see fieldNameWithAlias()
+ * @param array $fields Array( [alias] => field )
+ * @return string[] See fieldNameWithAlias()
*/
public function fieldNamesWithAlias( $fields ) {
$retval = array();
@@ -2262,6 +2485,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
$retval[] = $this->fieldNameWithAlias( $field, $alias );
}
+
return $retval;
}
@@ -2270,8 +2494,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* which might have a JOIN and/or USE INDEX clause
*
* @param array $tables ( [alias] => table )
- * @param $use_index array Same as for select()
- * @param $join_conds array Same as for select()
+ * @param array $use_index Same as for select()
+ * @param array $join_conds Same as for select()
* @return string
*/
protected function tableNamesWithUseIndexOrJOIN(
@@ -2304,11 +2528,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
$retJOIN[] = $tableClause;
- // Is there an INDEX clause for this table?
} elseif ( isset( $use_index[$alias] ) ) {
+ // Is there an INDEX clause for this table?
$tableClause = $this->tableNameWithAlias( $table, $alias );
$tableClause .= ' ' . $this->useIndexClause(
- implode( ',', (array)$use_index[$alias] ) );
+ implode( ',', (array)$use_index[$alias] )
+ );
$ret[] = $tableClause;
} else {
@@ -2329,8 +2554,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Get the name of an index in a given table
*
- * @param $index
- *
+ * @param string $index
* @return string
*/
protected function indexName( $index ) {
@@ -2351,8 +2575,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Adds quotes and backslashes.
*
- * @param $s string
- *
+ * @param string $s
* @return string
*/
public function addQuotes( $s ) {
@@ -2373,8 +2596,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Since MySQL is the odd one out here the double quotes are our generic
* and we implement backticks in DatabaseMysql.
*
- * @param $s string
- *
+ * @param string $s
* @return string
*/
public function addIdentifierQuotes( $s ) {
@@ -2385,37 +2607,36 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Returns if the given identifier looks quoted or not according to
* the database convention for quoting identifiers .
*
- * @param $name string
- *
- * @return boolean
+ * @param string $name
+ * @return bool
*/
public function isQuotedIdentifier( $name ) {
return $name[0] == '"' && substr( $name, -1, 1 ) == '"';
}
/**
- * @param $s string
+ * @param string $s
* @return string
*/
protected function escapeLikeInternal( $s ) {
- $s = str_replace( '\\', '\\\\', $s );
- $s = $this->strencode( $s );
- $s = str_replace( array( '%', '_' ), array( '\%', '\_' ), $s );
-
- return $s;
+ return addcslashes( $s, '\%_' );
}
/**
- * LIKE statement wrapper, receives a variable-length argument list with parts of pattern to match
- * containing either string literals that will be escaped or tokens returned by anyChar() or anyString().
- * Alternatively, the function could be provided with an array of aforementioned parameters.
+ * LIKE statement wrapper, receives a variable-length argument list with
+ * parts of pattern to match containing either string literals that will be
+ * escaped or tokens returned by anyChar() or anyString(). Alternatively,
+ * the function could be provided with an array of aforementioned
+ * parameters.
*
- * Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns a LIKE clause that searches
- * for subpages of 'My page title'.
- * Alternatively: $pattern = array( 'My_page_title/', $dbr->anyString() ); $query .= $dbr->buildLike( $pattern );
+ * Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns
+ * a LIKE clause that searches for subpages of 'My page title'.
+ * Alternatively:
+ * $pattern = array( 'My_page_title/', $dbr->anyString() );
+ * $query .= $dbr->buildLike( $pattern );
*
* @since 1.16
- * @return String: fully built LIKE statement
+ * @return string Fully built LIKE statement
*/
public function buildLike() {
$params = func_get_args();
@@ -2434,7 +2655,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
}
- return " LIKE '" . $s . "' ";
+ return " LIKE {$this->addQuotes( $s )} ";
}
/**
@@ -2463,21 +2684,21 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Any implementation of this function should *not* involve reusing
* sequence numbers created for rolled-back transactions.
* See http://bugs.mysql.com/bug.php?id=30767 for details.
- * @param $seqName string
- * @return null
+ * @param string $seqName
+ * @return null|int
*/
public function nextSequenceValue( $seqName ) {
return null;
}
/**
- * USE INDEX clause. Unlikely to be useful for anything but MySQL. This
+ * USE INDEX clause. Unlikely to be useful for anything but MySQL. This
* is only needed because a) MySQL must be as efficient as possible due to
* its use on Wikipedia, and b) MySQL 4.0 is kind of dumb sometimes about
- * which index to pick. Anyway, other databases might have different
- * indexes on a given table. So don't bother overriding this unless you're
+ * which index to pick. Anyway, other databases might have different
+ * indexes on a given table. So don't bother overriding this unless you're
* MySQL.
- * @param $index
+ * @param string $index
* @return string
*/
public function useIndexClause( $index ) {
@@ -2500,10 +2721,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* errors which wouldn't have occurred in MySQL.
*
* @param string $table The table to replace the row(s) in.
+ * @param array $uniqueIndexes Is an array of indexes. Each element may be either
+ * a field name or an array of field names
* @param array $rows Can be either a single row to insert, or multiple rows,
* in the same format as for DatabaseBase::insert()
- * @param array $uniqueIndexes is an array of indexes. Each element may be either
- * a field name or an array of field names
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
*/
public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
@@ -2558,7 +2779,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* statement.
*
* @param string $table Table name
- * @param array $rows Rows to insert
+ * @param array|string $rows Row(s) to insert
* @param string $fname Caller function name
*
* @return ResultWrapper
@@ -2609,26 +2830,28 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Usually throws a DBQueryError on failure. If errors are explicitly ignored,
* returns success.
*
+ * @since 1.22
+ *
* @param string $table Table name. This will be passed through DatabaseBase::tableName().
* @param array $rows A single row or list of rows to insert
* @param array $uniqueIndexes List of single field names or field name tuples
- * @param array $set An array of values to SET. For each array element,
- * the key gives the field name, and the value gives the data
- * to set that field to. The data will be quoted by
- * DatabaseBase::addQuotes().
+ * @param array $set An array of values to SET. For each array element, the
+ * key gives the field name, and the value gives the data to set that
+ * field to. The data will be quoted by DatabaseBase::addQuotes().
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
- * @param array $options of options
- *
+ * @throws Exception
* @return bool
- * @since 1.22
*/
- public function upsert(
- $table, array $rows, array $uniqueIndexes, array $set, $fname = __METHOD__
+ public function upsert( $table, array $rows, array $uniqueIndexes, array $set,
+ $fname = __METHOD__
) {
if ( !count( $rows ) ) {
return true; // nothing to do
}
- $rows = is_array( reset( $rows ) ) ? $rows : array( $rows );
+
+ if ( !is_array( reset( $rows ) ) ) {
+ $rows = array( $rows );
+ }
if ( count( $uniqueIndexes ) ) {
$clauses = array(); // list WHERE clauses that each identify a single row
@@ -2684,19 +2907,18 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* DO NOT put the join condition in $conds.
*
- * @param $delTable String: The table to delete from.
- * @param $joinTable String: The other table.
- * @param $delVar String: The variable to join on, in the first table.
- * @param $joinVar String: The variable to join on, in the second table.
- * @param $conds Array: Condition array of field names mapped to variables,
- * ANDed together in the WHERE clause
- * @param $fname String: Calling function name (use __METHOD__) for
- * logs/profiling
+ * @param string $delTable The table to delete from.
+ * @param string $joinTable The other table.
+ * @param string $delVar The variable to join on, in the first table.
+ * @param string $joinVar The variable to join on, in the second table.
+ * @param array $conds Condition array of field names mapped to variables,
+ * ANDed together in the WHERE clause
+ * @param string $fname Calling function name (use __METHOD__) for logs/profiling
* @throws DBUnexpectedError
*/
public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds,
- $fname = __METHOD__ )
- {
+ $fname = __METHOD__
+ ) {
if ( !$conds ) {
throw new DBUnexpectedError( $this,
'DatabaseBase::deleteJoin() called with empty $conds' );
@@ -2716,9 +2938,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Returns the size of a text field, or -1 for "unlimited"
*
- * @param $table string
- * @param $field string
- *
+ * @param string $table
+ * @param string $field
* @return int
*/
public function textFieldSize( $table, $field ) {
@@ -2740,7 +2961,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* A string to insert into queries to show that they're low-priority, like
- * MySQL's LOW_PRIORITY. If no such feature exists, return an empty
+ * MySQL's LOW_PRIORITY. If no such feature exists, return an empty
* string and nothing bad should happen.
*
* @return string Returns the text of the low priority option if it is
@@ -2754,10 +2975,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* DELETE query wrapper.
*
* @param array $table Table name
- * @param string|array $conds of conditions. See $conds in DatabaseBase::select() for
- * the format. Use $conds == "*" to delete all rows
- * @param string $fname name of the calling function
- *
+ * @param string|array $conds Array of conditions. See $conds in DatabaseBase::select()
+ * for the format. Use $conds == "*" to delete all rows
+ * @param string $fname Name of the calling function
* @throws DBUnexpectedError
* @return bool|ResultWrapper
*/
@@ -2787,7 +3007,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @param string|array $srcTable May be either a table name, or an array of table names
* to include in a join.
*
- * @param array $varMap must be an associative array of the form
+ * @param array $varMap Must be an associative array of the form
* array( 'dest1' => 'source1', ...). Source items may be literals
* rather than field names, but strings should be quoted with
* DatabaseBase::addQuotes()
@@ -2807,14 +3027,16 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*/
public function insertSelect( $destTable, $srcTable, $varMap, $conds,
$fname = __METHOD__,
- $insertOptions = array(), $selectOptions = array() )
- {
+ $insertOptions = array(), $selectOptions = array()
+ ) {
$destTable = $this->tableName( $destTable );
- if ( is_array( $insertOptions ) ) {
- $insertOptions = implode( ' ', $insertOptions );
+ if ( !is_array( $insertOptions ) ) {
+ $insertOptions = array( $insertOptions );
}
+ $insertOptions = $this->makeInsertOptions( $insertOptions );
+
if ( !is_array( $selectOptions ) ) {
$selectOptions = array( $selectOptions );
}
@@ -2844,22 +3066,21 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * Construct a LIMIT query with optional offset. This is used for query
- * pages. The SQL should be adjusted so that only the first $limit rows
- * are returned. If $offset is provided as well, then the first $offset
+ * Construct a LIMIT query with optional offset. This is used for query
+ * pages. The SQL should be adjusted so that only the first $limit rows
+ * are returned. If $offset is provided as well, then the first $offset
* rows should be discarded, and the next $limit rows should be returned.
* 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.
*
- * The version provided by default works in MySQL and SQLite. It will very
+ * The version provided by default works in MySQL and SQLite. It will very
* likely need to be overridden for most other DBMSes.
*
* @param string $sql SQL query we will append the limit too
- * @param $limit Integer the SQL limit
- * @param $offset Integer|bool the SQL offset (default false)
- *
+ * @param int $limit The SQL limit
+ * @param int|bool $offset The SQL offset (default false)
* @throws DBUnexpectedError
* @return string
*/
@@ -2867,6 +3088,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
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} ";
@@ -2875,7 +3097,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Returns true if current database backend supports ORDER BY or LIMIT for separate subqueries
* within the UNION construct.
- * @return Boolean
+ * @return bool
*/
public function unionSupportsOrderAndLimit() {
return true; // True for almost every DB supported
@@ -2886,27 +3108,29 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* This is used for providing overload point for other DB abstractions
* not compatible with the MySQL syntax.
* @param array $sqls SQL statements to combine
- * @param $all Boolean: use UNION ALL
- * @return String: SQL fragment
+ * @param bool $all Use UNION ALL
+ * @return string SQL fragment
*/
public function unionQueries( $sqls, $all ) {
$glue = $all ? ') UNION ALL (' : ') UNION (';
+
return '(' . implode( $glue, $sqls ) . ')';
}
/**
- * Returns an SQL expression for a simple conditional. This doesn't need
+ * Returns an SQL expression for a simple conditional. This doesn't need
* to be overridden unless CASE isn't supported in your DBMS.
*
* @param string|array $cond SQL expression which will result in a boolean value
* @param string $trueVal SQL expression to return if true
* @param string $falseVal SQL expression to return if false
- * @return String: SQL fragment
+ * @return string SQL fragment
*/
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) ";
}
@@ -2914,9 +3138,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Returns a comand for str_replace function in SQL query.
* Uses REPLACE() in MySQL
*
- * @param string $orig column to modify
- * @param string $old column to seek
- * @param string $new column to replace with
+ * @param string $orig Column to modify
+ * @param string $old Column to seek
+ * @param string $new Column to replace with
*
* @return string
*/
@@ -3027,9 +3251,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
if ( $tries <= 0 ) {
$this->rollback( __METHOD__ );
$this->reportQueryError( $error, $errno, $sql, $fname );
+
return false;
} else {
$this->commit( __METHOD__ );
+
return $retVal;
}
}
@@ -3037,38 +3263,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Wait for the slave to catch up to a given master position.
*
- * @param $pos DBMasterPos object
- * @param $timeout Integer: the maximum number of seconds to wait for
+ * @param DBMasterPos $pos
+ * @param int $timeout The maximum number of seconds to wait for
* synchronisation
- *
- * @return integer: zero if the slave was past that position already,
+ * @return int 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.
*/
public function masterPosWait( DBMasterPos $pos, $timeout ) {
- wfProfileIn( __METHOD__ );
-
- if ( !is_null( $this->mFakeSlaveLag ) ) {
- $wait = intval( ( $pos->pos - microtime( true ) + $this->mFakeSlaveLag ) * 1e6 );
-
- if ( $wait > $timeout * 1e6 ) {
- wfDebug( "Fake slave timed out waiting for $pos ($wait us)\n" );
- wfProfileOut( __METHOD__ );
- return -1;
- } elseif ( $wait > 0 ) {
- wfDebug( "Fake slave waiting $wait us\n" );
- usleep( $wait );
- wfProfileOut( __METHOD__ );
- return 1;
- } else {
- wfDebug( "Fake slave up to date ($wait us)\n" );
- wfProfileOut( __METHOD__ );
- return 0;
- }
- }
-
- wfProfileOut( __METHOD__ );
-
# Real waits are implemented in the subclass.
return 0;
}
@@ -3076,30 +3278,21 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Get the replication position of this slave
*
- * @return DBMasterPos, or false if this is not a slave.
+ * @return DBMasterPos|bool False if this is not a slave.
*/
public function getSlavePos() {
- if ( !is_null( $this->mFakeSlaveLag ) ) {
- $pos = new MySQLMasterPos( 'fake', microtime( true ) - $this->mFakeSlaveLag );
- wfDebug( __METHOD__ . ": fake slave pos = $pos\n" );
- return $pos;
- } else {
- # Stub
- return false;
- }
+ # Stub
+ return false;
}
/**
* Get the position of this master
*
- * @return DBMasterPos, or false if this is not a master
+ * @return DBMasterPos|bool False if this is not a master
*/
public function getMasterPos() {
- if ( $this->mFakeMaster ) {
- return new MySQLMasterPos( 'fake', microtime( true ) );
- } else {
- return false;
- }
+ # Stub
+ return false;
}
/**
@@ -3150,7 +3343,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
protected function runOnTransactionIdleCallbacks() {
$autoTrx = $this->getFlag( DBO_TRX ); // automatic begin() enabled?
- $e = null; // last exception
+ $e = $ePrior = null; // last exception
do { // callbacks may add callbacks :)
$callbacks = $this->mTrxIdleCallbacks;
$this->mTrxIdleCallbacks = array(); // recursion guard
@@ -3160,7 +3353,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$this->clearFlag( DBO_TRX ); // make each query its own transaction
call_user_func( $phpCallback );
$this->setFlag( $autoTrx ? DBO_TRX : 0 ); // restore automatic begin()
- } catch ( Exception $e ) {}
+ } catch ( Exception $e ) {
+ if ( $ePrior ) {
+ MWExceptionHandler::logException( $ePrior );
+ }
+ $ePrior = $e;
+ }
}
} while ( count( $this->mTrxIdleCallbacks ) );
@@ -3175,7 +3373,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @since 1.22
*/
protected function runOnTransactionPreCommitCallbacks() {
- $e = null; // last exception
+ $e = $ePrior = null; // last exception
do { // callbacks may add callbacks :)
$callbacks = $this->mTrxPreCommitCallbacks;
$this->mTrxPreCommitCallbacks = array(); // recursion guard
@@ -3183,7 +3381,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
try {
list( $phpCallback ) = $callback;
call_user_func( $phpCallback );
- } catch ( Exception $e ) {}
+ } catch ( Exception $e ) {
+ if ( $ePrior ) {
+ MWExceptionHandler::logException( $ePrior );
+ }
+ $ePrior = $e;
+ }
}
} while ( count( $this->mTrxPreCommitCallbacks ) );
@@ -3193,22 +3396,91 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
}
/**
- * Begin a transaction. If a transaction is already in progress, that transaction will be committed before the
- * new transaction is started.
+ * Begin an atomic section of statements
+ *
+ * If a transaction has been started already, just keep track of the given
+ * section name to make sure the transaction is not committed pre-maturely.
+ * This function can be used in layers (with sub-sections), so use a stack
+ * to keep track of the different atomic sections. If there is no transaction,
+ * start one implicitly.
+ *
+ * The goal of this function is to create an atomic section of SQL queries
+ * without having to start a new transaction if it already exists.
*
- * Note that when the DBO_TRX flag is set (which is usually the case for web requests, but not for maintenance scripts),
- * any previous database query will have started a transaction automatically.
+ * Atomic sections are more strict than transactions. With transactions,
+ * attempting to begin a new transaction when one is already running results
+ * in MediaWiki issuing a brief warning and doing an implicit commit. All
+ * atomic levels *must* be explicitly closed using DatabaseBase::endAtomic(),
+ * and any database transactions cannot be began or committed until all atomic
+ * levels are closed. There is no such thing as implicitly opening or closing
+ * an atomic section.
+ *
+ * @since 1.23
+ * @param string $fname
+ * @throws DBError
+ */
+ final public function startAtomic( $fname = __METHOD__ ) {
+ if ( !$this->mTrxLevel ) {
+ $this->begin( $fname );
+ $this->mTrxAutomatic = true;
+ $this->mTrxAutomaticAtomic = true;
+ }
+
+ $this->mTrxAtomicLevels->push( $fname );
+ }
+
+ /**
+ * Ends an atomic section of SQL statements
*
- * Nesting of transactions is not supported. Attempts to nest transactions will cause a warning, unless the current
- * transaction was started automatically because of the DBO_TRX flag.
+ * Ends the next section of atomic SQL statements and commits the transaction
+ * if necessary.
*
- * @param $fname string
+ * @since 1.23
+ * @see DatabaseBase::startAtomic
+ * @param string $fname
+ * @throws DBError
+ */
+ final public function endAtomic( $fname = __METHOD__ ) {
+ if ( !$this->mTrxLevel ) {
+ throw new DBUnexpectedError( $this, 'No atomic transaction is open.' );
+ }
+ if ( $this->mTrxAtomicLevels->isEmpty() ||
+ $this->mTrxAtomicLevels->pop() !== $fname
+ ) {
+ throw new DBUnexpectedError( $this, 'Invalid atomic section ended.' );
+ }
+
+ if ( $this->mTrxAtomicLevels->isEmpty() && $this->mTrxAutomaticAtomic ) {
+ $this->commit( $fname, 'flush' );
+ }
+ }
+
+ /**
+ * Begin a transaction. If a transaction is already in progress,
+ * that transaction will be committed before the new transaction is started.
+ *
+ * Note that when the DBO_TRX flag is set (which is usually the case for web
+ * requests, but not for maintenance scripts), any previous database query
+ * will have started a transaction automatically.
+ *
+ * Nesting of transactions is not supported. Attempts to nest transactions
+ * will cause a warning, unless the current transaction was started
+ * automatically because of the DBO_TRX flag.
+ *
+ * @param string $fname
+ * @throws DBError
*/
final public function begin( $fname = __METHOD__ ) {
global $wgDebugDBTransactions;
if ( $this->mTrxLevel ) { // implicit commit
- if ( !$this->mTrxAutomatic ) {
+ if ( !$this->mTrxAtomicLevels->isEmpty() ) {
+ // If the current transaction was an automatic atomic one, then we definitely have
+ // a problem. Same if there is any unclosed atomic level.
+ throw new DBUnexpectedError( $this,
+ "Attempted to start explicit transaction when atomic levels are still open."
+ );
+ } elseif ( !$this->mTrxAutomatic ) {
// We want to warn about inadvertently nested begin/commit pairs, but not about
// auto-committing implicit transactions that were started by query() via DBO_TRX
$msg = "$fname: Transaction already in progress (from {$this->mTrxFname}), " .
@@ -3228,22 +3500,33 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
- Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname );
+ Profiler::instance()->transactionWritingOut(
+ $this->mServer, $this->mDBname, $this->mTrxShortId );
}
$this->runOnTransactionIdleCallbacks();
}
+ # Avoid fatals if close() was called
+ if ( !$this->isOpen() ) {
+ throw new DBUnexpectedError( $this, "DB connection was already closed." );
+ }
+
$this->doBegin( $fname );
$this->mTrxFname = $fname;
$this->mTrxDoneWrites = false;
$this->mTrxAutomatic = false;
+ $this->mTrxAutomaticAtomic = false;
+ $this->mTrxAtomicLevels = new SplStack;
+ $this->mTrxIdleCallbacks = array();
+ $this->mTrxPreCommitCallbacks = array();
+ $this->mTrxShortId = wfRandomString( 12 );
}
/**
* Issues the BEGIN command to the database server.
*
* @see DatabaseBase::begin()
- * @param type $fname
+ * @param string $fname
*/
protected function doBegin( $fname ) {
$this->query( 'BEGIN', $fname );
@@ -3256,33 +3539,49 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* Nesting of transactions is not supported.
*
- * @param $fname string
- * @param string $flush Flush flag, set to 'flush' to disable warnings about explicitly committing implicit
- * transactions, or calling commit when no transaction is in progress.
- * This will silently break any ongoing explicit transaction. Only set the flush flag if you are sure
- * that it is safe to ignore these warnings in your context.
+ * @param string $fname
+ * @param string $flush Flush flag, set to 'flush' to disable warnings about
+ * explicitly committing implicit transactions, or calling commit when no
+ * transaction is in progress. This will silently break any ongoing
+ * explicit transaction. Only set the flush flag if you are sure that it
+ * is safe to ignore these warnings in your context.
+ * @throws DBUnexpectedError
*/
final public function commit( $fname = __METHOD__, $flush = '' ) {
- if ( $flush != 'flush' ) {
+ if ( !$this->mTrxAtomicLevels->isEmpty() ) {
+ // There are still atomic sections open. This cannot be ignored
+ throw new DBUnexpectedError(
+ $this,
+ "Attempted to commit transaction while atomic sections are still open"
+ );
+ }
+
+ if ( $flush === 'flush' ) {
if ( !$this->mTrxLevel ) {
- wfWarn( "$fname: No transaction to commit, something got out of sync!" );
- } elseif ( $this->mTrxAutomatic ) {
- wfWarn( "$fname: Explicit commit of implicit transaction. Something may be out of sync!" );
+ return; // nothing to do
+ } elseif ( !$this->mTrxAutomatic ) {
+ wfWarn( "$fname: Flushing an explicit transaction, getting out of sync!" );
}
} else {
if ( !$this->mTrxLevel ) {
+ wfWarn( "$fname: No transaction to commit, something got out of sync!" );
return; // nothing to do
- } elseif ( !$this->mTrxAutomatic ) {
- wfWarn( "$fname: Flushing an explicit transaction, getting out of sync!" );
+ } elseif ( $this->mTrxAutomatic ) {
+ wfWarn( "$fname: Explicit commit of implicit transaction. Something may be out of sync!" );
}
}
+ # Avoid fatals if close() was called
+ if ( !$this->isOpen() ) {
+ throw new DBUnexpectedError( $this, "DB connection was already closed." );
+ }
+
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
- Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname );
+ Profiler::instance()->transactionWritingOut(
+ $this->mServer, $this->mDBname, $this->mTrxShortId );
}
- $this->mTrxDoneWrites = false;
$this->runOnTransactionIdleCallbacks();
}
@@ -3290,7 +3589,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Issues the COMMIT command to the database server.
*
* @see DatabaseBase::commit()
- * @param type $fname
+ * @param string $fname
*/
protected function doCommit( $fname ) {
if ( $this->mTrxLevel ) {
@@ -3305,26 +3604,49 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* No-op on non-transactional databases.
*
- * @param $fname string
+ * @param string $fname
+ * @param string $flush Flush flag, set to 'flush' to disable warnings about
+ * calling rollback when no transaction is in progress. This will silently
+ * break any ongoing explicit transaction. Only set the flush flag if you
+ * are sure that it is safe to ignore these warnings in your context.
+ * @since 1.23 Added $flush parameter
*/
- final public function rollback( $fname = __METHOD__ ) {
- if ( !$this->mTrxLevel ) {
- wfWarn( "$fname: No transaction to rollback, something got out of sync!" );
+ final public function rollback( $fname = __METHOD__, $flush = '' ) {
+ if ( $flush !== 'flush' ) {
+ if ( !$this->mTrxLevel ) {
+ wfWarn( "$fname: No transaction to rollback, something got out of sync!" );
+ return; // nothing to do
+ } elseif ( $this->mTrxAutomatic ) {
+ wfWarn( "$fname: Explicit rollback of implicit transaction. Something may be out of sync!" );
+ }
+ } else {
+ if ( !$this->mTrxLevel ) {
+ return; // nothing to do
+ } elseif ( !$this->mTrxAutomatic ) {
+ wfWarn( "$fname: Flushing an explicit transaction, getting out of sync!" );
+ }
}
+
+ # Avoid fatals if close() was called
+ if ( !$this->isOpen() ) {
+ throw new DBUnexpectedError( $this, "DB connection was already closed." );
+ }
+
$this->doRollback( $fname );
$this->mTrxIdleCallbacks = array(); // cancel
$this->mTrxPreCommitCallbacks = array(); // cancel
+ $this->mTrxAtomicLevels = new SplStack;
if ( $this->mTrxDoneWrites ) {
- Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname );
+ Profiler::instance()->transactionWritingOut(
+ $this->mServer, $this->mDBname, $this->mTrxShortId );
}
- $this->mTrxDoneWrites = false;
}
/**
* Issues the ROLLBACK command to the database server.
*
* @see DatabaseBase::rollback()
- * @param type $fname
+ * @param string $fname
*/
protected function doRollback( $fname ) {
if ( $this->mTrxLevel ) {
@@ -3341,12 +3663,12 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* The table names passed to this function shall not be quoted (this
* function calls addIdentifierQuotes when needed).
*
- * @param string $oldName name of table whose structure should be copied
- * @param string $newName name of table to be created
- * @param $temporary Boolean: whether the new table should be temporary
- * @param string $fname calling function name
+ * @param string $oldName Name of table whose structure should be copied
+ * @param string $newName Name of table to be created
+ * @param bool $temporary Whether the new table should be temporary
+ * @param string $fname Calling function name
* @throws MWException
- * @return Boolean: true if operation was successful
+ * @return bool True if operation was successful
*/
public function duplicateTableStructure( $oldName, $newName, $temporary = false,
$fname = __METHOD__
@@ -3359,7 +3681,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* List all tables on the database
*
* @param string $prefix Only show tables with this prefix, e.g. mw_
- * @param string $fname calling function name
+ * @param string $fname Calling function name
* @throws MWException
*/
function listTables( $prefix = null, $fname = __METHOD__ ) {
@@ -3380,8 +3702,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* For caching purposes the list of all views should be stored in
* $this->allViews. The process cache can be cleared with clearViewsCache()
*
- * @param string $prefix Only show VIEWs with this prefix, eg. unit_test_
- * @param string $fname Name of calling function
+ * @param string $prefix Only show VIEWs with this prefix, eg. unit_test_
+ * @param string $fname Name of calling function
* @throws MWException
* @since 1.22
*/
@@ -3392,7 +3714,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Differentiates between a TABLE and a VIEW
*
- * @param $name string: Name of the database-structure to test.
+ * @param string $name Name of the database-structure to test.
* @throws MWException
* @since 1.22
*/
@@ -3407,7 +3729,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* The result is unquoted, and needs to be passed through addQuotes()
* before it can be included in raw SQL.
*
- * @param $ts string|int
+ * @param string|int $ts
*
* @return string
*/
@@ -3424,7 +3746,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* The result is unquoted, and needs to be passed through addQuotes()
* before it can be included in raw SQL.
*
- * @param $ts string|int
+ * @param string|int $ts
*
* @return string
*/
@@ -3447,8 +3769,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* callers, so this is unnecessary in external code. For compatibility with
* old code, ResultWrapper objects are passed through unaltered.
*
- * @param $result bool|ResultWrapper
- *
+ * @param bool|ResultWrapper|resource $result
* @return bool|ResultWrapper
*/
public function resultObject( $result ) {
@@ -3470,7 +3791,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @return bool Success or failure
*/
public function ping() {
- # Stub. Not essential to override.
+ # Stub. Not essential to override.
return true;
}
@@ -3484,7 +3805,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @return int Database replication lag in seconds
*/
public function getLag() {
- return intval( $this->mFakeSlaveLag );
+ return 0;
}
/**
@@ -3501,7 +3822,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* don't allow simple quoted strings to be inserted. To insert into such
* a field, pass the data through this function before passing it to
* DatabaseBase::insert().
- * @param $b string
+ *
+ * @param string $b
* @return string
*/
public function encodeBlob( $b ) {
@@ -3512,7 +3834,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Some DBMSs return a special placeholder object representing blob fields
* in result objects. Pass the object through this function to return the
* original string.
- * @param $b string
+ *
+ * @param string $b
* @return string
*/
public function decodeBlob( $b ) {
@@ -3526,7 +3849,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* full-wiki dumps, where a single query reads out over
* hours or days.
*
- * @param $options Array
+ * @param array $options
* @return void
*/
public function setSessionOptions( array $options ) {
@@ -3542,9 +3865,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* @param bool|callable $lineCallback Optional function called before reading each line
* @param bool|callable $resultCallback Optional function called for each MySQL result
* @param bool|string $fname Calling function name or false if name should be
- * generated dynamically using $filename
- * @param bool|callable $inputCallback Callback: Optional function called for each complete line sent
- * @throws MWException
+ * generated dynamically using $filename
+ * @param bool|callable $inputCallback Optional function called for each
+ * complete line sent
* @throws Exception|MWException
* @return bool|string
*/
@@ -3565,8 +3888,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
try {
$error = $this->sourceStream( $fp, $lineCallback, $resultCallback, $fname, $inputCallback );
- }
- catch ( MWException $e ) {
+ } catch ( MWException $e ) {
fclose( $fp );
throw $e;
}
@@ -3582,7 +3904,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* it fails back to MySQL if no DB-specific patch can be found
*
* @param string $patch The name of the patch, like patch-something.sql
- * @return String Full path to patch file
+ * @return string Full path to patch file
*/
public function patchPath( $patch ) {
global $IP;
@@ -3600,7 +3922,7 @@ abstract class DatabaseBase implements IDatabase, 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 bool|array $vars mapping variable name to value.
+ * @param bool|array $vars Mapping variable name to value.
*/
public function setSchemaVars( $vars ) {
$this->mSchemaVars = $vars;
@@ -3612,16 +3934,16 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Returns true on success, error string or exception on failure (depending
* on object's error ignore settings).
*
- * @param $fp Resource: File handle
- * @param $lineCallback Callback: Optional function called before reading each query
- * @param $resultCallback Callback: Optional function called for each MySQL result
+ * @param resource $fp File handle
+ * @param bool|callable $lineCallback Optional function called before reading each query
+ * @param bool|callable $resultCallback Optional function called for each MySQL result
* @param string $fname Calling function name
- * @param $inputCallback Callback: Optional function called for each complete query sent
+ * @param bool|callable $inputCallback Optional function called for each complete query sent
* @return bool|string
*/
public function sourceStream( $fp, $lineCallback = false, $resultCallback = false,
- $fname = __METHOD__, $inputCallback = false )
- {
+ $fname = __METHOD__, $inputCallback = false
+ ) {
$cmd = '';
while ( !feof( $fp ) ) {
@@ -3659,6 +3981,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
if ( false === $res ) {
$err = $this->lastError();
+
return "Query \"{$cmd}\" failed with error code \"$err\".\n";
}
}
@@ -3674,7 +3997,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* @param string $sql SQL assembled so far
* @param string $newLine New line about to be added to $sql
- * @return Bool Whether $newLine contains end of the statement
+ * @return bool Whether $newLine contains end of the statement
*/
public function streamStatementEnd( &$sql, &$newLine ) {
if ( $this->delimiter ) {
@@ -3684,6 +4007,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
return true;
}
}
+
return false;
}
@@ -3702,7 +4026,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* table options its use should be avoided.
*
* @param string $ins SQL statement to replace variables in
- * @return String The new SQL statement with variables replaced
+ * @return string The new SQL statement with variables replaced
*/
protected function replaceSchemaVars( $ins ) {
$vars = $this->getSchemaVars();
@@ -3714,14 +4038,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
// replace /*$var*/
$ins = str_replace( '/*$' . $var . '*/', $this->strencode( $value ), $ins );
}
+
return $ins;
}
/**
* Replace variables in sourced SQL
*
- * @param $ins string
- *
+ * @param string $ins
* @return string
*/
protected function replaceVars( $ins ) {
@@ -3767,8 +4091,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Table name callback
*
- * @param $matches array
- *
+ * @param array $matches
* @return string
*/
protected function tableNameCallback( $matches ) {
@@ -3778,8 +4101,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Index name callback
*
- * @param $matches array
- *
+ * @param array $matches
* @return string
*/
protected function indexNameCallback( $matches ) {
@@ -3789,9 +4111,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Check to see if a named lock is available. This is non-blocking.
*
- * @param string $lockName name of lock to poll
- * @param string $method name of method calling us
- * @return Boolean
+ * @param string $lockName Name of lock to poll
+ * @param string $method Name of method calling us
+ * @return bool
* @since 1.20
*/
public function lockIsFree( $lockName, $method ) {
@@ -3804,10 +4126,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Abstracted from Filestore::lock() so child classes can implement for
* their own needs.
*
- * @param string $lockName name of lock to aquire
- * @param string $method name of method calling us
- * @param $timeout Integer: timeout
- * @return Boolean
+ * @param string $lockName Name of lock to aquire
+ * @param string $method Name of method calling us
+ * @param int $timeout
+ * @return bool
*/
public function lock( $lockName, $method, $timeout = 5 ) {
return true;
@@ -3830,11 +4152,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Lock specific tables
*
- * @param array $read of tables to lock for read access
- * @param array $write of tables to lock for write access
- * @param string $method name of caller
+ * @param array $read Array of tables to lock for read access
+ * @param array $write Array of tables to lock for write access
+ * @param string $method Name of caller
* @param bool $lowPriority Whether to indicate writes to be LOW PRIORITY
- *
* @return bool
*/
public function lockTables( $read, $write, $method, $lowPriority = true ) {
@@ -3844,8 +4165,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Unlock specific tables
*
- * @param string $method the caller
- *
+ * @param string $method The caller
* @return bool
*/
public function unlockTables( $method ) {
@@ -3854,8 +4174,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Delete a table
- * @param $tableName string
- * @param $fName string
+ * @param string $tableName
+ * @param string $fName
* @return bool|ResultWrapper
* @since 1.18
*/
@@ -3867,6 +4187,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
if ( $this->cascadingDeletes() ) {
$sql .= " CASCADE";
}
+
return $this->query( $sql, $fName );
}
@@ -3874,7 +4195,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Get search engine class. All subclasses of this need to implement this
* if they wish to use searching.
*
- * @return String
+ * @return string
*/
public function getSearchEngine() {
return 'SearchEngineDummy';
@@ -3885,7 +4206,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* keyword for timestamps in PostgreSQL, and works with CHAR(14) as well
* because "i" sorts after all numbers.
*
- * @return String
+ * @return string
*/
public function getInfinity() {
return 'infinity';
@@ -3894,8 +4215,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* Encode an expiry time into the DBMS dependent format
*
- * @param string $expiry timestamp for expiry, or the 'infinity' string
- * @return String
+ * @param string $expiry Timestamp for expiry, or the 'infinity' string
+ * @return string
*/
public function encodeExpiry( $expiry ) {
return ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() )
@@ -3907,8 +4228,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
* Decode an expiry time into a DBMS independent format
*
* @param string $expiry DB timestamp field value for expiry
- * @param $format integer: TS_* constant, defaults to TS_MW
- * @return String
+ * @param int $format TS_* constant, defaults to TS_MW
+ * @return string
*/
public function decodeExpiry( $expiry, $format = TS_MW ) {
return ( $expiry == '' || $expiry == $this->getInfinity() )
@@ -3922,7 +4243,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
*
* This is a MySQL-specific feature.
*
- * @param $value Mixed: true for allow, false for deny, or "default" to
+ * @param bool|string $value True for allow, false for deny, or "default" to
* restore the initial value
*/
public function setBigSelects( $value = true ) {
@@ -3931,6 +4252,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
/**
* @since 1.19
+ * @return string
*/
public function __toString() {
return (string)$this->mConn;
@@ -3947,10 +4269,9 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
$callers = array();
foreach ( $this->mTrxIdleCallbacks as $callbackInfo ) {
$callers[] = $callbackInfo[1];
-
}
$callers = implode( ', ', $callers );
- trigger_error( "DB transaction callbacks still pending (from $callers)." );
+ trigger_error( "DB transaction callbacks still pending (from $callers)." );
}
}
}