From 567cbe40c01d6182368061a089e456a295265c6a Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 16 Mar 2021 20:05:18 +0300 Subject: [PATCH] Repair \Spiral\Database\Driver\Driver::$transactionLevel; add check for active transaction --- src/Driver/Driver.php | 50 ++++++++++++++++++++++---- src/Driver/Postgres/PostgresDriver.php | 5 +-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 17af3653..d4d9a6de 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -76,7 +76,7 @@ abstract class Driver implements DriverInterface, LoggerAwareInterface protected $pdo; /** @var int */ - protected $transactionLevel; + protected $transactionLevel = 0; /** @var HandlerInterface */ protected $schemaHandler; @@ -102,7 +102,6 @@ public function __construct( CompilerInterface $queryCompiler, BuilderInterface $queryBuilder ) { - $this->transactionLevel = 0; $this->schemaHandler = $schemaHandler->withDriver($this); $this->queryBuilder = $queryBuilder->withDriver($this); $this->queryCompiler = $queryCompiler; @@ -352,7 +351,7 @@ public function lastInsertID(string $sequence = null) */ public function beginTransaction(string $isolationLevel = null): bool { - $this->transactionLevel++; + ++$this->transactionLevel; if ($this->transactionLevel === 1) { if ($isolationLevel !== null) { @@ -377,10 +376,11 @@ public function beginTransaction(string $isolationLevel = null): bool try { return $this->getPDO()->beginTransaction(); } catch (Throwable $e) { + $this->transactionLevel = 0; throw $this->mapException($e, 'BEGIN TRANSACTION'); } } else { - $this->transactionLevel--; + $this->transactionLevel = 0; throw $e; } } @@ -395,10 +395,31 @@ public function beginTransaction(string $isolationLevel = null): bool * Commit the active database transaction. * * @return bool + * + * @throws StatementException */ public function commitTransaction(): bool { - $this->transactionLevel--; + // Check active transaction + if (!$this->getPDO()->inTransaction()) { + if ($this->logger !== null) { + $this->logger->warning( + sprintf( + 'Attempt to commit a transaction that has not yet begun. Transaction level: %d', + $this->transactionLevel + ) + ); + } + + if ($this->transactionLevel === 0) { + return false; + } + + $this->transactionLevel = 0; + return true; + } + + --$this->transactionLevel; if ($this->transactionLevel === 0) { if ($this->logger !== null) { @@ -421,10 +442,27 @@ public function commitTransaction(): bool * Rollback the active database transaction. * * @return bool + * + * @throws StatementException */ public function rollbackTransaction(): bool { - $this->transactionLevel--; + // Check active transaction + if (!$this->getPDO()->inTransaction()) { + if ($this->logger !== null) { + $this->logger->warning( + sprintf( + 'Attempt to rollback a transaction that has not yet begun. Transaction level: %d', + $this->transactionLevel + ) + ); + } + + $this->transactionLevel = 0; + return false; + } + + --$this->transactionLevel; if ($this->transactionLevel === 0) { if ($this->logger !== null) { diff --git a/src/Driver/Postgres/PostgresDriver.php b/src/Driver/Postgres/PostgresDriver.php index 37474bd7..3b6a3f29 100644 --- a/src/Driver/Postgres/PostgresDriver.php +++ b/src/Driver/Postgres/PostgresDriver.php @@ -119,7 +119,7 @@ public function resetPrimaryKeys(): void */ public function beginTransaction(string $isolationLevel = null): bool { - $this->transactionLevel++; + ++$this->transactionLevel; if ($this->transactionLevel === 1) { if ($this->logger !== null) { @@ -145,10 +145,11 @@ public function beginTransaction(string $isolationLevel = null): bool try { return $this->getPDO()->beginTransaction(); } catch (Throwable $e) { + $this->transactionLevel = 0; throw $this->mapException($e, 'BEGIN TRANSACTION'); } } else { - $this->transactionLevel--; + $this->transactionLevel = 0; throw $e; } }