/** 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;
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 );
}
/**
$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;
try {
$error = $this->sourceStream( $fp, $lineCallback, $resultCallback, $fname, $inputCallback );
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
fclose( $fp );
throw $e;
}