X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=includes%2Fdb%2FDatabase.php;h=db050f2df5a389addb02f8da2c30a4bd9b13af0f;hb=74869fe26d75a11c47bb54d3f380988f7e11b7c6;hp=5271208fb24d9ceacf9c6c0640d499b237752e2f;hpb=95166fa0b45e3bff875349c7c946567ea843cbbc;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/db/Database.php b/includes/db/Database.php index 5271208fb2..db050f2df5 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -266,6 +266,14 @@ abstract class DatabaseBase implements DatabaseType { */ private $mTrxDoneWrites = false; + /** + * Record if the current transaction was started implicitly due to DBO_TRX being set. + * + * @var Bool + * @see DatabaseBase::mTrxLevel + */ + private $mTrxAutomatic = false; + # ------------------------------------------------------------------------------ # Accessors # ------------------------------------------------------------------------------ @@ -282,6 +290,13 @@ abstract class DatabaseBase implements DatabaseType { return $this->getServerVersion(); } + /** + * @return string: command delimiter used by this database engine + */ + public function getDelimiter() { + return $this->delimiter; + } + /** * Boolean, controls output of large amounts of debug information. * @param $debug bool|null @@ -745,8 +760,14 @@ abstract class DatabaseBase implements DatabaseType { $this->mOpened = false; if ( $this->mConn ) { if ( $this->trxLevel() ) { - $this->commit( __METHOD__ ); + if ( !$this->mTrxAutomatic ) { + wfWarn( "Transaction still in progress (from {$this->mTrxFname}), " . + " performing implicit commit before closing connection!" ); + } + + $this->commit( __METHOD__, 'flush' ); } + $ret = $this->closeConnection(); $this->mConn = false; return $ret; @@ -764,6 +785,7 @@ abstract class DatabaseBase implements DatabaseType { /** * @param $error String: fallback error message, used if none is given by DB + * @throws DBConnectionError */ function reportConnectionError( $error = 'Unknown error' ) { $myError = $this->lastError(); @@ -813,9 +835,9 @@ abstract class DatabaseBase implements DatabaseType { * 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 - * @throws DBQueryError Thrown when the database returns an error of any kind */ public function query( $sql, $fname = '', $tempIgnore = false ) { $isMaster = !is_null( $this->getLBInfo( 'master' ) ); @@ -869,6 +891,7 @@ abstract class DatabaseBase implements DatabaseType { wfDebug("Implicit transaction start.\n"); } $this->begin( __METHOD__ . " ($fname)" ); + $this->mTrxAutomatic = true; } } @@ -903,6 +926,7 @@ abstract class DatabaseBase implements DatabaseType { if ( false === $ret && $this->wasErrorReissuable() ) { # Transaction is gone, like it or not $this->mTrxLevel = 0; + $this->trxIdleCallbacks = array(); // cancel wfDebug( "Connection lost, reconnecting...\n" ); if ( $this->ping() ) { @@ -942,6 +966,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $sql String * @param $fname String * @param $tempIgnore Boolean + * @throws DBQueryError */ public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { # Ignore errors during error handling to avoid infinite recursion @@ -1028,6 +1053,7 @@ abstract class DatabaseBase implements DatabaseType { * while we're doing this. * * @param $matches Array + * @throws DBUnexpectedError * @return String */ protected function fillPreparedArg( $matches ) { @@ -1743,7 +1769,7 @@ abstract class DatabaseBase implements DatabaseType { /** * Makes an encoded list of strings from an array * @param $a Array containing the data - * @param $mode int Constant + * @param int $mode Constant * - LIST_COMMA: comma separated, no field names * - LIST_AND: ANDed WHERE clause (without the WHERE). See * the documentation for $conds in DatabaseBase::select(). @@ -1751,6 +1777,7 @@ abstract class DatabaseBase implements DatabaseType { * - LIST_SET: comma separated with field names, like a SET clause * - LIST_NAMES: comma separated field names * + * @throws MWException|DBUnexpectedError * @return string */ public function makeList( $a, $mode = LIST_COMMA ) { @@ -1780,7 +1807,7 @@ abstract class DatabaseBase implements DatabaseType { $list .= "$value"; } elseif ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_array( $value ) ) { if ( count( $value ) == 0 ) { - throw new MWException( __METHOD__ . ': empty input' ); + 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 @@ -2452,6 +2479,7 @@ abstract class DatabaseBase implements DatabaseType { * ANDed together in the WHERE clause * @param $fname String: Calling function name (use __METHOD__) for * logs/profiling + * @throws DBUnexpectedError */ public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = 'DatabaseBase::deleteJoin' ) @@ -2517,6 +2545,7 @@ abstract class DatabaseBase implements DatabaseType { * the format. Use $conds == "*" to delete all rows * @param $fname String name of the calling function * + * @throws DBUnexpectedError * @return bool */ public function delete( $table, $conds, $fname = 'DatabaseBase::delete' ) { @@ -2615,6 +2644,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $limit Integer the SQL limit * @param $offset Integer|bool the SQL offset (default false) * + * @throws DBUnexpectedError * @return string */ public function limitResult( $sql, $limit, $offset = false ) { @@ -2904,8 +2934,8 @@ abstract class DatabaseBase implements DatabaseType { * Note that when the DBO_TRX flag is set (which is usually the case for web requests, but not for maintenance scripts), * any previous database query will have started a transaction automatically. * - * Nesting of transactions is not supported. Attempts to nest transactions will cause warnings if DBO_TRX is not set - * or the extsting transaction contained write operations. + * Nesting of transactions is not supported. Attempts to nest transactions will cause a warning, unless the current + * transaction was started automatically because of the DBO_TRX flag. * * @param $fname string */ @@ -2913,21 +2943,20 @@ abstract class DatabaseBase implements DatabaseType { global $wgDebugDBTransactions; if ( $this->mTrxLevel ) { // implicit commit - if ( $this->mTrxDoneWrites || ( $this->mFlags & DBO_TRX ) === 0 ) { - // In theory, we should always warn about nesting BEGIN statements. - // However, it is sometimes hard to avoid so we only warn if: - // - // a) the transaction has done writes. This gives warnings about bad transactions - // that could cause partial writes but not about read queries seeing more - // than one DB snapshot (when in REPEATABLE-READ) due to nested BEGINs. - // - // b) the DBO_TRX flag is not set. Explicit transactions should always be properly - // started and comitted. - /*wfWarn( "$fname: Transaction already in progress (from {$this->mTrxFname}), " . - " performing implicit commit!" );*/ - } elseif ( $wgDebugDBTransactions ) { - wfDebug( "$fname: Transaction already in progress (from {$this->mTrxFname}), " . - " performing implicit commit!\n" ); + if ( !$this->mTrxAutomatic ) { + // We want to warn about inadvertently nested begin/commit pairs, but not about auto-committing + // implicit transactions that were started by query() because DBO_TRX was set. + + wfWarn( "$fname: Transaction already in progress (from {$this->mTrxFname}), " . + " performing implicit commit!" ); + } else { + // if the transaction was automatic and has done write operations, + // log it if $wgDebugDBTransactions is enabled. + + if ( $this->mTrxDoneWrites && $wgDebugDBTransactions ) { + wfDebug( "$fname: Automatic transaction with writes in progress (from {$this->mTrxFname}), " . + " performing implicit commit!\n" ); + } } $this->doCommit( $fname ); @@ -2937,6 +2966,7 @@ abstract class DatabaseBase implements DatabaseType { $this->doBegin( $fname ); $this->mTrxFname = $fname; $this->mTrxDoneWrites = false; + $this->mTrxAutomatic = false; } /** @@ -2957,11 +2987,26 @@ abstract class DatabaseBase implements DatabaseType { * Nesting of transactions is not supported. * * @param $fname string - */ - final public function commit( $fname = 'DatabaseBase::commit' ) { - if ( !$this->mTrxLevel ) { - wfWarn( "$fname: No transaction to commit, something got out of sync!" ); + * @param $flush String Flush flag, set to 'flush' to disable warnings about explicitly committing implicit + * transactions, or calling commit when no transaction is in progress. + * This will silently break any ongoing explicit transaction. Only set the flush flag if you are sure + * that it is safe to ignore these warnings in your context. + */ + final public function commit( $fname = 'DatabaseBase::commit', $flush = '' ) { + if ( $flush != 'flush' ) { + if ( !$this->mTrxLevel ) { + wfWarn( "$fname: No transaction to commit, something got out of sync!" ); + } elseif( $this->mTrxAutomatic ) { + wfWarn( "$fname: Explicit commit of implicit transaction. Something may be out of sync!" ); + } + } else { + if ( !$this->mTrxLevel ) { + return; // nothing to do + } elseif( !$this->mTrxAutomatic ) { + wfWarn( "$fname: Flushing an explicit transaction, getting out of sync!" ); + } } + $this->doCommit( $fname ); $this->runOnTransactionIdleCallbacks(); } @@ -3020,6 +3065,7 @@ abstract class DatabaseBase implements DatabaseType { * @param $newName String: name of table to be created * @param $temporary Boolean: whether the new table should be temporary * @param $fname String: calling function name + * @throws MWException * @return Boolean: true if operation was successful */ public function duplicateTableStructure( $oldName, $newName, $temporary = false, @@ -3034,6 +3080,7 @@ abstract class DatabaseBase implements DatabaseType { * * @param $prefix string Only show tables with this prefix, e.g. mw_ * @param $fname String: calling function name + * @throws MWException */ function listTables( $prefix = null, $fname = 'DatabaseBase::listTables' ) { throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' ); @@ -3177,10 +3224,11 @@ abstract class DatabaseBase implements DatabaseType { * on object's error ignore settings). * * @param $filename String: File name to open - * @param $lineCallback Callback: Optional function called before reading each line - * @param $resultCallback Callback: Optional function called for each MySQL result - * @param $fname String: Calling function name or false if name should be + * @param bool|callable $lineCallback Optional function called before reading each line + * @param bool|callable $resultCallback Optional function called for each MySQL result + * @param bool|string $fname Calling function name or false if name should be * generated dynamically using $filename + * @throws MWException * @return bool|string */ public function sourceFile(