X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Fdatabase%2FDatabase.php;h=084500ac8e1297561f46ddf313182a479581dd7e;hb=88e3a888cc6823f11df79ac53eb963a7e4d2871a;hp=5a40f4443a747df1cc5f779935588319650f9d86;hpb=d3a30a3c58dfa795f4d236f23a99b64d094e6337;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index 5a40f4443a..5f59f34822 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -47,37 +47,6 @@ use Throwable; * @since 1.28 */ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAwareInterface { - /** @var string Server that this instance is currently connected to */ - protected $server; - /** @var string User that this instance is currently connected under the name of */ - protected $user; - /** @var string Password used to establish the current connection */ - protected $password; - /** @var array[] Map of (table => (dbname, schema, prefix) map) */ - protected $tableAliases = []; - /** @var string[] Map of (index alias => index) */ - protected $indexAliases = []; - /** @var bool Whether this PHP instance is for a CLI script */ - protected $cliMode; - /** @var string Agent name for query profiling */ - protected $agent; - /** @var int Bit field of class DBO_* constants */ - protected $flags; - /** @var array LoadBalancer tracking information */ - protected $lbInfo = []; - /** @var array|bool Variables use for schema element placeholders */ - protected $schemaVars = false; - /** @var array Parameters used by initConnection() to establish a connection */ - protected $connectionParams = []; - /** @var array SQL variables values to use for all new connections */ - protected $connectionVariables = []; - /** @var string Current SQL query delimiter */ - protected $delimiter = ';'; - /** @var string|bool|null Stashed value of html_errors INI setting */ - protected $htmlErrors; - /** @var int Row batch size to use for emulated INSERT SELECT queries */ - protected $nonNativeInsertSelectBatchSize = 10000; - /** @var BagOStuff APC cache */ protected $srvCache; /** @var LoggerInterface */ @@ -92,25 +61,62 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware protected $profiler; /** @var TransactionProfiler */ protected $trxProfiler; + /** @var DatabaseDomain */ protected $currentDomain; + /** @var object|resource|null Database connection */ protected $conn; /** @var IDatabase|null Lazy handle to the master DB this server replicates from */ private $lazyMasterHandle; + /** @var string Server that this instance is currently connected to */ + protected $server; + /** @var string User that this instance is currently connected under the name of */ + protected $user; + /** @var string Password used to establish the current connection */ + protected $password; + /** @var bool Whether this PHP instance is for a CLI script */ + protected $cliMode; + /** @var string Agent name for query profiling */ + protected $agent; + /** @var array Parameters used by initConnection() to establish a connection */ + protected $connectionParams; + /** @var string[]|int[]|float[] SQL variables values to use for all new connections */ + protected $connectionVariables; + /** @var int Row batch size to use for emulated INSERT SELECT queries */ + protected $nonNativeInsertSelectBatchSize; + + /** @var int Current bit field of class DBO_* constants */ + protected $flags; + /** @var array Current LoadBalancer tracking information */ + protected $lbInfo = []; + /** @var string Current SQL query delimiter */ + protected $delimiter = ';'; + /** @var array[] Current map of (table => (dbname, schema, prefix) map) */ + protected $tableAliases = []; + /** @var string[] Current map of (index alias => index) */ + protected $indexAliases = []; + /** @var array|null Current variables use for schema element placeholders */ + protected $schemaVars; + + /** @var string|bool|null Stashed value of html_errors INI setting */ + private $htmlErrors; + /** @var int[] Prior flags member variable values */ + private $priorFlags = []; + /** @var array Map of (name => 1) for locks obtained via lock() */ protected $sessionNamedLocks = []; /** @var array Map of (table name => 1) for TEMPORARY tables */ protected $sessionTempTables = []; /** @var string ID of the active transaction or the empty string otherwise */ - protected $trxShortId = ''; + private $trxShortId = ''; /** @var int Transaction status */ - protected $trxStatus = self::STATUS_TRX_NONE; + private $trxStatus = self::STATUS_TRX_NONE; /** @var Exception|null The last error that caused the status to become STATUS_TRX_ERROR */ - protected $trxStatusCause; + private $trxStatusCause; /** @var array|null Error details of the last statement-only rollback */ private $trxStatusIgnoredCause; /** @var float|null UNIX timestamp at the time of BEGIN for the last transaction */ @@ -154,9 +160,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware /** @var bool Whether to suppress triggering of transaction end callbacks */ private $trxEndCallbacksSuppressed = false; - /** @var int[] Prior flags member variable values */ - private $priorFlags = []; - /** @var integer|null Rows affected by the last query to query() or its CRUD wrappers */ protected $affectedRowCount; @@ -171,6 +174,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware /** @var float Query rount trip time estimate */ private $lastRoundTripEstimate = 0.0; + /** @var int|null Integer ID of the managing LBFactory instance or null if none */ + private $ownerId; + /** @var string Lock granularity is on the level of the entire database */ const ATTR_DB_LEVEL_LOCKING = 'db-level-locking'; /** @var string The SCHEMA keyword refers to a grouping of tables in a database */ @@ -233,15 +239,14 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * @note exceptions for missing libraries/drivers should be thrown in initConnection() * @param array $params Parameters passed from Database::factory() */ - protected function __construct( array $params ) { + public function __construct( array $params ) { + $this->connectionParams = []; foreach ( [ 'host', 'user', 'password', 'dbname', 'schema', 'tablePrefix' ] as $name ) { $this->connectionParams[$name] = $params[$name]; } - + $this->connectionVariables = $params['variables'] ?? []; $this->cliMode = $params['cliMode']; - // Agent name is added to SQL queries in a comment, so make sure it can't break out - $this->agent = str_replace( '/', '-', $params['agent'] ); - + $this->agent = $params['agent']; $this->flags = $params['flags']; if ( $this->flags & self::DBO_DEFAULT ) { if ( $this->cliMode ) { @@ -250,13 +255,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->flags |= self::DBO_TRX; } } - // Disregard deprecated DBO_IGNORE flag (T189999) - $this->flags &= ~self::DBO_IGNORE; - - $this->connectionVariables = $params['variables']; + $this->nonNativeInsertSelectBatchSize = $params['nonNativeInsertSelectBatchSize'] ?? 10000; $this->srvCache = $params['srvCache'] ?? new HashBagOStuff(); - $this->profiler = is_callable( $params['profiler'] ) ? $params['profiler'] : null; $this->trxProfiler = $params['trxProfiler']; $this->connLogger = $params['connLogger']; @@ -264,16 +265,14 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->errorLogger = $params['errorLogger']; $this->deprecationLogger = $params['deprecationLogger']; - if ( isset( $params['nonNativeInsertSelectBatchSize'] ) ) { - $this->nonNativeInsertSelectBatchSize = $params['nonNativeInsertSelectBatchSize']; - } - // Set initial dummy domain until open() sets the final DB/prefix $this->currentDomain = new DatabaseDomain( $params['dbname'] != '' ? $params['dbname'] : null, $params['schema'] != '' ? $params['schema'] : null, $params['tablePrefix'] ); + + $this->ownerId = $params['ownerId'] ?? null; } /** @@ -361,7 +360,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * - cliMode: Whether to consider the execution context that of a CLI script. * - agent: Optional name used to identify the end-user in query profiling/logging. * - srvCache: Optional BagOStuff instance to an APC-style cache. - * - nonNativeInsertSelectBatchSize: Optional batch size for non-native INSERT SELECT emulation. + * - nonNativeInsertSelectBatchSize: Optional batch size for non-native INSERT SELECT. + * - ownerId: Optional integer ID of a LoadBalancer instance that manages this instance. * @param int $connect One of the class constants (NEW_CONNECTED, NEW_UNCONNECTED) [optional] * @return Database|null If the database driver or extension cannot be found * @throws InvalidArgumentException If the database driver or extension cannot be found @@ -381,7 +381,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware 'flags' => 0, 'variables' => [], 'cliMode' => ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ), - 'agent' => basename( $_SERVER['SCRIPT_NAME'] ) . '@' . gethostname() + 'agent' => basename( $_SERVER['SCRIPT_NAME'] ) . '@' . gethostname(), + 'ownerId' => null ]; $normalizedParams = [ @@ -397,6 +398,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware 'cliMode' => (bool)$params['cliMode'], 'agent' => (string)$params['agent'], // Objects and callbacks + 'srvCache' => $params['srvCache'] ?? new HashBagOStuff(), 'profiler' => $params['profiler'] ?? null, 'trxProfiler' => $params['trxProfiler'] ?? new TransactionProfiler(), 'connLogger' => $params['connLogger'] ?? new NullLogger(), @@ -453,7 +455,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware // we auto-detect the first available driver. For types without built-in support, // an class named "Database" us used, eg. DatabaseFoo for type 'foo'. static $builtinTypes = [ - 'mssql' => DatabaseMssql::class, 'mysql' => [ 'mysqli' => DatabaseMysqli::class ], 'sqlite' => DatabaseSqlite::class, 'postgres' => DatabasePostgres::class, @@ -494,7 +495,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } /** - * @return array Map of (Database::ATTR_* constant => value + * @return array Map of (Database::ATTR_* constant => value) * @since 1.31 */ protected static function getAttributes() { @@ -516,15 +517,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware return $this->getServerVersion(); } + /** + * Backwards-compatibility no-op method for disabling query buffering + * + * @param null|bool $buffer Whether to buffer queries (ignored) + * @return bool Whether buffering was already enabled (always true) + * @deprecated Since 1.34 Use query batching; this no longer does anything + */ public function bufferResults( $buffer = null ) { - $res = !$this->getFlag( self::DBO_NOBUFFER ); - if ( $buffer !== null ) { - $buffer - ? $this->clearFlag( self::DBO_NOBUFFER ) - : $this->setFlag( self::DBO_NOBUFFER ); - } - - return $res; + return true; } final public function trxLevel() { @@ -872,8 +873,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware ); } - final public function close() { - $exception = null; // error to throw after disconnecting + final public function close( $fname = __METHOD__, $owner = null ) { + $error = null; // error to throw after disconnecting $wasOpen = (bool)$this->conn; // This should mostly do nothing if the connection is already closed @@ -883,34 +884,22 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $this->trxAtomicLevels ) { // Cannot let incomplete atomic sections be committed $levels = $this->flatAtomicSectionList(); - $exception = new DBUnexpectedError( - $this, - __METHOD__ . ": atomic sections $levels are still open" - ); + $error = "$fname: atomic sections $levels are still open"; } elseif ( $this->trxAutomatic ) { // Only the connection manager can commit non-empty DBO_TRX transactions // (empty ones we can silently roll back) if ( $this->writesOrCallbacksPending() ) { - $exception = new DBUnexpectedError( - $this, - __METHOD__ . - ": mass commit/rollback of peer transaction required (DBO_TRX set)" - ); + $error = "$fname: " . + "expected mass rollback of all peer transactions (DBO_TRX set)"; } } else { // Manual transactions should have been committed or rolled // back, even if empty. - $exception = new DBUnexpectedError( - $this, - __METHOD__ . ": transaction is still open (from {$this->trxFname})" - ); + $error = "$fname: transaction is still open (from {$this->trxFname})"; } - if ( $this->trxEndCallbacksSuppressed ) { - $exception = $exception ?: new DBUnexpectedError( - $this, - __METHOD__ . ': callbacks are suppressed; cannot properly commit' - ); + if ( $this->trxEndCallbacksSuppressed && $error === null ) { + $error = "$fname: callbacks are suppressed; cannot properly commit"; } // Rollback the changes and run any callbacks as needed @@ -925,9 +914,16 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->conn = null; - // Throw any unexpected errors after having disconnected - if ( $exception instanceof Exception ) { - throw $exception; + // Log or throw any unexpected errors after having disconnected + if ( $error !== null ) { + // T217819, T231443: if this is probably just LoadBalancer trying to recover from + // errors and shutdown, then log any problems and move on since the request has to + // end one way or another. Throwing errors is not very useful at some point. + if ( $this->ownerId !== null && $owner === $this->ownerId ) { + $this->queryLogger->error( $error ); + } else { + throw new DBUnexpectedError( $this, $error ); + } } // Note that various subclasses call close() at the start of open(), which itself is @@ -968,7 +964,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * @throws DBReadOnlyError */ protected function assertIsWritableMaster() { - if ( $this->getLBInfo( 'replica' ) === true ) { + if ( $this->getLBInfo( 'replica' ) ) { throw new DBReadOnlyRoleError( $this, 'Write operations are not allowed on replica database connections' @@ -1151,7 +1147,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware // Send the query to the server and fetch any corresponding errors list( $ret, $err, $errno, $unignorable ) = $this->executeQuery( $sql, $fname, $flags ); if ( $ret === false ) { - $ignoreErrors = $this->hasFlags( $flags, self::QUERY_SILENCE_ERRORS ); + $ignoreErrors = $this->fieldHasBit( $flags, self::QUERY_SILENCE_ERRORS ); // Throw an error unless both the ignore flag was set and a rollback is not needed $this->reportQueryError( $err, $errno, $sql, $fname, $ignoreErrors && !$unignorable ); } @@ -1191,11 +1187,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware // Do not treat temporary table writes as "meaningful writes" since they are only // visible to one session and are not permanent. Profile them as reads. Integration // tests can override this behavior via $flags. - $pseudoPermanent = $this->hasFlags( $flags, self::QUERY_PSEUDO_PERMANENT ); + $pseudoPermanent = $this->fieldHasBit( $flags, self::QUERY_PSEUDO_PERMANENT ); list( $tmpType, $tmpNew, $tmpDel ) = $this->getTempWrites( $sql, $pseudoPermanent ); $isPermWrite = ( $tmpType !== self::$TEMP_NORMAL ); // DBConnRef uses QUERY_REPLICA_ROLE to enforce the replica role for raw SQL queries - if ( $isPermWrite && $this->hasFlags( $flags, self::QUERY_REPLICA_ROLE ) ) { + if ( $isPermWrite && $this->fieldHasBit( $flags, self::QUERY_REPLICA_ROLE ) ) { throw new DBReadOnlyRoleError( $this, "Cannot write; target role is DB_REPLICA" ); } } else { @@ -1206,8 +1202,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } // Add trace comment to the begin of the sql string, right after the operator. - // Or, for one-word queries (like "BEGIN" or COMMIT") add it to the end (T44598) - $commentedSql = preg_replace( '/\s|$/', " /* $fname {$this->agent} */ ", $sql, 1 ); + // Or, for one-word queries (like "BEGIN" or COMMIT") add it to the end (T44598). + $encAgent = str_replace( '/', '-', $this->agent ); + $commentedSql = preg_replace( '/\s|$/', " /* $fname $encAgent */ ", $sql, 1 ); // Send the query to the server and fetch any corresponding errors. // This also doubles as a "ping" to see if the connection was dropped. @@ -1215,7 +1212,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->executeQueryAttempt( $sql, $commentedSql, $isPermWrite, $fname, $flags ); // Check if the query failed due to a recoverable connection loss - $allowRetry = !$this->hasFlags( $flags, self::QUERY_NO_RETRY ); + $allowRetry = !$this->fieldHasBit( $flags, self::QUERY_NO_RETRY ); if ( $ret === false && $recoverableCL && $reconnected && $allowRetry ) { // Silently resend the query to the server since it is safe and possible list( $ret, $err, $errno, $recoverableSR, $recoverableCL ) = @@ -1286,7 +1283,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } } - $prefix = !is_null( $this->getLBInfo( 'master' ) ) ? 'query-m: ' : 'query: '; + $prefix = $this->getLBInfo( 'master' ) ? 'query-m: ' : 'query: '; $generalizedSql = new GeneralizedSql( $sql, $this->trxShortId, $prefix ); $startTime = microtime( true ); @@ -1337,10 +1334,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware // Avoid the overhead of logging calls unless debug mode is enabled if ( $this->getFlag( self::DBO_DEBUG ) ) { $this->queryLogger->debug( - "{method} [{runtime}s] {db_host}: $sql", + "{method} [{runtime}s] {db_host}: {sql}", [ 'method' => $fname, 'db_host' => $this->getServer(), + 'sql' => $sql, 'domain' => $this->getDomainID(), 'runtime' => round( $queryRuntime, 3 ) ] @@ -1492,6 +1490,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->trxAtomicCounter = 0; $this->trxIdleCallbacks = []; // T67263; transaction already lost $this->trxPreCommitCallbacks = []; // T67263; transaction already lost + // Clear additional subclass fields + $this->doHandleSessionLossPreconnect(); // @note: leave trxRecurringCallbacks in place if ( $this->trxDoneWrites ) { $this->trxProfiler->transactionWritingOut( @@ -1504,6 +1504,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } } + /** + * Reset any additional subclass trx* and session* fields + */ + protected function doHandleSessionLossPreconnect() { + // no-op + } + /** * Clean things up after session (and thus transaction) loss after reconnect */ @@ -1677,12 +1684,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * Returns an optional USE INDEX clause to go after the table, and a * string to go at the end of the query. * + * @see Database::select() + * * @param array $options Associative array of options to be turned into * an SQL query, valid keys are listed in the function. * @return array - * @see Database::select() */ - protected function makeSelectOptions( $options ) { + protected function makeSelectOptions( array $options ) { $preLimitTail = $postLimitTail = ''; $startOpts = ''; @@ -1823,7 +1831,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->selectOptionsIncludeLocking( $options ) && $this->selectFieldsOrOptionsAggregate( $vars, $options ) ) { - // Some DB types (postgres/oracle) disallow FOR UPDATE with aggregate + // Some DB types (e.g. postgres) disallow FOR UPDATE with aggregate // functions. Discourage use of such queries to encourage compatibility. call_user_func( $this->deprecationLogger, @@ -3527,7 +3535,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( in_array( $entry[2], $sectionIds, true ) ) { $callback = $entry[0]; $this->trxEndCallbacks[$key][0] = function () use ( $callback ) { - // @phan-suppress-next-line PhanInfiniteRecursion No recursion at all here, phan is confused + // @phan-suppress-next-line PhanInfiniteRecursion, PhanUndeclaredInvokeInCallable return $callback( self::TRIGGER_ROLLBACK, $this ); }; // This "on resolution" callback no longer belongs to a section. @@ -3652,6 +3660,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware try { ++$count; list( $phpCallback ) = $callback; + // @phan-suppress-next-line PhanUndeclaredInvokeInCallable $phpCallback( $this ); } catch ( Exception $ex ) { ( $this->errorLogger )( $ex ); @@ -3687,6 +3696,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware foreach ( $callbacks as $entry ) { if ( $sectionIds === null || in_array( $entry[2], $sectionIds, true ) ) { try { + // @phan-suppress-next-line PhanUndeclaredInvokeInCallable $entry[0]( $trigger, $this ); } catch ( Exception $ex ) { ( $this->errorLogger )( $ex ); @@ -3974,17 +3984,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $this->trxLevel() ) { if ( $this->trxAtomicLevels ) { $levels = $this->flatAtomicSectionList(); - $msg = "$fname: Got explicit BEGIN while atomic section(s) $levels are open"; + $msg = "$fname: got explicit BEGIN while atomic section(s) $levels are open"; throw new DBUnexpectedError( $this, $msg ); } elseif ( !$this->trxAutomatic ) { - $msg = "$fname: Explicit transaction already active (from {$this->trxFname})"; + $msg = "$fname: explicit transaction already active (from {$this->trxFname})"; throw new DBUnexpectedError( $this, $msg ); } else { - $msg = "$fname: Implicit transaction already active (from {$this->trxFname})"; + $msg = "$fname: implicit transaction already active (from {$this->trxFname})"; throw new DBUnexpectedError( $this, $msg ); } } elseif ( $this->getFlag( self::DBO_TRX ) && $mode !== self::TRANSACTION_INTERNAL ) { - $msg = "$fname: Implicit transaction expected (DBO_TRX set)"; + $msg = "$fname: implicit transaction expected (DBO_TRX set)"; throw new DBUnexpectedError( $this, $msg ); } @@ -4038,7 +4048,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $levels = $this->flatAtomicSectionList(); throw new DBUnexpectedError( $this, - "$fname: Got COMMIT while atomic sections $levels are still open" + "$fname: got COMMIT while atomic sections $levels are still open" ); } @@ -4048,17 +4058,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } elseif ( !$this->trxAutomatic ) { throw new DBUnexpectedError( $this, - "$fname: Flushing an explicit transaction, getting out of sync" + "$fname: flushing an explicit transaction, getting out of sync" ); } } elseif ( !$this->trxLevel() ) { $this->queryLogger->error( - "$fname: No transaction to commit, something got out of sync" ); + "$fname: no transaction to commit, something got out of sync" ); return; // nothing to do } elseif ( $this->trxAutomatic ) { throw new DBUnexpectedError( $this, - "$fname: Expected mass commit of all peer transactions (DBO_TRX set)" + "$fname: expected mass commit of all peer transactions (DBO_TRX set)" ); } @@ -4282,10 +4292,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } // This will reconnect if possible or return false if not - $this->clearFlag( self::DBO_TRX, self::REMEMBER_PRIOR ); - $ok = ( $this->query( self::$PING_QUERY, __METHOD__, true ) !== false ); - $this->restoreFlags( self::RESTORE_PRIOR ); - + $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_SILENCE_ERRORS; + $ok = ( $this->query( self::$PING_QUERY, __METHOD__, $flags ) !== false ); if ( $ok ) { $rtt = $this->lastRoundTripEstimate; } @@ -4475,7 +4483,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } public function setSchemaVars( $vars ) { - $this->schemaVars = $vars; + $this->schemaVars = is_array( $vars ) ? $vars : null; } public function sourceStream( @@ -4627,11 +4635,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * @return array */ protected function getSchemaVars() { - if ( $this->schemaVars ) { - return $this->schemaVars; - } else { - return $this->getDefaultSchemaVars(); - } + return $this->schemaVars ?? $this->getDefaultSchemaVars(); } /** @@ -4821,8 +4825,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * @param int $field * @param int $flags * @return bool + * @since 1.34 */ - protected function hasFlags( $field, $flags ) { + final protected function fieldHasBit( $field, $flags ) { return ( ( $field & $flags ) === $flags ); }