Skip to content

Commit

Permalink
Merge pull request #12 from martok/pr/txn-nesting
Browse files Browse the repository at this point in the history
Rework nested transaction handling
  • Loading branch information
nicksagona authored Dec 18, 2023
2 parents 6f32cbf + 9950192 commit a7f7ed4
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 110 deletions.
33 changes: 17 additions & 16 deletions src/Adapter/AbstractAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,10 @@ abstract class AbstractAdapter implements AdapterInterface
protected ?Profiler\Profiler $profiler = null;

/**
* Is open transaction flag
* @var bool
* Transaction manager
* @var TransactionManager|null
*/
protected bool $isTransaction = false;

/**
* Transaction depth
* @var int
*/
protected int $transactionDepth = 0;
protected ?TransactionManager $transactionManager = null;

/**
* Constructor
Expand Down Expand Up @@ -146,14 +140,24 @@ abstract public function commit(): AbstractAdapter;
*/
abstract public function rollback(): AbstractAdapter;

/**
* Return the transaction manager object, initialize on first use
*
* @return TransactionManager
*/
protected function getTransactionManager(): TransactionManager
{
return ($this->transactionManager ??= new TransactionManager());
}

/**
* Check if adapter is in the middle of an open transaction
*
* @return bool
*/
public function isTransaction(): bool
{
return $this->isTransaction;
return !is_null($this->transactionManager) && $this->transactionManager->isTransaction();
}

/**
Expand All @@ -163,7 +167,7 @@ public function isTransaction(): bool
*/
public function getTransactionDepth(): int
{
return $this->transactionDepth;
return is_null($this->transactionManager) ? 0 : $this->transactionManager->getTransactionDepth();
}

/**
Expand All @@ -185,11 +189,8 @@ public function transaction(mixed $callable, mixed $params = null): void
$callable->call();
$this->commit();
} catch (\Exception $e) {
if ($this->transactionDepth == 0) {
$this->rollback();
} else {
throw $e;
}
$this->rollback();
throw $e;
}
}

Expand Down
73 changes: 36 additions & 37 deletions src/Adapter/Mysql.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,18 @@ public function hasOptions(): bool
*/
public function beginTransaction(?int $flags = null, ?string $name = null): Mysql
{
if ($this->transactionDepth == 0) {
if (($flags !== null) && ($name !== null)) {
$this->connection->begin_transaction($flags, $name);
} else if ($flags !== null) {
$this->connection->begin_transaction($flags);
} else {
$this->connection->begin_transaction();
}

$this->isTransaction = true;
}

$this->transactionDepth++;
$this->getTransactionManager()->enter(
beginFunc: function () use ($flags, $name) {
if (($flags !== null) && ($name !== null)) {
$this->connection->begin_transaction($flags, $name);
} else if ($flags !== null) {
$this->connection->begin_transaction($flags);
} else {
$this->connection->begin_transaction();
}
},
savepointFunc: function (string $sp) { $this->connection->savepoint($sp); },
);

return $this;
}
Expand All @@ -147,19 +146,18 @@ public function beginTransaction(?int $flags = null, ?string $name = null): Mysq
*/
public function commit(?int $flags = null, ?string $name = null): Mysql
{
$this->transactionDepth--;

if ($this->transactionDepth == 0) {
if (($flags !== null) && ($name !== null)) {
$this->connection->commit($flags, $name);
} else if ($flags !== null) {
$this->connection->commit($flags);
} else {
$this->connection->commit();
}

$this->isTransaction = false;
}
$this->getTransactionManager()->leave(true,
commitFunc: function () use ($flags, $name) {
if (($flags !== null) && ($name !== null)) {
$this->connection->commit($flags, $name);
} else if ($flags !== null) {
$this->connection->commit($flags);
} else {
$this->connection->commit();
}
},
savepointReleaseFunc: function (string $sp) { $this->connection->release_savepoint($sp); },
);

return $this;
}
Expand All @@ -173,17 +171,18 @@ public function commit(?int $flags = null, ?string $name = null): Mysql
*/
public function rollback(?int $flags = null, ?string $name = null): Mysql
{
$this->transactionDepth = 0;

if (($flags !== null) && ($name !== null)) {
$this->connection->rollback($flags, $name);
} else if ($flags !== null) {
$this->connection->rollback($flags);
} else {
$this->connection->rollback();
}

$this->isTransaction = false;
$this->getTransactionManager()->leave(false,
rollbackFunc: function () use ($flags, $name) {
if (($flags !== null) && ($name !== null)) {
$this->connection->rollback($flags, $name);
} else if ($flags !== null) {
$this->connection->rollback($flags);
} else {
$this->connection->rollback();
}
},
savepointRollbackFunc: function (string $sp) { $this->query('ROLLBACK TO SAVEPOINT ' . $sp); },
);

return $this;
}
Expand Down
29 changes: 13 additions & 16 deletions src/Adapter/Pdo.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,10 @@ public function getType(): ?string
*/
public function beginTransaction(): Pdo
{
if ($this->transactionDepth == 0) {
$this->connection->beginTransaction();
$this->isTransaction = true;
}

$this->transactionDepth++;
$this->getTransactionManager()->enter(
beginFunc: function () { $this->connection->beginTransaction(); },
savepointFunc: function (string $sp) { $this->query('SAVEPOINT ' . $sp); },
);

return $this;
}
Expand All @@ -199,13 +197,11 @@ public function beginTransaction(): Pdo
*/
public function commit(): Pdo
{
$this->transactionDepth--;

if ($this->transactionDepth == 0) {
$this->connection->commit();
$this->isTransaction = false;
}

$this->getTransactionManager()->leave(true,
commitFunc: function () { $this->connection->commit(); },
rollbackFunc: function () { $this->connection->rollBack(); },
savepointReleaseFunc: function (string $sp) { $this->query('RELEASE SAVEPOINT ' . $sp); },
);
return $this;
}

