@@ -929,6 +929,30 @@ public function import( $args, $assoc_args ) {
929929 return ;
930930 }
931931
932+ if ( ! $ this ->is_mysql_binary_available () ) {
933+ if ( '- ' === $ result_file ) {
934+ $ sql_content = stream_get_contents ( STDIN );
935+ if ( false === $ sql_content ) {
936+ WP_CLI ::error ( 'Failed to read from STDIN. ' );
937+ }
938+ $ result_file = 'STDIN ' ;
939+ } else {
940+ if ( ! is_readable ( $ result_file ) ) {
941+ WP_CLI ::error ( sprintf ( 'Import file missing or not readable: %s ' , $ result_file ) );
942+ }
943+ $ sql_content = file_get_contents ( $ result_file );
944+ if ( false === $ sql_content ) {
945+ WP_CLI ::error ( sprintf ( 'Could not read import file: %s ' , $ result_file ) );
946+ }
947+ }
948+
949+ WP_CLI ::debug ( 'MySQL/MariaDB binary not available, falling back to wpdb for import. ' , 'db ' );
950+ $ this ->maybe_load_wpdb ();
951+ $ this ->wpdb_import ( (string ) $ sql_content , $ assoc_args );
952+ WP_CLI ::success ( sprintf ( "Imported from '%s'. " , $ result_file ) );
953+ return ;
954+ }
955+
932956 // Process options to MySQL.
933957 $ mysql_args = array_merge (
934958 [ 'database ' => DB_NAME ],
@@ -1919,6 +1943,19 @@ private static function get_create_query() {
19191943 * @param array $assoc_args Optional. Associative array of arguments.
19201944 */
19211945 protected function run_query ( $ query , $ assoc_args = [] ) {
1946+ if ( ! $ this ->is_mysql_binary_available () ) {
1947+ WP_CLI ::debug ( "Query via wpdb: {$ query }" , 'db ' );
1948+ $ this ->maybe_load_wpdb ();
1949+ global $ wpdb ;
1950+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1951+ $ result = $ wpdb ->query ( $ query );
1952+ if ( false === $ result ) {
1953+ // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
1954+ WP_CLI ::error ( 'Query failed: ' . strip_tags ( $ wpdb ->last_error ) );
1955+ }
1956+ return ;
1957+ }
1958+
19221959 // Ensure that the SQL mode is compatible with WPDB.
19231960 $ query = $ this ->get_sql_mode_query ( $ assoc_args ) . $ query ;
19241961
@@ -2410,6 +2447,7 @@ protected function maybe_load_wpdb() {
24102447 // Load required WordPress files if not already loaded.
24112448 if ( ! function_exists ( 'add_action ' ) ) {
24122449 $ required_files = [
2450+ ABSPATH . WPINC . '/load.php ' ,
24132451 ABSPATH . WPINC . '/compat.php ' ,
24142452 ABSPATH . WPINC . '/plugin.php ' ,
24152453 // Defines `wp_debug_backtrace_summary()` as used by wpdb.
@@ -2484,4 +2522,130 @@ protected function wpdb_query( $query, $assoc_args = [] ) {
24842522 $ this ->display_query_results ( $ headers , $ results , $ skip_column_names );
24852523 }
24862524 }
2525+
2526+ /**
2527+ * Import SQL content into the database using wpdb.
2528+ *
2529+ * Used as a fallback when the mysql/mariadb binary is not available.
2530+ *
2531+ * @param string $sql_content SQL content to import.
2532+ * @param array $assoc_args Associative arguments.
2533+ */
2534+ protected function wpdb_import ( $ sql_content , $ assoc_args = [] ) {
2535+ global $ wpdb ;
2536+
2537+ if ( ! isset ( $ wpdb ) || ! ( $ wpdb instanceof wpdb ) ) {
2538+ WP_CLI ::error ( 'WordPress database (wpdb) is not available. Please install MySQL or MariaDB client tools. ' );
2539+ }
2540+
2541+ $ skip_optimization = Utils \get_flag_value ( $ assoc_args , 'skip-optimization ' , false );
2542+
2543+ if ( ! $ skip_optimization ) {
2544+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2545+ $ wpdb ->query ( 'SET autocommit = 0 ' );
2546+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2547+ $ wpdb ->query ( 'SET unique_checks = 0 ' );
2548+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2549+ $ wpdb ->query ( 'SET foreign_key_checks = 0 ' );
2550+ }
2551+
2552+ $ statements = $ this ->split_sql_statements ( $ sql_content );
2553+
2554+ foreach ( $ statements as $ statement ) {
2555+ $ statement = trim ( $ statement );
2556+ if ( '' === $ statement ) {
2557+ continue ;
2558+ }
2559+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2560+ $ result = $ wpdb ->query ( $ statement );
2561+ if ( false === $ result ) {
2562+ if ( ! $ skip_optimization ) {
2563+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2564+ $ wpdb ->query ( 'ROLLBACK ' );
2565+ }
2566+ // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
2567+ WP_CLI ::error ( 'Import failed: ' . strip_tags ( $ wpdb ->last_error ) );
2568+ }
2569+ }
2570+
2571+ if ( ! $ skip_optimization ) {
2572+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2573+ $ wpdb ->query ( 'COMMIT ' );
2574+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2575+ $ wpdb ->query ( 'SET autocommit = 1 ' );
2576+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2577+ $ wpdb ->query ( 'SET unique_checks = 1 ' );
2578+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2579+ $ wpdb ->query ( 'SET foreign_key_checks = 1 ' );
2580+ }
2581+ }
2582+
2583+ /**
2584+ * Split a SQL string into individual statements.
2585+ *
2586+ * Handles single-quoted strings, double-quoted strings, and comments
2587+ * so that semicolons inside them are not treated as statement delimiters.
2588+ *
2589+ * @param string $sql SQL string to split.
2590+ * @return string[] Array of individual SQL statements.
2591+ */
2592+ private function split_sql_statements ( $ sql ) {
2593+ $ statements = [];
2594+ $ current = '' ;
2595+ $ in_single_quote = false ;
2596+ $ in_double_quote = false ;
2597+ $ in_comment = false ;
2598+ $ in_line_comment = false ;
2599+ $ length = strlen ( $ sql );
2600+
2601+ for ( $ i = 0 ; $ i < $ length ; $ i ++ ) {
2602+ $ char = $ sql [ $ i ];
2603+ $ next = ( $ i + 1 < $ length ) ? $ sql [ $ i + 1 ] : '' ;
2604+
2605+ if ( $ in_line_comment ) {
2606+ if ( "\n" === $ char ) {
2607+ $ in_line_comment = false ;
2608+ }
2609+ continue ;
2610+ }
2611+
2612+ if ( $ in_comment ) {
2613+ if ( '* ' === $ char && '/ ' === $ next ) {
2614+ $ in_comment = false ;
2615+ ++$ i ;
2616+ }
2617+ continue ;
2618+ }
2619+
2620+ if ( '/ ' === $ char && '* ' === $ next && ! $ in_single_quote && ! $ in_double_quote ) {
2621+ $ in_comment = true ;
2622+ ++$ i ;
2623+ continue ;
2624+ }
2625+
2626+ if ( '- ' === $ char && '- ' === $ next && ! $ in_single_quote && ! $ in_double_quote ) {
2627+ $ in_line_comment = true ;
2628+ continue ;
2629+ }
2630+
2631+ if ( "' " === $ char && ! $ in_double_quote ) {
2632+ $ in_single_quote = ! $ in_single_quote ;
2633+ } elseif ( '" ' === $ char && ! $ in_single_quote ) {
2634+ $ in_double_quote = ! $ in_double_quote ;
2635+ }
2636+
2637+ if ( '; ' === $ char && ! $ in_single_quote && ! $ in_double_quote ) {
2638+ $ statements [] = $ current ;
2639+ $ current = '' ;
2640+ } else {
2641+ $ current .= $ char ;
2642+ }
2643+ }
2644+
2645+ if ( '' !== trim ( $ current ) ) {
2646+ $ statements [] = $ current ;
2647+ }
2648+
2649+ return $ statements ;
2650+ }
24872651}
0 commit comments