Skip to content

Commit 9b08c7d

Browse files
authored
Merge pull request #199 from ryotsun/fix/#144_change_default_character_set
2 parents 0f48012 + 6627ad4 commit 9b08c7d

File tree

4 files changed

+117
-10
lines changed

4 files changed

+117
-10
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
},
1717
"require-dev": {
1818
"wp-cli/entity-command": "^1.3 || ^2",
19-
"wp-cli/wp-cli-tests": "^3.0.11"
19+
"wp-cli/wp-cli-tests": "^3.0.17"
2020
},
2121
"config": {
2222
"process-timeout": 7200,

features/db-import.feature

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,40 @@ Feature: Import a WordPress database
151151
"""
152152
Debug (db): Running shell command: /usr/bin/env mysql --no-defaults --no-auto-rehash
153153
"""
154+
155+
@require-wp-4.2
156+
Scenario: Import db that has emoji in post
157+
Given a WP install
158+
159+
When I run `wp post create --post_title="🍣"`
160+
And I run `wp post list`
161+
Then the return code should be 0
162+
And STDOUT should contain:
163+
"""
164+
🍣
165+
"""
166+
167+
When I try `wp db export wp_cli_test.sql --debug`
168+
Then the return code should be 0
169+
And the wp_cli_test.sql file should exist
170+
And STDERR should contain:
171+
"""
172+
Detected character set of the posts table: utf8mb4
173+
"""
174+
And STDERR should contain:
175+
"""
176+
Setting missing default character set to utf8mb4
177+
"""
178+
179+
When I run `wp db import --dbuser=wp_cli_test --dbpass=password1`
180+
Then STDOUT should be:
181+
"""
182+
Success: Imported from 'wp_cli_test.sql'.
183+
"""
184+
185+
When I run `wp post list`
186+
Then the return code should be 0
187+
And STDOUT should contain:
188+
"""
189+
🍣
190+
"""

features/db-search.feature

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -917,42 +917,42 @@ Feature: Search through the database
917917
Given a WP install
918918

919919
When I run `SHELL_PIPE=0 wp db search example.com`
920-
Then STDOUT should contain:
920+
Then STDOUT should strictly contain:
921921
"""
922922
wp_options:option_value
923923
1:http://example.com
924924
"""
925925

926926
When I run `SHELL_PIPE=0 wp db search example.com --table_column_color=%r --id_color=%g --match_color=%b`
927-
Then STDOUT should contain:
927+
Then STDOUT should strictly contain:
928928
"""
929929
wp_options:option_value
930930
1:http://example.com
931931
"""
932932

933933
When I run `SHELL_PIPE=0 wp db search example.com --table_column_color=%r`
934-
Then STDOUT should contain:
934+
Then STDOUT should strictly contain:
935935
"""
936936
wp_options:option_value
937937
1:http://example.com
938938
"""
939939

940940
When I run `SHELL_PIPE=0 wp db search example.com --id_color=%g`
941-
Then STDOUT should contain:
941+
Then STDOUT should strictly contain:
942942
"""
943943
wp_options:option_value
944944
1:http://example.com
945945
"""
946946

947947
When I run `SHELL_PIPE=0 wp db search example.com --match_color=%b`
948-
Then STDOUT should contain:
948+
Then STDOUT should strictly contain:
949949
"""
950950
wp_options:option_value
951951
1:http://example.com
952952
"""
953953

954954
When I run `SHELL_PIPE=0 wp db search example.com --before_context=0 --after_context=0`
955-
Then STDOUT should contain:
955+
Then STDOUT should strictly contain:
956956
"""
957957
wp_options:option_value
958958
1:example.com
@@ -967,7 +967,7 @@ Feature: Search through the database
967967
"""
968968
example.com
969969
"""
970-
And STDOUT should not contain:
970+
And STDOUT should strictly not contain:
971971
"""
972972

973973
"""

src/DB_Command.php

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@
2727
*/
2828
class DB_Command extends WP_CLI_Command {
2929

30+
/**
31+
* Legacy UTF-8 encoding for MySQL.
32+
*
33+
* @var string
34+
*/
35+
const ENCODING_UTF8 = 'utf8';
36+
37+
/**
38+
* Standards-compliant UTF-8 encoding for MySQL.
39+
*
40+
* @var string
41+
*/
42+
const ENCODING_UTF8MB4 = 'utf8mb4';
43+
3044
/**
3145
* A list of incompatible SQL modes.
3246
*
@@ -554,6 +568,23 @@ public function export( $args, $assoc_args ) {
554568

555569
$support_column_statistics = exec( $mysqldump_binary . ' --help | grep "column-statistics"' );
556570

571+
/*
572+
* In case that `--default-character-set` is not given and `DB_CHARSET` is `utf8`,
573+
* we try to deduce what the actual character set for the posts table of the
574+
* current database is and use `utf8mb4` as a `default-character-set` if that
575+
* seems like the safer default, to ensure emojis are encoded correctly.
576+
*/
577+
if (
578+
! isset( $assoc_args['default-character-set'] )
579+
&&
580+
( defined( 'DB_CHARSET' ) && self::ENCODING_UTF8 === constant( 'DB_CHARSET' ) )
581+
&&
582+
self::ENCODING_UTF8MB4 === $this->get_posts_table_charset( $assoc_args )
583+
) {
584+
WP_CLI::debug( 'Setting missing default character set to ' . self::ENCODING_UTF8MB4, 'db' );
585+
$assoc_args['default-character-set'] = self::ENCODING_UTF8MB4;
586+
}
587+
557588
$initial_command = sprintf( "{$mysqldump_binary}%s ", $this->get_defaults_flag_string( $assoc_args ) );
558589
WP_CLI::debug( "Running initial shell command: {$initial_command}", 'db' );
559590

@@ -607,6 +638,45 @@ public function export( $args, $assoc_args ) {
607638
}
608639
}
609640

641+
/**
642+
* Get the current character set of the posts table.
643+
*
644+
* @param array Associative array of associative arguments.
645+
* @return string Posts table character set.
646+
*/
647+
private function get_posts_table_charset( $assoc_args ) {
648+
$query = 'SELECT CCSA.character_set_name '
649+
. 'FROM information_schema.`TABLES` T, '
650+
. 'information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA '
651+
. 'WHERE CCSA.collation_name = T.table_collation '
652+
. 'AND T.table_schema = "' . DB_NAME . '" '
653+
. 'AND T.table_name LIKE "%\_posts";';
654+
655+
list( $stdout, $stderr, $exit_code ) = self::run(
656+
sprintf(
657+
'/usr/bin/env mysql%s --no-auto-rehash --batch --skip-column-names',
658+
$this->get_defaults_flag_string( $assoc_args )
659+
),
660+
[ 'execute' => $query ],
661+
false
662+
);
663+
664+
if ( $exit_code ) {
665+
WP_CLI::warning(
666+
'Failed to get current character set of the posts table.'
667+
. ( ! empty( $stderr ) ? " Reason: {$stderr}" : '' )
668+
);
669+
670+
return self::ENCODING_UTF8MB4;
671+
}
672+
673+
$stdout = trim( $stdout );
674+
675+
WP_CLI::debug( "Detected character set of the posts table: {$stdout}.", 'db' );
676+
677+
return $stdout;
678+
}
679+
610680
/**
611681
* Imports a database from a file or from STDIN.
612682
*
@@ -1239,7 +1309,7 @@ public function search( $args, $assoc_args ) {
12391309
}
12401310

12411311
$encoding = null;
1242-
if ( 0 === strpos( $wpdb->charset, 'utf8' ) ) {
1312+
if ( 0 === strpos( $wpdb->charset, self::ENCODING_UTF8 ) ) {
12431313
$encoding = 'UTF-8';
12441314
}
12451315

@@ -1611,7 +1681,7 @@ private static function is_text_col( $type ) {
16111681
* @return string|array An escaped string if given a string, or an array of escaped strings if given an array of strings.
16121682
*/
16131683
private static function esc_sql_ident( $idents ) {
1614-
$backtick = function ( $v ) {
1684+
$backtick = static function ( $v ) {
16151685
// Escape any backticks in the identifier by doubling.
16161686
return '`' . str_replace( '`', '``', $v ) . '`';
16171687
};

0 commit comments

Comments
 (0)