/** * Run an SQL query and return the result. Normally throws a DBQueryError * on failure. If errors are ignored, returns false instead. * * In new code, the query wrappers select(), insert(), update(), delete(), * etc. should be used where possible, since they give much better DBMS * independence and automatically quote or validate user input in a variety * of contexts. This function is generally only useful for queries which are * explicitly DBMS-dependent and are unsupported by the query wrappers, such * as CREATE TABLE. * * However, the query wrappers themselves should call this function. * * @param $sql String: SQL query * @param $fname String: Name of the calling function, for profiling/SHOW PROCESSLIST * comment (you can use __METHOD__ or add some extra info) * @param $tempIgnore Boolean: Whether to avoid throwing an exception on errors... * maybe best to catch the exception instead? * @throws MWException * @return boolean|ResultWrapper. true for a successful write query, ResultWrapper object * for a successful read query, or false on failure if $tempIgnore set */ public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) { global $wgUser, $wgDebugDBTransactions; $this->mLastQuery = $sql; if ( !$this->mDoneWrites && $this->isWriteQuery( $sql ) ) { # Set a flag indicating that writes have been done wfDebug( __METHOD__ . ": Writes done: $sql\n" ); $this->mDoneWrites = 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 ); # If DBO_TRX is set, start a transaction if ( ( $this->mFlags & DBO_TRX ) && !$this->mTrxLevel && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK' ) { # Avoid establishing transactions for SHOW and SET statements too - # that would delay transaction initializations to once connection # is really used by application $sqlstart = substr( $sql, 0, 10 ); // very much worth it, benchmark certified(tm) if ( strpos( $sqlstart, "SHOW " ) !== 0 && strpos( $sqlstart, "SET " ) !== 0 ) { if ( $wgDebugDBTransactions ) { wfDebug( "Implicit transaction start.\n" ); } $this->begin( __METHOD__ . " ($fname)" ); $this->mTrxAutomatic = true; } } # Keep track of whether the transaction has write queries pending if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery( $sql ) ) { $this->mTrxDoneWrites = true; Profiler::instance()->transactionWritingIn( $this->mServer, $this->mDBname ); } $isMaster = !is_null( $this->getLBInfo( 'master' ) ); if ( !Profiler::instance()->isStub() ) { # 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'; } wfProfileIn( $totalProf ); wfProfileIn( $queryProf ); } if ( $this->debug() ) { static $cnt = 0; $cnt++; $sqlx = substr( $commentedSql, 0, 500 ); $sqlx = strtr( $sqlx, "\t\n", ' ' ); $master = $isMaster ? 'master' : 'slave'; wfDebug( "Query {$this->mDBname} ($cnt) ($master): $sqlx\n" ); } $queryId = MWDebug::query( $sql, $fname, $isMaster ); # Do the query and handle errors $ret = $this->doQuery( $commentedSql ); MWDebug::queryTime( $queryId ); # Try reconnecting if the connection was lost if ( false === $ret && $this->wasErrorReissuable() ) { # Transaction is gone, like it or not $this->mTrxLevel = 0; $this->mTrxIdleCallbacks = array(); // cancel $this->mTrxPreCommitCallbacks = array(); // cancel wfDebug( "Connection lost, reconnecting...\n" ); if ( $this->ping() ) { wfDebug( "Reconnected\n" ); $sqlx = substr( $commentedSql, 0, 500 ); $sqlx = strtr( $sqlx, "\t\n", ' ' ); global $wgRequestTime; $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\n" ); } $ret = $this->doQuery( $commentedSql ); } else { wfDebug( "Failed\n" ); } } if ( false === $ret ) { $this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore ); } if ( !Profiler::instance()->isStub() ) { wfProfileOut( $queryProf ); wfProfileOut( $totalProf ); } return $this->resultObject( $ret ); }
/** * Run an SQL query and return the result. Normally throws a DBQueryError * on failure. If errors are ignored, returns false instead. * * In new code, the query wrappers select(), insert(), update(), delete(), * etc. should be used where possible, since they give much better DBMS * independence and automatically quote or validate user input in a variety * of contexts. This function is generally only useful for queries which are * explicitly DBMS-dependent and are unsupported by the query wrappers, such * as CREATE TABLE. * * However, the query wrappers themselves should call this function. * * @param string $sql SQL query * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST * comment (you can use __METHOD__ or add some extra info) * @param bool $tempIgnore Whether to avoid throwing an exception on errors... * maybe best to catch the exception instead? * @throws MWException * @return bool|ResultWrapper True for a successful write query, ResultWrapper object * for a successful read query, or false on failure if $tempIgnore set */ public function query($sql, $fname = __METHOD__, $tempIgnore = false) { global $wgUser; $this->mLastQuery = $sql; $isWriteQuery = $this->isWriteQuery($sql); if ($isWriteQuery) { $reason = $this->getReadOnlyReason(); if ($reason !== false) { throw new DBReadOnlyError($this, "Database is read-only: {$reason}"); } # Set a flag indicating that writes have been done $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); if (!$this->mTrxLevel && $this->getFlag(DBO_TRX) && $this->isTransactableQuery($sql)) { $this->begin(__METHOD__ . " ({$fname})"); $this->mTrxAutomatic = true; } # Keep track of whether the transaction has write queries pending if ($this->mTrxLevel && !$this->mTrxDoneWrites && $isWriteQuery) { $this->mTrxDoneWrites = true; $this->getTransactionProfiler()->transactionWritingIn($this->mServer, $this->mDBname, $this->mTrxShortId); } $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) { $totalProfSection = $profiler->scopedProfileIn($totalProf); $queryProfSection = $profiler->scopedProfileIn($queryProf); } if ($this->debug()) { wfDebugLog('queries', sprintf("%s: %s", $this->mDBname, $sql)); } $queryId = MWDebug::query($sql, $fname, $isMaster); # Avoid fatals if close() was called $this->assertOpen(); # Do the query and handle errors $startTime = microtime(true); $ret = $this->doQuery($commentedSql); $queryRuntime = microtime(true) - $startTime; # Log the query time and feed it into the DB trx profiler $this->getTransactionProfiler()->recordQueryCompletion($queryProf, $startTime, $isWriteQuery, $this->affectedRows()); MWDebug::queryTime($queryId); # Try reconnecting if the connection was lost if (false === $ret && $this->wasErrorReissuable()) { # Transaction is gone, like it or not $hadTrx = $this->mTrxLevel; // possible lost transaction $this->mTrxLevel = 0; $this->mTrxIdleCallbacks = array(); // bug 65263 $this->mTrxPreCommitCallbacks = array(); // bug 65263 wfDebug("Connection lost, reconnecting...\n"); # Stash the last error values since ping() might clear them $lastError = $this->lastError(); $lastErrno = $this->lastErrno(); if ($this->ping()) { wfDebug("Reconnected\n"); $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($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); $queryRuntime = microtime(true) - $startTime; # Log the query time and feed it into the DB trx profiler $this->getTransactionProfiler()->recordQueryCompletion($queryProf, $startTime, $isWriteQuery, $this->affectedRows()); } } else { wfDebug("Failed\n"); } } if (false === $ret) { $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore); } $res = $this->resultObject($ret); // Destroy profile sections in the opposite order to their creation ScopedCallback::consume($queryProfSection); ScopedCallback::consume($totalProfSection); if ($isWriteQuery && $this->mTrxLevel) { $this->mTrxWriteDuration += $queryRuntime; } return $res; }
/** * Usually aborts on failure. If errors are explicitly ignored, returns success. * * @param $sql String: SQL query * @param $fname String: Name of the calling function, for profiling/SHOW PROCESSLIST * comment (you can use __METHOD__ or add some extra info) * @param $tempIgnore Boolean: Whether to avoid throwing an exception on errors... * maybe best to catch the exception instead? * @return boolean or ResultWrapper. true for a successful write query, ResultWrapper object for a successful read query, * or false on failure if $tempIgnore set * @throws DBQueryError Thrown when the database returns an error of any kind */ public function query($sql, $fname = '', $tempIgnore = false) { global $wgProfiler; $isMaster = !is_null($this->getLBInfo('master')); if (isset($wgProfiler)) { # generalizeSQL will probably cut down the query to reasonable # logging size most of the time. The substr is really just a sanity check. # Who's been wasting my precious column space? -- TS # $profName = 'query: ' . $fname . ' ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 ); 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'; } wfProfileIn($totalProf); wfProfileIn($queryProf); } $this->mLastQuery = $sql; if (!$this->mDoneWrites && $this->isWriteQuery($sql)) { // Set a flag indicating that writes have been done wfDebug(__METHOD__ . ": Writes done: {$sql}\n"); $this->mDoneWrites = true; } # Add a comment for easy SHOW PROCESSLIST interpretation # if ( $fname ) { global $wgUser; if (is_object($wgUser) && $wgUser->mDataLoaded) { $userName = $wgUser->getName(); if (mb_strlen($userName) > 15) { $userName = mb_substr($userName, 0, 15) . '...'; } $userName = str_replace('/', '', $userName); } else { $userName = ''; } $commentedSql = preg_replace('/\\s/', " /* {$fname} {$userName} */ ", $sql, 1); # } else { # $commentedSql = $sql; # } # If DBO_TRX is set, start a transaction if ($this->mFlags & DBO_TRX && !$this->trxLevel() && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') { // avoid establishing transactions for SHOW and SET statements too - // that would delay transaction initializations to once connection // is really used by application $sqlstart = substr($sql, 0, 10); // very much worth it, benchmark certified(tm) if (strpos($sqlstart, "SHOW ") !== 0 and strpos($sqlstart, "SET ") !== 0) { $this->begin(); } } if ($this->debug()) { static $cnt = 0; $cnt++; $sqlx = substr($commentedSql, 0, 500); $sqlx = strtr($sqlx, "\t\n", ' '); if ($isMaster) { wfDebug("Query {$cnt} (master): {$sqlx}\n"); } else { wfDebug("Query {$cnt} (slave): {$sqlx}\n"); } } if (istainted($sql) & TC_MYSQL) { throw new MWException('Tainted query found'); } # Do the query and handle errors $ret = $this->doQuery($commentedSql); # Try reconnecting if the connection was lost if (false === $ret && $this->wasErrorReissuable()) { # Transaction is gone, like it or not $this->mTrxLevel = 0; wfDebug("Connection lost, reconnecting...\n"); if ($this->ping()) { wfDebug("Reconnected\n"); $sqlx = substr($commentedSql, 0, 500); $sqlx = strtr($sqlx, "\t\n", ' '); global $wgRequestTime; $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}\n"); } $ret = $this->doQuery($commentedSql); } else { wfDebug("Failed\n"); } } if (false === $ret) { $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore); } if (isset($wgProfiler)) { wfProfileOut($queryProf); wfProfileOut($totalProf); } return $this->resultObject($ret); }
/** * Run an SQL query and return the result. Normally throws a DBQueryError * on failure. If errors are ignored, returns false instead. * * In new code, the query wrappers select(), insert(), update(), delete(), * etc. should be used where possible, since they give much better DBMS * independence and automatically quote or validate user input in a variety * of contexts. This function is generally only useful for queries which are * explicitly DBMS-dependent and are unsupported by the query wrappers, such * as CREATE TABLE. * * However, the query wrappers themselves should call this function. * * @param string $sql SQL query * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST * comment (you can use __METHOD__ or add some extra info) * @param bool $tempIgnore Whether to avoid throwing an exception on errors... * maybe best to catch the exception instead? * @throws MWException * @return bool|ResultWrapper True for a successful write query, ResultWrapper object * for a successful read query, or false on failure if $tempIgnore set */ public function query($sql, $fname = __METHOD__, $tempIgnore = false) { global $wgUser, $wgDebugDBTransactions, $wgDebugDumpSqlLength; $this->mLastQuery = $sql; if ($this->isWriteQuery($sql)) { # Set a flag indicating that writes have been done wfDebug(__METHOD__ . ': Writes done: ' . DatabaseBase::generalizeSQL($sql) . "\n"); $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); # If DBO_TRX is set, start a transaction if ($this->mFlags & DBO_TRX && !$this->mTrxLevel && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') { # Avoid establishing transactions for SHOW and SET statements too - # that would delay transaction initializations to once connection # is really used by application $sqlstart = substr($sql, 0, 10); // very much worth it, benchmark certified(tm) if (strpos($sqlstart, "SHOW ") !== 0 && strpos($sqlstart, "SET ") !== 0) { if ($wgDebugDBTransactions) { wfDebug("Implicit transaction start.\n"); } $this->begin(__METHOD__ . " ({$fname})"); $this->mTrxAutomatic = true; } } # Keep track of whether the transaction has write queries pending if ($this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery($sql)) { $this->mTrxDoneWrites = true; Profiler::instance()->transactionWritingIn($this->mServer, $this->mDBname, $this->mTrxShortId); } $queryProf = ''; $totalProf = ''; $isMaster = !is_null($this->getLBInfo('master')); if (!Profiler::instance()->isStub()) { # 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}]" : ""; $trx = $this->mTrxLevel ? 'TRX=yes' : 'TRX=no'; wfProfileIn($totalProf); wfProfileIn($queryProf); } if ($this->debug()) { static $cnt = 0; $cnt++; $sqlx = $wgDebugDumpSqlLength ? substr($commentedSql, 0, $wgDebugDumpSqlLength) : $commentedSql; $sqlx = strtr($sqlx, "\t\n", ' '); $master = $isMaster ? 'master' : 'slave'; wfDebug("Query {$this->mDBname} ({$cnt}) ({$master}): {$sqlx}\n"); } $queryId = MWDebug::query($sql, $fname, $isMaster); # Avoid fatals if close() was called if (!$this->isOpen()) { throw new DBUnexpectedError($this, "DB connection was already closed."); } # Do the query and handle errors $ret = $this->doQuery($commentedSql); MWDebug::queryTime($queryId); # Try reconnecting if the connection was lost if (false === $ret && $this->wasErrorReissuable()) { # Transaction is gone, like it or not $hadTrx = $this->mTrxLevel; // possible lost transaction $this->mTrxLevel = 0; $this->mTrxIdleCallbacks = array(); // bug 65263 $this->mTrxPreCommitCallbacks = array(); // bug 65263 wfDebug("Connection lost, reconnecting...\n"); # Stash the last error values since ping() might clear them $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}"); } 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($lastError, $lastErrno, $sql, $fname, $tempIgnore); } else { # Should be safe to silently retry (no trx and thus no callbacks) $ret = $this->doQuery($commentedSql); } } else { wfDebug("Failed\n"); } } if (false === $ret) { $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore); } if (!Profiler::instance()->isStub()) { wfProfileOut($queryProf); wfProfileOut($totalProf); } return $this->resultObject($ret); }
/** * Run an SQL query and return the result. Normally throws a DBQueryError * on failure. If errors are ignored, returns false instead. * * In new code, the query wrappers select(), insert(), update(), delete(), * etc. should be used where possible, since they give much better DBMS * independence and automatically quote or validate user input in a variety * of contexts. This function is generally only useful for queries which are * explicitly DBMS-dependent and are unsupported by the query wrappers, such * as CREATE TABLE. * * However, the query wrappers themselves should call this function. * * @param string $sql : SQL query * @param string $fname : Name of the calling function, for profiling/SHOW PROCESSLIST * comment (you can use __METHOD__ or add some extra info) * @param bool $tempIgnore : Whether to avoid throwing an exception on errors... * maybe best to catch the exception instead? * * @return bool|ResultWrapper true for a successful write query, ResultWrapper object * for a successful read query, or false on failure if $tempIgnore set * * @throws DBQueryError * @throws MWException */ public function query($sql, $fname = '', $tempIgnore = false) { $isMaster = !is_null($this->getLBInfo('master')); if (!Profiler::instance()->isStub()) { # 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'; } wfProfileIn($totalProf); wfProfileIn($queryProf); } $this->mLastQuery = $sql; $is_writeable = $this->isWriteQuery($sql); if (!$this->mDoneWrites && $is_writeable) { # Set a flag indicating that writes have been done wfDebug(__METHOD__ . ": Writes done: {$sql}\n"); $this->mDoneWrites = true; } # <Wikia> global $wgDBReadOnly; if ($is_writeable && $wgDBReadOnly) { if (!Profiler::instance()->isStub()) { wfProfileOut($queryProf); wfProfileOut($totalProf); } WikiaLogger::instance()->error('DB readonly mode', ['exception' => new Exception($sql), 'server' => $this->mServer]); wfDebug(sprintf("%s: DB read-only mode prevented the following query: %s\n", __METHOD__, $sql)); return false; } # </Wikia> # Add a comment for easy SHOW PROCESSLIST interpretation global $wgUser; 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 = ''; } # Wikia change - begin # @author macbre if ($fname === '') { wfDebug("Query: \$fname autogenerated, please pass __METHOD__ to the query() call!\n"); $fname = wfGetCallerClassMethod(['WikiaSQL', 'FluentSql\\SQL', 'WikiaDataAccess', __CLASS__]); } # Wikia change - end $commentedSql = preg_replace('/\\s/', " /* {$fname} {$userName} */ ", $sql, 1); # Wikia change - begin # @author macbre # Add profiling data to queries like BEGIN or COMMIT (preg_replace above will not handle them) if (strpos($sql, ' ') === false) { $commentedSql = "{$sql} /* {$fname} {$userName} */"; } # Wikia change - end # If DBO_TRX is set, start a transaction if ($this->mFlags & DBO_TRX && !$this->trxLevel() && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') { # avoid establishing transactions for SHOW and SET statements too - # that would delay transaction initializations to once connection # is really used by application $sqlstart = substr($sql, 0, 10); // very much worth it, benchmark certified(tm) if (strpos($sqlstart, "SHOW ") !== 0 && strpos($sqlstart, "SET ") !== 0) { $this->begin(__METHOD__ . " ({$fname})"); } } if ($this->debug()) { static $cnt = 0; $cnt++; $sqlx = substr($commentedSql, 0, 500); $sqlx = strtr($sqlx, "\t\n", ' '); $master = $isMaster ? 'master' : 'slave'; wfDebug("Query {$this->mDBname} ({$cnt}) ({$master}): {$sqlx}\n"); } if (istainted($sql) & TC_MYSQL) { throw new MWException('Tainted query found'); } $ret = $this->executeAndProfileQuery($commentedSql, $fname, $isMaster); # Try reconnecting if the connection was lost if (false === $ret && $this->wasErrorReissuable()) { # Transaction is gone, like it or not $this->mTrxLevel = 0; wfDebug("Connection lost, reconnecting...\n"); if ($this->ping()) { wfDebug("Reconnected\n"); $sqlx = substr($commentedSql, 0, 500); $sqlx = strtr($sqlx, "\t\n", ' '); global $wgRequestTime; $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}\n"); } $ret = $this->executeAndProfileQuery($commentedSql, $fname, $isMaster); } else { wfDebug("Failed\n"); } } if (false === $ret) { $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore); } if (!Profiler::instance()->isStub()) { wfProfileOut($queryProf); wfProfileOut($totalProf); } return $this->resultObject($ret); }