diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ca78c847b32..2c3b93c64d4 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,7 @@ +Drupal 7.77, 2020-12-03 +----------------------- +- Hotfix for schema.prefixed tables + Drupal 7.76, 2020-12-02 ----------------------- - Support for MySQL 8 diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index f862144e4f5..cb70533e46a 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.76'); +define('VERSION', '7.77'); /** * Core API compatibility. diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc index af12c57e0de..00df3c13e91 100644 --- a/includes/database/mysql/database.inc +++ b/includes/database/mysql/database.inc @@ -392,8 +392,11 @@ class DatabaseConnection_mysql extends DatabaseConnection { if (substr($prefixSearch, 0, 1) === '{') { // If the prefix already contains one or more quotes remove them. // This can happen when - for example - DrupalUnitTestCase sets up a - // "temporary prefixed database". - $this->prefixReplace[$i] = $quote_char . str_replace($quote_char, '', $this->prefixReplace[$i]); + // "temporary prefixed database". Also if there's a dot in the prefix, + // wrap it in quotes to cater for schema names in prefixes. + $search = array($quote_char, '.'); + $replace = array('', $quote_char . '.' . $quote_char); + $this->prefixReplace[$i] = $quote_char . str_replace($search, $replace, $this->prefixReplace[$i]); } if (substr($prefixSearch, -1) === '}') { $this->prefixReplace[$i] .= $quote_char; diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index dca8168f0a6..04be5c85b84 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -4247,9 +4247,9 @@ class ConnectionUnitTest extends DrupalUnitTestCase { } } - /** - * Test reserved keyword handling (introduced for MySQL 8+) - */ +/** + * Test reserved keyword handling (introduced for MySQL 8+) +*/ class DatabaseReservedKeywordTestCase extends DatabaseTestCase { public static function getInfo() { return array( @@ -4373,5 +4373,50 @@ class DatabaseReservedKeywordTestCase extends DatabaseTestCase { $num_records_after = db_query('SELECT COUNT(*) FROM {virtual}')->fetchField(); $this->assertIdentical($num_records_before, $num_records_after, 'Successful merge query on a table with a name and column which are reserved words.'); } +} + +/** + * Test table prefix handling. +*/ +class DatabaseTablePrefixTestCase extends DatabaseTestCase { + public static function getInfo() { + return array( + 'name' => 'Table prefixes', + 'description' => 'Test handling of table prefixes.', + 'group' => 'Database', + ); + } + public function testSchemaDotTablePrefixes() { + // Get a copy of the default connection options. + $db = Database::getConnection('default', 'default'); + $connection_options = $db->getConnectionOptions(); + + if ($connection_options['driver'] === 'sqlite') { + // In SQLite simpletest's prefixed db tables exist in their own schema + // (e.g. simpletest124904.system), so we cannot test the schema.table + // prefix syntax here. + $this->assert(TRUE, 'Skipping schema.table prefixed tables test for SQLite.'); + return; + } + + $db_name = $connection_options['database']; + // This prefix is usually something like simpletest12345 + $test_prefix = $connection_options['prefix']['default']; + + // Set up a new connection with table prefixes in the form "schema.table" + $prefixed = $connection_options; + $prefixed['prefix'] = array( + 'default' => $test_prefix, + 'users' => $db_name . '.' . $test_prefix, + 'role' => $db_name . '.' . $test_prefix, + ); + Database::addConnectionInfo('default', 'prefixed', $prefixed); + + // Test that the prefixed database connection can query the prefixed tables. + $num_users_prefixed = Database::getConnection('prefixed', 'default')->query('SELECT COUNT(1) FROM {users}')->fetchField(); + $this->assertTrue((int) $num_users_prefixed > 0, 'Successfully queried the users table using a schema.table prefix'); + $num_users_default = Database::getConnection('default', 'default')->query('SELECT COUNT(1) FROM {users}')->fetchField(); + $this->assertEqual($num_users_default, $num_users_prefixed, 'Verified results of query using a connection with schema.table prefixed tables'); + } }