X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fcore%2Flib%2FDrupal%2FCore%2FDatabase%2FDriver%2Fmysql%2FSchema.php;fp=web%2Fcore%2Flib%2FDrupal%2FCore%2FDatabase%2FDriver%2Fmysql%2FSchema.php;h=9766cfaef11c2183dcf3841230851560fe56fab8;hp=878607c55dc127f2eb453b969f3c2ac4505fbcac;hb=0bf8d09d2542548982e81a441b1f16e75873a04f;hpb=74df008bdbb3a11eeea356744f39b802369bda3c diff --git a/web/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php b/web/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php index 878607c55..9766cfaef 100644 --- a/web/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php +++ b/web/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php @@ -108,6 +108,9 @@ class Schema extends DatabaseSchema { } // Process keys & indexes. + if (!empty($table['primary key']) && is_array($table['primary key'])) { + $this->ensureNotNullPrimaryKey($table['primary key'], $table['fields']); + } $keys = $this->createKeysSql($table); if (count($keys)) { $sql .= implode(", \n", $keys) . ", \n"; @@ -118,8 +121,9 @@ class Schema extends DatabaseSchema { $sql .= 'ENGINE = ' . $table['mysql_engine'] . ' DEFAULT CHARACTER SET ' . $table['mysql_character_set']; // By default, MySQL uses the default collation for new tables, which is - // 'utf8mb4_general_ci' for utf8mb4. If an alternate collation has been - // set, it needs to be explicitly specified. + // 'utf8mb4_general_ci' (MySQL 5) or 'utf8mb4_0900_ai_ci' (MySQL 8) for + // utf8mb4. If an alternate collation has been set, it needs to be + // explicitly specified. // @see \Drupal\Core\Database\Driver\mysql\Schema if (!empty($info['collation'])) { $sql .= ' COLLATE ' . $info['collation']; @@ -151,12 +155,15 @@ class Schema extends DatabaseSchema { if (isset($spec['length'])) { $sql .= '(' . $spec['length'] . ')'; } + if (isset($spec['type']) && $spec['type'] == 'varchar_ascii') { + $sql .= ' CHARACTER SET ascii'; + } if (!empty($spec['binary'])) { $sql .= ' BINARY'; } // Note we check for the "type" key here. "mysql_type" is VARCHAR: - if (isset($spec['type']) && $spec['type'] == 'varchar_ascii') { - $sql .= ' CHARACTER SET ascii COLLATE ascii_general_ci'; + elseif (isset($spec['type']) && $spec['type'] == 'varchar_ascii') { + $sql .= ' COLLATE ascii_general_ci'; } } elseif (isset($spec['precision']) && isset($spec['scale'])) { @@ -212,7 +219,7 @@ class Schema extends DatabaseSchema { // Set the correct database-engine specific datatype. // In case one is already provided, force it to uppercase. if (isset($field['mysql_type'])) { - $field['mysql_type'] = Unicode::strtoupper($field['mysql_type']); + $field['mysql_type'] = mb_strtoupper($field['mysql_type']); } else { $map = $this->getFieldTypeMap(); @@ -409,6 +416,9 @@ class Schema extends DatabaseSchema { // Fields that are part of a PRIMARY KEY must be added as NOT NULL. $is_primary_key = isset($keys_new['primary key']) && in_array($field, $keys_new['primary key'], TRUE); + if ($is_primary_key) { + $this->ensureNotNullPrimaryKey($keys_new['primary key'], [$field => $spec]); + } $fixnull = FALSE; if (!empty($spec['not null']) && !isset($spec['default']) && !$is_primary_key) { @@ -428,14 +438,22 @@ class Schema extends DatabaseSchema { $query .= ', ADD ' . implode(', ADD ', $keys_sql); } $this->connection->query($query); - if (isset($spec['initial'])) { + if (isset($spec['initial_from_field'])) { + if (isset($spec['initial'])) { + $expression = 'COALESCE(' . $spec['initial_from_field'] . ', :default_initial_value)'; + $arguments = [':default_initial_value' => $spec['initial']]; + } + else { + $expression = $spec['initial_from_field']; + $arguments = []; + } $this->connection->update($table) - ->fields([$field => $spec['initial']]) + ->expression($field, $expression, $arguments) ->execute(); } - if (isset($spec['initial_from_field'])) { + elseif (isset($spec['initial'])) { $this->connection->update($table) - ->expression($field, $spec['initial_from_field']) + ->fields([$field => $spec['initial']]) ->execute(); } if ($fixnull) { @@ -452,6 +470,18 @@ class Schema extends DatabaseSchema { return FALSE; } + // When dropping a field that is part of a composite primary key MySQL + // automatically removes the field from the primary key, which can leave the + // table in an invalid state. MariaDB 10.2.8 requires explicitly dropping + // the primary key first for this reason. We perform this deletion + // explicitly which also makes the behavior on both MySQL and MariaDB + // consistent with PostgreSQL. + // @see https://mariadb.com/kb/en/library/alter-table + $primary_key = $this->findPrimaryKeyColumns($table); + if ((count($primary_key) > 1) && in_array($field, $primary_key, TRUE)) { + $this->dropPrimaryKey($table); + } + $this->connection->query('ALTER TABLE {' . $table . '} DROP `' . $field . '`'); return TRUE; } @@ -514,6 +544,17 @@ class Schema extends DatabaseSchema { return TRUE; } + /** + * {@inheritdoc} + */ + protected function findPrimaryKeyColumns($table) { + if (!$this->tableExists($table)) { + return FALSE; + } + $result = $this->connection->query("SHOW KEYS FROM {" . $table . "} WHERE Key_name = 'PRIMARY'")->fetchAllAssoc('Column_name'); + return array_keys($result); + } + /** * {@inheritdoc} */ @@ -579,6 +620,9 @@ class Schema extends DatabaseSchema { if (($field != $field_new) && $this->fieldExists($table, $field_new)) { throw new SchemaObjectExistsException(t("Cannot rename field @table.@name to @name_new: target field already exists.", ['@table' => $table, '@name' => $field, '@name_new' => $field_new])); } + if (isset($keys_new['primary key']) && in_array($field_new, $keys_new['primary key'], TRUE)) { + $this->ensureNotNullPrimaryKey($keys_new['primary key'], [$field_new => $spec]); + } $sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec)); if ($keys_sql = $this->createKeysSql($keys_new)) { @@ -610,11 +654,11 @@ class Schema extends DatabaseSchema { $condition->condition('column_name', $column); $condition->compile($this->connection, $this); // Don't use {} around information_schema.columns table. - return $this->connection->query("SELECT column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField(); + return $this->connection->query("SELECT column_comment as column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField(); } $condition->compile($this->connection, $this); // Don't use {} around information_schema.tables table. - $comment = $this->connection->query("SELECT table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField(); + $comment = $this->connection->query("SELECT table_comment as table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField(); // Work-around for MySQL 5.0 bug http://bugs.mysql.com/bug.php?id=11379 return preg_replace('/; InnoDB free:.*$/', '', $comment); }