}
try {
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
$affectedRowCount = 0;
foreach ( $rows as $row ) {
// Delete rows which collide with this one
$affectedRowCount = 0;
try {
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
# Update any existing conflicting row(s)
if ( $where !== false ) {
$ok = $this->update( $table, $set, $where, $fname );
try {
$affectedRowCount = 0;
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
$rows = [];
$ok = true;
foreach ( $res as $row ) {
$this->trxPreCommitCallbacks[] = [ $callback, $fname ];
} else {
// No transaction is active nor will start implicitly, so make one for this callback
- $this->startAtomic( __METHOD__ );
+ $this->startAtomic( __METHOD__, self::ATOMIC_CANCELABLE );
try {
call_user_func( $callback );
$this->endAtomic( __METHOD__ );
$this->query( 'ROLLBACK TO SAVEPOINT ' . $this->addIdentifierQuotes( $identifier ), $fname );
}
- final public function startAtomic( $fname = __METHOD__ ) {
+ final public function startAtomic(
+ $fname = __METHOD__, $cancelable = self::ATOMIC_NOT_CANCELABLE
+ ) {
+ $savepointId = $cancelable === self::ATOMIC_CANCELABLE ? 'n/a' : null;
if ( !$this->trxLevel ) {
$this->begin( $fname, self::TRANSACTION_INTERNAL );
// If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
if ( !$this->getFlag( self::DBO_TRX ) ) {
$this->trxAutomaticAtomic = true;
}
- $savepointId = null;
- } else {
+ } elseif ( $cancelable === self::ATOMIC_CANCELABLE ) {
$savepointId = 'wikimedia_rdbms_atomic' . ++$this->trxAtomicCounter;
if ( strlen( $savepointId ) > 30 ) { // 30 == Oracle's identifier length limit (pre 12c)
$this->queryLogger->warning(
throw new DBUnexpectedError( $this, "Invalid atomic section ended (got $fname)." );
}
- if ( !$savepointId ) {
+ if ( !$this->trxAtomicLevels && $this->trxAutomaticAtomic ) {
$this->commit( $fname, self::FLUSHING_INTERNAL );
- } else {
+ } elseif ( $savepointId && $savepointId !== 'n/a' ) {
$this->doReleaseSavepoint( $savepointId, $fname );
}
}
if ( $savedFname !== $fname ) {
throw new DBUnexpectedError( $this, "Invalid atomic section ended (got $fname)." );
}
-
if ( !$savepointId ) {
+ throw new DBUnexpectedError( $this, "Uncancelable atomic section canceled (got $fname)." );
+ }
+
+ if ( !$this->trxAtomicLevels && $this->trxAutomaticAtomic ) {
$this->rollback( $fname, self::FLUSHING_INTERNAL );
- } else {
+ } elseif ( $savepointId !== 'n/a' ) {
$this->doRollbackToSavepoint( $savepointId, $fname );
}
}
final public function doAtomicSection( $fname, callable $callback ) {
- $this->startAtomic( $fname );
+ $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
try {
$res = call_user_func_array( $callback, [ $this, $fname ] );
} catch ( Exception $e ) {