'AtomFeed' => __DIR__ . '/includes/Feed.php',
'AtomicSectionUpdate' => __DIR__ . '/includes/deferred/AtomicSectionUpdate.php',
'AttachLatest' => __DIR__ . '/maintenance/attachLatest.php',
+ 'AugmentPageProps' => __DIR__ . '/includes/search/AugmentPageProps.php',
'AuthManagerSpecialPage' => __DIR__ . '/includes/specialpage/AuthManagerSpecialPage.php',
'AuthPlugin' => __DIR__ . '/includes/AuthPlugin.php',
'AuthPluginUser' => __DIR__ . '/includes/AuthPlugin.php',
'ConvertExtensionToRegistration' => __DIR__ . '/maintenance/convertExtensionToRegistration.php',
'ConvertLinks' => __DIR__ . '/maintenance/convertLinks.php',
'ConvertUserOptions' => __DIR__ . '/maintenance/convertUserOptions.php',
+ 'ConvertableTimestamp' => __DIR__ . '/includes/libs/time/ConvertableTimestamp.php',
'ConverterRule' => __DIR__ . '/languages/ConverterRule.php',
'Cookie' => __DIR__ . '/includes/libs/Cookie.php',
'CookieJar' => __DIR__ . '/includes/libs/CookieJar.php',
'IExpiringStore' => __DIR__ . '/includes/libs/objectcache/IExpiringStore.php',
'IJobSpecification' => __DIR__ . '/includes/jobqueue/JobSpecification.php',
'ILoadBalancer' => __DIR__ . '/includes/libs/rdbms/loadbalancer/ILoadBalancer.php',
+ 'ILoadMonitor' => __DIR__ . '/includes/libs/rdbms/loadmonitor/ILoadMonitor.php',
'IP' => __DIR__ . '/includes/utils/IP.php',
'IPSet' => __DIR__ . '/includes/compat/IPSetCompat.php',
'IPTC' => __DIR__ . '/includes/media/IPTC.php',
'PatrolLog' => __DIR__ . '/includes/logging/PatrolLog.php',
'PatrolLogFormatter' => __DIR__ . '/includes/logging/PatrolLogFormatter.php',
'Pbkdf2Password' => __DIR__ . '/includes/password/Pbkdf2Password.php',
+ 'PerRowAugmentor' => __DIR__ . '/includes/search/PerRowAugmentor.php',
'PermissionsError' => __DIR__ . '/includes/exception/PermissionsError.php',
'PhpHttpRequest' => __DIR__ . '/includes/HttpFunctions.php',
'PhpXmlBugTester' => __DIR__ . '/includes/installer/PhpBugTests.php',
'ResourceLoaderUserTokensModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserTokensModule.php',
'ResourceLoaderWikiModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderWikiModule.php',
'RestbaseVirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/RestbaseVirtualRESTService.php',
+ 'ResultAugmentor' => __DIR__ . '/includes/search/ResultAugmentor.php',
+ 'ResultSetAugmentor' => __DIR__ . '/includes/search/ResultSetAugmentor.php',
'ResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/ResultWrapper.php',
'RevDelArchiveItem' => __DIR__ . '/includes/revisiondelete/RevDelArchiveItem.php',
'RevDelArchiveList' => __DIR__ . '/includes/revisiondelete/RevDelArchiveList.php',
'ThumbnailRenderJob' => __DIR__ . '/includes/jobqueue/jobs/ThumbnailRenderJob.php',
'TidyUpBug37714' => __DIR__ . '/maintenance/tidyUpBug37714.php',
'TiffHandler' => __DIR__ . '/includes/media/Tiff.php',
- 'TimestampException' => __DIR__ . '/includes/exception/TimestampException.php',
+ 'TimestampException' => __DIR__ . '/includes/libs/time/TimestampException.php',
'Timing' => __DIR__ . '/includes/libs/Timing.php',
'Title' => __DIR__ . '/includes/Title.php',
'TitleArray' => __DIR__ . '/includes/TitleArray.php',
protected $mDBname;
/** @var array[] $aliases Map of (table => (dbname, schema, prefix) map) */
protected $tableAliases = [];
- /** @var bool */
+ /** @var bool Whether this PHP instance is for a CLI script */
protected $cliMode;
+ /** @var string Agent name for query profiling */
+ protected $agent;
/** @var BagOStuff APC cache */
protected $srvCache;
protected $mTrxPreCommitCallbacks = [];
/** @var array[] List of (callable, method name) */
protected $mTrxEndCallbacks = [];
- /** @var array[] Map of (name => (callable, method name)) */
+ /** @var callable[] Map of (name => callable) */
protected $mTrxRecurringCallbacks = [];
/** @var bool Whether to suppress triggering of transaction end callbacks */
protected $mTrxEndCallbacksSuppressed = false;
$this->cliMode = isset( $params['cliMode'] )
? $params['cliMode']
: ( PHP_SAPI === 'cli' );
+ $this->agent = isset( $params['agent'] )
+ ? str_replace( '/', '-', $params['agent'] ) // escape for comment
+ : '';
$this->mFlags = $flags;
if ( $this->mFlags & DBO_DEFAULT ) {
* @throws InvalidArgumentException If the database driver or extension cannot be found
*/
final public static function factory( $dbType, $p = [] ) {
- global $wgCommandLineMode;
-
$canonicalDBTypes = [
'mysql' => [ 'mysqli', 'mysql' ],
'postgres' => [],
$p['schema'] = isset( $defaultSchemas[$dbType] ) ? $defaultSchemas[$dbType] : null;
}
$p['foreign'] = isset( $p['foreign'] ) ? $p['foreign'] : false;
- $p['cliMode'] = $wgCommandLineMode;
$conn = new $class( $p );
if ( isset( $p['connLogger'] ) ) {
if ( isset( $p['errorLogger'] ) ) {
$conn->errorLogger = $p['errorLogger'];
} else {
- $conn->errorLogger = [ MWExceptionHandler::class, 'logException' ];
+ $conn->errorLogger = function ( Exception $e ) {
+ trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_WARNING );
+ };
}
} else {
$conn = null;
* - false to disable debugging
* - omitted or null to do nothing
*
- * @return bool|null Previous value of the flag
+ * @return bool Previous value of the flag
+ * @deprecated since 1.28; use setFlag()
*/
public function debug( $debug = null ) {
- return wfSetBit( $this->mFlags, DBO_DEBUG, $debug );
+ $res = $this->getFlag( DBO_DEBUG );
+ if ( $debug !== null ) {
+ $debug ? $this->setFlag( DBO_DEBUG ) : $this->clearFlag( DBO_DEBUG );
+ }
+
+ return $res;
}
public function bufferResults( $buffer = null ) {
- if ( is_null( $buffer ) ) {
- return !(bool)( $this->mFlags & DBO_NOBUFFER );
- } else {
- return !wfSetBit( $this->mFlags, DBO_NOBUFFER, !$buffer );
+ $res = !$this->getFlag( DBO_NOBUFFER );
+ if ( $buffer !== null ) {
+ $buffer ? $this->clearFlag( DBO_NOBUFFER ) : $this->setFlag( DBO_NOBUFFER );
}
+
+ return $res;
}
/**
* @return bool The previous value of the flag.
*/
protected function ignoreErrors( $ignoreErrors = null ) {
- return wfSetBit( $this->mFlags, DBO_IGNORE, $ignoreErrors );
+ $res = $this->getFlag( DBO_IGNORE );
+ if ( $ignoreErrors !== null ) {
+ $ignoreErrors ? $this->setFlag( DBO_IGNORE ) : $this->clearFlag( DBO_IGNORE );
+ }
+
+ return $res;
}
public function trxLevel() {
}
public function tablePrefix( $prefix = null ) {
- return wfSetVar( $this->mTablePrefix, $prefix );
+ $old = $this->mTablePrefix;
+ $this->mTablePrefix = $prefix;
+
+ return $old;
}
public function dbSchema( $schema = null ) {
- return wfSetVar( $this->mSchema, $schema );
+ $old = $this->mSchema;
+ $this->mSchema = $schema;
+
+ return $old;
}
/**
return $this->mTrxLevel ? $this->mTrxWriteCallers : [];
}
+ protected function pendingWriteAndCallbackCallers() {
+ if ( !$this->mTrxLevel ) {
+ return [];
+ }
+
+ $fnames = $this->mTrxWriteCallers;
+ foreach ( [
+ $this->mTrxIdleCallbacks,
+ $this->mTrxPreCommitCallbacks,
+ $this->mTrxEndCallbacks
+ ] as $callbacks ) {
+ foreach ( $callbacks as $callback ) {
+ $fnames[] = $callback[1];
+ }
+ }
+
+ return $fnames;
+ }
+
public function isOpen() {
return $this->mOpened;
}
}
public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
- global $wgUser;
-
$priorWritesPending = $this->writesOrCallbacksPending();
$this->mLastQuery = $sql;
$this->mDoneWrites = microtime( true );
}
- # Add a comment for easy SHOW PROCESSLIST interpretation
- if ( is_object( $wgUser ) && $wgUser->isItemLoaded( 'name' ) ) {
- $userName = $wgUser->getName();
- if ( mb_strlen( $userName ) > 15 ) {
- $userName = mb_substr( $userName, 0, 15 ) . '...';
- }
- $userName = str_replace( '/', '', $userName );
- } else {
- $userName = '';
- }
-
// 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 (bug 42598)
- $commentedSql = preg_replace( '/\s|$/', " /* $fname $userName */ ", $sql, 1 );
+ $commentedSql = preg_replace( '/\s|$/', " /* $fname {$this->agent} */ ", $sql, 1 );
# Start implicit transactions that wrap the request if DBO_TRX is enabled
if ( !$this->mTrxLevel && $this->getFlag( DBO_TRX )
return false;
}
- final public function onTransactionResolution( callable $callback ) {
+ final public function onTransactionResolution( callable $callback, $fname = __METHOD__ ) {
if ( !$this->mTrxLevel ) {
throw new DBUnexpectedError( $this, "No transaction is active." );
}
- $this->mTrxEndCallbacks[] = [ $callback, wfGetCaller() ];
+ $this->mTrxEndCallbacks[] = [ $callback, $fname ];
}
- final public function onTransactionIdle( callable $callback ) {
- $this->mTrxIdleCallbacks[] = [ $callback, wfGetCaller() ];
+ final public function onTransactionIdle( callable $callback, $fname = __METHOD__ ) {
+ $this->mTrxIdleCallbacks[] = [ $callback, $fname ];
if ( !$this->mTrxLevel ) {
$this->runOnTransactionIdleCallbacks( self::TRIGGER_IDLE );
}
}
- final public function onTransactionPreCommitOrIdle( callable $callback ) {
+ final public function onTransactionPreCommitOrIdle( callable $callback, $fname = __METHOD__ ) {
if ( $this->mTrxLevel ) {
- $this->mTrxPreCommitCallbacks[] = [ $callback, wfGetCaller() ];
+ $this->mTrxPreCommitCallbacks[] = [ $callback, $fname ];
} else {
// If no transaction is active, then make one for this callback
$this->startAtomic( __METHOD__ );
final public function setTransactionListener( $name, callable $callback = null ) {
if ( $callback ) {
- $this->mTrxRecurringCallbacks[$name] = [ $callback, wfGetCaller() ];
+ $this->mTrxRecurringCallbacks[$name] = $callback;
} else {
unset( $this->mTrxRecurringCallbacks[$name] );
}
/** @var Exception $e */
$e = null; // first exception
- foreach ( $this->mTrxRecurringCallbacks as $callback ) {
+ foreach ( $this->mTrxRecurringCallbacks as $phpCallback ) {
try {
- list( $phpCallback ) = $callback;
$phpCallback( $trigger, $this );
} catch ( Exception $ex ) {
call_user_func( $this->errorLogger, $ex );
$this->mTrxAutomatic = ( $mode === self::TRANSACTION_INTERNAL );
$this->mTrxAutomaticAtomic = false;
$this->mTrxAtomicLevels = [];
- $this->mTrxShortId = wfRandomString( 12 );
+ $this->mTrxShortId = sprintf( '%06x', mt_rand( 0, 0xffffff ) );
$this->mTrxWriteDuration = 0.0;
$this->mTrxWriteQueryCount = 0;
$this->mTrxWriteAdjDuration = 0.0;
public function flushSnapshot( $fname = __METHOD__ ) {
if ( $this->writesOrCallbacksPending() || $this->explicitTrxActive() ) {
// This only flushes transactions to clear snapshots, not to write data
+ $fnames = implode( ', ', $this->pendingWriteAndCallbackCallers() );
throw new DBUnexpectedError(
$this,
- "$fname: Cannot COMMIT to clear snapshot because writes are pending."
+ "$fname: Cannot COMMIT to clear snapshot because writes are pending ($fnames)."
);
}
}
public function timestamp( $ts = 0 ) {
- return wfTimestamp( TS_MW, $ts );
+ $t = new ConvertableTimestamp( $ts );
+ // Let errors bubble up to avoid putting garbage in the DB
+ return $t->getTimestamp( TS_MW );
}
public function timestampOrNull( $ts = null ) {
public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
if ( $this->writesOrCallbacksPending() ) {
// This only flushes transactions to clear snapshots, not to write data
+ $fnames = implode( ', ', $this->pendingWriteAndCallbackCallers() );
throw new DBUnexpectedError(
$this,
- "$fname: Cannot COMMIT to clear snapshot because writes are pending."
+ "$fname: Cannot COMMIT to clear snapshot because writes are pending ($fnames)."
);
}
// There is a good chance an exception was thrown, causing any early return
// from the caller. Let any error handler get a chance to issue rollback().
// If there isn't one, let the error bubble up and trigger server-side rollback.
- $this->onTransactionResolution( function () use ( $lockKey, $fname ) {
- $this->unlock( $lockKey, $fname );
- } );
+ $this->onTransactionResolution(
+ function () use ( $lockKey, $fname ) {
+ $this->unlock( $lockKey, $fname );
+ },
+ $fname
+ );
} else {
$this->unlock( $lockKey, $fname );
}
} );
- $this->commit( __METHOD__, self::FLUSHING_INTERNAL );
+ $this->commit( $fname, self::FLUSHING_INTERNAL );
return $unlocker;
}
}
public function decodeExpiry( $expiry, $format = TS_MW ) {
- return ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() )
- ? 'infinity'
- : wfTimestamp( $format, $expiry );
+ if ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() ) {
+ return 'infinity';
+ }
+
+ try {
+ $t = new ConvertableTimestamp( $expiry );
+
+ return $t->getTimestamp( $format );
+ } catch ( TimestampException $e ) {
+ return false;
+ }
}
public function setBigSelects( $value = true ) {
if ( $this->mTrxLevel && $this->mTrxDoneWrites ) {
trigger_error( "Uncommitted DB writes (transaction from {$this->mTrxFname})." );
}
- $danglingCallbacks = array_merge(
- $this->mTrxIdleCallbacks,
- $this->mTrxPreCommitCallbacks,
- $this->mTrxEndCallbacks
- );
- if ( $danglingCallbacks ) {
- $callers = [];
- foreach ( $danglingCallbacks as $callbackInfo ) {
- $callers[] = $callbackInfo[1];
- }
- $callers = implode( ', ', $callers );
- trigger_error( "DB transaction callbacks still pending (from $callers)." );
+
+ $danglingWriters = $this->pendingWriteAndCallbackCallers();
+ if ( $danglingWriters ) {
+ $fnames = implode( ', ', $danglingWriters );
+ trigger_error( "DB transaction writes or callbacks still pending ($fnames)." );
}
}
}