X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Fdatabase%2FDatabase.php;h=3d40417d65d086a882d1b058b37b99838ade3271;hp=c04e16773886b5efb27b7f942287f6316893ce95;hb=4ddb207a32e0235e87954b0d4167c5d7afa85b64;hpb=90845301542482bd4e502221e6485a7375193529 diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index c04e167738..3d40417d65 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -236,6 +236,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware /** @var TransactionProfiler */ protected $trxProfiler; + /** + * @var bool Whether writing is allowed on this connection. + * Should be false for connections to replicas. + */ + protected $allowWrite = true; + /** * Constructor and database handle and attempt to connect to the DB server * @@ -277,6 +283,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->connLogger = $params['connLogger']; $this->queryLogger = $params['queryLogger']; $this->errorLogger = $params['errorLogger']; + $this->allowWrite = empty( $params['noWrite'] ); // Set initial dummy domain until open() sets the final DB/prefix $this->currentDomain = DatabaseDomain::newUnspecified(); @@ -461,9 +468,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware protected function ignoreErrors( $ignoreErrors = null ) { $res = $this->getFlag( self::DBO_IGNORE ); if ( $ignoreErrors !== null ) { - $ignoreErrors - ? $this->setFlag( self::DBO_IGNORE ) - : $this->clearFlag( self::DBO_IGNORE ); + // setFlag()/clearFlag() do not allow DBO_IGNORE changes for sanity + if ( $ignoreErrors ) { + $this->mFlags |= self::DBO_IGNORE; + } else { + $this->mFlags &= ~self::DBO_IGNORE; + } } return $res; @@ -621,6 +631,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } public function setFlag( $flag, $remember = self::REMEMBER_NOTHING ) { + if ( ( $flag & self::DBO_IGNORE ) ) { + throw new \UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." ); + } + if ( $remember === self::REMEMBER_PRIOR ) { array_push( $this->priorFlags, $this->mFlags ); } @@ -628,6 +642,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } public function clearFlag( $flag, $remember = self::REMEMBER_NOTHING ) { + if ( ( $flag & self::DBO_IGNORE ) ) { + throw new \UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." ); + } + if ( $remember === self::REMEMBER_PRIOR ) { array_push( $this->priorFlags, $this->mFlags ); } @@ -897,6 +915,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } if ( $isWrite ) { + if ( !$this->allowWrite ) { + throw new DBError( + $this, + 'Write operations are not allowed on this database connection!' + ); + } + # In theory, non-persistent writes are allowed in read-only mode, but due to things # like https://bugs.mysql.com/bug.php?id=33669 that might not work anyway... $reason = $this->getReadOnlyReason(); @@ -945,10 +970,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware # Update state tracking to reflect transaction loss due to disconnection $this->handleSessionLoss(); if ( $this->reconnect() ) { - $msg = __METHOD__ . ": lost connection to {$this->getServer()}; reconnected"; - $this->connLogger->warning( $msg ); - $this->queryLogger->warning( - "$msg:\n" . ( new RuntimeException() )->getTraceAsString() ); + $msg = __METHOD__ . ': lost connection to {dbserver}; reconnected'; + $params = [ 'dbserver' => $this->getServer() ]; + $this->connLogger->warning( $msg, $params ); + $this->queryLogger->warning( $msg, $params + + [ 'trace' => ( new RuntimeException() )->getTraceAsString() ] ); if ( !$recoverable ) { # Callers may catch the exception and continue to use the DB @@ -958,8 +984,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $ret = $this->doProfiledQuery( $sql, $commentedSql, $isNonTempWrite, $fname ); } } else { - $msg = __METHOD__ . ": lost connection to {$this->getServer()} permanently"; - $this->connLogger->error( $msg ); + $msg = __METHOD__ . ': lost connection to {dbserver} permanently'; + $this->connLogger->error( $msg, [ 'dbserver' => $this->getServer() ] ); } } @@ -2018,9 +2044,19 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( is_array( $table ) ) { // A parenthesized group - $joinedTable = '(' - . $this->tableNamesWithIndexClauseOrJOIN( $table, $use_index, $ignore_index, $join_conds ) - . ')'; + if ( count( $table ) > 1 ) { + $joinedTable = '(' + . $this->tableNamesWithIndexClauseOrJOIN( $table, $use_index, $ignore_index, $join_conds ) + . ')'; + } else { + // Degenerate case + $innerTable = reset( $table ); + $innerAlias = key( $table ); + $joinedTable = $this->tableNameWithAlias( + $innerTable, + is_string( $innerAlias ) ? $innerAlias : $innerTable + ); + } } else { $joinedTable = $this->tableNameWithAlias( $table, $alias ); } @@ -3272,14 +3308,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * @see WANObjectCache::getWithSetCallback() * * @param IDatabase $db1 - * @param IDatabase $dbs,... + * @param IDatabase $db2 [optional] * @return array Map of values: * - lag: highest lag of any of the DBs or false on error (e.g. replication stopped) * - since: oldest UNIX timestamp of any of the DB lag estimates * - pending: whether any of the DBs have uncommitted changes + * @throws DBError * @since 1.27 */ - public static function getCacheSetOptions( IDatabase $db1 ) { + public static function getCacheSetOptions( IDatabase $db1, IDatabase $db2 = null ) { $res = [ 'lag' => 0, 'since' => INF, 'pending' => false ]; foreach ( func_get_args() as $db ) { /** @var IDatabase $db */