Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/storage/connection/AphrontDatabaseConnection.php
12241 views
1
<?php
2
3
/**
4
* @task xaction Transaction Management
5
*/
6
abstract class AphrontDatabaseConnection
7
extends Phobject
8
implements PhutilQsprintfInterface {
9
10
private $transactionState;
11
private $readOnly;
12
private $queryTimeout;
13
private $locks = array();
14
private $lastActiveEpoch;
15
private $persistent;
16
17
abstract public function getInsertID();
18
abstract public function getAffectedRows();
19
abstract public function selectAllResults();
20
abstract public function executeQuery(PhutilQueryString $query);
21
abstract public function executeRawQueries(array $raw_queries);
22
abstract public function close();
23
abstract public function openConnection();
24
25
public function __destruct() {
26
// NOTE: This does not actually close persistent connections: PHP maintains
27
// them in the connection pool.
28
$this->close();
29
}
30
31
final public function setLastActiveEpoch($epoch) {
32
$this->lastActiveEpoch = $epoch;
33
return $this;
34
}
35
36
final public function getLastActiveEpoch() {
37
return $this->lastActiveEpoch;
38
}
39
40
final public function setPersistent($persistent) {
41
$this->persistent = $persistent;
42
return $this;
43
}
44
45
final public function getPersistent() {
46
return $this->persistent;
47
}
48
49
public function queryData($pattern/* , $arg, $arg, ... */) {
50
$args = func_get_args();
51
array_unshift($args, $this);
52
return call_user_func_array('queryfx_all', $args);
53
}
54
55
public function query($pattern/* , $arg, $arg, ... */) {
56
$args = func_get_args();
57
array_unshift($args, $this);
58
return call_user_func_array('queryfx', $args);
59
}
60
61
62
public function supportsAsyncQueries() {
63
return false;
64
}
65
66
public function supportsParallelQueries() {
67
return false;
68
}
69
70
public function setReadOnly($read_only) {
71
$this->readOnly = $read_only;
72
return $this;
73
}
74
75
public function getReadOnly() {
76
return $this->readOnly;
77
}
78
79
public function setQueryTimeout($query_timeout) {
80
$this->queryTimeout = $query_timeout;
81
return $this;
82
}
83
84
public function getQueryTimeout() {
85
return $this->queryTimeout;
86
}
87
88
public function asyncQuery($raw_query) {
89
throw new Exception(pht('Async queries are not supported.'));
90
}
91
92
public static function resolveAsyncQueries(array $conns, array $asyncs) {
93
throw new Exception(pht('Async queries are not supported.'));
94
}
95
96
/**
97
* Is this connection idle and safe to close?
98
*
99
* A connection is "idle" if it can be safely closed without loss of state.
100
* Connections inside a transaction or holding locks are not idle, even
101
* though they may not actively be executing queries.
102
*
103
* @return bool True if the connection is idle and can be safely closed.
104
*/
105
public function isIdle() {
106
if ($this->isInsideTransaction()) {
107
return false;
108
}
109
110
if ($this->isHoldingAnyLock()) {
111
return false;
112
}
113
114
return true;
115
}
116
117
118
/* -( Global Locks )------------------------------------------------------- */
119
120
121
public function rememberLock($lock) {
122
if (isset($this->locks[$lock])) {
123
throw new Exception(
124
pht(
125
'Trying to remember lock "%s", but this lock has already been '.
126
'remembered.',
127
$lock));
128
}
129
130
$this->locks[$lock] = true;
131
return $this;
132
}
133
134
135
public function forgetLock($lock) {
136
if (empty($this->locks[$lock])) {
137
throw new Exception(
138
pht(
139
'Trying to forget lock "%s", but this connection does not remember '.
140
'that lock.',
141
$lock));
142
}
143
144
unset($this->locks[$lock]);
145
return $this;
146
}
147
148
149
public function forgetAllLocks() {
150
$this->locks = array();
151
return $this;
152
}
153
154
155
public function isHoldingAnyLock() {
156
return (bool)$this->locks;
157
}
158
159
160
/* -( Transaction Management )--------------------------------------------- */
161
162
163
/**
164
* Begin a transaction, or set a savepoint if the connection is already
165
* transactional.
166
*
167
* @return this
168
* @task xaction
169
*/
170
public function openTransaction() {
171
$state = $this->getTransactionState();
172
$point = $state->getSavepointName();
173
$depth = $state->getDepth();
174
175
$new_transaction = ($depth == 0);
176
if ($new_transaction) {
177
$this->query('START TRANSACTION');
178
} else {
179
$this->query('SAVEPOINT '.$point);
180
}
181
182
$state->increaseDepth();
183
184
return $this;
185
}
186
187
188
/**
189
* Commit a transaction, or stage a savepoint for commit once the entire
190
* transaction completes if inside a transaction stack.
191
*
192
* @return this
193
* @task xaction
194
*/
195
public function saveTransaction() {
196
$state = $this->getTransactionState();
197
$depth = $state->decreaseDepth();
198
199
if ($depth == 0) {
200
$this->query('COMMIT');
201
}
202
203
return $this;
204
}
205
206
207
/**
208
* Rollback a transaction, or unstage the last savepoint if inside a
209
* transaction stack.
210
*
211
* @return this
212
*/
213
public function killTransaction() {
214
$state = $this->getTransactionState();
215
$depth = $state->decreaseDepth();
216
217
if ($depth == 0) {
218
$this->query('ROLLBACK');
219
} else {
220
$this->query('ROLLBACK TO SAVEPOINT '.$state->getSavepointName());
221
}
222
223
return $this;
224
}
225
226
227
/**
228
* Returns true if the connection is transactional.
229
*
230
* @return bool True if the connection is currently transactional.
231
* @task xaction
232
*/
233
public function isInsideTransaction() {
234
$state = $this->getTransactionState();
235
return ($state->getDepth() > 0);
236
}
237
238
239
/**
240
* Get the current @{class:AphrontDatabaseTransactionState} object, or create
241
* one if none exists.
242
*
243
* @return AphrontDatabaseTransactionState Current transaction state.
244
* @task xaction
245
*/
246
protected function getTransactionState() {
247
if (!$this->transactionState) {
248
$this->transactionState = new AphrontDatabaseTransactionState();
249
}
250
return $this->transactionState;
251
}
252
253
254
/**
255
* @task xaction
256
*/
257
public function beginReadLocking() {
258
$this->getTransactionState()->beginReadLocking();
259
return $this;
260
}
261
262
263
/**
264
* @task xaction
265
*/
266
public function endReadLocking() {
267
$this->getTransactionState()->endReadLocking();
268
return $this;
269
}
270
271
272
/**
273
* @task xaction
274
*/
275
public function isReadLocking() {
276
return $this->getTransactionState()->isReadLocking();
277
}
278
279
280
/**
281
* @task xaction
282
*/
283
public function beginWriteLocking() {
284
$this->getTransactionState()->beginWriteLocking();
285
return $this;
286
}
287
288
289
/**
290
* @task xaction
291
*/
292
public function endWriteLocking() {
293
$this->getTransactionState()->endWriteLocking();
294
return $this;
295
}
296
297
298
/**
299
* @task xaction
300
*/
301
public function isWriteLocking() {
302
return $this->getTransactionState()->isWriteLocking();
303
}
304
305
}
306
307