return $this->mDoneWrites ?: false;
}
+ /**
+ * @return bool Whether there is a transaction open with possible write queries
+ * @since 1.27
+ */
+ public function writesPending() {
+ return $this->mTrxLevel && $this->mTrxDoneWrites;
+ }
+
/**
* Returns true if there is a transaction open with possible write
* queries or transaction pre-commit/idle callbacks waiting on it to finish.
function __construct( array $params ) {
global $wgDBprefix, $wgDBmwschema, $wgCommandLineMode;
- $this->mTrxAtomicLevels = new SplStack;
- $this->srvCache = ObjectCache::newAccelerator( 'hash' );
+ $this->srvCache = ObjectCache::getLocalServerInstance( 'hash' );
$server = $params['host'];
$user = $params['user'];
$isWriteQuery = $this->isWriteQuery( $sql );
if ( $isWriteQuery ) {
- $reason = $this->getLBInfo( 'readOnlyReason' );
- if ( is_string( $reason ) ) {
+ $reason = $this->getReadOnlyReason();
+ if ( $reason !== false ) {
throw new DBReadOnlyError( $this, "Database is read-only: $reason" );
}
# Set a flag indicating that writes have been done
}
if ( $this->debug() ) {
- wfDebugLog( 'queries', sprintf( "%s: %s", $this->mDBname, $sql ) );
+ wfDebugLog( 'queries', sprintf( "%s: %s", $this->mDBname, $commentedSql ) );
}
$queryId = MWDebug::query( $sql, $fname, $isMaster );
*
* Takes the same arguments as DatabaseBase::select().
*
- * @param string $table Table name
+ * @since 1.27 Added $join_conds parameter
+ *
+ * @param array|string $tables Table names
* @param string $vars Unused
* @param array|string $conds Filters on the table
* @param string $fname Function name for profiling
* @param array $options Options for select
+ * @param array $join_conds Join conditions (since 1.27)
* @return int Row count
- * @since 1.24
*/
public function selectRowCount(
- $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ $tables, $vars = '*', $conds = '', $fname = __METHOD__, $options = array(), $join_conds = array()
) {
$rows = 0;
- $sql = $this->selectSQLText( $table, '1', $conds, $fname, $options );
+ $sql = $this->selectSQLText( $tables, '1', $conds, $fname, $options, $join_conds );
$res = $this->query( "SELECT COUNT(*) AS rowcount FROM ($sql) tmp_count", $fname );
if ( $res ) {
MWExceptionHandler::logException( $ePrior );
}
$ePrior = $e;
+ // Some callbacks may use startAtomic/endAtomic, so make sure
+ // their transactions are ended so other callbacks don't fail
+ if ( $this->trxLevel() ) {
+ $this->rollback( __METHOD__ );
+ }
}
}
} while ( count( $this->mTrxIdleCallbacks ) );
$levels = implode( ', ', $this->mTrxAtomicLevels );
throw new DBUnexpectedError(
$this,
- "Got explicit BEGIN while atomic sections $levels are still open."
+ "Got explicit BEGIN from $fname while atomic section(s) $levels are open."
);
} elseif ( !$this->mTrxAutomatic ) {
// We want to warn about inadvertently nested begin/commit pairs, but not about
*
* @param IDatabase $db1
* @param IDatabase ...
- * @return array ('lag': highest lag, 'since': lowest estimate UNIX timestamp)
+ * @return array Map of values:
+ * - lag: highest lag of any of the DBs
+ * - since: oldest UNIX timestamp of any of the DB lag estimates
+ * - pending: whether any of the DBs have uncommitted changes
* @since 1.27
*/
public static function getCacheSetOptions( IDatabase $db1 ) {
- $res = array( 'lag' => 0, 'since' => INF );
+ $res = array( 'lag' => 0, 'since' => INF, 'pending' => false );
foreach ( func_get_args() as $db ) {
/** @var IDatabase $db */
$status = $db->getSessionLagStatus();
$res['lag'] = max( $res['lag'], $status['lag'] );
$res['since'] = min( $res['since'], $status['since'] );
+ $res['pending'] = $res['pending'] ?: $db->writesPending();
}
return $res;
// no-op
}
+ public function isReadOnly() {
+ return ( $this->getReadOnlyReason() !== false );
+ }
+
+ /**
+ * @return string|bool Reason this DB is read-only or false if it is not
+ */
+ protected function getReadOnlyReason() {
+ $reason = $this->getLBInfo( 'readOnlyReason' );
+
+ return is_string( $reason ) ? $reason : false;
+ }
+
/**
* @since 1.19
* @return string