$totalProf = '';
$isMaster = !is_null( $this->getLBInfo( 'master' ) );
- if ( !Profiler::instance()->isStub() ) {
+ $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 ) {
# Include query transaction state
$queryProf .= $this->mTrxShortId ? " [TRX#{$this->mTrxShortId}]" : "";
- wfProfileIn( $totalProf );
- wfProfileIn( $queryProf );
+ $totalProfSection = $profiler->scopedProfileIn( $totalProf );
+ $queryProfSection = $profiler->scopedProfileIn( $queryProf );
}
if ( $this->debug() ) {
if ( $queryProf != '' ) {
$queryStartTime = microtime( true );
$queryProfile = new ScopedCallback(
- function() use ( $queryStartTime, $queryProf, $isMaster ) {
+ function () use ( $queryStartTime, $queryProf, $isMaster ) {
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$trxProfiler->recordQueryCompletion( $queryProf, $queryStartTime, $isMaster );
}
$lastError = $this->lastError();
$lastErrno = $this->lastErrno();
if ( $this->ping() ) {
- global $wgRequestTime;
wfDebug( "Reconnected\n" );
- $sqlx = $wgDebugDumpSqlLength ? substr( $commentedSql, 0, $wgDebugDumpSqlLength )
- : $commentedSql;
- $sqlx = strtr( $sqlx, "\t\n", ' ' );
- $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",
- $this->getLogContext( array(
- 'method' => __METHOD__,
- 'query' => $sqlx,
- ) )
- );
- }
+ $server = $this->getServer();
+ $msg = __METHOD__ . ": lost connection to $server; reconnected";
+ wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
+
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( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
}
- if ( !Profiler::instance()->isStub() ) {
- wfProfileOut( $queryProf );
- wfProfileOut( $totalProf );
- }
-
return $this->resultObject( $ret );
}
}
/**
- * Get the name of an index in a given table
+ * Get the name of an index in a given table.
*
+ * @protected Don't use outside of DatabaseBase and childs
* @param string $index
* @return string
*/
- protected function indexName( $index ) {
+ public function indexName( $index ) {
+ // @FIXME: Make this protected once we move away from PHP 5.3
+ // Needs to be public because of usage in closure (in DatabaseBase::replaceVars)
+
// Backwards-compatibility hack
$renamed = array(
'ar_usertext_timestamp' => 'usertext_timestamp',
*
* - '{$var}' should be used for text and is passed through the database's
* addQuotes method.
- * - `{$var}` should be used for identifiers (eg: table and database names),
- * it is passed through the database's addIdentifierQuotes method which
+ * - `{$var}` should be used for identifiers (e.g. table and database names).
+ * It is passed through the database's addIdentifierQuotes method which
* can be overridden if the database uses something other than backticks.
- * - / *$var* / is just encoded, besides traditional table prefix and
- * table options its use should be avoided.
+ * - / *_* / or / *$wgDBprefix* / passes the name that follows through the
+ * database's tableName method.
+ * - / *i* / passes the name that follows through the database's indexName method.
+ * - In all other cases, / *$var* / is left unencoded. Except for table options,
+ * its use should be avoided. In 1.24 and older, string encoding was applied.
*
* @param string $ins SQL statement to replace variables in
* @return string The new SQL statement with variables replaced
*/
- protected function replaceSchemaVars( $ins ) {
- $vars = $this->getSchemaVars();
- foreach ( $vars as $var => $value ) {
- // replace '{$var}'
- $ins = str_replace( '\'{$' . $var . '}\'', $this->addQuotes( $value ), $ins );
- // replace `{$var}`
- $ins = str_replace( '`{$' . $var . '}`', $this->addIdentifierQuotes( $value ), $ins );
- // replace /*$var*/
- $ins = str_replace( '/*$' . $var . '*/', $this->strencode( $value ), $ins );
- }
-
- return $ins;
- }
-
- /**
- * Replace variables in sourced SQL
- *
- * @param string $ins
- * @return string
- */
protected function replaceVars( $ins ) {
- $ins = $this->replaceSchemaVars( $ins );
-
- // Table prefixes
- $ins = preg_replace_callback( '!/\*(?:\$wgDBprefix|_)\*/([a-zA-Z_0-9]*)!',
- array( $this, 'tableNameCallback' ), $ins );
-
- // Index names
- $ins = preg_replace_callback( '!/\*i\*/([a-zA-Z_0-9]*)!',
- array( $this, 'indexNameCallback' ), $ins );
-
- return $ins;
+ $that = $this;
+ $vars = $this->getSchemaVars();
+ return preg_replace_callback(
+ '!
+ /\* (\$wgDBprefix|[_i]) \*/ (\w*) | # 1-2. tableName, indexName
+ \'\{\$ (\w+) }\' | # 3. addQuotes
+ `\{\$ (\w+) }` | # 4. addIdentifierQuotes
+ /\*\$ (\w+) \*/ # 5. leave unencoded
+ !x',
+ function ( $m ) use ( $that, $vars ) {
+ // Note: Because of <https://bugs.php.net/bug.php?id=51881>,
+ // check for both nonexistent keys *and* the empty string.
+ if ( isset( $m[1] ) && $m[1] !== '' ) {
+ if ( $m[1] === 'i' ) {
+ return $that->indexName( $m[2] );
+ } else {
+ return $that->tableName( $m[2] );
+ }
+ } elseif ( isset( $m[3] ) && $m[3] !== '' && array_key_exists( $m[3], $vars ) ) {
+ return $that->addQuotes( $vars[$m[3]] );
+ } elseif ( isset( $m[4] ) && $m[4] !== '' && array_key_exists( $m[4], $vars ) ) {
+ return $that->addIdentifierQuotes( $vars[$m[4]] );
+ } elseif ( isset( $m[5] ) && $m[5] !== '' && array_key_exists( $m[5], $vars ) ) {
+ return $vars[$m[5]];
+ } else {
+ return $m[0];
+ }
+ },
+ $ins
+ );
}
/**
return array();
}
- /**
- * Table name callback
- *
- * @param array $matches
- * @return string
- */
- protected function tableNameCallback( $matches ) {
- return $this->tableName( $matches[1] );
- }
-
- /**
- * Index name callback
- *
- * @param array $matches
- * @return string
- */
- protected function indexNameCallback( $matches ) {
- return $this->indexName( $matches[1] );
- }
-
/**
* Check to see if a named lock is available. This is non-blocking.
*