Expand All @@ -216,9 +212,10 @@ public function commit(): Pdo
*/
public function rollback(): Pdo
{
$this->transactionDepth = 0;
$this->connection->rollBack();
$this->isTransaction = false;
$this->getTransactionManager()->leave(false,
rollbackFunc: function () { $this->connection->rollBack(); },
savepointRollbackFunc: function (string $sp) { $this->query('ROLLBACK TO SAVEPOINT ' . $sp); },
);

return $this;
}
Expand Down
23 changes: 12 additions & 11 deletions src/Adapter/Pgsql.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,10 @@ public function hasOptions(): bool
*/
public function beginTransaction(): Pgsql
{
if ($this->transactionDepth == 0) {
$this->query('BEGIN TRANSACTION');
$this->isTransaction = true;
}
$this->transactionDepth++;
$this->getTransactionManager()->enter(
beginFunc: function () { $this->query('BEGIN TRANSACTION'); },
savepointFunc: function (string $sp) { $this->query('SAVEPOINT ' . $sp); },
);

return $this;
}
Expand All @@ -169,9 +168,10 @@ public function beginTransaction(): Pgsql
*/
public function commit(): Pgsql
{
$this->transactionDepth--;
$this->query('COMMIT');
$this->isTransaction = false;
$this->getTransactionManager()->leave(true,
commitFunc: function () { $this->query('COMMIT'); },
savepointReleaseFunc: function (string $sp) { $this->query('RELEASE SAVEPOINT ' . $sp); },
);

return $this;
}
Expand All @@ -183,9 +183,10 @@ public function commit(): Pgsql
*/
public function rollback(): Pgsql
{
$this->transactionDepth = 0;
$this->query('ROLLBACK');
$this->isTransaction = false;
$this->getTransactionManager()->leave(false,
rollbackFunc: function () { $this->query('ROLLBACK'); },
savepointRollbackFunc: function (string $sp) { $this->query('ROLLBACK TO SAVEPOINT ' . $sp); },
);

return $this;
}
Expand Down
27 changes: 12 additions & 15 deletions src/Adapter/Sqlite.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,10 @@ public function dbFileExists(): bool
*/
public function beginTransaction(): Sqlite
{
if ($this->transactionDepth == 0) {
$this->query('BEGIN TRANSACTION');
$this->isTransaction = true;
}

$this->transactionDepth++;
$this->getTransactionManager()->enter(
beginFunc: function () { $this->query('BEGIN TRANSACTION'); },
savepointFunc: function (string $sp) { $this->query('SAVEPOINT ' . $sp); },
);

return $this;
}
Expand All @@ -151,12 +149,10 @@ public function beginTransaction(): Sqlite
*/
public function commit(): Sqlite
{
$this->transactionDepth--;

if ($this->transactionDepth == 0) {
$this->query('COMMIT');
$this->isTransaction = false;
}
$this->getTransactionManager()->leave(true,
commitFunc: function () { $this->query('COMMIT'); },
savepointReleaseFunc: function (string $sp) { $this->query('RELEASE SAVEPOINT ' . $sp); },
);

return $this;
}
Expand All @@ -168,9 +164,10 @@ public function commit(): Sqlite
*/
public function rollback(): Sqlite
{
$this->transactionDepth = 0;
$this->query('ROLLBACK');
$this->isTransaction = false;
$this->getTransactionManager()->leave(false,
rollbackFunc: function () { $this->query('ROLLBACK'); },
savepointRollbackFunc: function (string $sp) { $this->query('ROLLBACK TO SAVEPOINT ' . $sp); },
);

return $this;
}
Expand Down
27 changes: 12 additions & 15 deletions src/Adapter/Sqlsrv.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,10 @@ public function hasOptions(): bool
*/
public function beginTransaction(): Sqlsrv
{
if ($this->transactionDepth == 0) {
sqlsrv_begin_transaction($this->connection);
$this->isTransaction = true;
}

$this->transactionDepth++;
$this->getTransactionManager()->enter(
beginFunc: function () { sqlsrv_begin_transaction($this->connection); },
savepointFunc: function (string $sp) { $this->query('SAVE TRANSACTION ' . $sp); },
);

return $this;
}
Expand All @@ -154,12 +152,10 @@ public function beginTransaction(): Sqlsrv
*/
public function commit(): Sqlsrv
{
$this->transactionDepth--;

if ($this->transactionDepth == 0) {
sqlsrv_commit($this->connection);
$this->isTransaction = false;
}
$this->getTransactionManager()->leave(true,
commitFunc: function () { sqlsrv_commit($this->connection); },
savepointReleaseFunc: function (string $sp) { /* Sqlsrv does not manage successful savepoints explicitly */ },
);

return $this;
}
Expand All @@ -171,9 +167,10 @@ public function commit(): Sqlsrv
*/
public function rollback(): Sqlsrv
{
$this->transactionDepth = 0;
sqlsrv_rollback($this->connection);
$this->isTransaction = false;
$this->getTransactionManager()->leave(false,
rollbackFunc: function () { sqlsrv_rollback($this->connection); },
savepointRollbackFunc: function (string $sp) { $this->query('ROLLBACK TRANSACTION ' . $sp); },
);

return $this;
}
Expand Down
Loading

0 comments on commit a7f7ed4

Please sign in to comment.