From 50aa07938510c1a2e58c62123bb0286dd7560d5a Mon Sep 17 00:00:00 2001 From: Ryan Schmidt Date: Tue, 2 Jan 2018 11:56:32 -0600 Subject: [PATCH] Fix $wgSharedDB with sqlite At the time of the constructor, tableAliases will always be an empty array. As such, the ATTACH command is never run for shared dbs, and we get query errors when later trying to reference them. This changes it so that the shared db is attached whenever the table aliases are finally set. Since table aliases may be set multiple times, the list of already attached dbs was moved into class scope so that subsequent calls to set the aliases do not result in query errors. Bug: T181962 Change-Id: Ia654e996f54077bc3749b884a528e121ab25a2d2 --- .../libs/rdbms/database/DatabaseSqlite.php | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/includes/libs/rdbms/database/DatabaseSqlite.php b/includes/libs/rdbms/database/DatabaseSqlite.php index 2b0660707c..3bdcd65671 100644 --- a/includes/libs/rdbms/database/DatabaseSqlite.php +++ b/includes/libs/rdbms/database/DatabaseSqlite.php @@ -56,6 +56,9 @@ class DatabaseSqlite extends Database { /** @var FSLockManager (hopefully on the same server as the DB) */ protected $lockMgr; + /** @var array List of shared database already attached to this connection */ + private $alreadyAttached = []; + /** * Additional params include: * - dbDirectory : directory containing the DB and the lock file directory @@ -82,16 +85,7 @@ class DatabaseSqlite extends Database { parent::__construct( $p ); // Super doesn't open when $user is false, but we can work with $dbName if ( $p['dbname'] && !$this->isOpen() ) { - if ( $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ) ) { - $done = []; - foreach ( $this->tableAliases as $params ) { - if ( isset( $done[$params['dbname']] ) ) { - continue; - } - $this->attachDatabase( $params['dbname'] ); - $done[$params['dbname']] = 1; - } - } + $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ); } } @@ -302,6 +296,14 @@ class DatabaseSqlite extends Database { return parent::isWriteQuery( $sql ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql ); } + protected function isTransactableQuery( $sql ) { + return parent::isTransactableQuery( $sql ) && !in_array( + $this->getQueryVerb( $sql ), + [ 'ATTACH', 'PRAGMA' ], + true + ); + } + /** * SQLite doesn't allow buffered results or data seeking etc, so we'll use fetchAll as the result * @@ -1033,6 +1035,17 @@ class DatabaseSqlite extends Database { return $this->query( $sql, $fName ); } + public function setTableAliases( array $aliases ) { + parent::setTableAliases( $aliases ); + foreach ( $this->tableAliases as $params ) { + if ( isset( $this->alreadyAttached[$params['dbname']] ) ) { + continue; + } + $this->attachDatabase( $params['dbname'] ); + $this->alreadyAttached[$params['dbname']] = true; + } + } + protected function requiresDatabaseUser() { return false; // just a file } -- 2.20.1