1
|
|
|
<?php |
2
|
|
|
namespace Ivory\Connection; |
3
|
|
|
|
4
|
|
|
use Ivory\Exception\InvalidStateException; |
5
|
|
|
use Ivory\Result\IQueryResult; |
6
|
|
|
use Ivory\Type\Ivory\IdentifierSerializer; |
7
|
|
|
use Ivory\Type\Std\StringType; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* {@inheritdoc} |
11
|
|
|
* |
12
|
|
|
* This implementation checks, upon destruction, whether the transaction has properly been closed. If not, i.e., when |
13
|
|
|
* the transaction handle gets lost and thus no further means of controlling the transaction are available, a warning is |
14
|
|
|
* emitted. |
15
|
|
|
*/ |
16
|
|
|
class TxHandle implements ITxHandle |
17
|
|
|
{ |
18
|
|
|
private $open = true; |
19
|
|
|
private $stmtExec; |
20
|
|
|
private $txCtl; |
21
|
|
|
private $identSerializer; |
22
|
|
|
private $stringSerializer; |
23
|
|
|
|
24
|
|
|
public function __construct(IStatementExecution $stmtExec, IObservableTransactionControl $observableTxCtl) |
25
|
|
|
{ |
26
|
|
|
$this->stmtExec = $stmtExec; |
27
|
|
|
$this->txCtl = $observableTxCtl; |
28
|
|
|
$this->identSerializer = new IdentifierSerializer(); |
29
|
|
|
$this->stringSerializer = new StringType('pg_catalog', 'text'); |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
public function __destruct() |
33
|
|
|
{ |
34
|
|
|
if ($this->open) { |
|
|
|
|
35
|
|
|
// TODO: notify on an open transaction handle |
36
|
|
|
} |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
private function assertOpen() |
40
|
|
|
{ |
41
|
|
|
if (!$this->open) { |
42
|
|
|
if ($this->txCtl->inTransaction()) { |
43
|
|
|
throw new InvalidStateException( |
44
|
|
|
'Controlling the transaction using a wrong handle - this has already been closed' |
45
|
|
|
); |
46
|
|
|
} else { |
47
|
|
|
throw new InvalidStateException('The transaction is not open anymore'); |
48
|
|
|
} |
49
|
|
|
} |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
public function isOpen(): bool |
53
|
|
|
{ |
54
|
|
|
return $this->open; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
public function setupTransaction($transactionOptions) |
58
|
|
|
{ |
59
|
|
|
$this->assertOpen(); |
60
|
|
|
$txConfig = TxConfig::create($transactionOptions); |
61
|
|
|
$this->stmtExec->rawCommand('SET TRANSACTION ' . $txConfig->toSql()); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
public function setTransactionSnapshot(string $snapshotId) |
65
|
|
|
{ |
66
|
|
|
$this->assertOpen(); |
67
|
|
|
$this->stmtExec->rawCommand("SET TRANSACTION SNAPSHOT {$this->stringSerializer->serializeValue($snapshotId)}"); |
68
|
|
|
return true; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
public function exportTransactionSnapshot(): string |
72
|
|
|
{ |
73
|
|
|
$this->assertOpen(); |
74
|
|
|
|
75
|
|
|
/** @var IQueryResult $r */ |
76
|
|
|
$r = $this->stmtExec->rawQuery('SELECT pg_export_snapshot()'); |
77
|
|
|
return $r->value(); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
public function commit() |
81
|
|
|
{ |
82
|
|
|
$this->assertOpen(); |
83
|
|
|
$this->stmtExec->rawCommand('COMMIT'); |
84
|
|
|
$this->open = false; |
85
|
|
|
$this->txCtl->notifyTransactionCommit(); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
public function rollback() |
89
|
|
|
{ |
90
|
|
|
$this->assertOpen(); |
91
|
|
|
$this->stmtExec->rawCommand('ROLLBACK'); |
92
|
|
|
$this->open = false; |
93
|
|
|
$this->txCtl->notifyTransactionRollback(); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function savepoint(string $name) |
97
|
|
|
{ |
98
|
|
|
$this->assertOpen(); |
99
|
|
|
$this->stmtExec->rawCommand(sprintf('SAVEPOINT %s', $this->identSerializer->serializeValue($name))); |
100
|
|
|
$this->txCtl->notifySavepointSaved($name); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
public function rollbackToSavepoint(string $name) |
104
|
|
|
{ |
105
|
|
|
$this->assertOpen(); |
106
|
|
|
$this->stmtExec->rawCommand(sprintf('ROLLBACK TO SAVEPOINT %s', $this->identSerializer->serializeValue($name))); |
107
|
|
|
$this->txCtl->notifyRollbackToSavepoint($name); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public function releaseSavepoint(string $name) |
111
|
|
|
{ |
112
|
|
|
$this->assertOpen(); |
113
|
|
|
$this->stmtExec->rawCommand(sprintf('RELEASE SAVEPOINT %s', $this->identSerializer->serializeValue($name))); |
114
|
|
|
$this->txCtl->notifySavepointReleased($name); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
public function prepareTransaction(string $name) |
118
|
|
|
{ |
119
|
|
|
$this->assertOpen(); |
120
|
|
|
$this->stmtExec->rawCommand("PREPARE TRANSACTION {$this->stringSerializer->serializeValue($name)}"); |
121
|
|
|
$this->open = false; |
122
|
|
|
$this->txCtl->notifyTransactionPrepared($name); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.