Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions src/Adapter/Driver/Pdo/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class Connection extends AbstractConnection
*/
protected $dsn = null;

/**
* @var int
*/
protected $internalNestedTransactionCount = 0;

/**
* Constructor
*
Expand Down Expand Up @@ -307,7 +312,8 @@ public function beginTransaction()
$this->inTransaction = true;
}

$this->nestedTransactionsCount ++;
++$this->nestedTransactionsCount;
++$this->internalNestedTransactionCount;

return $this;
}
Expand All @@ -322,7 +328,8 @@ public function commit()
}

if ($this->inTransaction) {
$this->nestedTransactionsCount -= 1;
--$this->nestedTransactionsCount;
--$this->internalNestedTransactionCount;
}

/*
Expand All @@ -348,14 +355,16 @@ public function rollback()
throw new Exception\RuntimeException('Must be connected before you can rollback');
}

if (! $this->inTransaction()) {
if (! $this->inTransaction() && $this->internalNestedTransactionCount === 0) {
throw new Exception\RuntimeException('Must call beginTransaction() before you can rollback');
}

$this->resource->rollBack();

$this->inTransaction = false;
$this->nestedTransactionsCount = 0;
--$this->internalNestedTransactionCount;
if ($this->nestedTransactionsCount) {
$this->resource->rollBack();
$this->nestedTransactionsCount = 0;
$this->inTransaction = false;
}

return $this;
}
Expand Down
66 changes: 63 additions & 3 deletions test/unit/Adapter/Driver/Pdo/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace ZendTest\Db\Adapter\Driver\Pdo;

use Exception;
use PHPUnit\Framework\TestCase;
use Zend\Db\Adapter\Driver\Pdo\Connection;

Expand Down Expand Up @@ -50,7 +51,7 @@ public function testGetDsn()
$this->connection->setConnectionParameters(['dsn' => $dsn]);
try {
$this->connection->connect();
} catch (\Exception $e) {
} catch (Exception $e) {
}
$responseString = $this->connection->getDsn();

Expand All @@ -71,7 +72,7 @@ public function testArrayOfConnectionParametersCreatesCorrectDsn()
]);
try {
$this->connection->connect();
} catch (\Exception $e) {
} catch (Exception $e) {
}
$responseString = $this->connection->getDsn();

Expand Down Expand Up @@ -110,7 +111,7 @@ public function testDblibArrayOfConnectionParametersCreatesCorrectDsn()
]);
try {
$this->connection->connect();
} catch (\Exception $e) {
} catch (Exception $e) {
}
$responseString = $this->connection->getDsn();

Expand All @@ -120,4 +121,63 @@ public function testDblibArrayOfConnectionParametersCreatesCorrectDsn()
$this->assertContains('port=1433', $responseString);
$this->assertContains('version=7.3', $responseString);
}

public function testNestedTransactionsNoErrors()
{
$dsn = 'sqlite::memory:';
$this->connection->setConnectionParameters(['dsn' => $dsn]);
$this->connection->connect();

$nestedTransaction = static function (Connection $connection) {
$connection->beginTransaction();
try {
throw new Exception('Custom exception message!');
} catch (Exception $ex) {
$connection->rollback();
throw $ex;
}
};

$parentTransaction = static function (Connection $connection) use ($nestedTransaction) {
$connection->beginTransaction();
try {
$nestedTransaction($connection);
$connection->commit();
} catch (Exception $ex) {
$connection->rollback();
throw $ex;
}
};

$this->expectExceptionMessage('Custom exception message');
$parentTransaction($this->connection);
}

public function testNestedTransactionErrorOnParentCommitIfNestedRollback()
{
$dsn = 'sqlite::memory:';
$this->connection->setConnectionParameters(['dsn' => $dsn]);
$this->connection->connect();

$this->connection->beginTransaction();
$this->connection->beginTransaction();
$this->connection->rollback();

// As PDO does not support nested transaction this commit cannot be successful.
// Everything what was executed between opening transactions is rollbacked.
$this->expectExceptionMessage('There is no active transaction');
$this->connection->commit();
}

public function testNestedTransactionNoErrorsOnParentAndNestedRollback()
{
$dsn = 'sqlite::memory:';
$this->connection->setConnectionParameters(['dsn' => $dsn]);
$this->connection->connect();

$this->connection->beginTransaction();
$this->connection->beginTransaction();
$this->connection->rollback();
$this->connection->rollback();
}
}
9 changes: 9 additions & 0 deletions test/unit/Adapter/Driver/Pdo/ConnectionTransactionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,15 @@ public function testNestedTransactionsRollback()
$this->wrapper->rollback();
self::assertFalse($this->wrapper->inTransaction());
self::assertSame(0, $this->wrapper->getNestedTransactionsCount());

// 2nd Rollback
$this->wrapper->rollback();
self::assertFalse($this->wrapper->inTransaction());
self::assertSame(0, $this->wrapper->getNestedTransactionsCount());

// 3rd Rollback
$this->expectExceptionMessage('Must call beginTransaction() before you can rollback');
$this->wrapper->rollback();
}

/**
Expand Down