From 6793b60ecad1db75f07b494e67aa852cdf2ca6f4 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Tue, 9 May 2017 18:27:28 -0700 Subject: [PATCH] Fix some postgres test failures Bug: T75174 Change-Id: If9812ae301f0af84fa012e2e980b92036c1b29b2 --- includes/libs/rdbms/database/DBConnRef.php | 4 ++++ includes/libs/rdbms/database/Database.php | 4 ++++ .../libs/rdbms/database/DatabasePostgres.php | 10 +++++++++- includes/libs/rdbms/database/IDatabase.php | 14 ++++++++++++++ .../api/ApiQueryWatchlistIntegrationTest.php | 3 +++ tests/phpunit/includes/db/LBFactoryTest.php | 19 +++++++++++++++---- 6 files changed, 49 insertions(+), 5 deletions(-) diff --git a/includes/libs/rdbms/database/DBConnRef.php b/includes/libs/rdbms/database/DBConnRef.php index c15572c4f7..b6167aa7ab 100644 --- a/includes/libs/rdbms/database/DBConnRef.php +++ b/includes/libs/rdbms/database/DBConnRef.php @@ -349,6 +349,10 @@ class DBConnRef implements IDatabase { return $this->__call( __FUNCTION__, func_get_args() ); } + public function databasesAreIndependent() { + return $this->__call( __FUNCTION__, func_get_args() ); + } + public function selectDB( $db ) { return $this->__call( __FUNCTION__, func_get_args() ); } diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index 3bb7e6ab5d..3de86ac8fb 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -1691,6 +1691,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware return $field; } + public function databasesAreIndependent() { + return false; + } + public function selectDB( $db ) { # Stub. Shouldn't cause serious problems if it's not overridden, but # if your database engine supports a concept similar to MySQL's diff --git a/includes/libs/rdbms/database/DatabasePostgres.php b/includes/libs/rdbms/database/DatabasePostgres.php index b92d072112..6cf890dfc1 100644 --- a/includes/libs/rdbms/database/DatabasePostgres.php +++ b/includes/libs/rdbms/database/DatabasePostgres.php @@ -105,7 +105,10 @@ class DatabasePostgres extends Database { $this->mDBname = $dbName; $connectVars = [ - 'dbname' => $dbName, + // pg_connect() user $user as the default database. Since a database is *required*, + // at least pick a "don't care" database that is more likely to exist. This case + // arrises when LoadBalancer::getConnection( $i, [], '' ) is used. + 'dbname' => strlen( $dbName ) ? $dbName : 'postgres', 'user' => $user, 'password' => $password ]; @@ -165,11 +168,16 @@ class DatabasePostgres extends Database { return $this->mConn; } + public function databasesAreIndependent() { + return true; + } + /** * Postgres doesn't support selectDB in the same way MySQL does. So if the * DB name doesn't match the open connection, open a new one * @param string $db * @return bool + * @throws DBUnexpectedError */ public function selectDB( $db ) { if ( $this->mDBname !== $db ) { diff --git a/includes/libs/rdbms/database/IDatabase.php b/includes/libs/rdbms/database/IDatabase.php index ac9914b08c..bec26a617a 100644 --- a/includes/libs/rdbms/database/IDatabase.php +++ b/includes/libs/rdbms/database/IDatabase.php @@ -1029,11 +1029,25 @@ interface IDatabase { */ public function buildStringCast( $field ); + /** + * Returns true if DBs are assumed to be on potentially different servers + * + * In systems like mysql/mariadb, different databases can easily be referenced on a single + * connection merely by name, even in a single query via JOIN. On the other hand, Postgres + * treats databases as fully separate, only allowing mechanisms like postgres_fdw to + * effectively "mount" foreign DBs. This is true even among DBs on the same server. + * + * @return bool + * @since 1.29 + */ + public function databasesAreIndependent(); + /** * Change the current database * * @param string $db * @return bool Success or failure + * @throws DBConnectionError If databasesAreIndependent() is true and an error occurs */ public function selectDB( $db ); diff --git a/tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php b/tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php index 0a2cd83dd7..b508928381 100644 --- a/tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php +++ b/tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php @@ -1475,6 +1475,9 @@ class ApiQueryWatchlistIntegrationTest extends ApiTestCase { $this->watchPages( $otherUser, [ $target ] ); + $reloadedUser = User::newFromName( $otherUser->getName() ); + $this->assertEquals( '1234567890', $reloadedUser->getOption( 'watchlisttoken' ) ); + $result = $this->doListWatchlistRequest( [ 'wlowner' => $otherUser->getName(), 'wltoken' => '1234567890', diff --git a/tests/phpunit/includes/db/LBFactoryTest.php b/tests/phpunit/includes/db/LBFactoryTest.php index 8b285cbdf5..049f81f383 100644 --- a/tests/phpunit/includes/db/LBFactoryTest.php +++ b/tests/phpunit/includes/db/LBFactoryTest.php @@ -409,16 +409,27 @@ class LBFactoryTest extends MediaWikiTestCase { "Correct full table name" ); - \MediaWiki\suppressWarnings(); - $this->assertFalse( $db->selectDB( 'garbage-db' ) ); - \MediaWiki\restoreWarnings(); - $this->assertEquals( $this->quoteTable( $db, 'garbage-db' ) . '.' . $this->quoteTable( $db, 'page' ), $db->tableName( 'garbage-db.page' ), "Correct full table name" ); + if ( $db->databasesAreIndependent() ) { + try { + $e = null; + $db->selectDB( 'garbage-db' ); + } catch ( \Wikimedia\Rdbms\DBConnectionError $e ) { + // expected + } + $this->assertInstanceOf( '\Wikimedia\Rdbms\DBConnectionError', $e ); + $this->assertFalse( $db->isOpen() ); + } else { + \MediaWiki\suppressWarnings(); + $this->assertFalse( $db->selectDB( 'garbage-db' ) ); + \MediaWiki\restoreWarnings(); + } + $factory->closeAll(); $factory->destroy(); } -- 2.20.1