Character set converter for database tables.
This class is used to upgrade tables from "utf8" character set encoding to
"utf8mb4" encoding. This allows for uses of 4 byte characters such as
emoji and mathematical symbols.
In Backdrop this conversion may be done through UI at
admin/config/development/utf8mb4-upgrade. More information about this upgrade
can be found in the Backdrop documentation on database configuration:
https://docs.backdropcms.org/documentation/database-configuration
Although this class is used within Backdrop purely for the utf8mb4 upgrade,
it is a general purpose converter and could be used for other purposes in
custom scripts or command-line tools.
Based on utf8mb4_convert https://www.drupal.org/project/utf8mb4_convert by
joelpittet and stefan.r.
Hierarchy
Expanded class hierarchy of DatabaseCharsetConverter
See also
system_utf8mb4_convert_form ()
_system_utf8mb4_convert_batch ()
1 string reference to 'DatabaseCharsetConverter'
File
core/includes/database/charset_converter.inc , line 24
View source class DatabaseCharsetConverter {
protected $charset = 'utf8mb4' ;
protected $collation = 'utf8mb4_general_ci' ;
protected $connection ;
public function __construct ($charset = NULL , $collation = NULL ) {
if ($charset ) {
$this ->charset = $charset ;
}
if ($collation ) {
$this ->collation = $collation ;
}
$this ->connection = Database ::getConnection ();
}
public function setConnection (DatabaseConnection $connection ) {
$this ->connection = $connection ;
}
public function convertAllDatabases (array $databases ) {
$success = FALSE ;
foreach ($databases as $database_key => $database_values ) {
foreach ($database_values as $target => $database ) {
$no_driver = !isset ($database ['driver' ]);
$no_mysql_driver = strpos ($database ['driver' ], 'mysql' ) !== 0 ;
if ($target === 'replica' || $no_driver || $no_mysql_driver ) {
continue ;
}
$connection = Database ::getConnection ($target , $database_key );
if ($this ->charset == 'utf8mb4' && !$connection ->utf8mb4IsSupported ()) {
throw new Exception ('The ' . $database_key . ':' . $target . ' MySQL database does not support UTF8MB4! Ensure that the conditions listed in settings.php related to innodb_large_prefix, the server version, and the MySQL driver version are met. See https://docs.backdropcms.org/documentation/database-configuration for more information.' );
}
$this ->setConnection ($connection );
$this ->convertDatabase ($database ['database' ]);
$like = '' ;
if ($database ['prefix' ]) {
$like = ' LIKE "' . $database ['prefix' ] . '%"' ;
}
$tables = $connection ->query ('SHOW TABLES' . $like )->fetchAllKeyed ();
$this ->convertTables ($tables );
$success = TRUE ;
}
}
return $success ;
}
public function convertDatabase ($database_name , $charset = NULL , $collation = NULL ) {
$sql = "ALTER DATABASE `$database_name` CHARACTER SET = :charset COLLATE = :collation;" ;
return $this ->connection ->query ($sql , array (
':charset' => $charset ? : $this ->charset ,
':collation' => $collation ? : $this ->collation ,
));
}
public function convertTables (array $table_names , $charset = NULL , $collation = NULL ) {
foreach ($table_names as $table_name ) {
if (!$this ->connection ->schema ()->tableExists ($table_name )) {
continue ;
}
$this ->convertTable ($table_name , $charset , $collation );
}
}
public function convertTable ($table_name , $charset = NULL , $collation = NULL ) {
$this ->connection ->query ("ALTER TABLE `$table_name` ROW_FORMAT=DYNAMIC ENGINE=INNODB" );
$sql = "ALTER TABLE `$table_name` CHARACTER SET = :charset COLLATE = :collation" ;
$result = $this ->connection ->query ($sql , array (
':charset' => $charset ? : $this ->charset ,
':collation' => $collation ? : $this ->collation ,
));
if ($result ) {
$result = $this ->convertTableFields ($table_name , $charset , $collation );
$this ->connection ->query ("OPTIMIZE TABLE `$table_name`" );
}
return $result ;
}
public function convertTableFields ($table_name , $charset = NULL , $collation = NULL ) {
$return = TRUE ;
$results = $this ->connection ->query ("SHOW FULL FIELDS FROM `$table_name`" )->fetchAllAssoc ('Field' );
$charset = $charset ? : $this ->charset ;
$collation = $collation ? : $this ->collation ;
foreach ($results as $row ) {
if (!$row ->Collation || $row ->Collation === $collation || strpos ($row ->Collation , '_bin' ) !== FALSE ) {
continue ;
}
$default = '' ;
if ($row ->Default !== NULL ) {
$default = 'DEFAULT ' . ($row ->Default == "CURRENT_TIMESTAMP" ? "CURRENT_TIMESTAMP" : ":default" );
}
elseif ($row ->Null == 'YES' && $row ->Key == '' ) {
if ($row ->Type == 'timestamp' ) {
$default = 'NULL ' ;
}
$default .= 'DEFAULT NULL' ;
}
$sql = "ALTER TABLE `$table_name`
MODIFY `" . $row ->Field . "` " .
$row ->Type . " " . "CHARACTER SET :charset COLLATE :collation " .
($row ->Null == "YES" ? "" : "NOT NULL " ) .
$default . " " .
$row ->Extra . " " . "COMMENT :comment" ;
$params = array (
':charset' => $charset ,
':collation' => $collation ,
':comment' => $row ->Comment ,
);
if (strstr ($default , ':default' )) {
$params [':default' ] = $row ->Default ;
}
$result = $this ->connection ->query ($sql , $params );
if (!$result ) {
$return = FALSE ;
}
}
return $return ;
}
}
Members