Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / lib / Drupal / Core / Database / Driver / mysql / Schema.php
index 878607c55dc127f2eb453b969f3c2ac4505fbcac..9766cfaef11c2183dcf3841230851560fe56fab8 100644 (file)
@@ -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);
   }