From b105158ab75a593a59d26b10897f10fa1e7e5f1e Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Tue, 2 Jun 2015 10:13:37 +0100
Subject: [PATCH] Issue #1314214 by stefan.r, phayes, ergophobe, YesCT,
 damienwhaley, Tor Arne Thune, kbasarab, pfrenssen, basic, yannickoo,
 simolokid: MySQL driver does not support full UTF-8 (emojis, asian symbols,
 mathematical symbols)

---
 .../Core/Database/Driver/mysql/Connection.php | 10 ++--
 .../Core/Database/Driver/mysql/Schema.php     |  6 +--
 .../aggregator/src/FeedStorageSchema.php      |  2 +-
 .../src/BlockContentStorageSchema.php         | 52 -------------------
 .../block_content/src/Entity/BlockContent.php |  1 -
 core/modules/file/src/Entity/File.php         |  3 +-
 core/modules/file/src/FileStorageSchema.php   |  2 +-
 .../Validation/Constraint/FileUriUnique.php   | 31 +++++++++++
 core/modules/file/src/Tests/SaveTest.php      | 18 ++++++-
 .../migrate/src/Plugin/migrate/id_map/Sql.php |  6 +++
 .../src/Tests/Table/d6/System.php             |  4 +-
 core/modules/node/src/Tests/NodeViewTest.php  | 12 +++++
 .../src/Tests/Database/RegressionTest.php     | 10 ++--
 .../system/src/Tests/Database/SchemaTest.php  |  2 +-
 .../database_test/database_test.install       | 10 ++--
 .../src/Entity/EntityTestStringId.php         |  5 +-
 core/modules/user/src/UserStorageSchema.php   |  3 ++
 core/modules/user/user.module                 |  2 +
 core/modules/views/src/Tests/ViewTestData.php |  2 +-
 core/scripts/dump-database-d6.sh              |  5 ++
 .../Tests/Core/Routing/RoutingFixtures.php    |  2 +-
 sites/default/default.settings.php            |  4 +-
 22 files changed, 108 insertions(+), 84 deletions(-)
 delete mode 100644 core/modules/block_content/src/BlockContentStorageSchema.php
 create mode 100644 core/modules/file/src/Plugin/Validation/Constraint/FileUriUnique.php

diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
index e092a982a28d..a94c0d30a9b8 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
@@ -64,7 +64,7 @@ public static function open(array &$connection_options = array()) {
     // Character set is added to dsn to ensure PDO uses the proper character
     // set when escaping. This has security implications. See
     // https://www.drupal.org/node/1201452 for further discussion.
-    $dsn .= ';charset=utf8';
+    $dsn .= ';charset=utf8mb4';
     if (!empty($connection_options['database'])) {
       $dsn .= ';dbname=' . $connection_options['database'];
     }
@@ -92,13 +92,13 @@ public static function open(array &$connection_options = array()) {
     $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
 
     // Force MySQL to use the UTF-8 character set. Also set the collation, if a
-    // certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
-    // for UTF-8.
+    // certain one has been set; otherwise, MySQL defaults to
+    // 'utf8mb4_general_ci' for utf8mb4.
     if (!empty($connection_options['collation'])) {
-      $pdo->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
+      $pdo->exec('SET NAMES utf8mb4 COLLATE ' . $connection_options['collation']);
     }
     else {
-      $pdo->exec('SET NAMES utf8');
+      $pdo->exec('SET NAMES utf8mb4');
     }
 
     // Set MySQL init_commands if not already defined.  Default Drupal's MySQL
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
index 8237c79112c8..6326bcf38316 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
@@ -87,7 +87,7 @@ protected function createTableSql($name, $table) {
     // Provide defaults if needed.
     $table += array(
       'mysql_engine' => 'InnoDB',
-      'mysql_character_set' => 'utf8',
+      'mysql_character_set' => 'utf8mb4',
     );
 
     $sql = "CREATE TABLE {" . $name . "} (\n";
@@ -108,8 +108,8 @@ protected function createTableSql($name, $table) {
 
     $sql .= 'ENGINE = ' . $table['mysql_engine'] . ' DEFAULT CHARACTER SET ' . $table['mysql_character_set'];
     // By default, MySQL uses the default collation for new tables, which is
-    // 'utf8_general_ci' for utf8. If an alternate collation has been set, it
-    // needs to be explicitly specified.
+    // 'utf8mb4_general_ci' for utf8mb4. If an alternate collation has been
+    // set, it needs to be explicitly specified.
     // @see DatabaseConnection_mysql
     if (!empty($info['collation'])) {
       $sql .= ' COLLATE ' . $info['collation'];
diff --git a/core/modules/aggregator/src/FeedStorageSchema.php b/core/modules/aggregator/src/FeedStorageSchema.php
index d251ed5f1ea0..4d51bdb1e7e2 100644
--- a/core/modules/aggregator/src/FeedStorageSchema.php
+++ b/core/modules/aggregator/src/FeedStorageSchema.php
@@ -33,7 +33,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
           break;
 
         case 'title':
-          $this->addSharedTableFieldUniqueKey($storage_definition, $schema);
+          $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
           break;
       }
     }
diff --git a/core/modules/block_content/src/BlockContentStorageSchema.php b/core/modules/block_content/src/BlockContentStorageSchema.php
deleted file mode 100644
index c1674aef125d..000000000000
--- a/core/modules/block_content/src/BlockContentStorageSchema.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\block_content\BlockContentStorageSchema.
- */
-
-namespace Drupal\block_content;
-
-use Drupal\Core\Entity\ContentEntityTypeInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
-
-/**
- * Defines the block content schema handler.
- */
-class BlockContentStorageSchema extends SqlContentEntityStorageSchema {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
-    $schema = parent::getEntitySchema($entity_type, $reset);
-
-    $schema['block_content_field_data']['unique keys'] += array(
-      'block_content__info' => array('info', 'langcode'),
-    );
-
-    return $schema;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) {
-    $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
-    $field_name = $storage_definition->getName();
-
-    if ($table_name == 'block_content_field_data') {
-      switch ($field_name) {
-        case 'info':
-          // Improves the performance of the block_content__info index defined
-          // in getEntitySchema().
-          $schema['fields'][$field_name]['not null'] = TRUE;
-          break;
-      }
-    }
-
-    return $schema;
-  }
-
-}
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 82e16f52da1e..cf5e21af546f 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -23,7 +23,6 @@
  *   bundle_label = @Translation("Custom block type"),
  *   handlers = {
  *     "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
- *     "storage_schema" = "Drupal\block_content\BlockContentStorageSchema",
  *     "access" = "Drupal\block_content\BlockContentAccessControlHandler",
  *     "list_builder" = "Drupal\block_content\BlockContentListBuilder",
  *     "view_builder" = "Drupal\block_content\BlockContentViewBuilder",
diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php
index 8a5bd427011c..511c5d594036 100644
--- a/core/modules/file/src/Entity/File.php
+++ b/core/modules/file/src/Entity/File.php
@@ -252,7 +252,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setLabel(t('URI'))
       ->setDescription(t('The URI to access the file (either local or remote).'))
       ->setSetting('max_length', 255)
-      ->setSetting('case_sensitive', TRUE);
+      ->setSetting('case_sensitive', TRUE)
+      ->addConstraint('FileUriUnique');
 
     $fields['filemime'] = BaseFieldDefinition::create('string')
       ->setLabel(t('File MIME type'))
diff --git a/core/modules/file/src/FileStorageSchema.php b/core/modules/file/src/FileStorageSchema.php
index f253020bc5c6..e0856f4311f4 100644
--- a/core/modules/file/src/FileStorageSchema.php
+++ b/core/modules/file/src/FileStorageSchema.php
@@ -30,7 +30,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
           break;
 
         case 'uri':
-          $this->addSharedTableFieldUniqueKey($storage_definition, $schema, TRUE);
+          $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
           break;
       }
     }
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileUriUnique.php b/core/modules/file/src/Plugin/Validation/Constraint/FileUriUnique.php
new file mode 100644
index 000000000000..1d795056df6a
--- /dev/null
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileUriUnique.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\file\Plugin\Validation\Constraint\FileUriUnique.
+ */
+
+namespace Drupal\file\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Supports validating file URIs.
+ *
+ * @Plugin(
+ *   id = "FileUriUnique",
+ *   label = @Translation("File URI", context = "Validation")
+ * )
+ */
+class FileUriUnique extends Constraint {
+
+  public $message = 'The file %value already exists. Enter a unique file URI.';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validatedBy() {
+    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
+  }
+
+}
diff --git a/core/modules/file/src/Tests/SaveTest.php b/core/modules/file/src/Tests/SaveTest.php
index 666b08de91bb..7b4bb180c31b 100644
--- a/core/modules/file/src/Tests/SaveTest.php
+++ b/core/modules/file/src/Tests/SaveTest.php
@@ -8,6 +8,9 @@
 namespace Drupal\file\Tests;
 
 use Drupal\file\Entity\File;
+use Drupal\Core\Entity\EntityStorageException;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
 
 /**
  * File saving tests.
@@ -57,16 +60,27 @@ function testFileSave() {
 
     // Try to insert a second file with the same name apart from case insensitivity
     // to ensure the 'uri' index allows for filenames with different cases.
-    $uppercase_file = File::create(array(
+    $uppercase_values = array(
       'uid' => 1,
       'filename' => 'DRUPLICON.txt',
       'uri' => 'public://DRUPLICON.txt',
       'filemime' => 'text/plain',
       'status' => FILE_STATUS_PERMANENT,
-    ));
+    );
+    $uppercase_file = File::create($uppercase_values);
     file_put_contents($uppercase_file->getFileUri(), 'hello world');
+    $violations = $uppercase_file->validate();
+    $this->assertEqual(count($violations), 0, 'No violations when adding an URI with an existing filename in upper case.');
     $uppercase_file->save();
 
+    // Ensure the database URI uniqueness constraint is triggered.
+    $uppercase_file_duplicate = File::create($uppercase_values);
+    file_put_contents($uppercase_file_duplicate->getFileUri(), 'hello world');
+    $violations = $uppercase_file_duplicate->validate();
+    $this->assertEqual(count($violations), 1);
+    $this->assertEqual($violations[0]->getMessage(), t('The file %value already exists. Enter a unique file URI.', [
+      '%value' => $uppercase_file_duplicate->getFileUri(),
+    ]));
     // Ensure that file URI entity queries are case sensitive.
     $fids = \Drupal::entityQuery('file')
       ->condition('uri', $uppercase_file->getFileUri())
diff --git a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
index 42488c7d534f..f1507a3b87e5 100644
--- a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
+++ b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
@@ -261,6 +261,12 @@ protected function ensureTables() {
       foreach ($this->migration->getSourcePlugin()->getIds() as $id_definition) {
         $mapkey = 'sourceid' . $count++;
         $source_id_schema[$mapkey] = $this->getFieldSchema($id_definition);
+
+        // With InnoDB, utf8mb4-based primary keys can't be over 191 characters.
+        // Use ASCII-based primary keys instead.
+        if (isset($source_id_schema[$mapkey]['type']) && $source_id_schema[$mapkey]['type'] == 'varchar') {
+          $source_id_schema[$mapkey]['type'] = 'varchar_ascii';
+        }
         $pks[] = $mapkey;
       }
 
diff --git a/core/modules/migrate_drupal/src/Tests/Table/d6/System.php b/core/modules/migrate_drupal/src/Tests/Table/d6/System.php
index 23bcbd66847c..5bf482f9f78a 100644
--- a/core/modules/migrate_drupal/src/Tests/Table/d6/System.php
+++ b/core/modules/migrate_drupal/src/Tests/Table/d6/System.php
@@ -26,7 +26,7 @@ public function load() {
       ),
       'fields' => array(
         'filename' => array(
-          'type' => 'varchar',
+          'type' => 'varchar_ascii',
           'not null' => TRUE,
           'length' => '255',
           'default' => '',
@@ -916,4 +916,4 @@ public function load() {
   }
 
 }
-#8867fc0eccc6c8439bff0a269ec597ae
+#e15f00f5d9b1c571ee015c40f8fc7b00
diff --git a/core/modules/node/src/Tests/NodeViewTest.php b/core/modules/node/src/Tests/NodeViewTest.php
index 2281dd8b816c..c60d44a0a950 100644
--- a/core/modules/node/src/Tests/NodeViewTest.php
+++ b/core/modules/node/src/Tests/NodeViewTest.php
@@ -33,4 +33,16 @@ public function testHtmlHeadLinks() {
     $this->assertEqual($result[0]['href'], $node->url());
   }
 
+  /**
+   * Tests that we store and retrieve multi-byte UTF-8 characters correctly.
+   */
+  public function testMultiByteUtf8() {
+    $title = '🐝';
+    $this->assertTrue(mb_strlen($title, 'utf-8') < strlen($title), 'Title has multi-byte characters.');
+    $node = $this->drupalCreateNode(array('title' => $title));
+    $this->drupalGet($node->urlInfo());
+    $result = $this->xpath('//span[contains(@class, "field-name-title")]');
+    $this->assertEqual((string) $result[0], $title, 'The passed title was returned.');
+  }
+
 }
