Merge "Make DBAccessBase use DBConnRef, rename $wiki, and hide getLoadBalancer()"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / DatabaseSqlite.php
index 8d417e6..0e2dc8f 100644 (file)
@@ -55,10 +55,7 @@ class DatabaseSqlite extends Database {
        protected $lockMgr;
 
        /** @var array List of shared database already attached to this connection */
-       private $alreadyAttached = [];
-
-       /** @var bool Whether full text is enabled */
-       private static $fulltextEnabled = null;
+       private $sessionAttachedDbs = [];
 
        /** @var string[] See https://www.sqlite.org/lang_transaction.html */
        private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
@@ -68,21 +65,21 @@ class DatabaseSqlite extends Database {
         *   - dbDirectory : directory containing the DB and the lock file directory
         *   - dbFilePath  : use this to force the path of the DB file
         *   - trxMode     : one of (deferred, immediate, exclusive)
-        * @param array $params
+        * @param array $p
         */
-       public function __construct( array $params ) {
-               if ( isset( $params['dbFilePath'] ) ) {
-                       $this->dbPath = $params['dbFilePath'];
-                       if ( !strlen( $params['dbname'] ) ) {
-                               $params['dbname'] = self::generateDatabaseName( $this->dbPath );
+       public function __construct( array $p ) {
+               if ( isset( $p['dbFilePath'] ) ) {
+                       $this->dbPath = $p['dbFilePath'];
+                       if ( !strlen( $p['dbname'] ) ) {
+                               $p['dbname'] = self::generateDatabaseName( $this->dbPath );
                        }
-               } elseif ( isset( $params['dbDirectory'] ) ) {
-                       $this->dbDir = $params['dbDirectory'];
+               } elseif ( isset( $p['dbDirectory'] ) ) {
+                       $this->dbDir = $p['dbDirectory'];
                }
 
-               parent::__construct( $params );
+               parent::__construct( $p );
 
-               $this->trxMode = strtoupper( $params['trxMode'] ?? '' );
+               $this->trxMode = strtoupper( $p['trxMode'] ?? '' );
 
                $lockDirectory = $this->getLockFileDirectory();
                if ( $lockDirectory !== null ) {
@@ -96,10 +93,7 @@ class DatabaseSqlite extends Database {
        }
 
        protected static function getAttributes() {
-               return [
-                       self::ATTR_DB_IS_FILE => true,
-                       self::ATTR_DB_LEVEL_LOCKING => true
-               ];
+               return [ self::ATTR_DB_LEVEL_LOCKING => true ];
        }
 
        /**
@@ -188,6 +182,7 @@ class DatabaseSqlite extends Database {
                        if ( in_array( $sync, [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ], true ) ) {
                                $this->query( "PRAGMA synchronous = $sync", __METHOD__, $flags );
                        }
+                       $this->attachDatabasesFromTableAliases();
                } catch ( Exception $e ) {
                        throw $this->newExceptionAfterConnectError( $e->getMessage() );
                }
@@ -294,8 +289,9 @@ class DatabaseSqlite extends Database {
        }
 
        /**
-        * Attaches external database to our connection, see https://sqlite.org/lang_attach.html
-        * for details.
+        * Attaches external database to the connection handle
+        *
+        * @see https://sqlite.org/lang_attach.html
         *
         * @param string $name Database name to be used in queries like
         *   SELECT foo FROM dbname.table
@@ -607,15 +603,10 @@ class DatabaseSqlite extends Database {
                return in_array( 'UNIQUE', $options );
        }
 
-       /**
-        * Filter the options used in SELECT statements
-        *
-        * @param array $options
-        * @return array
-        */
-       function makeSelectOptions( $options ) {
+       protected function makeSelectOptions( array $options ) {
+               // Remove problematic options that the base implementation converts to SQL
                foreach ( $options as $k => $v ) {
-                       if ( is_numeric( $k ) && ( $v == 'FOR UPDATE' || $v == 'LOCK IN SHARE MODE' ) ) {
+                       if ( is_numeric( $k ) && ( $v === 'FOR UPDATE' || $v === 'LOCK IN SHARE MODE' ) ) {
                                $options[$k] = '';
                        }
                }
@@ -1129,12 +1120,23 @@ class DatabaseSqlite extends Database {
 
        public function setTableAliases( array $aliases ) {
                parent::setTableAliases( $aliases );
+               if ( $this->isOpen() ) {
+                       $this->attachDatabasesFromTableAliases();
+               }
+       }
+
+       /**
+        * Issue ATTATCH statements for all unattached foreign DBs in table aliases
+        */
+       private function attachDatabasesFromTableAliases() {
                foreach ( $this->tableAliases as $params ) {
-                       if ( isset( $this->alreadyAttached[$params['dbname']] ) ) {
-                               continue;
+                       if (
+                               $params['dbname'] !== $this->getDBname() &&
+                               !isset( $this->sessionAttachedDbs[$params['dbname']] )
+                       ) {
+                               $this->attachDatabase( $params['dbname'] );
+                               $this->sessionAttachedDbs[$params['dbname']] = true;
                        }
-                       $this->attachDatabase( $params['dbname'] );
-                       $this->alreadyAttached[$params['dbname']] = true;
                }
        }
 
@@ -1152,6 +1154,10 @@ class DatabaseSqlite extends Database {
                return true;
        }
 
+       protected function doHandleSessionLossPreconnect() {
+               $this->sessionAttachedDbs = [];
+       }
+
        /**
         * @return PDO
         */