Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20namespace Wikimedia\Rdbms;
21
22use Exception;
23use Wikimedia\ScopedCallback;
24
25/**
26 * @defgroup Database Database
27 * This group deals with database interface functions
28 * and query specifics/optimisations.
29 */
30
31// Very long type annotations :(
32// phpcs:disable Generic.Files.LineLength
33
34/**
35 * Interface to a relational database
36 *
37 * This is used for both primary databases and replicas, and used for both concrete
38 * connections, as well as wrappers around shared connections, like DBConnRef.
39 *
40 * As such, callers should not assume that the object represents a live connection
41 * (when using DBConnRef, the object may lazily defer the connection to the first query),
42 * and should not assume that they have complete control over the connection
43 * (when using DBConnRef, multiple objects may automatically share and reuse the same
44 * underlying connection).
45 *
46 * @ingroup Database
47 */
48interface IDatabase extends IReadableDatabase {
49    /** Callback triggered immediately due to no active transaction */
50    public const TRIGGER_IDLE = 1;
51    /** Callback triggered by COMMIT */
52    public const TRIGGER_COMMIT = 2;
53    /** Callback triggered by ROLLBACK */
54    public const TRIGGER_ROLLBACK = 3;
55    /** Callback triggered by atomic section cancel (ROLLBACK TO SAVEPOINT) */
56    public const TRIGGER_CANCEL = 4;
57
58    /** Transaction is requested by regular caller outside of the DB layer */
59    public const TRANSACTION_EXPLICIT = '';
60    /** Transaction is requested internally via DBO_TRX/startAtomic() */
61    public const TRANSACTION_INTERNAL = 'implicit';
62
63    /** Atomic section is not cancelable */
64    public const ATOMIC_NOT_CANCELABLE = '';
65    /** Atomic section is cancelable */
66    public const ATOMIC_CANCELABLE = 'cancelable';
67
68    /** Commit/rollback is from outside the IDatabase handle and connection manager */
69    public const FLUSHING_ONE = '';
70    /**
71     * Commit/rollback is from the owning connection manager for the IDatabase handle
72     * @internal Only for use within the rdbms library
73     */
74    public const FLUSHING_ALL_PEERS = 'flush';
75    /**
76     * Commit/rollback is from the IDatabase handle internally
77     * @internal Only for use within the rdbms library
78     */
79    public const FLUSHING_INTERNAL = 'flush-internal';
80
81    /** Estimate total time (RTT, scanning, waiting on locks, applying) */
82    public const ESTIMATE_TOTAL = 'total';
83    /** Estimate time to apply (scanning, applying) */
84    public const ESTIMATE_DB_APPLY = 'apply';
85
86    /** Flag to return the lock acquisition timestamp (null if not acquired) */
87    public const LOCK_TIMESTAMP = 1;
88
89    /** Field for getLBInfo()/setLBInfo() */
90    public const LB_TRX_ROUND_ID = 'trxRoundId';
91    /** Field for getLBInfo()/setLBInfo() */
92    public const LB_READ_ONLY_REASON = 'readOnlyReason';
93
94    /** Primary server than can stream writes to replica servers */
95    public const ROLE_STREAMING_MASTER = 'streaming-master';
96    /** Replica server that receives writes from a primary server */
97    public const ROLE_STREAMING_REPLICA = 'streaming-replica';
98    /** Replica server within a static dataset */
99    public const ROLE_STATIC_CLONE = 'static-clone';
100    /** Server with unknown topology role */
101    public const ROLE_UNKNOWN = 'unknown';
102
103    /**
104     * Gets the current transaction level.
105     *
106     * Historically, transactions were allowed to be "nested". This is no
107     * longer supported, so this function really only returns a boolean.
108     *
109     * @return int The previous value
110     */
111    public function trxLevel();
112
113    /**
114     * Get the UNIX timestamp of the time that the transaction was established
115     *
116     * This can be used to reason about the staleness of SELECT data in REPEATABLE-READ
117     * transaction isolation level. Callers can assume that if a view-snapshot isolation
118     * is used, then the data read by SQL queries is *at least* up to date to that point
119     * (possibly more up-to-date since the first SELECT defines the snapshot).
120     *
121     * @return float|null Returns null if there is not active transaction
122     * @since 1.25
123     */
124    public function trxTimestamp();
125
126    /**
127     * Check whether there is a transaction open at the specific request of a caller
128     *
129     * Explicit transactions are spawned by begin(), startAtomic(), and doAtomicSection().
130     * Note that explicit transactions should not be confused with explicit transaction rounds.
131     *
132     * @return bool
133     * @since 1.28
134     */
135    public function explicitTrxActive();
136
137    /**
138     * Get properties passed down from the server info array of the load balancer
139     *
140     * @internal should not be called outside of rdbms library.
141     *
142     * @param string|null $name The entry of the info array to get, or null to get the whole array
143     * @return array|mixed|null
144     */
145    public function getLBInfo( $name = null );
146
147    /**
148     * Get the sequence-based ID assigned by the last query method call
149     *
150     * This method should only be called when all the following hold true:
151     *   - (a) A method call was made to insert(), upsert(), replace(), or insertSelect()
152     *   - (b) The method call attempts to insert exactly one row
153     *   - (c) The method call omits the value of exactly one auto-increment column
154     *   - (d) The method call succeeded
155     *   - (e) No subsequent method calls were made, with the exception of affectedRows(),
156     *         lastErrno(), lastError(), and getType()
157     *
158     * In all other cases, the return value is unspecified.
159     *
160     * When the query method is either insert() with "IGNORE", upsert(), or insertSelect(),
161     * callers should first check affectedRows() before calling this method, making sure that
162     * the query method actually created a row. Otherwise, an ID from a previous insert might
163     * be incorrectly assumed to belong to last insert.
164     *
165     * @return int
166     */
167    public function insertId();
168
169    /**
170     * Get the number of rows affected by the last query method call
171     *
172     * This method should only be called when all the following hold true:
173     *   - (a) A method call was made to insert(), upsert(), replace(), update(), delete(),
174     *         insertSelect(), query() with a non-SELECT statement, or queryMulti() with a
175     *         non-SELECT terminal statement
176     *   - (b) The method call succeeded
177     *   - (c) No subsequent method calls were made, with the exception of affectedRows(),
178     *         lastErrno(), lastError(), and getType()
179     *
180     * In all other cases, the return value is unspecified.
181     *
182     * UPDATE queries consider rows affected even when all their new column values match
183     * the previous values. Such rows can be excluded from the count by changing the WHERE
184     * clause to filter them out.
185     *
186     * If the last query method call was to query() or queryMulti(), then the results
187     * are based on the (last) statement provided to that call and are driver-specific.
188     *
189     * @return int
190     */
191    public function affectedRows();
192
193    /**
194     * Run an SQL query statement and return the result
195     *
196     * If a connection loss is detected, then an attempt to reconnect will be made.
197     * For queries that involve no larger transactions or locks, they will be re-issued
198     * for convenience, provided the connection was re-established.
199     *
200     * In new code, the query wrappers select(), insert(), update(), delete(),
201     * etc. should be used where possible, since they give much better DBMS
202     * independence and automatically quote or validate user input in a variety
203     * of contexts. This function is generally only useful for queries which are
204     * explicitly DBMS-dependent and are unsupported by the query wrappers, such
205     * as CREATE TABLE.
206     *
207     * However, the query wrappers themselves should call this function.
208     *
209     * Callers should avoid the use of statements like BEGIN, COMMIT, and ROLLBACK.
210     * Methods like startAtomic(), endAtomic(), and cancelAtomic() can be used instead.
211     *
212     * @param string|Query $sql Single-statement SQL query
213     * @param-taint $sql exec_sql
214     * @param string $fname Caller name; used for profiling/SHOW PROCESSLIST comments @phan-mandatory-param
215     * @param int $flags Bit field of ISQLPlatform::QUERY_* constants
216     * @return bool|IResultWrapper True for a successful write query, IResultWrapper object
217     *     for a successful read query, or false on failure if QUERY_SILENCE_ERRORS is set
218     * @return-taint tainted
219     * @throws DBQueryError If the query is issued, fails, and QUERY_SILENCE_ERRORS is not set
220     * @throws DBExpectedError If the query is not, and cannot, be issued yet (non-DBQueryError)
221     * @throws DBError If the query is inherently not allowed (non-DBExpectedError)
222     */
223    public function query( $sql, $fname = __METHOD__, $flags = 0 );
224
225    /**
226     * Get an UpdateQueryBuilder bound to this connection. This is overridden by
227     * DBConnRef.
228     *
229     * @note A new query builder must be created per query. Query builders
230     *   should not be reused since this uses a fluent interface and the state of
231     *   the builder changes during the query which may cause unexpected results.
232     *
233     * @return UpdateQueryBuilder
234     */
235    public function newUpdateQueryBuilder(): UpdateQueryBuilder;
236
237    /**
238     * Get an DeleteQueryBuilder bound to this connection. This is overridden by
239     * DBConnRef.
240     *
241     * @note A new query builder must be created per query. Query builders
242     *   should not be reused since this uses a fluent interface and the state of
243     *   the builder changes during the query which may cause unexpected results.
244     *
245     * @return DeleteQueryBuilder
246     */
247    public function newDeleteQueryBuilder(): DeleteQueryBuilder;
248
249    /**
250     * Get an InsertQueryBuilder bound to this connection. This is overridden by
251     * DBConnRef.
252     *
253     * @note A new query builder must be created per query. Query builders
254     *   should not be reused since this uses a fluent interface and the state of
255     *   the builder changes during the query which may cause unexpected results.
256     *
257     * @return InsertQueryBuilder
258     */
259    public function newInsertQueryBuilder(): InsertQueryBuilder;
260
261    /**
262     * Get an ReplaceQueryBuilder bound to this connection. This is overridden by
263     * DBConnRef.
264     *
265     * @note A new query builder must be created per query. Query builders
266     *   should not be reused since this uses a fluent interface and the state of
267     *   the builder changes during the query which may cause unexpected results.
268     *
269     * @return ReplaceQueryBuilder
270     */
271    public function newReplaceQueryBuilder(): ReplaceQueryBuilder;
272
273    /**
274     * Lock all rows meeting the given conditions/options FOR UPDATE
275     *
276     * @param string|string[] $table The unqualified name of table(s) (use an array for a join)
277     * @param string|IExpression|array<string,?scalar|non-empty-array<int,?scalar>|RawSQLValue>|array<int,string|IExpression> $conds
278     *   Condition in the format of IDatabase::select() conditions
279     * @param string $fname Function name for profiling @phan-mandatory-param
280     * @param array $options Options for select ("FOR UPDATE" is added automatically)
281     * @param array $join_conds Join conditions
282     * @return int Number of matching rows found (and locked)
283     * @throws DBError If an error occurs, {@see query}
284     * @since 1.32
285     * @deprecated since 1.43; Use SelectQueryBuilder::acquireRowLocks
286     */
287    public function lockForUpdate(
288        $table, $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
289    );
290
291    /**
292     * Insert row(s) into a table, in the provided order
293     *
294     * This operation will be seen by affectedRows()/insertId() as one query statement,
295     * regardless of how many statements are actually sent by the class implementation.
296     *
297     * @internal callers outside of rdbms library should use InsertQueryBuilder instead.
298     *
299     * @param string $table The unqualified name of a table
300     * @param array|array[] $rows Row(s) to insert, as either:
301     *   - A string-keyed map of (column name => value) defining a new row. Values are
302     *     treated as literals and quoted appropriately; null is interpreted as NULL.
303     *   - An integer-keyed list of such string-keyed maps, defining a list of new rows.
304     *     The keys in each map must be identical to each other and in the same order.
305     *     The rows must not collide with each other.
306     * @param string $fname Calling function name (use __METHOD__) for logs/profiling @phan-mandatory-param
307     * @param string|array $options Combination map/list where each string-keyed entry maps
308     *   a non-boolean option to the option parameters and each integer-keyed value is the
309     *   name of a boolean option. Supported options are:
310     *     - IGNORE: Boolean: skip insertion of rows that would cause unique key conflicts.
311     *       IDatabase::affectedRows() can be used to determine how many rows were inserted.
312     * @return bool Return true if no exception was thrown (deprecated since 1.33)
313     * @throws DBError If an error occurs, {@see query}
314     */
315    public function insert( $table, $rows, $fname = __METHOD__, $options = [] );
316
317    /**
318     * Update all rows in a table that match a given condition
319     *
320     * This operation will be seen by affectedRows()/insertId() as one query statement,
321     * regardless of how many statements are actually sent by the class implementation.
322     *
323     * @internal callers outside of rdbms library should use UpdateQueryBuilder instead.
324     *
325     * @param string $table The unqualified name of a table
326     * @param-taint $table exec_sql
327     * @param array<string,?scalar|RawSQLValue>|array<int,string> $set
328     *   Combination map/list where each string-keyed entry maps a column
329     *   to a literal assigned value and each integer-keyed value is a SQL expression in the
330     *   format of a column assignment within UPDATE...SET. The (column => value) entries are
331     *   convenient due to automatic value quoting and conversion of null to NULL. The SQL
332     *   assignment format is useful for updates like "column = column + X". All assignments
333     *   have no defined execution order, so they should not depend on each other. Do not
334     *   modify AUTOINCREMENT or UUID columns in assignments.
335     * @param-taint $set exec_sql_numkey
336     * @param string|IExpression|array<string,?scalar|non-empty-array<int,?scalar>|RawSQLValue>|array<int,string|IExpression> $conds
337     *   Condition in the format of IDatabase::select() conditions.
338     *   In order to prevent possible performance or replication issues or damaging a data
339     *   accidentally, an empty condition for 'update' queries isn't allowed.
340     *   IDatabase::ALL_ROWS should be passed explicitly in order to update all rows.
341     * @param-taint $conds exec_sql_numkey
342     * @param string $fname Calling function name (use __METHOD__) for logs/profiling @phan-mandatory-param
343     * @param-taint $fname exec_sql
344     * @param string|array $options Combination map/list where each string-keyed entry maps
345     *   a non-boolean option to the option parameters and each integer-keyed value is the
346     *   name of a boolean option. Supported options are:
347     *     - IGNORE: Boolean: skip update of rows that would cause unique key conflicts.
348     *       IDatabase::affectedRows() includes all matching rows,
349     *       that includes also rows not updated due to key conflict.
350     * @param-taint $options none
351     * @return bool Return true if no exception was thrown (deprecated since 1.33)
352     * @return-taint none
353     * @throws DBError If an error occurs, {@see query}
354     */
355    public function update( $table, $set, $conds, $fname = __METHOD__, $options = [] );
356
357    /**
358     * Insert row(s) into a table, in the provided order, while deleting conflicting rows
359     *
360     * Conflicts are determined by the provided unique indexes. Note that it is possible
361     * for the provided rows to conflict even among themselves; it is preferable for the
362     * caller to de-duplicate such input beforehand.
363     *
364     * Note some important implications of the deletion semantics:
365     *   - If the table has an AUTOINCREMENT column and $rows omit that column, then any
366     *     conflicting existing rows will be replaced with newer having higher values for
367     *     that column, even if nothing else changed.
368     *   - There might be worse contention than upsert() due to the use of gap-locking.
369     *     This does not apply to RDBMS types that use predicate locking nor those that
370     *     just lock the whole table or databases anyway.
371     *
372     * This operation will be seen by affectedRows()/insertId() as one query statement,
373     * regardless of how many statements are actually sent by the class implementation.
374     *
375     * @internal callers outside of rdbms library should use ReplaceQueryBuilder instead.
376     *
377     * @param string $table The unqualified name of a table
378     * @param string|string[]|string[][] $uniqueKeys Column name or non-empty list of column
379     *   name lists that define all applicable unique keys on the table. There must only be
380     *   one such key. Each unique key on the table is "applicable" unless either:
381     *     - It involves an AUTOINCREMENT column for which no values are assigned in $rows
382     *     - It involves a UUID column for which newly generated UUIDs are assigned in $rows
383     * @param array|array[] $rows Row(s) to insert, in the form of either:
384     *   - A string-keyed map of (column name => value) defining a new row. Values are
385     *     treated as literals and quoted appropriately; null is interpreted as NULL.
386     *     Columns belonging to a key in $uniqueKeys must be defined here and non-null.
387     *   - An integer-keyed list of such string-keyed maps, defining a list of new rows.
388     *     The keys in each map must be identical to each other and in the same order.
389     *     The rows must not collide with each other.
390     * @param string $fname Calling function name (use __METHOD__) for logs/profiling @phan-mandatory-param
391     * @throws DBError If an error occurs, {@see query}
392     */
393    public function replace( $table, $uniqueKeys, $rows, $fname = __METHOD__ );
394
395    /**
396     * Upsert row(s) into a table, in the provided order, while updating conflicting rows
397     *
398     * Conflicts are determined by the provided unique indexes. Note that it is possible
399     * for the provided rows to conflict even among themselves; it is preferable for the
400     * caller to de-duplicate such input beforehand.
401     *
402     * This operation will be seen by affectedRows()/insertId() as one query statement,
403     * regardless of how many statements are actually sent by the class implementation.
404     *
405     * @internal callers outside of rdbms library should use InsertQueryBuilder instead.
406     *
407     * @param string $table The unqualified name of a table
408     * @param array|array[] $rows Row(s) to insert, in the form of either:
409     *   - A string-keyed map of (column name => value) defining a new row. Values are
410     *     treated as literals and quoted appropriately; null is interpreted as NULL.
411     *     Columns belonging to a key in $uniqueKeys must be defined here and non-null.
412     *   - An integer-keyed list of such string-keyed maps, defining a list of new rows.
413     *     The keys in each map must be identical to each other and in the same order.
414     *     The rows must not collide with each other.
415     * @param string|string[]|string[][] $uniqueKeys Column name or non-empty list of column
416     *   name lists that define all applicable unique keys on the table. There must only be
417     *   one such key. Each unique key on the table is "applicable" unless either:
418     *     - It involves an AUTOINCREMENT column for which no values are assigned in $rows
419     *     - It involves a UUID column for which newly generated UUIDs are assigned in $rows
420     * @param array<string,?scalar|RawSQLValue>|array<int,string> $set
421     *   Combination map/list where each string-keyed entry maps a column
422     *   to a literal assigned value and each integer-keyed value is a SQL assignment expression
423     *   of the form "<unquoted alphanumeric column> = <SQL expression>". The (column => value)
424     *   entries are convenient due to automatic value quoting and conversion of null to NULL.
425     *   The SQL assignment entries are useful for updates like "column = column + X". All of
426     *   the assignments have no defined execution order, so callers should make sure that they
427     *   not depend on each other. Do not modify AUTOINCREMENT or UUID columns in assignments,
428     *   even if they are just "secondary" unique keys. For multi-row upserts, use
429     *   buildExcludedValue() to reference the value of a column from the corresponding row
430     *   in $rows that conflicts with the current row.
431     * @param string $fname Calling function name (use __METHOD__) for logs/profiling @phan-mandatory-param
432     * @throws DBError If an error occurs, {@see query}
433     * @since 1.22
434     */
435    public function upsert(
436        $table, array $rows, $uniqueKeys, array $set, $fname = __METHOD__
437    );
438
439    /**
440     * Delete all rows in a table that match a condition which includes a join
441     *
442     * For safety, an empty $conds will not delete everything. If you want to
443     * delete all rows where the join condition matches, set $conds=IDatabase::ALL_ROWS.
444     *
445     * DO NOT put the join condition in $conds.
446     *
447     * This operation will be seen by affectedRows()/insertId() as one query statement,
448     * regardless of how many statements are actually sent by the class implementation.
449     *
450     * @param string $delTable The unqualified name of the table to delete rows from.
451     * @param string $joinTable The unqualified name of the reference table to join on.
452     * @param string $delVar The variable to join on, in the first table.
453     * @param string $joinVar The variable to join on, in the second table.
454     * @param string|IExpression|array<string,?scalar|non-empty-array<int,?scalar>|RawSQLValue>|array<int,string|IExpression> $conds
455     *   Condition array of field names mapped to variables,
456     *   ANDed together in the WHERE clause
457     * @param string $fname Calling function name (use __METHOD__) for logs/profiling @phan-mandatory-param
458     * @throws DBError If an error occurs, {@see query}
459     */
460    public function deleteJoin(
461        $delTable,
462        $joinTable,
463        $delVar,
464        $joinVar,
465        $conds,
466        $fname = __METHOD__
467    );
468
469    /**
470     * Delete all rows in a table that match a condition
471     *
472     * This operation will be seen by affectedRows()/insertId() as one query statement,
473     * regardless of how many statements are actually sent by the class implementation.
474     *
475     * @internal callers outside of rdbms library should use DeleteQueryBuilder instead.
476     *
477     * @param string $table The unqualified name of a table
478     * @param-taint $table exec_sql
479     * @param string|IExpression|array<string,?scalar|non-empty-array<int,?scalar>|RawSQLValue>|array<int,string|IExpression> $conds
480     *   Array of conditions. See $conds in IDatabase::select()
481     *   In order to prevent possible performance or replication issues or damaging a data
482     *   accidentally, an empty condition for 'delete' queries isn't allowed.
483     *   IDatabase::ALL_ROWS should be passed explicitly in order to delete all rows.
484     * @param-taint $conds exec_sql_numkey
485     * @param string $fname Name of the calling function @phan-mandatory-param
486     * @param-taint $fname exec_sql
487     * @return bool Return true if no exception was thrown (deprecated since 1.33)
488     * @return-taint none
489     * @throws DBError If an error occurs, {@see query}
490     */
491    public function delete( $table, $conds, $fname = __METHOD__ );
492
493    /**
494     * INSERT SELECT wrapper
495     *
496     * @warning If the insert will use an auto-increment or sequence to
497     *  determine the value of a column, this may break replication on
498     *  databases using statement-based replication if the SELECT is not
499     *  deterministically ordered.
500     *
501     * This operation will be seen by affectedRows()/insertId() as one query statement,
502     * regardless of how many statements are actually sent by the class implementation.
503     *
504     * @param string $destTable Unqualified name of destination table
505     * @param string|array $srcTable Unqualified name of source table(s) (use an array for a join)
506     * @param array $varMap Must be an associative array of the form
507     *    [ 'dest1' => 'source1', ... ]. Source items may be literals
508     *    rather than field names, but strings should be quoted with
509     *    IDatabase::addQuotes()
510     * @param string|IExpression|array<string,?scalar|non-empty-array<int,?scalar>|RawSQLValue>|array<int,string|IExpression> $conds
511     *    Condition array. See $conds in IDatabase::select() for
512     *    the details of the format of condition arrays. May be "*" to copy the
513     *    whole table.
514     * @param string $fname The function name of the caller, from __METHOD__ @phan-mandatory-param
515     * @param array $insertOptions Options for the INSERT part of the query, see
516     *    IDatabase::insert() for details. Also, one additional option is
517     *    available: pass 'NO_AUTO_COLUMNS' to hint that the query does not use
518     *    an auto-increment or sequence to determine any column values.
519     * @param array $selectOptions Options for the SELECT part of the query, see
520     *    IDatabase::select() for details.
521     * @param array $selectJoinConds Join conditions for the SELECT part of the query, see
522     *    IDatabase::select() for details.
523     * @return bool Return true if no exception was thrown (deprecated since 1.33)
524     * @throws DBError If an error occurs, {@see query}
525     */
526    public function insertSelect(
527        $destTable,
528        $srcTable,
529        $varMap,
530        $conds,
531        $fname = __METHOD__,
532        $insertOptions = [],
533        $selectOptions = [],
534        $selectJoinConds = []
535    );
536
537    /**
538     * Run a callback when the current transaction commits or rolls back
539     *
540     * An error is thrown if no transaction is pending.
541     *
542     * When transaction round mode (DBO_TRX) is set, the callback will run at the end
543     * of the round, just after all peer transactions COMMIT/ROLLBACK.
544     *
545     * This IDatabase instance will start off in auto-commit mode when the callback starts.
546     * The use of other IDatabase handles from the callback should be avoided unless they are
547     * known to be in auto-commit mode. Callbacks that create transactions via begin() or
548     * startAtomic() must have matching calls to commit()/endAtomic().
549     *
550     * Use this method only for the following purposes:
551     *   - (a) Release of cooperative locks on resources
552     *   - (b) Cancellation of in-process deferred tasks
553     *
554     * The callback takes the following arguments:
555     *   - How the current atomic section (if any) or overall transaction (otherwise) ended
556     *     (IDatabase::TRIGGER_COMMIT or IDatabase::TRIGGER_ROLLBACK)
557     *   - This IDatabase instance (since 1.32)
558     *
559     * Callbacks will execute in the order they were enqueued.
560     *
561     * @param callable $callback
562     * @param string $fname Caller name @phan-mandatory-param
563     * @throws DBError If an error occurs, {@see query}
564     * @throws Exception If the callback runs immediately and an error occurs in it
565     * @since 1.28
566     */
567    public function onTransactionResolution( callable $callback, $fname = __METHOD__ );
568
569    /**
570     * Run a callback when the current transaction commits or now if there is none
571     *
572     * If there is a transaction and it is rolled back, then the callback is cancelled.
573     *
574     * When transaction round mode (DBO_TRX) is set, the callback will run at the end
575     * of the round, just after all peer transactions COMMIT. If the transaction round
576     * is rolled back, then the callback is cancelled.
577     *
578     * This IDatabase instance will start off in auto-commit mode when the callback starts.
579     * The use of other IDatabase handles from the callback should be avoided unless they are
580     * known to be in auto-commit mode. Callbacks that create transactions via begin() or
581     * startAtomic() must have matching calls to commit()/endAtomic().
582     *
583     * Use this method only for the following purposes:
584     *   - (a) RDBMS updates, prone to lock timeouts/deadlocks, that do not require
585     *         atomicity with respect to the updates in the current transaction (if any)
586     *   - (b) Purges to lightweight cache services due to RDBMS updates
587     *   - (c) Updates to secondary DBs/stores that must only commit once the updates in
588     *         the current transaction (if any) are committed (e.g. insert user account row
589     *         to DB1, then, initialize corresponding LDAP account)
590     *
591     * The callback takes the following arguments:
592     *   - How the transaction ended (IDatabase::TRIGGER_COMMIT or IDatabase::TRIGGER_IDLE)
593     *   - This IDatabase instance (since 1.32)
594     *
595     * Callbacks will execute in the order they were enqueued.
596     *
597     * @param callable $callback
598     * @param string $fname Caller name @phan-mandatory-param
599     * @throws DBError If an error occurs, {@see query}
600     * @throws Exception If the callback runs immediately and an error occurs in it
601     * @since 1.32
602     */
603    public function onTransactionCommitOrIdle( callable $callback, $fname = __METHOD__ );
604
605    /**
606     * Run a callback before the current transaction commits or now if there is none
607     *
608     * If there is a transaction and it is rolled back, then the callback is cancelled.
609     *
610     * When transaction round mode (DBO_TRX) is set, the callback will run at the end
611     * of the round, just after all peer transactions COMMIT. If the transaction round
612     * is rolled back, then the callback is cancelled.
613     *
614     * If there is no current transaction, one will be created to wrap the callback.
615     * Callbacks cannot use begin()/commit() to manage transactions. The use of other
616     * IDatabase handles from the callback should be avoided.
617     *
618     * Use this method only for the following purposes:
619     *   - a) RDBMS updates, prone to lock timeouts/deadlocks, that require atomicity
620     *        with respect to the updates in the current transaction (if any)
621     *   - b) Purges to lightweight cache services due to RDBMS updates
622     *
623     * The callback takes the one argument:
624     *   - This IDatabase instance (since 1.32)
625     *
626     * Callbacks will execute in the order they were enqueued.
627     *
628     * @param callable $callback
629     * @param string $fname Caller name @phan-mandatory-param
630     * @throws DBError If an error occurs, {@see query}
631     * @throws Exception If the callback runs immediately and an error occurs in it
632     * @since 1.22
633     */
634    public function onTransactionPreCommitOrIdle( callable $callback, $fname = __METHOD__ );
635
636    /**
637     * Begin an atomic section of SQL statements
638     *
639     * Start an implicit transaction if no transaction is already active, set a savepoint
640     * (if $cancelable is ATOMIC_CANCELABLE), and track the given section name to enforce
641     * that the transaction is not committed prematurely. The end of the section must be
642     * signified exactly once, either by endAtomic() or cancelAtomic(). Sections can have
643     * have layers of inner sections (sub-sections), but all sections must be ended in order
644     * of innermost to outermost. Transactions cannot be started or committed until all
645     * atomic sections are closed.
646     *
647     * ATOMIC_CANCELABLE is useful when the caller needs to handle specific failure cases
648     * by discarding the section's writes.  This should not be used for failures when:
649     *   - upsert() could easily be used instead
650     *   - insert() with IGNORE could easily be used instead
651     *   - select() with FOR UPDATE could be checked before issuing writes instead
652     *   - The failure is from code that runs after the first write but doesn't need to
653     *   - The failures are from contention solvable via onTransactionPreCommitOrIdle()
654     *   - The failures are deadlocks; the RDBMs usually discard the whole transaction
655     *
656     * @note callers must use additional measures for situations involving two or more
657     *   (peer) transactions (e.g. updating two database servers at once). The transaction
658     *   and savepoint logic of this method only applies to this specific IDatabase instance.
659     *
660     * Example usage:
661     * @code
662     *     // Start a transaction if there isn't one already
663     *     $dbw->startAtomic( __METHOD__ );
664     *     // Serialize these thread table updates
665     *     $dbw->select( 'thread', '1', [ 'td_id' => $tid ], __METHOD__, 'FOR UPDATE' );
666     *     // Add a new comment for the thread
667     *     $dbw->insert( 'comment', $row, __METHOD__ );
668     *     $cid = $db->insertId();
669     *     // Update thread reference to last comment
670     *     $dbw->update( 'thread', [ 'td_latest' => $cid ], [ 'td_id' => $tid ], __METHOD__ );
671     *     // Demark the end of this conceptual unit of updates
672     *     $dbw->endAtomic( __METHOD__ );
673     * @endcode
674     *
675     * Example usage (atomic changes that might have to be discarded):
676     * @code
677     *     // Start a transaction if there isn't one already
678     *     $sectionId = $dbw->startAtomic( __METHOD__, $dbw::ATOMIC_CANCELABLE );
679     *     // Create new record metadata row
680     *     $dbw->insert( 'records', $row, __METHOD__ );
681     *     // Figure out where to store the data based on the new row's ID
682     *     $path = $recordDirectory . '/' . $dbw->insertId();
683     *     // Write the record data to the storage system
684     *     $status = $fileBackend->create( [ 'dst' => $path, 'content' => $data ] );
685     *     if ( $status->isOK() ) {
686     *         // Try to cleanup files orphaned by transaction rollback
687     *         $dbw->onTransactionResolution(
688     *             function ( $type ) use ( $fileBackend, $path ) {
689     *                 if ( $type === IDatabase::TRIGGER_ROLLBACK ) {
690     *                     $fileBackend->delete( [ 'src' => $path ] );
691     *                 }
692     *             },
693     *             __METHOD__
694     *         );
695     *         // Demark the end of this conceptual unit of updates
696     *         $dbw->endAtomic( __METHOD__ );
697     *     } else {
698     *         // Discard these writes from the transaction (preserving prior writes)
699     *         $dbw->cancelAtomic( __METHOD__, $sectionId );
700     *     }
701     * @endcode
702     *
703     * @since 1.23
704     * @param string $fname @phan-mandatory-param
705     * @param string $cancelable Pass self::ATOMIC_CANCELABLE to use a
706     *  savepoint and enable self::cancelAtomic() for this section.
707     * @return AtomicSectionIdentifier section ID token
708     * @throws DBError If an error occurs, {@see query}
709     */
710    public function startAtomic( $fname = __METHOD__, $cancelable = self::ATOMIC_NOT_CANCELABLE );
711
712    /**
713     * Ends an atomic section of SQL statements
714     *
715     * Ends the next section of atomic SQL statements and commits the transaction
716     * if necessary.
717     *
718     * @since 1.23
719     * @see IDatabase::startAtomic
720     * @param string $fname @phan-mandatory-param
721     * @throws DBError If an error occurs, {@see query}
722     */
723    public function endAtomic( $fname = __METHOD__ );
724
725    /**
726     * Cancel an atomic section of SQL statements
727     *
728     * This will roll back only the statements executed since the start of the
729     * most recent atomic section, and close that section. If a transaction was
730     * open before the corresponding startAtomic() call, any statements before
731     * that call are *not* rolled back and the transaction remains open. If the
732     * corresponding startAtomic() implicitly started a transaction, that
733     * transaction is rolled back.
734     *
735     * @note callers must use additional measures for situations involving two or more
736     *   (peer) transactions (e.g. updating two database servers at once). The transaction
737     *   and savepoint logic of startAtomic() are bound to specific IDatabase instances.
738     *
739     * Note that a call to IDatabase::rollback() will also roll back any open atomic sections.
740     *
741     * @note As an optimization to save rountrips, this method may only be called
742     *   when startAtomic() was called with the ATOMIC_CANCELABLE flag.
743     * @since 1.31
744     * @see IDatabase::startAtomic
745     * @param string $fname @phan-mandatory-param
746     * @param AtomicSectionIdentifier|null $sectionId Section ID from startAtomic();
747     *   passing this enables cancellation of unclosed nested sections [optional]
748     * @throws DBError If an error occurs, {@see query}
749     */
750    public function cancelAtomic( $fname = __METHOD__, ?AtomicSectionIdentifier $sectionId = null );
751
752    /**
753     * Perform an atomic section of reversible SQL statements from a callback
754     *
755     * The $callback takes the following arguments:
756     *   - This database object
757     *   - The value of $fname
758     *
759     * This will execute the callback inside a pair of startAtomic()/endAtomic() calls.
760     * If any exception occurs during execution of the callback, it will be handled as follows:
761     *   - If $cancelable is ATOMIC_CANCELABLE, cancelAtomic() will be called to back out any
762     *     (and only) statements executed during the atomic section. If that succeeds, then the
763     *     exception will be re-thrown; if it fails, then a different exception will be thrown
764     *     and any further query attempts will fail until rollback() is called.
765     *   - If $cancelable is ATOMIC_NOT_CANCELABLE, cancelAtomic() will be called to mark the
766     *     end of the section and the error will be re-thrown. Any further query attempts will
767     *     fail until rollback() is called.
768     *
769     * This method is convenient for letting calls to the caller of this method be wrapped
770     * in a try/catch blocks for exception types that imply that the caller failed but was
771     * able to properly discard the changes it made in the transaction. This method can be
772     * an alternative to explicit calls to startAtomic()/endAtomic()/cancelAtomic().
773     *
774     * Example usage, "RecordStore::save" method:
775     * @code
776     *     $dbw->doAtomicSection( __METHOD__, function ( $dbw ) use ( $record ) {
777     *         // Create new record metadata row
778     *         $dbw->insert( 'records', $record->toArray(), __METHOD__ );
779     *         // Figure out where to store the data based on the new row's ID
780     *         $path = $this->recordDirectory . '/' . $dbw->insertId();
781     *         // Write the record data to the storage system;
782     *         // blob store throws StoreFailureException on failure
783     *         $this->blobStore->create( $path, $record->getJSON() );
784     *         // Try to cleanup files orphaned by transaction rollback
785     *         $dbw->onTransactionResolution(
786     *             function ( $type ) use ( $path ) {
787     *                 if ( $type === IDatabase::TRIGGER_ROLLBACK ) {
788     *                     $this->blobStore->delete( $path );
789     *                 }
790     *             },
791     *             __METHOD__
792     *          );
793     *     }, $dbw::ATOMIC_CANCELABLE );
794     * @endcode
795     *
796     * Example usage, caller of the "RecordStore::save" method:
797     * @code
798     *     $dbw->startAtomic( __METHOD__ );
799     *     // ...various SQL writes happen...
800     *     try {
801     *         $recordStore->save( $record );
802     *     } catch ( StoreFailureException $e ) {
803     *         // ...various SQL writes happen...
804     *     }
805     *     // ...various SQL writes happen...
806     *     $dbw->endAtomic( __METHOD__ );
807     * @endcode
808     *
809     * @see Database::startAtomic
810     * @see Database::endAtomic
811     * @see Database::cancelAtomic
812     *
813     * @param string $fname Caller name (usually __METHOD__) @phan-mandatory-param
814     * @param callable $callback Callback that issues write queries
815     * @param string $cancelable Pass self::ATOMIC_CANCELABLE to use a
816     *  savepoint and enable self::cancelAtomic() for this section.
817     * @return mixed Result of the callback (since 1.28)
818     * @throws DBError If an error occurs, {@see query}
819     * @throws Exception If an error occurs in the callback
820     * @since 1.27; prior to 1.31 this did a rollback() instead of
821     *  cancelAtomic(), and assumed no callers up the stack would ever try to
822     *  catch the exception.
823     */
824    public function doAtomicSection(
825        $fname, callable $callback, $cancelable = self::ATOMIC_NOT_CANCELABLE
826    );
827
828    /**
829     * Begin a transaction
830     *
831     * Only call this from code with outer transaction scope.
832     * See https://www.mediawiki.org/wiki/Database_transactions for details.
833     * Nesting of transactions is not supported.
834     *
835     * Note that when the DBO_TRX flag is set (which is usually the case for web
836     * requests, but not for maintenance scripts), any previous database query
837     * will have started a transaction automatically.
838     *
839     * Nesting of transactions is not supported. Attempts to nest transactions
840     * will cause a warning, unless the current transaction was started
841     * automatically because of the DBO_TRX flag.
842     *
843     * @param string $fname Calling function name @phan-mandatory-param
844     * @param string $mode A situationally valid IDatabase::TRANSACTION_* constant [optional]
845     * @throws DBError If an error occurs, {@see query}
846     */
847    public function begin( $fname = __METHOD__, $mode = self::TRANSACTION_EXPLICIT );
848
849    /**
850     * Commits a transaction previously started using begin()
851     *
852     * If no transaction is in progress, a warning is issued.
853     *
854     * Only call this from code with outer transaction scope.
855     * See https://www.mediawiki.org/wiki/Database_transactions for details.
856     * Nesting of transactions is not supported.
857     *
858     * @param string $fname @phan-mandatory-param
859     * @param string $flush Flush flag, set to situationally valid IDatabase::FLUSHING_*
860     *   constant to disable warnings about explicitly committing implicit transactions,
861     *   or calling commit when no transaction is in progress.
862     *   This will trigger an exception if there is an ongoing explicit transaction.
863     *   Only set the flush flag if you are sure that these warnings are not applicable,
864     *   and no explicit transactions are open.
865     * @throws DBError If an error occurs, {@see query}
866     */
867    public function commit( $fname = __METHOD__, $flush = self::FLUSHING_ONE );
868
869    /**
870     * Rollback a transaction previously started using begin()
871     *
872     * Only call this from code with outer transaction scope.
873     * See https://www.mediawiki.org/wiki/Database_transactions for details.
874     * Nesting of transactions is not supported. If a serious unexpected error occurs,
875     * throwing an Exception is preferable, using a pre-installed error handler to trigger
876     * rollback (in any case, failure to issue COMMIT will cause rollback server-side).
877     *
878     * Query, connection, and onTransaction* callback errors will be suppressed and logged.
879     *
880     * @param string $fname Calling function name @phan-mandatory-param
881     * @param string $flush Flush flag, set to a situationally valid IDatabase::FLUSHING_*
882     *   constant to disable warnings about explicitly rolling back implicit transactions.
883     *   This will silently break any ongoing explicit transaction. Only set the flush flag
884     *   if you are sure that it is safe to ignore these warnings in your context.
885     * @throws DBError If an error occurs, {@see query}
886     * @since 1.23 Added $flush parameter
887     */
888    public function rollback( $fname = __METHOD__, $flush = self::FLUSHING_ONE );
889
890    /**
891     * Commit any transaction but error out if writes or callbacks are pending
892     *
893     * This is intended for clearing out REPEATABLE-READ snapshots so that callers can
894     * see a new point-in-time of the database. This is useful when one of many transaction
895     * rounds finished and significant time will pass in the script's lifetime. It is also
896     * useful to call on a replica server after waiting on replication to catch up to the
897     * primary server.
898     *
899     * @param string $fname Calling function name @phan-mandatory-param
900     * @param string $flush Flush flag, set to situationally valid IDatabase::FLUSHING_*
901     *   constant to disable warnings about explicitly committing implicit transactions,
902     *   or calling commit when no transaction is in progress.
903     *   This will trigger an exception if there is an ongoing explicit transaction.
904     *   Only set the flush flag if you are sure that these warnings are not applicable,
905     *   and no explicit transactions are open.
906     * @throws DBError If an error occurs, {@see query}
907     * @since 1.28
908     * @since 1.34 Added $flush parameter
909     */
910    public function flushSnapshot( $fname = __METHOD__, $flush = self::FLUSHING_ONE );
911
912    /**
913     * Override database's default behavior.
914     * Not all options are supported on all database backends;
915     * unsupported options are silently ignored.
916     *
917     * $options include:
918     * - 'connTimeout': Set the connection timeout value in seconds.
919     *   May be useful for very long batch queries such as full-wiki dumps,
920     *   where a single query reads out over hours or days.
921     *   Only supported on MySQL and MariaDB.
922     * - 'groupConcatMaxLen': Maximum length of a GROUP_CONCAT() result.
923     *   Only supported on MySQL and MariaDB.
924     *
925     * @param array $options
926     * @return void
927     * @throws DBError If an error occurs, {@see query}
928     */
929    public function setSessionOptions( array $options );
930
931    /**
932     * Check to see if a named lock is not locked by any thread (non-blocking)
933     *
934     * @param string $lockName Name of lock to poll
935     * @param string $method Name of method calling us
936     * @return bool
937     * @throws DBError If an error occurs, {@see query}
938     * @since 1.20
939     */
940    public function lockIsFree( $lockName, $method );
941
942    /**
943     * Acquire a named lock
944     *
945     * Named locks are not related to transactions
946     *
947     * @param string $lockName Name of lock to acquire
948     * @param string $method Name of the calling method
949     * @param int $timeout Acquisition timeout in seconds (0 means non-blocking)
950     * @param int $flags Bit field of IDatabase::LOCK_* constants
951     * @return bool|float|null Success (bool); acquisition time (float/null) if LOCK_TIMESTAMP
952     * @throws DBError If an error occurs, {@see query}
953     */
954    public function lock( $lockName, $method, $timeout = 5, $flags = 0 );
955
956    /**
957     * Release a lock
958     *
959     * Named locks are not related to transactions
960     *
961     * @param string $lockName Name of lock to release
962     * @param string $method Name of the calling method
963     * @return bool Success
964     * @throws DBError If an error occurs, {@see query}
965     */
966    public function unlock( $lockName, $method );
967
968    /**
969     * Acquire a named lock, flush any transaction, and return an RAII style unlocker object
970     *
971     * Only call this from outer transaction scope and when only one DB server will be affected.
972     * See https://www.mediawiki.org/wiki/Database_transactions for details.
973     *
974     * This is suitable for transactions that need to be serialized using cooperative locks,
975     * where each transaction can see each others' changes. Any transaction is flushed to clear
976     * out stale REPEATABLE-READ snapshot data. Once the returned object falls out of PHP scope,
977     * the lock will be released unless a transaction is active. If one is active, then the lock
978     * will be released when it either commits or rolls back.
979     *
980     * If the lock acquisition failed, then no transaction flush happens, and null is returned.
981     *
982     * @param string $lockKey Name of lock to release
983     * @param string $fname Name of the calling method
984     * @param int $timeout Acquisition timeout in seconds
985     * @return ScopedCallback|null
986     * @throws DBError If an error occurs, {@see query}
987     * @since 1.27
988     */
989    public function getScopedLockAndFlush( $lockKey, $fname, $timeout );
990
991    /**
992     * Check if this DB server is marked as read-only according to load balancer info
993     *
994     * @note LoadBalancer checks serverIsReadOnly() when setting the load balancer info array
995     *
996     * @return bool
997     * @since 1.27
998     */
999    public function isReadOnly();
1000}