Skip to content

Commit 77655d1

Browse files
swissspidyCopilot
andauthored
db import: Pass import file via STDIN redirection (#341)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 0455621 commit 77655d1

2 files changed

Lines changed: 58 additions & 9 deletions

File tree

‎features/db-import.feature‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,3 +374,39 @@ Feature: Import a WordPress database
374374
"""
375375
Success: Imported from 'zerodate_compose.sql'.
376376
"""
377+
378+
@require-mysql-or-mariadb
379+
Scenario: `wp db import` handles filenames containing semicolons and client directives
380+
Given a WP install
381+
And a prefix.sql;\!touch_side_effect.sql#.sql file:
382+
"""
383+
CREATE TABLE wp_cli_meta_test (id int NOT NULL);
384+
INSERT INTO wp_cli_meta_test (id) VALUES (42);
385+
"""
386+
387+
When I run `wp db import 'prefix.sql;\!touch_side_effect.sql#.sql'`
388+
Then STDOUT should contain:
389+
"""
390+
Success: Imported from 'prefix.sql;\!touch_side_effect.sql#.sql'.
391+
"""
392+
And the side_effect.sql file should not exist
393+
394+
When I run `wp db query 'SELECT id FROM wp_cli_meta_test;' --skip-column-names`
395+
Then STDOUT should be:
396+
"""
397+
42
398+
"""
399+
400+
@require-mysql-or-mariadb
401+
Scenario: `wp db import` does not execute embedded client meta-commands in dump content
402+
Given a WP install
403+
And a dump_with_command_injection.sql file:
404+
"""
405+
CREATE TABLE wp_cli_meta_content_test (id int NOT NULL);
406+
INSERT INTO wp_cli_meta_content_test (id) VALUES (99);
407+
\! touch side_effect_content.sql
408+
"""
409+
410+
When I try `wp db import dump_with_command_injection.sql`
411+
Then the side_effect_content.sql file should not exist
412+

‎src/DB_Command.php‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ private function command_supports_option( $command, $option ) {
926926
* : Extra arguments to pass to mysql. [Refer to mysql binary docs](https://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html).
927927
*
928928
* [--skip-optimization]
929-
* : When using an SQL file, do not include speed optimization such as disabling auto-commit and key checks.
929+
* : Do not disable unique checks and foreign key checks during import.
930930
*
931931
* [--skip-sql-mode-compat]
932932
* : Do not adapt the session SQL mode for WordPress compatibility. By default, `wp db import` strips the SQL modes that WordPress Core disables (such as `STRICT_TRANS_TABLES` and `NO_ZERO_DATE`) so that dumps containing legacy values like `0000-00-00` import cleanly. Pass this flag to import under the server's own SQL modes instead.
@@ -943,8 +943,10 @@ private function command_supports_option( $command, $option ) {
943943
public function import( $args, $assoc_args ) {
944944
$this->maybe_load_sqlite_dropin();
945945

946+
$is_stdin = false;
946947
if ( ! empty( $args[0] ) ) {
947948
$result_file = $args[0];
949+
$is_stdin = '-' === $result_file;
948950
} else {
949951
$result_file = sprintf( '%s.sql', DB_NAME );
950952
}
@@ -956,7 +958,10 @@ public function import( $args, $assoc_args ) {
956958

957959
// Process options to MySQL.
958960
$mysql_args = array_merge(
959-
[ 'database' => DB_NAME ],
961+
[
962+
'database' => DB_NAME,
963+
'binary-mode' => true,
964+
],
960965
self::get_dbuser_dbpass_args( $assoc_args ),
961966
self::get_mysql_args( $assoc_args )
962967
);
@@ -967,25 +972,33 @@ public function import( $args, $assoc_args ) {
967972
// no separate probe connection.
968973
$this->apply_sql_mode_compat_init_command( $mysql_args, $assoc_args );
969974

970-
if ( '-' !== $result_file ) {
975+
if ( ! $is_stdin ) {
971976
if ( ! is_readable( $result_file ) ) {
972977
WP_CLI::error( sprintf( 'Import file missing or not readable: %s', $result_file ) );
973978
}
974-
975-
$query = Utils\get_flag_value( $assoc_args, 'skip-optimization' )
976-
? 'SOURCE %s;'
977-
: 'SET autocommit = 0; SET unique_checks = 0; SET foreign_key_checks = 0; SOURCE %s; COMMIT;';
978-
979-
$mysql_args['execute'] = sprintf( $query, $result_file );
980979
} else {
981980
$result_file = 'STDIN';
982981
}
983982

983+
if ( ! Utils\get_flag_value( $assoc_args, 'skip-optimization' ) ) {
984+
$optimization_sql = 'SET unique_checks = 0; SET foreign_key_checks = 0;';
985+
if ( isset( $mysql_args['init-command'] ) && '' !== trim( (string) $mysql_args['init-command'] ) ) {
986+
$mysql_args['init-command'] .= '; ' . $optimization_sql;
987+
} else {
988+
$mysql_args['init-command'] = $optimization_sql;
989+
}
990+
}
991+
984992
$command = sprintf(
985993
'%s%s --no-auto-rehash',
986994
Utils\get_mysql_binary_path(),
987995
$this->get_defaults_flag_string( $assoc_args )
988996
);
997+
998+
if ( ! $is_stdin ) {
999+
$command .= ' < ' . escapeshellarg( $result_file );
1000+
}
1001+
9891002
WP_CLI::debug( "Running shell command: {$command}", 'db' );
9901003
WP_CLI::debug( 'Associative arguments: ' . json_encode( $assoc_args ), 'db' );
9911004

0 commit comments

Comments
 (0)