diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php index 4b954ed..aab4236 100644 --- a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php +++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php @@ -58,12 +58,12 @@ protected function createIndexSql($tablename, $schema) { $info = $this->getPrefixInfo($tablename); if (!empty($schema['unique keys'])) { foreach ($schema['unique keys'] as $key => $fields) { - $sql[] = 'CREATE UNIQUE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . ")\n"; + $sql[] = 'CREATE UNIQUE INDEX ' . $info['schema'] . '.' . $this->generatePrefixedIndex($info['table'], $key) . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . ")\n"; } } if (!empty($schema['indexes'])) { foreach ($schema['indexes'] as $key => $fields) { - $sql[] = 'CREATE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . ")\n"; + $sql[] = 'CREATE INDEX ' . $info['schema'] . '.' . $this->generatePrefixedIndex($info['table'], $key) . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . ")\n"; } } return $sql; @@ -491,7 +491,7 @@ protected function introspectSchema($table) { foreach ($indexes as $index) { $name = $index['name']; // Get index name without prefix. - $index_name = substr($name, strlen($info['table']) + 1); + $index_name = substr($name, strlen($info['table']) + 2); $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.index_info(' . $name . ')'); foreach ($result as $row) { $schema[$index['schema_key']][$index_name][] = $row->name; @@ -617,7 +617,7 @@ public function addIndex($table, $name, $fields, array $spec) { public function indexExists($table, $name) { $info = $this->getPrefixInfo($table); - return $this->connection->query('PRAGMA ' . $info['schema'] . '.index_info(' . $info['table'] . '_' . $name . ')')->fetchField() != ''; + return $this->connection->query('PRAGMA ' . $info['schema'] . '.index_info(' . $this->generatePrefixedIndex($info['table'], $name) . ')')->fetchField() != ''; } public function dropIndex($table, $name) { @@ -627,7 +627,7 @@ public function dropIndex($table, $name) { $info = $this->getPrefixInfo($table); - $this->connection->query('DROP INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $name); + $this->connection->query('DROP INDEX ' . $info['schema'] . '.' . $this->generatePrefixedIndex($info['table'], $name)); return TRUE; } @@ -653,7 +653,7 @@ public function dropUniqueKey($table, $name) { $info = $this->getPrefixInfo($table); - $this->connection->query('DROP INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $name); + $this->connection->query('DROP INDEX ' . $info['schema'] . '.' . $this->generatePrefixedIndex($info['table'], $name)); return TRUE; } @@ -737,4 +737,20 @@ public function findTables($table_expression) { return $tables; } + /** + * Generates a prefixed index name, based on table and index. + * + * @param string $table + * The table name. + * @param string $index + * The index name. + * + * @return string + * The prefixed name of the index. + */ + protected function generatePrefixedIndex($table, $index) { + $info = $this->getPrefixInfo($table); + return $info['table'] . '__' . $index; + } + } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index c7cc531..7a5ffdb 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1677,5 +1677,33 @@ function system_update_8200() { } /** + * Rename indexes for SQLite. + */ +function system_update_8201() { + $database = \Drupal::database(); + if ($database->driver() == 'sqlite') { + $database_schema = $database->schema(); + $schema = \Drupal::keyValue('entity.storage_schema.sql')->getAll(); + foreach ($schema as $item) { + foreach ($item as $table_name => $table_schema) { + foreach ($table_schema as $schema_key => $schema_data) { + if ($schema_key == 'indexes') { + foreach ($schema_data as $index_name => $index_data) { + // Do not use dropIndex() because the index naming has changed. + $table_prefix = $database->tablePrefix($table_name); + $exists = $database->query('PRAGMA index_info(' . $table_prefix . $table_name . '_' . $index_name . ')')->fetchField() != ''; + if ($exists) { + $database->query('DROP INDEX ' . $table_prefix . $table_name . '_' . $index_name); + } + $database_schema->addIndex($table_name, $index_name, $index_data, $table_schema); + } + } + } + } + } + } +} + +/** * @} End of "addtogroup updates-8.2.0". */ diff --git a/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php b/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php index 8641fd3..54704c3 100644 --- a/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php +++ b/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php @@ -804,4 +804,85 @@ public function testFindTables() { Database::setActiveConnection('default'); } + /** + * Test corner cases of the Schema support. + */ + function testSchemaCornerCases() { + // We should be able to create a table without a primary key. + try { + $table_specification = array( + 'fields' => array( + 'id' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), + ), + 'indexes' => array( + 'id' => array('id'), + ), + ); + Database::getConnection()->schema()->createTable('test_non_primary_key', $table_specification); + + $this->pass('The creation of a table without a primary key succeeded.'); + } + catch (\Exception $e) { + $this->fail('The creation of a table without a primary key failed.'); + } + + // We should be able to create two tables sharing the same index name. + try { + $table_specification = array( + 'fields' => array( + 'name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE), + ), + 'indexes' => array( + 'name' => array('name'), + ), + ); + Database::getConnection()->schema()->createTable('test_index_1', $table_specification); + + $table_specification = array( + 'fields' => array( + 'name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE), + ), + 'indexes' => array( + 'name' => array('name'), + ), + ); + Database::getConnection()->schema()->createTable('test_index_2', $table_specification); + + $this->pass('The creation of two tables sharing the same index name succeeded.'); + } + catch (\Exception $e) { + $this->fail('The creation of two tables sharing the same index name failed.'); + } + + // We should be able to create a table and an index sharing the same name. + try { + // A table name 'test' has an index named 'field'. Does that collide with + // a table named 'test_field'? + $table_specification = array( + 'fields' => array( + 'field' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE), + ), + 'indexes' => array( + 'field' => array('field'), + ) + ); + Database::getConnection()->schema()->createTable('test', $table_specification); + + $table_specification = array( + 'fields' => array( + 'id' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), + ), + 'indexes' => array( + 'id' => array('id'), + ), + ); + Database::getConnection()->schema()->createTable('test_field', $table_specification); + + $this->pass('The creation of a table and an index sharing the same name succeeded.'); + } + catch (\Exception $e) { + $this->fail('The creation of a table and an index sharing the same name failed.'); + } + } + }