Merge "rdbms: inject the mysql index name aliases into Database"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 14 Mar 2018 01:57:50 +0000 (01:57 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 14 Mar 2018 01:57:50 +0000 (01:57 +0000)
1  2 
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/IDatabase.php

@@@ -76,8 -76,10 +76,10 @@@ abstract class Database implements IDat
        protected $password;
        /** @var string */
        protected $dbName;
-       /** @var array[] $aliases Map of (table => (dbname, schema, prefix) map) */
+       /** @var array[] Map of (table => (dbname, schema, prefix) map) */
        protected $tableAliases = [];
+       /** @var string[] Map of (index alias => index) */
+       protected $indexAliases = [];
        /** @var bool Whether this PHP instance is for a CLI script */
        protected $cliMode;
        /** @var string Agent name for query profiling */
  
        public function writesOrCallbacksPending() {
                return $this->trxLevel && (
 -                      $this->trxDoneWrites || $this->trxIdleCallbacks || $this->trxPreCommitCallbacks
 +                      $this->trxDoneWrites ||
 +                      $this->trxIdleCallbacks ||
 +                      $this->trxPreCommitCallbacks ||
 +                      $this->trxEndCallbacks
                );
        }
  
  
        public function close() {
                if ( $this->conn ) {
 +                      // Resolve any dangling transaction first
                        if ( $this->trxLevel() ) {
 +                              // Meaningful transactions should ideally have been resolved by now
 +                              if ( $this->writesOrCallbacksPending() ) {
 +                                      $this->queryLogger->warning(
 +                                              __METHOD__ . ": writes or callbacks still pending.",
 +                                              [ 'trace' => ( new RuntimeException() )->getTraceAsString() ]
 +                                      );
 +                              }
 +                              // Check if it is possible to properly commit and trigger callbacks
 +                              if ( $this->trxEndCallbacksSuppressed ) {
 +                                      throw new DBUnexpectedError(
 +                                              $this,
 +                                              __METHOD__ . ': callbacks are suppressed; cannot properly commit.'
 +                                      );
 +                              }
 +                              // Commit the changes and run any callbacks as needed
                                $this->commit( __METHOD__, self::FLUSHING_INTERNAL );
                        }
 -
 +                      // Close the actual connection in the binding handle
                        $closed = $this->closeConnection();
                        $this->conn = false;
 -              } elseif (
 -                      $this->trxIdleCallbacks ||
 -                      $this->trxPreCommitCallbacks ||
 -                      $this->trxEndCallbacks
 -              ) { // sanity
 -                      throw new RuntimeException( "Transaction callbacks still pending." );
 +                      // Sanity check that no callbacks are dangling
 +                      if (
 +                              $this->trxIdleCallbacks || $this->trxPreCommitCallbacks || $this->trxEndCallbacks
 +                      ) {
 +                              throw new RuntimeException( "Transaction callbacks still pending." );
 +                      }
                } else {
 -                      $closed = true;
 +                      $closed = true; // already closed; nothing to do
                }
 +
                $this->opened = false;
  
                return $closed;
         * @return string
         */
        protected function indexName( $index ) {
-               return $index;
+               return isset( $this->indexAliases[$index] )
+                       ? $this->indexAliases[$index]
+                       : $index;
        }
  
        public function addQuotes( $s ) {
                $this->tableAliases = $aliases;
        }
  
+       public function setIndexAliases( array $aliases ) {
+               $this->indexAliases = $aliases;
+       }
        /**
         * @return bool Whether a DB user is required to access the DB
         * @since 1.28
@@@ -357,7 -357,7 +357,7 @@@ interface IDatabase 
        public function getType();
  
        /**
 -       * Open a connection to the database. Usually aborts on failure
 +       * Open a new connection to the database (closing any existing one)
         *
         * @param string $server Database server host
         * @param string $user Database user name
        public function getServerVersion();
  
        /**
 -       * Closes a database connection.
 -       * if it is open : commits any open transactions
 +       * Close the database connection
 +       *
 +       * This should only be called after any transactions have been resolved,
 +       * aside from read-only transactions (assuming no callbacks are registered).
 +       * If a transaction is still open anyway, it will be committed if possible.
         *
         * @throws DBError
         * @return bool Operation success. true if already closed.
         * @since 1.28
         */
        public function setTableAliases( array $aliases );
+       /**
+        * Convert certain index names to alternative names before querying the DB
+        *
+        * Note that this applies to indexes regardless of the table they belong to.
+        *
+        * This can be employed when an index was renamed X => Y in code, but the new Y-named
+        * indexes were not yet built on all DBs. After all the Y-named ones are added by the DBA,
+        * the aliases can be removed, and then the old X-named indexes dropped.
+        *
+        * @param string[] $aliases
+        * @return mixed
+        * @since 1.31
+        */
+       public function setIndexAliases( array $aliases );
  }
  
  class_alias( IDatabase::class, 'IDatabase' );