diff --git a/core/modules/system/src/Tests/Database/RegressionTest.php b/core/modules/system/src/Tests/Database/RegressionTest.php
index 81f962d0da1e..6f87d2a6444b 100644
--- a/core/modules/system/src/Tests/Database/RegressionTest.php
+++ b/core/modules/system/src/Tests/Database/RegressionTest.php
@@ -26,16 +26,16 @@ class RegressionTest extends DatabaseTestBase {
    */
   function testRegression_310447() {
     // That's a 255 character UTF-8 string.
-    $name = str_repeat("é", 255);
+    $job = str_repeat("é", 255);
     db_insert('test')
       ->fields(array(
-        'name' => $name,
+        'name' => $this->randomMachineName(),
         'age' => 20,
-        'job' => 'Dancer',
+        'job' => $job,
       ))->execute();
 
-    $from_database = db_query('SELECT name FROM {test} WHERE name = :name', array(':name' => $name))->fetchField();
-    $this->assertIdentical($name, $from_database, 'The database handles UTF-8 characters cleanly.');
+    $from_database = db_query('SELECT job FROM {test} WHERE job = :job', array(':job' => $job))->fetchField();
+    $this->assertIdentical($job, $from_database, 'The database handles UTF-8 characters cleanly.');
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Database/SchemaTest.php b/core/modules/system/src/Tests/Database/SchemaTest.php
index 9a234edd5b2d..df1b0b6530c1 100644
--- a/core/modules/system/src/Tests/Database/SchemaTest.php
+++ b/core/modules/system/src/Tests/Database/SchemaTest.php
@@ -72,7 +72,7 @@ function testSchema() {
       $columns = db_query('SHOW FULL COLUMNS FROM {test_table}');
       foreach ($columns as $column) {
         if ($column->Field == 'test_field_string') {
-          $string_check = ($column->Collation == 'utf8_general_ci');
+          $string_check = ($column->Collation == 'utf8mb4_general_ci');
         }
         if ($column->Field == 'test_field_string_ascii') {
           $string_ascii_check = ($column->Collation == 'ascii_general_ci');
diff --git a/core/modules/system/tests/modules/database_test/database_test.install b/core/modules/system/tests/modules/database_test/database_test.install
index 7c74c1c4be64..cfd72d5fe357 100644
--- a/core/modules/system/tests/modules/database_test/database_test.install
+++ b/core/modules/system/tests/modules/database_test/database_test.install
@@ -24,7 +24,7 @@ function database_test_schema() {
       ),
       'name' => array(
         'description' => "A person's name",
-        'type' => 'varchar',
+        'type' => 'varchar_ascii',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
@@ -75,7 +75,7 @@ function database_test_schema() {
       ),
       'job' => array(
         'description' => "The person's job",
-        'type' => 'varchar',
+        'type' => 'varchar_ascii',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
@@ -106,7 +106,7 @@ function database_test_schema() {
       ),
       'job' => array(
         'description' => "The person's job",
-        'type' => 'varchar',
+        'type' => 'varchar_ascii',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
@@ -197,7 +197,7 @@ function database_test_schema() {
       ),
       'name' => array(
         'description' => "A person's name.",
-        'type' => 'varchar',
+        'type' => 'varchar_ascii',
         'length' => 255,
         'not null' => FALSE,
         'default' => '',
@@ -228,7 +228,7 @@ function database_test_schema() {
       ),
       'name' => array(
         'description' => "A person's name.",
-        'type' => 'varchar',
+        'type' => 'varchar_ascii',
         'length' => 255,
         'not null' => FALSE,
         'default' => '',
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
index 7e057d4b4aeb..d6b6c59ea129 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
@@ -45,7 +45,10 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['id'] = BaseFieldDefinition::create('string')
       ->setLabel(t('ID'))
       ->setDescription(t('The ID of the test entity.'))
-      ->setReadOnly(TRUE);
+      ->setReadOnly(TRUE)
+      // In order to work around the InnoDB 191 character limit on utf8mb4
+      // primary keys, we set the character set for the field to ASCII.
+      ->setSetting('is_ascii', TRUE);
     return $fields;
   }
 
diff --git a/core/modules/user/src/UserStorageSchema.php b/core/modules/user/src/UserStorageSchema.php
index 447469d34e94..6247b10db157 100644
--- a/core/modules/user/src/UserStorageSchema.php
+++ b/core/modules/user/src/UserStorageSchema.php
@@ -52,6 +52,9 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
           // Improves the performance of the user__name index defined
           // in getEntitySchema().
           $schema['fields'][$field_name]['not null'] = TRUE;
+          // Make sure the field is no longer than 191 characters so we can
+          // add a unique constraint in MySQL.
+          $schema['fields'][$field_name]['length'] = USERNAME_MAX_LENGTH;
           break;
 
         case 'mail':
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 1e6de88c236d..7a3e84329c7c 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -26,6 +26,8 @@
 
 /**
  * Maximum length of username text field.
+ *
+ * Keep this under 191 characters so we can use a unique constraint in MySQL.
  */
 const USERNAME_MAX_LENGTH = 60;
 
diff --git a/core/modules/views/src/Tests/ViewTestData.php b/core/modules/views/src/Tests/ViewTestData.php
index 4b5340ea9603..34fcd444dde1 100644
--- a/core/modules/views/src/Tests/ViewTestData.php
+++ b/core/modules/views/src/Tests/ViewTestData.php
@@ -75,7 +75,7 @@ public static function schemaDefinition() {
         ),
         'name' => array(
           'description' => "A person's name",
-          'type' => 'varchar',
+          'type' => 'varchar_ascii',
           'length' => 255,
           'not null' => TRUE,
           'default' => '',
diff --git a/core/scripts/dump-database-d6.sh b/core/scripts/dump-database-d6.sh
index ace93d9d34f6..d0a89d7b1ce8 100644
--- a/core/scripts/dump-database-d6.sh
+++ b/core/scripts/dump-database-d6.sh
@@ -53,6 +53,11 @@
 $schema = drupal_get_schema();
 ksort($schema);
 
+// Override the field type of the filename primary key to bypass the
+// InnoDB 191 character limitation.
+if (isset($schema['system']['primary key']) && $schema['system']['primary key'] == 'filename' && isset($schema['system']['fields']['filename']['type']) && $schema['system']['fields']['filename']['type'] == 'varchar') {
+  $schema['system']['fields']['filename']['type'] = 'varchar_ascii';
+}
 // Export all the tables in the schema.
 foreach ($schema as $table => $data) {
   // Remove descriptions to save time and code.
diff --git a/core/tests/Drupal/Tests/Core/Routing/RoutingFixtures.php b/core/tests/Drupal/Tests/Core/Routing/RoutingFixtures.php
index 54cd70de7663..05762353d33f 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RoutingFixtures.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RoutingFixtures.php
@@ -172,7 +172,7 @@ public function routingTableDefinition() {
       'fields' => array(
         'name' => array(
           'description' => 'Primary Key: Machine name of this route',
-          'type' => 'varchar',
+          'type' => 'varchar_ascii',
           'length' => 255,
           'not null' => TRUE,
           'default' => '',
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index ef839391355b..d894b11729f2 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -75,7 +75,7 @@
  *   'host' => 'localhost',
  *   'port' => 3306,
  *   'prefix' => 'myprefix_',
- *   'collation' => 'utf8_general_ci',
+ *   'collation' => 'utf8mb4_general_ci',
  * );
  * @endcode
  *
@@ -127,7 +127,7 @@
  *   'password' => 'password',
  *   'host' => 'localhost',
  *   'prefix' => 'main_',
- *   'collation' => 'utf8_general_ci',
+ *   'collation' => 'utf8mb4_general_ci',
  * );
  * @endcode
  *
-- 
GitLab