From 47a6ebb4e380256d72ace0931161f5efa427fa72 Mon Sep 17 00:00:00 2001 From: Daniel Hensby <dhensby@silverstripe.com> Date: Thu, 8 Feb 2018 20:00:49 +0000 Subject: [PATCH] FIX Allow nested transactions --- code/PostgreSQLDatabase.php | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/code/PostgreSQLDatabase.php b/code/PostgreSQLDatabase.php index 3d488d7..a0d1048 100644 --- a/code/PostgreSQLDatabase.php +++ b/code/PostgreSQLDatabase.php @@ -36,6 +36,11 @@ class PostgreSQLDatabase extends Database */ protected $schema; + /** + * @var bool + */ + protected $transactionNesting = 0; + /** * Toggle if transactions are supported. Defaults to true. * @@ -519,15 +524,20 @@ public function supportsExtensions($extensions = array('partitions', 'tablespace public function transactionStart($transaction_mode = false, $session_characteristics = false) { - $this->query('BEGIN;'); + if ($this->transactionNesting > 0) { + $this->transactionSavepoint('NESTEDTRANSACTION' . $this->transactionNesting); + } else { + $this->query('BEGIN;'); - if ($transaction_mode) { - $this->query("SET TRANSACTION {$transaction_mode};"); - } + if ($transaction_mode) { + $this->query("SET TRANSACTION {$transaction_mode};"); + } - if ($session_characteristics) { - $this->query("SET SESSION CHARACTERISTICS AS TRANSACTION {$session_characteristics};"); + if ($session_characteristics) { + $this->query("SET SESSION CHARACTERISTICS AS TRANSACTION {$session_characteristics};"); + } } + ++$this->transactionNesting; } public function transactionSavepoint($savepoint) @@ -538,15 +548,24 @@ public function transactionSavepoint($savepoint) public function transactionRollback($savepoint = false) { if ($savepoint) { - $this->query("ROLLBACK TO {$savepoint};"); + $this->query('ROLLBACK TO ' . $savepoint); } else { - $this->query('ROLLBACK;'); + --$this->transactionNesting; + if ($this->transactionNesting > 0) { + $this->transactionRollback('NESTEDTRANSACTION' . $this->transactionNesting); + } else { + $this->query('ROLLBACK'); + } } } public function transactionEnd($chain = false) { - $this->query('COMMIT;'); + --$this->transactionNesting; + if ($this->transactionNesting <= 0) { + $this->transactionNesting = 0; + $this->query('COMMIT;'); + } } public function comparisonClause($field, $value, $exact = false, $negate = false, $caseSensitive = null, $parameterised = false)