rdbms: IDatabase interface cleanups
[lhc/web/wiklou.git] / includes / libs / rdbms / database / IMaintainableDatabase.php
index 8395359..18e3cbb 100644 (file)
  * http://www.gnu.org/copyleft/gpl.html
  *
  * @file
- * @ingroup Database
  */
+namespace Wikimedia\Rdbms;
+
+use Exception;
+use RuntimeException;
 
 /**
  * Advanced database interface for IDatabase handles that include maintenance methods
@@ -59,8 +62,8 @@ interface IMaintainableDatabase extends IDatabase {
         * This is handy when you need to construct SQL for joins
         *
         * Example:
-        * extract( $dbr->tableNames( 'user', 'watchlist' ) );
-        * $sql = "SELECT wl_namespace,wl_title FROM $watchlist,$user
+        * list( $user, $watchlist ) = $dbr->tableNames( 'user', 'watchlist' ) );
+        * $sql = "SELECT wl_namespace, wl_title FROM $watchlist, $user
         *         WHERE wl_user=user_id AND wl_user=$nameWithQuotes";
         *
         * @return array
@@ -186,4 +189,123 @@ interface IMaintainableDatabase extends IDatabase {
         * @return array
         */
        public function listViews( $prefix = null, $fname = __METHOD__ );
+
+       /**
+        * Creates a new table with structure copied from existing table
+        *
+        * Note that unlike most database abstraction functions, this function does not
+        * automatically append database prefix, because it works at a lower abstraction level.
+        * The table names passed to this function shall not be quoted (this function calls
+        * addIdentifierQuotes() when needed).
+        *
+        * @param string $oldName Name of table whose structure should be copied
+        * @param string $newName Name of table to be created
+        * @param bool $temporary Whether the new table should be temporary
+        * @param string $fname Calling function name
+        * @return bool True if operation was successful
+        * @throws RuntimeException
+        */
+       public function duplicateTableStructure(
+               $oldName, $newName, $temporary = false, $fname = __METHOD__
+       );
+
+       /**
+        * Checks if table locks acquired by lockTables() are transaction-bound in their scope
+        *
+        * Transaction-bound table locks will be released when the current transaction terminates.
+        * Table locks that are not bound to a transaction are not effected by BEGIN/COMMIT/ROLLBACK
+        * and will last until either lockTables()/unlockTables() is called or the TCP connection to
+        * the database is closed.
+        *
+        * @return bool
+        * @since 1.29
+        */
+       public function tableLocksHaveTransactionScope();
+
+       /**
+        * Lock specific tables
+        *
+        * Any pending transaction should be resolved before calling this method, since:
+        *   a) Doing so resets any REPEATABLE-READ snapshot of the data to a fresh one.
+        *   b) Previous row and table locks from the transaction or session may be released
+        *      by LOCK TABLES, which may be unsafe for the changes in such a transaction.
+        *   c) The main use case of lockTables() is to avoid deadlocks and timeouts by locking
+        *      entire tables in order to do long-running, batched, and lag-aware, updates. Batching
+        *      and replication lag checks do not work when all the updates happen in a transaction.
+        *
+        * Always get all relevant table locks up-front in one call, since LOCK TABLES might release
+        * any prior table locks on some RDBMes (e.g MySQL).
+        *
+        * For compatibility, callers should check tableLocksHaveTransactionScope() before using
+        * this method. If locks are scoped specifically to transactions then caller must either:
+        *   - a) Start a new transaction and acquire table locks for the scope of that transaction,
+        *        doing all row updates within that transaction. It will not be possible to update
+        *        rows in batches; this might result in high replication lag.
+        *   - b) Forgo table locks entirely and avoid calling this method. Careful use of hints like
+        *        LOCK IN SHARE MODE and FOR UPDATE and the use of query batching may be preferrable
+        *        to using table locks with a potentially large transaction. Use of MySQL and Postges
+        *        style REPEATABLE-READ (Snapshot Isolation with or without First-Committer-Rule) can
+        *        also be considered for certain tasks that require a consistent view of entire tables.
+        *
+        * If session scoped locks are not supported, then calling lockTables() will trigger
+        * startAtomic(), with unlockTables() triggering endAtomic(). This will automatically
+        * start a transaction if one is not already present and cause the locks to be released
+        * when the transaction finishes (normally during the unlockTables() call).
+        *
+        * In any case, avoid using begin()/commit() in code that runs while such table locks are
+        * acquired, as that breaks in case when a transaction is needed. The startAtomic() and
+        * endAtomic() methods are safe, however, since they will join any existing transaction.
+        *
+        * @param array $read Array of tables to lock for read access
+        * @param array $write Array of tables to lock for write access
+        * @param string $method Name of caller
+        * @return bool
+        * @since 1.29
+        */
+       public function lockTables( array $read, array $write, $method );
+
+       /**
+        * Unlock all tables locked via lockTables()
+        *
+        * If table locks are scoped to transactions, then locks might not be released until the
+        * transaction ends, which could happen after this method is called.
+        *
+        * @param string $method The caller
+        * @return bool
+        * @since 1.29
+        */
+       public function unlockTables( $method );
+
+       /**
+        * List all tables on the database
+        *
+        * @param string $prefix Only show tables with this prefix, e.g. mw_
+        * @param string $fname Calling function name
+        * @throws DBError
+        * @return array
+        */
+       public function listTables( $prefix = null, $fname = __METHOD__ );
+
+       /**
+        * Determines if a given index is unique
+        *
+        * @param string $table
+        * @param string $index
+        *
+        * @return bool
+        */
+       public function indexUnique( $table, $index );
+
+       /**
+        * mysql_fetch_field() wrapper
+        * Returns false if the field doesn't exist
+        *
+        * @param string $table Table name
+        * @param string $field Field name
+        *
+        * @return Field
+        */
+       public function fieldInfo( $table, $field );
 }
+
+class_alias( IMaintainableDatabase::class, 'IMaintainableDatabase' );