- if ( false === $ret ) {
- # Deadlocks cause the entire transaction to abort, not just the statement.
- # https://dev.mysql.com/doc/refman/5.7/en/innodb-error-handling.html
- # https://www.postgresql.org/docs/9.1/static/explicit-locking.html
- if ( $this->wasDeadlock() ) {
- if ( $this->explicitTrxActive() || $priorWritesPending ) {
- $tempIgnore = false; // not recoverable
+ if ( $ret === false ) {
+ if ( $this->trxLevel ) {
+ if ( !$this->wasKnownStatementRollbackError() ) {
+ # Either the query was aborted or all queries after BEGIN where aborted.
+ if ( $this->explicitTrxActive() || $priorWritesPending ) {
+ # In the first case, the only options going forward are (a) ROLLBACK, or
+ # (b) ROLLBACK TO SAVEPOINT (if one was set). If the later case, the only
+ # option is ROLLBACK, since the snapshots would have been released.
+ $this->trxStatus = self::STATUS_TRX_ERROR;
+ $this->trxStatusCause =
+ $this->makeQueryException( $lastError, $lastErrno, $sql, $fname );
+ $tempIgnore = false; // cannot recover
+ } else {
+ # Nothing prior was there to lose from the transaction,
+ # so just roll it back.
+ $this->doRollback( __METHOD__ . " ($fname)" );
+ $this->trxStatus = self::STATUS_TRX_OK;
+ }
+ $this->trxStatusIgnoredCause = null;
+ } else {
+ # We're ignoring an error that caused just the current query to be aborted.
+ # But log the cause so we can log a deprecation notice if a
+ # caller actually does ignore it.
+ $this->trxStatusIgnoredCause = [ $lastError, $lastErrno, $fname ];