global $wgAutoloadLocalClasses;
$wgAutoloadLocalClasses = array(
- 'APCBagOStuff' => __DIR__ . '/includes/objectcache/APCBagOStuff.php',
+ 'APCBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCBagOStuff.php',
'AbstractContent' => __DIR__ . '/includes/content/AbstractContent.php',
'Action' => __DIR__ . '/includes/actions/Action.php',
'ActiveUsersPager' => __DIR__ . '/includes/specials/SpecialActiveusers.php',
'AnsiTermColorer' => __DIR__ . '/maintenance/term/MWTerm.php',
'ApiBase' => __DIR__ . '/includes/api/ApiBase.php',
'ApiBlock' => __DIR__ . '/includes/api/ApiBlock.php',
+ 'ApiCheckToken' => __DIR__ . '/includes/api/ApiCheckToken.php',
'ApiClearHasMsg' => __DIR__ . '/includes/api/ApiClearHasMsg.php',
'ApiComparePages' => __DIR__ . '/includes/api/ApiComparePages.php',
'ApiCreateAccount' => __DIR__ . '/includes/api/ApiCreateAccount.php',
'ApiLogin' => __DIR__ . '/includes/api/ApiLogin.php',
'ApiLogout' => __DIR__ . '/includes/api/ApiLogout.php',
'ApiMain' => __DIR__ . '/includes/api/ApiMain.php',
+ 'ApiManageTags' => __DIR__ . '/includes/api/ApiManageTags.php',
'ApiModuleManager' => __DIR__ . '/includes/api/ApiModuleManager.php',
'ApiMove' => __DIR__ . '/includes/api/ApiMove.php',
'ApiOpenSearch' => __DIR__ . '/includes/api/ApiOpenSearch.php',
'BackupDumper' => __DIR__ . '/maintenance/backup.inc',
'BackupReader' => __DIR__ . '/maintenance/importDump.php',
'BadTitleError' => __DIR__ . '/includes/exception/BadTitleError.php',
- 'BagOStuff' => __DIR__ . '/includes/objectcache/BagOStuff.php',
+ 'BagOStuff' => __DIR__ . '/includes/libs/objectcache/BagOStuff.php',
'BaseDump' => __DIR__ . '/maintenance/backupPrefetch.inc',
'BaseTemplate' => __DIR__ . '/includes/skins/BaseTemplate.php',
'BatchedQueryRunner' => __DIR__ . '/maintenance/runBatchedQuery.php',
'Blob' => __DIR__ . '/includes/db/DatabaseUtility.php',
'Block' => __DIR__ . '/includes/Block.php',
'BlockListPager' => __DIR__ . '/includes/specials/SpecialBlockList.php',
+ 'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
'BloomCache' => __DIR__ . '/includes/cache/bloom/BloomCache.php',
'BloomCacheRedis' => __DIR__ . '/includes/cache/bloom/BloomCacheRedis.php',
'BloomFilterTitleHasLogs' => __DIR__ . '/includes/cache/bloom/BloomFilters.php',
'DumpPipeOutput' => __DIR__ . '/includes/Export.php',
'DumpRenderer' => __DIR__ . '/maintenance/renderDump.php',
'DumpRev' => __DIR__ . '/maintenance/storage/dumpRev.php',
- 'DumpSisterSites' => __DIR__ . '/maintenance/dumpSisterSites.php',
'DuplicateJob' => __DIR__ . '/includes/jobqueue/jobs/DuplicateJob.php',
'EditAction' => __DIR__ . '/includes/actions/EditAction.php',
'EditCLI' => __DIR__ . '/maintenance/edit.php',
'EmailInvalidation' => __DIR__ . '/includes/specials/SpecialConfirmemail.php',
'EmailNotification' => __DIR__ . '/includes/mail/EmailNotification.php',
'EmaillingJob' => __DIR__ . '/includes/jobqueue/jobs/EmaillingJob.php',
- 'EmptyBagOStuff' => __DIR__ . '/includes/objectcache/EmptyBagOStuff.php',
+ 'EmptyBagOStuff' => __DIR__ . '/includes/libs/objectcache/EmptyBagOStuff.php',
'EmptyBloomCache' => __DIR__ . '/includes/cache/bloom/BloomCache.php',
'EncryptedPassword' => __DIR__ . '/includes/password/EncryptedPassword.php',
'EnhancedChangesList' => __DIR__ . '/includes/changes/EnhancedChangesList.php',
'ExifBitmapHandler' => __DIR__ . '/includes/media/ExifBitmap.php',
'ExplodeIterator' => __DIR__ . '/includes/libs/ExplodeIterator.php',
'ExportProgressFilter' => __DIR__ . '/maintenance/backup.inc',
+ 'ExportSites' => __DIR__ . '/maintenance/exportSites.php',
'ExtensionLanguages' => __DIR__ . '/maintenance/language/languages.inc',
'ExtensionProcessor' => __DIR__ . '/includes/registration/ExtensionProcessor.php',
'ExtensionRegistry' => __DIR__ . '/includes/registration/ExtensionRegistry.php',
'HTMLTextAreaField' => __DIR__ . '/includes/htmlform/HTMLTextAreaField.php',
'HTMLTextField' => __DIR__ . '/includes/htmlform/HTMLTextField.php',
'HWLDFWordAccumulator' => __DIR__ . '/includes/diff/DairikiDiff.php',
- 'HashBagOStuff' => __DIR__ . '/includes/objectcache/HashBagOStuff.php',
+ 'HashBagOStuff' => __DIR__ . '/includes/libs/objectcache/HashBagOStuff.php',
'HashConfig' => __DIR__ . '/includes/config/HashConfig.php',
'HashRing' => __DIR__ . '/includes/libs/HashRing.php',
'HashtableReplacer' => __DIR__ . '/includes/libs/replacers/HashtableReplacer.php',
'ImageQueryPage' => __DIR__ . '/includes/specialpage/ImageQueryPage.php',
'ImportReporter' => __DIR__ . '/includes/specials/SpecialImport.php',
'ImportSiteScripts' => __DIR__ . '/maintenance/importSiteScripts.php',
+ 'ImportSites' => __DIR__ . '/maintenance/importSites.php',
+ 'ImportSource' => __DIR__ . '/includes/Import.php',
'ImportStreamSource' => __DIR__ . '/includes/Import.php',
'ImportStringSource' => __DIR__ . '/includes/Import.php',
'ImportTitleFactory' => __DIR__ . '/includes/title/ImportTitleFactory.php',
'MWLoggerMonologProcessor' => __DIR__ . '/includes/debug/logger/monolog/Processor.php',
'MWLoggerMonologSamplingHandler' => __DIR__ . '/includes/debug/logger/monolog/SamplingHandler.php',
'MWLoggerMonologSpi' => __DIR__ . '/includes/debug/logger/monolog/Spi.php',
+ 'MWLoggerMonologSyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/SyslogHandler.php',
'MWLoggerNullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
'MWLoggerSpi' => __DIR__ . '/includes/debug/logger/Spi.php',
'MWMemcached' => __DIR__ . '/includes/objectcache/MemcachedClient.php',
'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformOutput.php',
+ 'MediaTransformInvalidParametersException' => __DIR__ . '/includes/media/MediaTransformInvalidParametersException.php',
'MediaTransformOutput' => __DIR__ . '/includes/media/MediaTransformOutput.php',
'MediaWiki' => __DIR__ . '/includes/MediaWiki.php',
- 'MediaWikiBagOStuff' => __DIR__ . '/includes/objectcache/SqlBagOStuff.php',
'MediaWikiI18N' => __DIR__ . '/includes/skins/MediaWikiI18N.php',
'MediaWikiPageLinkRenderer' => __DIR__ . '/includes/title/MediaWikiPageLinkRenderer.php',
'MediaWikiSite' => __DIR__ . '/includes/site/MediaWikiSite.php',
'MessageBlobStore' => __DIR__ . '/includes/MessageBlobStore.php',
'MessageCache' => __DIR__ . '/includes/cache/MessageCache.php',
'MessageContent' => __DIR__ . '/includes/content/MessageContent.php',
+ 'MessageSpecifier' => __DIR__ . '/includes/libs/MessageSpecifier.php',
'MigrateUserGroup' => __DIR__ . '/maintenance/migrateUserGroup.php',
'MimeMagic' => __DIR__ . '/includes/MimeMagic.php',
'MinifyScript' => __DIR__ . '/maintenance/minify.php',
'PopulateRevisionLength' => __DIR__ . '/maintenance/populateRevisionLength.php',
'PopulateRevisionSha1' => __DIR__ . '/maintenance/populateRevisionSha1.php',
'PostgreSqlLockManager' => __DIR__ . '/includes/filebackend/lockmanager/DBLockManager.php',
+ 'PostgresBlob' => __DIR__ . '/includes/db/DatabasePostgres.php',
'PostgresField' => __DIR__ . '/includes/db/DatabasePostgres.php',
'PostgresInstaller' => __DIR__ . '/includes/installer/PostgresInstaller.php',
'PostgresTransactionState' => __DIR__ . '/includes/db/DatabasePostgres.php',
'RebuildSitesCache' => __DIR__ . '/maintenance/rebuildSitesCache.php',
'RebuildTextIndex' => __DIR__ . '/maintenance/rebuildtextindex.php',
'RecentChange' => __DIR__ . '/includes/changes/RecentChange.php',
+ 'RecentChangesUpdateJob' => __DIR__ . '/includes/jobqueue/jobs/RecentChangesUpdateJob.php',
'RecompressTracked' => __DIR__ . '/maintenance/storage/recompressTracked.php',
'RedirectSpecialArticle' => __DIR__ . '/includes/specialpage/RedirectSpecialPage.php',
'RedirectSpecialPage' => __DIR__ . '/includes/specialpage/RedirectSpecialPage.php',
'RefreshImageMetadata' => __DIR__ . '/maintenance/refreshImageMetadata.php',
'RefreshLinks' => __DIR__ . '/maintenance/refreshLinks.php',
'RefreshLinksJob' => __DIR__ . '/includes/jobqueue/jobs/RefreshLinksJob.php',
- 'RefreshLinksJob2' => __DIR__ . '/includes/jobqueue/jobs/RefreshLinksJob2.php',
'RegexlikeReplacer' => __DIR__ . '/includes/libs/replacers/RegexlikeReplacer.php',
'RemoveInvalidEmails' => __DIR__ . '/maintenance/removeInvalidEmails.php',
'RemoveUnusedAccounts' => __DIR__ . '/maintenance/removeUnusedAccounts.php',
'RenderAction' => __DIR__ . '/includes/actions/RenderAction.php',
'ReplacementArray' => __DIR__ . '/includes/libs/ReplacementArray.php',
'Replacer' => __DIR__ . '/includes/libs/replacers/Replacer.php',
+ 'ReplicatedBagOStuff' => __DIR__ . '/includes/objectcache/ReplicatedBagOStuff.php',
'RepoGroup' => __DIR__ . '/includes/filerepo/RepoGroup.php',
'RequestContext' => __DIR__ . '/includes/context/RequestContext.php',
'ResetUserTokens' => __DIR__ . '/maintenance/resetUserTokens.php',
'Site' => __DIR__ . '/includes/site/Site.php',
'SiteArray' => __DIR__ . '/includes/site/SiteList.php',
'SiteConfiguration' => __DIR__ . '/includes/SiteConfiguration.php',
+ 'SiteExporter' => __DIR__ . '/includes/site/SiteExporter.php',
+ 'SiteImporter' => __DIR__ . '/includes/site/SiteImporter.php',
'SiteList' => __DIR__ . '/includes/site/SiteList.php',
'SiteListFileCache' => __DIR__ . '/includes/site/SiteListFileCache.php',
'SiteListFileCacheBuilder' => __DIR__ . '/includes/site/SiteListFileCacheBuilder.php',
'StatCounter' => __DIR__ . '/includes/StatCounter.php',
'StatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
'Status' => __DIR__ . '/includes/Status.php',
+ 'StatusValue' => __DIR__ . '/includes/libs/StatusValue.php',
'StorageTypeStats' => __DIR__ . '/maintenance/storage/storageTypeStats.php',
'StoreFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'StreamFile' => __DIR__ . '/includes/StreamFile.php',
'TablePager' => __DIR__ . '/includes/pager/TablePager.php',
'TempFSFile' => __DIR__ . '/includes/filebackend/TempFSFile.php',
'TempFileRepo' => __DIR__ . '/includes/filerepo/FileRepo.php',
+ 'TemplateParser' => __DIR__ . '/includes/TemplateParser.php',
'TestFileOpPerformance' => __DIR__ . '/maintenance/fileOpPerfTest.php',
'TextContent' => __DIR__ . '/includes/content/TextContent.php',
'TextContentHandler' => __DIR__ . '/includes/content/TextContentHandler.php',
'WikiStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
'WikitextContent' => __DIR__ . '/includes/content/WikitextContent.php',
'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
- 'WinCacheBagOStuff' => __DIR__ . '/includes/objectcache/WinCacheBagOStuff.php',
+ 'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
'WithoutInterwikiPage' => __DIR__ . '/includes/specials/SpecialWithoutinterwiki.php',
'WordLevelDiff' => __DIR__ . '/includes/diff/DairikiDiff.php',
'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
'XCFHandler' => __DIR__ . '/includes/media/XCF.php',
- 'XCacheBagOStuff' => __DIR__ . '/includes/objectcache/XCacheBagOStuff.php',
+ 'XCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/XCacheBagOStuff.php',
'XMLRCFeedFormatter' => __DIR__ . '/includes/rcfeed/XMLRCFeedFormatter.php',
'XMPInfo' => __DIR__ . '/includes/media/XMPInfo.php',
'XMPReader' => __DIR__ . '/includes/media/XMP.php',
/** Maximum time to wait before retry */
const DEADLOCK_DELAY_MAX = 1500000;
- /** How many row changes in a write query trigger a log entry */
- const LOG_WRITE_THRESHOLD = 300;
-
protected $mLastQuery = '';
protected $mDoneWrites = false;
protected $mPHPError = false;
*
* @param array $params Parameters passed from DatabaseBase::factory()
*/
- function __construct( $params = null ) {
+ function __construct( array $params ) {
global $wgDBprefix, $wgDBmwschema, $wgCommandLineMode, $wgDebugDBTransactions;
$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;
- }
+ $server = $params['host'];
+ $user = $params['user'];
+ $password = $params['password'];
+ $dbName = $params['dbname'];
+ $flags = $params['flags'];
+ $tablePrefix = $params['tablePrefix'];
+ $schema = $params['schema'];
+ $foreign = $params['foreign'];
$this->mFlags = $flags;
if ( $this->mFlags & DBO_DEFAULT ) {
if ( $user ) {
$this->open( $server, $user, $password, $dbName );
}
+
+ $isMaster = !is_null( $this->getLBInfo( 'master' ) );
+ $trxProf = Profiler::instance()->getTransactionProfiler();
+ $trxProf->recordConnection( $this->mServer, $this->mDBname, $isMaster );
}
/**
$class = 'Database' . ucfirst( $driver );
if ( class_exists( $class ) && is_subclass_of( $class, 'DatabaseBase' ) ) {
- $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 );
+ // Resolve some defaults for b/c
+ $p['host'] = isset( $p['host'] ) ? $p['host'] : false;
+ $p['user'] = isset( $p['user'] ) ? $p['user'] : false;
+ $p['password'] = isset( $p['password'] ) ? $p['password'] : false;
+ $p['dbname'] = isset( $p['dbname'] ) ? $p['dbname'] : false;
+ $p['flags'] = isset( $p['flags'] ) ? $p['flags'] : 0;
+ $p['tablePrefix'] = isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global';
+ $p['schema'] = isset( $p['schema'] ) ? $p['schema'] : $defaultSchemas[$dbType];
+ $p['foreign'] = isset( $p['foreign'] ) ? $p['foreign'] : false;
+
+ return new $class( $p );
} else {
return null;
}
$isWriteQuery = $this->isWriteQuery( $sql );
if ( $isWriteQuery ) {
+ if ( !$this->mDoneWrites ) {
+ wfDebug( __METHOD__ . ': Writes done: ' .
+ DatabaseBase::generalizeSQL( $sql ) . "\n" );
+ }
# Set a flag indicating that writes have been done
- wfDebug( __METHOD__ . ': Writes done: ' . DatabaseBase::generalizeSQL( $sql ) . "\n" );
$this->mDoneWrites = microtime( true );
}
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
- $queryProf = '';
- $totalProf = '';
$isMaster = !is_null( $this->getLBInfo( 'master' ) );
+ # generalizeSQL will probably cut down the query to reasonable
+ # logging size most of the time. The substr is really just a sanity check.
+ if ( $isMaster ) {
+ $queryProf = 'query-m: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
+ $totalProf = 'DatabaseBase::query-master';
+ } else {
+ $queryProf = 'query: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
+ $totalProf = 'DatabaseBase::query';
+ }
+ # Include query transaction state
+ $queryProf .= $this->mTrxShortId ? " [TRX#{$this->mTrxShortId}]" : "";
$profiler = Profiler::instance();
if ( !$profiler instanceof ProfilerStub ) {
- # generalizeSQL will probably cut down the query to reasonable
- # logging size most of the time. The substr is really just a sanity check.
- if ( $isMaster ) {
- $queryProf = 'query-m: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
- $totalProf = 'DatabaseBase::query-master';
- } else {
- $queryProf = 'query: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
- $totalProf = 'DatabaseBase::query';
- }
- # Include query transaction state
- $queryProf .= $this->mTrxShortId ? " [TRX#{$this->mTrxShortId}]" : "";
-
$totalProfSection = $profiler->scopedProfileIn( $totalProf );
$queryProfSection = $profiler->scopedProfileIn( $queryProf );
}
throw new DBUnexpectedError( $this, "DB connection was already closed." );
}
- # Log the query time and feed it into the DB trx profiler
- if ( $queryProf != '' ) {
- $queryStartTime = microtime( true );
- $queryProfile = new ScopedCallback(
- function () use ( $queryStartTime, $queryProf, $isMaster ) {
- $trxProfiler = Profiler::instance()->getTransactionProfiler();
- $trxProfiler->recordQueryCompletion( $queryProf, $queryStartTime, $isMaster );
- }
- );
- }
-
# Do the query and handle errors
+ $startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
+ # Log the query time and feed it into the DB trx profiler
+ $profiler->getTransactionProfiler()->recordQueryCompletion(
+ $queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
MWDebug::queryTime( $queryId );
$this->reportQueryError( $lastError, $lastErrno, $sql, $fname, $tempIgnore );
} else {
# Should be safe to silently retry (no trx and thus no callbacks)
+ $startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
+ # Log the query time and feed it into the DB trx profiler
+ $profiler->getTransactionProfiler()->recordQueryCompletion(
+ $queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
}
} else {
wfDebug( "Failed\n" );
}
if ( false === $ret ) {
- $this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
- } else {
- $n = $this->affectedRows();
- if ( $isWriteQuery && $n > self::LOG_WRITE_THRESHOLD && PHP_SAPI !== 'cli' ) {
- wfDebugLog( 'DBPerformance',
- "Query affected $n rows:\n" .
- DatabaseBase::generalizeSQL( $sql ) . "\n" . wfBacktrace( true ) );
- }
+ $this->reportQueryError(
+ $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
}
$res = $this->resultObject( $ret );
*
* @return bool|mixed The value from the field, or false on failure.
*/
- public function selectField( $table, $var, $cond = '', $fname = __METHOD__,
- $options = array()
+ public function selectField(
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array()
) {
+ if ( $var === '*' ) { // sanity
+ throw new DBUnexpectedError( $this, "Cannot use a * field: got '$var'" );
+ }
+
if ( !is_array( $options ) ) {
$options = array( $options );
}
$options['LIMIT'] = 1;
$res = $this->select( $table, $var, $cond, $fname, $options );
-
if ( $res === false || !$this->numRows( $res ) ) {
return false;
}
}
}
+ /**
+ * A SELECT wrapper which returns a list of single field values from result rows.
+ *
+ * Usually throws a DBQueryError on failure. If errors are explicitly
+ * ignored, returns false on failure.
+ *
+ * If no result rows are returned from the query, false is returned.
+ *
+ * @param string|array $table Table name. See DatabaseBase::select() for details.
+ * @param string $var The field name to select. This must be a valid SQL
+ * fragment: do not use unvalidated user input.
+ * @param string|array $cond The condition array. See DatabaseBase::select() for details.
+ * @param string $fname The function name of the caller.
+ * @param string|array $options The query options. See DatabaseBase::select() for details.
+ *
+ * @return bool|array The values from the field, or false on failure
+ * @since 1.25
+ */
+ public function selectFieldValues(
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array()
+ ) {
+ if ( $var === '*' ) { // sanity
+ throw new DBUnexpectedError( $this, "Cannot use a * field: got '$var'" );
+ }
+
+ if ( !is_array( $options ) ) {
+ $options = array( $options );
+ }
+
+ $res = $this->select( $table, $var, $cond, $fname, $options );
+ if ( $res === false ) {
+ return false;
+ }
+
+ $values = array();
+ foreach ( $res as $row ) {
+ $values[] = $row->$var;
+ }
+
+ return $values;
+ }
+
/**
* Returns an optional USE INDEX clause to go after the table, and a
* string to go at the end of the query.
* - If the value of such an array element is a scalar (such as a
* string), it will be treated as data and thus quoted appropriately.
* If it is null, an IS NULL clause will be added.
- * - If the value is an array, an IN(...) clause will be constructed,
- * such that the field name may match any of the elements in the
- * array. The elements of the array will be quoted.
+ * - If the value is an array, an IN (...) clause will be constructed
+ * from its non-null elements, and an IS NULL clause will be added
+ * if null is present, such that the field may match any of the
+ * elements in the array. The non-null elements will be quoted.
*
* Note that expressions are often DBMS-dependent in their syntax.
* DBMS-independent wrappers are provided for constructing several types of
if ( $res ) {
$row = $this->fetchRow( $res );
- $rows = ( isset( $row['rowcount'] ) ) ? $row['rowcount'] : 0;
+ $rows = ( isset( $row['rowcount'] ) ) ? (int)$row['rowcount'] : 0;
}
return $rows;
if ( $res ) {
$row = $this->fetchRow( $res );
- $rows = ( isset( $row['rowcount'] ) ) ? $row['rowcount'] : 0;
+ $rows = ( isset( $row['rowcount'] ) ) ? (int)$row['rowcount'] : 0;
}
return $rows;
/**
* Adds quotes and backslashes.
*
- * @param string $s
+ * @param string|Blob $s
* @return string
*/
public function addQuotes( $s ) {
+ if ( $s instanceof Blob ) {
+ $s = $s->fetch();
+ }
if ( $s === null ) {
return 'NULL';
} else {
* in result objects. Pass the object through this function to return the
* original string.
*
- * @param string $b
+ * @param string|Blob $b
* @return string
*/
public function decodeBlob( $b ) {
+ if ( $b instanceof Blob ) {
+ $b = $b->fetch();
+ }
return $b;
}
$row = $this->fetchRow( $res );
if ( isset( $row['EstimateRows'] ) ) {
- $rows = $row['EstimateRows'];
+ $rows = (int)$row['EstimateRows'];
}
}
'DatabaseBase::makeList called with incorrect parameters' );
}
- $first = true;
- $list = '';
+ if ( $mode != LIST_NAMES ) {
+ // In MS SQL, values need to be specially encoded when they are
+ // inserted into binary fields. Perform this necessary encoding
+ // for the specified set of columns.
+ foreach ( array_keys( $a ) as $field ) {
+ if ( !isset( $binaryColumns[$field] ) ) {
+ continue;
+ }
- foreach ( $a as $field => $value ) {
- if ( $mode != LIST_NAMES && isset( $binaryColumns[$field] ) ) {
- if ( is_array( $value ) ) {
- foreach ( $value as &$v ) {
+ if ( is_array( $a[$field] ) ) {
+ foreach ( $a[$field] as &$v ) {
$v = new MssqlBlob( $v );
}
+ unset( $v );
} else {
- $value = new MssqlBlob( $value );
- }
- }
-
- if ( !$first ) {
- if ( $mode == LIST_AND ) {
- $list .= ' AND ';
- } elseif ( $mode == LIST_OR ) {
- $list .= ' OR ';
- } else {
- $list .= ',';
- }
- } else {
- $first = false;
- }
-
- if ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_numeric( $field ) ) {
- $list .= "($value)";
- } elseif ( ( $mode == LIST_SET ) && is_numeric( $field ) ) {
- $list .= "$value";
- } elseif ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_array( $value ) ) {
- if ( count( $value ) == 0 ) {
- throw new MWException( __METHOD__ . ": empty input for field $field" );
- } elseif ( count( $value ) == 1 ) {
- // Special-case single values, as IN isn't terribly efficient
- // Don't necessarily assume the single key is 0; we don't
- // enforce linear numeric ordering on other arrays here.
- $value = array_values( $value );
- $list .= $field . " = " . $this->addQuotes( $value[0] );
- } else {
- $list .= $field . " IN (" . $this->makeList( $value ) . ") ";
- }
- } elseif ( $value === null ) {
- if ( $mode == LIST_AND || $mode == LIST_OR ) {
- $list .= "$field IS ";
- } elseif ( $mode == LIST_SET ) {
- $list .= "$field = ";
- }
- $list .= 'NULL';
- } else {
- if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
- $list .= "$field = ";
+ $a[$field] = new MssqlBlob( $a[$field] );
}
- $list .= $mode == LIST_NAMES ? $value : $this->addQuotes( $value );
}
}
- return $list;
+ return parent::makeList( $a, $mode );
}
/**
}
/**
- * @param string $s
+ * @param string|Blob $s
* @return string
*/
public function addQuotes( $s ) {
$row = $this->fetchRow( $res );
$count = array();
if ( preg_match( '/rows=(\d+)/', $row[0], $count ) ) {
- $rows = $count[1];
+ $rows = (int)$count[1];
}
}
* @return Blob
*/
function encodeBlob( $b ) {
- return new Blob( pg_escape_bytea( $this->mConn, $b ) );
+ return new PostgresBlob( pg_escape_bytea( $b ) );
}
function decodeBlob( $b ) {
- if ( $b instanceof Blob ) {
+ if ( $b instanceof PostgresBlob ) {
$b = $b->fetch();
+ } elseif ( $b instanceof Blob ) {
+ return $b->fetch();
}
return pg_unescape_bytea( $b );
} elseif ( is_bool( $s ) ) {
return intval( $s );
} elseif ( $s instanceof Blob ) {
- return "'" . $s->fetch( $s ) . "'";
+ if ( $s instanceof PostgresBlob ) {
+ $s = $s->fetch();
+ } else {
+ $s = pg_escape_bytea( $this->mConn, $s->fetch() );
+ }
+ return "'$s'";
}
return "'" . pg_escape_string( $this->mConn, $s ) . "'";
return wfBaseConvert( substr( sha1( $lockName ), 0, 15 ), 16, 10 );
}
} // end DatabasePostgres class
+
+ class PostgresBlob extends Blob {}