diff --git a/core/modules/mysql/src/Driver/Database/mysql/Schema.php b/core/modules/mysql/src/Driver/Database/mysql/Schema.php index cdadb045da4..7b314000604 100644 --- a/core/modules/mysql/src/Driver/Database/mysql/Schema.php +++ b/core/modules/mysql/src/Driver/Database/mysql/Schema.php @@ -146,7 +146,7 @@ protected function createTableSql($name, $table) { * The field specification, as per the schema data structure format. */ protected function createFieldSql($name, $spec) { - $sql = "`" . $name . "` " . $spec['mysql_type']; + $sql = "[" . $name . "] " . $spec['mysql_type']; if (in_array($spec['mysql_type'], $this->mysqlStringTypes)) { if (isset($spec['length'])) { @@ -284,13 +284,13 @@ protected function createKeysSql($spec) { } if (!empty($spec['unique keys'])) { foreach ($spec['unique keys'] as $key => $fields) { - $keys[] = 'UNIQUE KEY `' . $key . '` (' . $this->createKeySql($fields) . ')'; + $keys[] = 'UNIQUE KEY [' . $key . '] (' . $this->createKeySql($fields) . ')'; } } if (!empty($spec['indexes'])) { $indexes = $this->getNormalizedIndexes($spec); foreach ($indexes as $index => $fields) { - $keys[] = 'INDEX `' . $index . '` (' . $this->createKeySql($fields) . ')'; + $keys[] = 'INDEX [' . $index . '] (' . $this->createKeySql($fields) . ')'; } } @@ -364,10 +364,10 @@ protected function createKeySql($fields) { $return = []; foreach ($fields as $field) { if (is_array($field)) { - $return[] = '`' . $field[0] . '`(' . $field[1] . ')'; + $return[] = '[' . $field[0] . '] (' . $field[1] . ')'; } else { - $return[] = '`' . $field . '`'; + $return[] = '[' . $field . ']'; } } return implode(', ', $return); @@ -385,7 +385,7 @@ public function renameTable($table, $new_name) { } $info = $this->getPrefixInfo($new_name); - $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO `' . $info['table'] . '`'); + $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO [' . $info['table'] . ']'); } /** @@ -479,7 +479,7 @@ public function dropField($table, $field) { $this->dropPrimaryKey($table); } - $this->connection->query('ALTER TABLE {' . $table . '} DROP `' . $field . '`'); + $this->connection->query('ALTER TABLE {' . $table . '} DROP [' . $field . ']'); return TRUE; } @@ -541,7 +541,7 @@ public function addUniqueKey($table, $name, $fields) { throw new SchemaObjectExistsException("Cannot add unique key '$name' to table '$table': unique key already exists."); } - $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')'); + $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY [' . $name . '] (' . $this->createKeySql($fields) . ')'); } /** @@ -552,7 +552,7 @@ public function dropUniqueKey($table, $name) { return FALSE; } - $this->connection->query('ALTER TABLE {' . $table . '} DROP KEY `' . $name . '`'); + $this->connection->query('ALTER TABLE {' . $table . '} DROP KEY [' . $name . ']'); return TRUE; } @@ -570,7 +570,7 @@ public function addIndex($table, $name, $fields, array $spec) { $spec['indexes'][$name] = $fields; $indexes = $this->getNormalizedIndexes($spec); - $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($indexes[$name]) . ')'); + $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX [' . $name . '] (' . $this->createKeySql($indexes[$name]) . ')'); } /** @@ -581,7 +581,7 @@ public function dropIndex($table, $name) { return FALSE; } - $this->connection->query('ALTER TABLE {' . $table . '} DROP INDEX `' . $name . '`'); + $this->connection->query('ALTER TABLE {' . $table . '} DROP INDEX [' . $name . ']'); return TRUE; } @@ -629,7 +629,7 @@ public function changeField($table, $field, $field_new, $spec, $keys_new = []) { $this->ensureNotNullPrimaryKey($keys_new['primary key'], [$field_new => $spec]); } - $sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec)); + $sql = 'ALTER TABLE {' . $table . '} CHANGE [' . $field . '] ' . $this->createFieldSql($field_new, $this->processField($spec)); if ($keys_sql = $this->createKeysSql($keys_new)) { $sql .= ', ADD ' . implode(', ADD ', $keys_sql); } diff --git a/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php b/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php index ecf514018c9..1cadd69902e 100644 --- a/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php +++ b/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php @@ -810,6 +810,7 @@ public function addUniqueKey($table, $name, $fields) { throw new SchemaObjectExistsException("Cannot add unique key '$name' to table '$table': unique key already exists."); } + $fields = array_map([$this->connection, 'escapeField'], $fields); $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT ' . $this->ensureIdentifiersLength($table, $name, 'key') . ' UNIQUE (' . implode(',', $fields) . ')'); $this->resetTableInformation($table); } @@ -926,11 +927,11 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = []) { $field_info = $this->queryFieldInformation($table, $field); foreach ($field_info as $check) { - $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $check . '"'); + $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT [' . $check . ']'); } // Remove old default. - $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT'); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN [' . $field . '] DROP DEFAULT'); // Convert field type. // Usually, we do this via a simple typecast 'USING fieldname::type'. But @@ -940,10 +941,10 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = []) { $is_bytea = !empty($table_information->blob_fields[$field]); if ($spec['pgsql_type'] != 'bytea') { if ($is_bytea) { - $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING convert_from("' . $field . '"' . ", 'UTF8')"); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER [' . $field . '] TYPE ' . $field_def . ' USING convert_from([' . $field . ']' . ", 'UTF8')"); } else { - $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING "' . $field . '"::' . $field_def); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER [' . $field . '] TYPE ' . $field_def . ' USING [' . $field . ']::' . $field_def); } } else { @@ -952,7 +953,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = []) { // Convert to a bytea type by using the SQL replace() function to // convert any single backslashes in the field content to double // backslashes ('\' to '\\'). - $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING decode(replace("' . $field . '"' . ", E'\\\\', E'\\\\\\\\'), 'escape');"); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER [' . $field . '] TYPE ' . $field_def . ' USING decode(replace("' . $field . '"' . ", E'\\\\', E'\\\\\\\\'), 'escape');"); } } @@ -963,7 +964,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = []) { else { $null_action = 'DROP NOT NULL'; } - $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" ' . $null_action); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER [' . $field . '] ' . $null_action); } if (in_array($spec['pgsql_type'], ['serial', 'bigserial'])) { @@ -974,28 +975,28 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = []) { $this->connection->query("CREATE SEQUENCE " . $seq); // Set sequence to maximal field value to not conflict with existing // entries. - $this->connection->query("SELECT setval('" . $seq . "', MAX(\"" . $field . '")) FROM {' . $table . "}"); - $this->connection->query('ALTER TABLE {' . $table . '} ALTER ' . $field . ' SET DEFAULT nextval(' . $this->connection->quote($seq) . ')'); + $this->connection->query("SELECT setval('" . $seq . "', MAX([" . $field . "])) FROM {" . $table . "}"); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER [' . $field . '] SET DEFAULT nextval(' . $this->connection->quote($seq) . ')'); } // Rename the column if necessary. if ($field != $field_new) { - $this->connection->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '"'); + $this->connection->query('ALTER TABLE {' . $table . '} RENAME [' . $field . '] TO [' . $field_new . ']'); } // Add unsigned check if necessary. if (!empty($spec['unsigned'])) { - $this->connection->query('ALTER TABLE {' . $table . '} ADD CHECK ("' . $field_new . '" >= 0)'); + $this->connection->query('ALTER TABLE {' . $table . '} ADD CHECK ([' . $field_new . '] >= 0)'); } // Add default if necessary. if (isset($spec['default'])) { - $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field_new . '" SET DEFAULT ' . $this->escapeDefaultValue($spec['default'])); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN [' . $field_new . '] SET DEFAULT ' . $this->escapeDefaultValue($spec['default'])); } // Change description if necessary. if (!empty($spec['description'])) { - $this->connection->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description'])); + $this->connection->query('COMMENT ON COLUMN {' . $table . '}.[' . $field_new . '] IS ' . $this->prepareComment($spec['description'])); } if (isset($new_keys)) { diff --git a/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php b/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php index ff893d27518..42ffda6e2d8 100644 --- a/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php +++ b/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php @@ -32,7 +32,7 @@ public function tableExists($table) { $info = $this->getPrefixInfo($table); // Don't use {} around sqlite_master table. - return (bool) $this->connection->query('SELECT 1 FROM ' . $info['schema'] . '.sqlite_master WHERE type = :type AND name = :name', [':type' => 'table', ':name' => $info['table']])->fetchField(); + return (bool) $this->connection->query('SELECT 1 FROM [' . $info['schema'] . '].sqlite_master WHERE type = :type AND name = :name', [':type' => 'table', ':name' => $info['table']])->fetchField(); } /** @@ -72,12 +72,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'] . '].[' . $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'] . '].[' . $info['table'] . '_' . $key . '] ON [' . $info['table'] . '] (' . $this->createKeySql($fields) . ")\n"; } } return $sql; @@ -114,10 +114,10 @@ protected function createKeySql($fields) { $return = []; foreach ($fields as $field) { if (is_array($field)) { - $return[] = $field[0]; + $return[] = '[' . $field[0] . ']'; } else { - $return[] = $field; + $return[] = '[' . $field . ']'; } } return implode(', ', $return); @@ -280,7 +280,7 @@ public function renameTable($table, $new_name) { // the table with curly braces in case the db_prefix contains a reference // to a database outside of our existing database. $info = $this->getPrefixInfo($new_name); - $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table']); + $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO [' . $info['table'] . ']'); // Drop the indexes, there is no RENAME INDEX command in SQLite. if (!empty($schema['unique keys'])) { @@ -491,7 +491,7 @@ protected function introspectSchema($table) { ]; $info = $this->getPrefixInfo($table); - $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.table_info(' . $info['table'] . ')'); + $result = $this->connection->query('PRAGMA [' . $info['schema'] . '].table_info([' . $info['table'] . '])'); foreach ($result as $row) { if (preg_match('/^([^(]+)\((.*)\)$/', $row->type, $matches)) { $type = $matches[1]; @@ -547,7 +547,7 @@ protected function introspectSchema($table) { $schema['primary key'] = array_values($schema['primary key']); $indexes = []; - $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.index_list(' . $info['table'] . ')'); + $result = $this->connection->query('PRAGMA [' . $info['schema'] . '].index_list([' . $info['table'] . '])'); foreach ($result as $row) { if (strpos($row->name, 'sqlite_autoindex_') !== 0) { $indexes[] = [ @@ -560,7 +560,7 @@ protected function introspectSchema($table) { $name = $index['name']; // Get index name without prefix. $index_name = substr($name, strlen($info['table']) + 1); - $result = $this->connection->query('PRAGMA ' . $info['schema'] . '.index_info(' . $name . ')'); + $result = $this->connection->query('PRAGMA [' . $info['schema'] . '].index_info([' . $name . '])'); foreach ($result as $row) { $schema[$index['schema_key']][$index_name][] = $row->name; } @@ -701,7 +701,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([' . $info['table'] . '_' . $name . '])')->fetchField() != ''; } /** @@ -714,7 +714,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'] . '].[' . $info['table'] . '_' . $name . ']'); return TRUE; } @@ -746,7 +746,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'] . '].[' . $info['table'] . '_' . $name . ']'); return TRUE; } @@ -825,7 +825,7 @@ public function findTables($table_expression) { // Can't use query placeholders for the schema because the query would // have to be :prefixsqlite_master, which does not work. We also need to // ignore the internal SQLite tables. - $result = $this->connection->query("SELECT name FROM " . $schema . ".sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", [ + $result = $this->connection->query("SELECT name FROM [" . $schema . "].sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", [ ':type' => 'table', ':table_name' => $table_expression, ':pattern' => 'sqlite_%', diff --git a/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php b/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php index 87fa76586c4..c352d84c5f0 100644 --- a/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php +++ b/core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php @@ -19,7 +19,8 @@ * * @group Database */ -class SchemaTest extends KernelTestBase { +class SchemaTest extends KernelTestBase +{ use SchemaIntrospectionTestTrait; @@ -47,7 +48,8 @@ class SchemaTest extends KernelTestBase { /** * {@inheritdoc} */ - protected function setUp(): void { + protected function setUp(): void + { parent::setUp(); $this->connection = Database::getConnection(); $this->schema = $this->connection->schema(); @@ -56,28 +58,29 @@ protected function setUp(): void { /** * Tests database interactions. */ - public function testSchema() { + public function testSchema() + { // Try creating a table. $table_specification = [ 'description' => 'Schema table description may contain "quotes" and could be long—very long indeed.', 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'default' => NULL, ], - 'test_field' => [ + 'test_field' => [ 'type' => 'int', 'not null' => TRUE, 'description' => 'Schema table description may contain "quotes" and could be long—very long indeed. There could be "multiple quoted regions".', ], - 'test_field_string' => [ + 'test_field_string' => [ 'type' => 'varchar', 'length' => 20, 'not null' => TRUE, 'default' => "'\"funky default'\"", 'description' => 'Schema column description for string.', ], - 'test_field_string_ascii' => [ + 'test_field_string_ascii' => [ 'type' => 'varchar_ascii', 'length' => 255, 'description' => 'Schema column description for ASCII string.', @@ -205,11 +208,11 @@ public function testSchema() { $this->schema->dropTable('test_table'); $table_specification = [ 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'serial', 'not null' => TRUE, ], - 'test_field' => [ + 'test_field' => [ 'type' => 'int', 'default' => 0, ], @@ -244,14 +247,14 @@ public function testSchema() { // re-constructed. Hence we can only check that we still have a sequence on // the new table name. if ($this->connection->databaseType() == 'pgsql') { - $sequence_exists = (bool) $this->connection->query("SELECT pg_get_serial_sequence('{" . $new_table_name . "}', 'id')")->fetchField(); + $sequence_exists = (bool)$this->connection->query("SELECT pg_get_serial_sequence('{" . $new_table_name . "}', 'id')")->fetchField(); $this->assertTrue($sequence_exists, 'Sequence was renamed.'); // Rename the table again and repeat the check. $another_table_name = strtolower($this->getRandomGenerator()->name(63 - strlen($this->getDatabasePrefix()))); $this->schema->renameTable($new_table_name, $another_table_name); - $sequence_exists = (bool) $this->connection->query("SELECT pg_get_serial_sequence('{" . $another_table_name . "}', 'id')")->fetchField(); + $sequence_exists = (bool)$this->connection->query("SELECT pg_get_serial_sequence('{" . $another_table_name . "}', 'id')")->fetchField(); $this->assertTrue($sequence_exists, 'Sequence was renamed.'); } @@ -259,7 +262,7 @@ public function testSchema() { $table_specification = [ 'description' => 'Schema table description.', 'fields' => [ - 'timestamp' => [ + 'timestamp' => [ 'mysql_type' => 'timestamp', 'pgsql_type' => 'timestamp', 'sqlite_type' => 'datetime', @@ -270,8 +273,7 @@ public function testSchema() { ]; try { $this->schema->createTable('test_timestamp', $table_specification); - } - catch (\Exception $e) { + } catch (\Exception $e) { } $this->assertTrue($this->schema->tableExists('test_timestamp'), 'Table with database specific datatype was created.'); } @@ -281,32 +283,33 @@ public function testSchema() { * @covers \Drupal\pgsql\Driver\Database\pgsql\Schema::introspectIndexSchema * @covers \Drupal\sqlite\Driver\Database\sqlite\Schema::introspectIndexSchema */ - public function testIntrospectIndexSchema() { + public function testIntrospectIndexSchema() + { $table_specification = [ 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'not null' => TRUE, 'default' => 0, ], - 'test_field_1' => [ + 'test_field_1' => [ 'type' => 'int', 'not null' => TRUE, 'default' => 0, ], - 'test_field_2' => [ + 'test_field_2' => [ 'type' => 'int', 'default' => 0, ], - 'test_field_3' => [ + 'test_field_3' => [ 'type' => 'int', 'default' => 0, ], - 'test_field_4' => [ + 'test_field_4' => [ 'type' => 'int', 'default' => 0, ], - 'test_field_5' => [ + 'test_field_5' => [ 'type' => 'int', 'default' => 0, ], @@ -358,31 +361,32 @@ public function testIntrospectIndexSchema() { * * @see \Drupal\mysql\Driver\Database\mysql\Schema::getNormalizedIndexes() */ - public function testIndexLength() { + public function testIndexLength() + { if ($this->connection->databaseType() !== 'mysql') { $this->markTestSkipped("The '{$this->connection->databaseType()}' database type does not support setting column length for indexes."); } $table_specification = [ 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'default' => NULL, ], - 'test_field_text' => [ + 'test_field_text' => [ 'type' => 'text', 'not null' => TRUE, ], - 'test_field_string_long' => [ + 'test_field_string_long' => [ 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ], - 'test_field_string_ascii_long' => [ + 'test_field_string_ascii_long' => [ 'type' => 'varchar_ascii', 'length' => 255, ], - 'test_field_string_short' => [ + 'test_field_string_short' => [ 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, @@ -418,8 +422,7 @@ public function testIndexLength() { try { $this->schema->addIndex('test_table_index_length', 'test_separate', [['test_field_text', 200]], $missing_field_spec); $this->fail('SchemaException not thrown when adding index with missing information.'); - } - catch (SchemaException $e) { + } catch (SchemaException $e) { $this->assertEquals($expected_exception_message, $e->getMessage()); } @@ -432,16 +435,14 @@ public function testIndexLength() { try { $this->schema->addIndex('test_table_index_length', 'test_separate', [['test_field_text', 200]], $table_specification); $this->fail('\Drupal\Core\Database\SchemaObjectExistsException exception missed.'); - } - catch (SchemaObjectExistsException $e) { + } catch (SchemaObjectExistsException $e) { // Expected exception; just continue testing. } try { $this->schema->addIndex('test_table_non_existing', 'test_separate', [['test_field_text', 200]], $table_specification); $this->fail('\Drupal\Core\Database\SchemaObjectDoesNotExistException exception missed.'); - } - catch (SchemaObjectDoesNotExistException $e) { + } catch (SchemaObjectDoesNotExistException $e) { // Expected exception; just continue testing. } @@ -495,15 +496,15 @@ public function testIndexLength() { * @return bool * TRUE if the insert succeeded, FALSE otherwise. */ - public function tryInsert($table = 'test_table') { + public function tryInsert($table = 'test_table') + { try { $this->connection ->insert($table) ->fields(['id' => mt_rand(10, 20)]) ->execute(); return TRUE; - } - catch (\Exception $e) { + } catch (\Exception $e) { return FALSE; } } @@ -518,7 +519,8 @@ public function tryInsert($table = 'test_table') { * @param $column * Optional column to test. */ - public function checkSchemaComment($description, $table, $column = NULL) { + public function checkSchemaComment($description, $table, $column = NULL) + { if (method_exists($this->schema, 'getComment')) { $comment = $this->schema->getComment($table, $column); // The schema comment truncation for mysql is different. @@ -533,7 +535,8 @@ public function checkSchemaComment($description, $table, $column = NULL) { /** * Tests creating unsigned columns and data integrity thereof. */ - public function testUnsignedColumns() { + public function testUnsignedColumns() + { // First create the table with just a serial column. $table_name = 'unsigned_table'; $table_spec = [ @@ -572,15 +575,15 @@ public function testUnsignedColumns() { * @return bool * TRUE if the insert succeeded, FALSE otherwise. */ - public function tryUnsignedInsert($table_name, $column_name) { + public function tryUnsignedInsert($table_name, $column_name) + { try { $this->connection ->insert($table_name) ->fields([$column_name => -1]) ->execute(); return TRUE; - } - catch (\Exception $e) { + } catch (\Exception $e) { return FALSE; } } @@ -588,7 +591,8 @@ public function tryUnsignedInsert($table_name, $column_name) { /** * Tests adding columns to an existing table with default and initial value. */ - public function testSchemaAddFieldDefaultInitial() { + public function testSchemaAddFieldDefaultInitial() + { // Test varchar types. foreach ([1, 32, 128, 256, 512] as $length) { $base_field_spec = [ @@ -627,7 +631,7 @@ public function testSchemaAddFieldDefaultInitial() { [ 'not null' => TRUE, 'initial_from_field' => 'test_nullable_field', - 'initial' => 100, + 'initial' => 100, ], ]; @@ -678,7 +682,8 @@ public function testSchemaAddFieldDefaultInitial() { * * @internal */ - protected function assertFieldAdditionRemoval(array $field_spec): void { + protected function assertFieldAdditionRemoval(array $field_spec): void + { // Try creating the field on a new table. $table_name = 'test_table_' . ($this->counter++); $table_spec = [ @@ -743,7 +748,8 @@ protected function assertFieldAdditionRemoval(array $field_spec): void { * * @internal */ - protected function assertFieldCharacteristics(string $table_name, string $field_name, array $field_spec): void { + protected function assertFieldCharacteristics(string $table_name, string $field_name, array $field_spec): void + { // Check that the initial value has been registered. if (isset($field_spec['initial'])) { // There should be no row with a value different then $field_spec['initial']. @@ -769,8 +775,7 @@ protected function assertFieldCharacteristics(string $table_name, string $field_ ->execute() ->fetchField(); $this->assertEquals(0, $count, 'Initial values from another field filled out.'); - } - elseif (isset($field_spec['initial_from_field']) && isset($field_spec['initial'])) { + } elseif (isset($field_spec['initial_from_field']) && isset($field_spec['initial'])) { // There should be no row with a value different than '100'. $count = $this->connection ->select($table_name) @@ -814,7 +819,8 @@ protected function assertFieldCharacteristics(string $table_name, string $field_ * @covers ::dropField * @covers ::findPrimaryKeyColumns */ - public function testSchemaChangePrimaryKey(array $initial_primary_key, array $renamed_primary_key) { + public function testSchemaChangePrimaryKey(array $initial_primary_key, array $renamed_primary_key) + { $find_primary_key_columns = new \ReflectionMethod(get_class($this->schema), 'findPrimaryKeyColumns'); $find_primary_key_columns->setAccessible(TRUE); @@ -889,7 +895,8 @@ public function testSchemaChangePrimaryKey(array $initial_primary_key, array $re * @return array * An array of test cases for SchemaTest::testSchemaCreateTablePrimaryKey(). */ - public function providerTestSchemaCreateTablePrimaryKey() { + public function providerTestSchemaCreateTablePrimaryKey() + { $tests = []; $tests['simple_primary_key'] = [ @@ -911,7 +918,8 @@ public function providerTestSchemaCreateTablePrimaryKey() { /** * Tests an invalid field specification as a primary key on table creation. */ - public function testInvalidPrimaryKeyOnTableCreation() { + public function testInvalidPrimaryKeyOnTableCreation() + { // Test making an invalid field the primary key of the table upon creation. $table_name = 'test_table'; $table_spec = [ @@ -928,13 +936,14 @@ public function testInvalidPrimaryKeyOnTableCreation() { /** * Tests converting an int to a serial when the int column has data. */ - public function testChangePrimaryKeyToSerial() { + public function testChangePrimaryKeyToSerial() + { // Test making an invalid field the primary key of the table upon creation. $table_name = 'test_table'; $table_spec = [ 'fields' => [ 'test_field' => ['type' => 'int', 'not null' => TRUE], - 'test_field_string' => ['type' => 'varchar', 'length' => 20], + 'test_field_string' => ['type' => 'varchar', 'length' => 20], ], 'primary key' => ['test_field'], ]; @@ -947,8 +956,7 @@ public function testChangePrimaryKeyToSerial() { ->fields(['test_field_string' => 'test']) ->execute(); $this->fail('Expected IntegrityConstraintViolationException not thrown'); - } - catch (IntegrityConstraintViolationException $e) { + } catch (IntegrityConstraintViolationException $e) { } } @@ -977,8 +985,7 @@ public function testChangePrimaryKeyToSerial() { ->fields(['test_field' => 1]) ->execute(); $this->fail('Expected IntegrityConstraintViolationException not thrown'); - } - catch (IntegrityConstraintViolationException $e) { + } catch (IntegrityConstraintViolationException $e) { } // Ensure auto numbering now works. @@ -992,7 +999,8 @@ public function testChangePrimaryKeyToSerial() { /** * Tests adding an invalid field specification as a primary key. */ - public function testInvalidPrimaryKeyAddition() { + public function testInvalidPrimaryKeyAddition() + { // Test adding a new invalid field to the primary key. $table_name = 'test_table'; $table_spec = [ @@ -1011,7 +1019,8 @@ public function testInvalidPrimaryKeyAddition() { /** * Tests changing the primary key with an invalid field specification. */ - public function testInvalidPrimaryKeyChange() { + public function testInvalidPrimaryKeyChange() + { // Test adding a new invalid field to the primary key. $table_name = 'test_table'; $table_spec = [ @@ -1031,7 +1040,8 @@ public function testInvalidPrimaryKeyChange() { /** * Tests changing columns between types with default and initial values. */ - public function testSchemaChangeFieldDefaultInitial() { + public function testSchemaChangeFieldDefaultInitial() + { $field_specs = [ ['type' => 'int', 'size' => 'normal', 'not null' => FALSE], ['type' => 'int', 'size' => 'normal', 'not null' => TRUE, 'initial' => 1, 'default' => 17], @@ -1085,7 +1095,8 @@ public function testSchemaChangeFieldDefaultInitial() { * * @internal */ - protected function assertFieldChange(array $old_spec, array $new_spec, $test_data = NULL): void { + protected function assertFieldChange(array $old_spec, array $new_spec, $test_data = NULL): void + { $table_name = 'test_table_' . ($this->counter++); $table_spec = [ 'fields' => [ @@ -1132,7 +1143,8 @@ protected function assertFieldChange(array $old_spec, array $new_spec, $test_dat /** * @covers ::findPrimaryKeyColumns */ - public function testFindPrimaryKeyColumns() { + public function testFindPrimaryKeyColumns() + { $method = new \ReflectionMethod(get_class($this->schema), 'findPrimaryKeyColumns'); $method->setAccessible(TRUE); @@ -1140,11 +1152,11 @@ public function testFindPrimaryKeyColumns() { $this->schema->createTable('table_with_pk_0', [ 'description' => 'Table with primary key.', 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'not null' => TRUE, ], - 'test_field' => [ + 'test_field' => [ 'type' => 'int', 'not null' => TRUE, ], @@ -1157,15 +1169,15 @@ public function testFindPrimaryKeyColumns() { $this->schema->createTable('table_with_pk_1', [ 'description' => 'Table with primary key with multiple columns.', 'fields' => [ - 'id0' => [ + 'id0' => [ 'type' => 'int', 'not null' => TRUE, ], - 'id1' => [ + 'id1' => [ 'type' => 'int', 'not null' => TRUE, ], - 'test_field' => [ + 'test_field' => [ 'type' => 'int', 'not null' => TRUE, ], @@ -1179,19 +1191,19 @@ public function testFindPrimaryKeyColumns() { $this->schema->createTable('table_with_pk_2', [ 'description' => 'Table with primary key with multiple columns at the end and in reverted sequence.', 'fields' => [ - 'test_field_1' => [ + 'test_field_1' => [ 'type' => 'int', 'not null' => TRUE, ], - 'test_field_2' => [ + 'test_field_2' => [ 'type' => 'int', 'not null' => TRUE, ], - 'id3' => [ + 'id3' => [ 'type' => 'int', 'not null' => TRUE, ], - 'id4' => [ + 'id4' => [ 'type' => 'int', 'not null' => TRUE, ], @@ -1206,19 +1218,19 @@ public function testFindPrimaryKeyColumns() { $this->schema->createTable('table_with_pk_3', [ 'description' => 'Table with primary key with multiple columns at the end and in reverted sequence.', 'fields' => [ - 'test_field_1' => [ + 'test_field_1' => [ 'type' => 'int', 'not null' => TRUE, ], - 'test_field_2' => [ + 'test_field_2' => [ 'type' => 'int', 'not null' => TRUE, ], - 'id3' => [ + 'id3' => [ 'type' => 'int', 'not null' => TRUE, ], - 'id4' => [ + 'id4' => [ 'type' => 'int', 'not null' => TRUE, ], @@ -1231,11 +1243,11 @@ public function testFindPrimaryKeyColumns() { $this->schema->createTable('table_without_pk_1', [ 'description' => 'Table without primary key.', 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'not null' => TRUE, ], - 'test_field' => [ + 'test_field' => [ 'type' => 'int', 'not null' => TRUE, ], @@ -1247,11 +1259,11 @@ public function testFindPrimaryKeyColumns() { $this->schema->createTable('table_without_pk_2', [ 'description' => 'Table without primary key.', 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'not null' => TRUE, ], - 'test_field' => [ + 'test_field' => [ 'type' => 'int', 'not null' => TRUE, ], @@ -1267,7 +1279,8 @@ public function testFindPrimaryKeyColumns() { /** * Tests the findTables() method. */ - public function testFindTables() { + public function testFindTables() + { // We will be testing with three tables, two of them using the default // prefix and the third one with an individually specified prefix. // Set up a new connection with different connection info. @@ -1287,7 +1300,7 @@ public function testFindTables() { $table_specification = [ 'description' => 'Test table.', 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'default' => NULL, ], @@ -1382,14 +1395,15 @@ public function testFindTables() { /** * Tests handling of uppercase table names. */ - public function testUpperCaseTableName() { + public function testUpperCaseTableName() + { $table_name = 'A_UPPER_CASE_TABLE_NAME'; // Create the tables. $table_specification = [ 'description' => 'Test table.', 'fields' => [ - 'id' => [ + 'id' => [ 'type' => 'int', 'default' => NULL, ], @@ -1405,41 +1419,42 @@ public function testUpperCaseTableName() { /** * Tests default values after altering table. */ - public function testDefaultAfterAlter() { + public function testDefaultAfterAlter() + { $table_name = 'test_table'; // Create the table. $table_specification = [ 'description' => 'Test table.', 'fields' => [ - 'column1' => [ + 'column1' => [ 'type' => 'int', 'default' => NULL, ], - 'column2' => [ + 'column2' => [ 'type' => 'varchar', 'length' => 20, 'default' => NULL, ], - 'column3' => [ + 'column3' => [ 'type' => 'int', 'default' => 200, ], - 'column4' => [ + 'column4' => [ 'type' => 'float', 'default' => 1.23, ], - 'column5' => [ + 'column5' => [ 'type' => 'varchar', 'length' => 20, 'default' => "'s o'clock'", ], - 'column6' => [ + 'column6' => [ 'type' => 'varchar', 'length' => 20, 'default' => "o'clock", ], - 'column7' => [ + 'column7' => [ 'type' => 'varchar', 'length' => 20, 'default' => 'default value', @@ -1476,7 +1491,8 @@ public function testDefaultAfterAlter() { /** * @covers \Drupal\Core\Database\Driver\pgsql\Schema::extensionExists */ - public function testPgsqlExtensionExists() { + public function testPgsqlExtensionExists() + { if ($this->connection->databaseType() !== 'pgsql') { $this->markTestSkipped("This test only runs for PostgreSQL."); } @@ -1488,4 +1504,114 @@ public function testPgsqlExtensionExists() { $this->assertTrue($this->schema->extensionExists('pg_trgm')); } + /** + * Tests handling with reserved keywords for naming tables, fields and more. + */ + public function testReservedKeywordsForNaming() + { + $table_specification = [ + 'description' => 'A test table with an ANSI reserved keywords for naming.', + 'fields' => [ + 'primary' => [ + 'description' => 'Simple unique ID.', + 'type' => 'int', + 'not null' => TRUE, + ], + 'update' => [ + 'description' => 'A column with reserved name.', + 'type' => 'varchar', + 'length' => 255, + ], + ], + 'primary key' => ['primary'], + 'unique keys' => [ + 'having' => ['update'], + ], + 'indexes' => [ + 'in' => ['primary', 'update'], + ], + ]; + + // Creating a table. + $table_name = 'select'; + $this->schema->createTable($table_name, $table_specification); + $this->assertTrue($this->schema->tableExists($table_name)); + + // Finding all tables. + $tables = $this->schema->findTables('%'); + sort($tables); + $this->assertEqual(['config', 'select'], $tables); + + // Renaming a table. + $table_name_new = 'from'; + $this->schema->renameTable($table_name, $table_name_new); + $this->assertFalse($this->schema->tableExists($table_name)); + $this->assertTrue($this->schema->tableExists($table_name_new)); + + // Adding a field. + $field_name = 'delete'; + $this->schema->addField($table_name_new, $field_name, ['type' => 'int', 'not null' => TRUE]); + $this->assertTrue($this->schema->fieldExists($table_name_new, $field_name)); + + // Dropping a primary key. + $this->schema->dropPrimaryKey($table_name_new); + + // Adding a primary key. + $this->schema->addPrimaryKey($table_name_new, [$field_name]); + + // Check the primary key columns. + $find_primary_key_columns = new \ReflectionMethod(get_class($this->schema), 'findPrimaryKeyColumns'); + $find_primary_key_columns->setAccessible(TRUE); + $this->assertEquals([$field_name], $find_primary_key_columns->invoke($this->schema, $table_name_new)); + + // Dropping a primary key. + $this->schema->dropPrimaryKey($table_name_new); + + // Changing a field. + $field_name_new = 'where'; + $this->schema->changeField($table_name_new, $field_name, $field_name_new, ['type' => 'int', 'not null' => FALSE]); + $this->assertFalse($this->schema->fieldExists($table_name_new, $field_name)); + $this->assertTrue($this->schema->fieldExists($table_name_new, $field_name_new)); + + // Adding an unique key + $unique_key_name = $unique_key_introspect_name = 'unique'; + $this->schema->addUniqueKey($table_name_new, $unique_key_name, [$field_name_new]); + + // Check the unique key columns. + $introspect_index_schema = new \ReflectionMethod(get_class($this->schema), 'introspectIndexSchema'); + $introspect_index_schema->setAccessible(TRUE); + if ($this->connection->databaseType() == 'pgsql') { + $ensure_identifiers_length = new \ReflectionMethod(get_class($this->schema), 'ensureIdentifiersLength'); + $ensure_identifiers_length->setAccessible(TRUE); + $unique_key_introspect_name = $ensure_identifiers_length->invoke($this->schema, $table_name_new, $unique_key_name, 'key'); + } + $this->assertEquals([$field_name_new], $introspect_index_schema->invoke($this->schema, $table_name_new)['unique keys'][$unique_key_introspect_name]); + + // Dropping an unique key + $this->schema->dropUniqueKey($table_name_new, $unique_key_name); + + // Dropping a field. + $this->schema->dropField($table_name_new, $field_name_new); + $this->assertFalse($this->schema->fieldExists($table_name_new, $field_name_new)); + + // Adding an index. + $index_name = $index_introspect_name = 'index'; + $this->schema->addIndex($table_name_new, $index_name, ['update'], $table_specification); + $this->assertTrue($this->schema->indexExists($table_name_new, $index_name)); + + // Check the index columns. + if ($this->connection->databaseType() == 'pgsql') { + $index_introspect_name = $ensure_identifiers_length->invoke($this->schema, $table_name_new, $index_name, 'idx'); + } + $this->assertEquals(['update'], $introspect_index_schema->invoke($this->schema, $table_name_new)['indexes'][$index_introspect_name]); + + // Dropping an index. + $this->schema->dropIndex($table_name_new, $index_name); + $this->assertFalse($this->schema->indexExists($table_name_new, $index_name)); + + // Dropping a table. + $this->schema->dropTable($table_name_new); + $this->assertFalse($this->schema->tableExists($table_name_new)); + } + }