From 5965c5a1a85a54d6e59e2604486d27db36807257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jake=C5=A1?= Date: Fri, 18 Sep 2026 10:56:53 +0200 Subject: [PATCH 1/6] Align import fixtures with supported driver behavior Test MySQL backslash escapes with the default SQL mode, since the current driver explicitly rejects NO_BACKSLASH_ESCAPES. Keep assertions for every escape case and expect literal backslashes in quoted identifiers. --- features/sqlite-import.feature | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/features/sqlite-import.feature b/features/sqlite-import.feature index ab4975e..9c7ae4b 100644 --- a/features/sqlite-import.feature +++ b/features/sqlite-import.feature @@ -45,10 +45,9 @@ Feature: WP-CLI SQLite Import Command And the SQLite database should contain the imported data @require-sqlite - Scenario: Import a file with escape sequences + Scenario: Import a file with MySQL backslash escape sequences Given a SQL dump file named "test_import.sql" with content: """ - SET sql_mode='NO_BACKSLASH_ESCAPES'; CREATE TABLE test_table (id INTEGER PRIMARY KEY AUTO_INCREMENT, name TEXT); INSERT INTO test_table (name) VALUES ('Test that escaping a backslash \\ works'); INSERT INTO test_table (name) VALUES ('Test that escaping multiple backslashes \\\\\\ works'); @@ -62,11 +61,11 @@ Feature: WP-CLI SQLite Import Command Success: Imported from 'test_import.sql'. """ And the SQLite database should contain a table named "test_table" - And the "test_table" should contain a row with name "Test that escaping a backslash \\ works" - And the "test_table" should contain a row with name "Test that escaping multiple backslashes \\\\\\ works" - And the "test_table" should contain a row with name "Test that escaping a character \a works" - And the "test_table" should contain a row with name "Test that escaping a backslash followed by a character \\a works" - And the "test_table" should contain a row with name "Test that escaping a backslash and a character \\\a works" + And the "test_table" should contain a row with name "Test that escaping a backslash \ works" + And the "test_table" should contain a row with name "Test that escaping multiple backslashes \\\ works" + And the "test_table" should contain a row with name "Test that escaping a character a works" + And the "test_table" should contain a row with name "Test that escaping a backslash followed by a character \a works" + And the "test_table" should contain a row with name "Test that escaping a backslash and a character \a works" @require-sqlite Scenario: Import a file with newlines in strings @@ -150,7 +149,7 @@ Feature: WP-CLI SQLite Import Command Success: Imported from 'test_import.sql'. """ - And the SQLite database should contain a table named "a'strange`identifier\name" + And the SQLite database should contain a table named "a'strange`identifier\\name" @require-sqlite Scenario: Import a file with whitespace and empty lines From 7a3e60a3ef2692e6f2a1777a71f9b4ba31b5e70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 23 Sep 2026 17:33:07 +0200 Subject: [PATCH 2/6] Align PHP compatibility checks with PHP 7.4 Match the PHPCompatibility target to the existing Composer requirement. The PHP 5.6 target incorrectly rejects supported features such as Throwable and void return types. --- phpcs.xml.dist | 2 +- phpstan/stubs.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 6ddc54d..5a1df5c 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -38,7 +38,7 @@ - + diff --git a/phpstan/stubs.php b/phpstan/stubs.php index 10dc55a..51777ed 100644 --- a/phpstan/stubs.php +++ b/phpstan/stubs.php @@ -8,8 +8,6 @@ // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound // phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound -// phpcs:disable PHPCompatibility.FunctionDeclarations.NewReturnTypeDeclarations -// phpcs:disable PHPCompatibility.FunctionDeclarations.NewParamTypeDeclarations class WP_SQLite_Connection { /** From a49c4ded1b5cc28b703ca0b91e4e7b7ad1c9590e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 23 Sep 2026 17:33:08 +0200 Subject: [PATCH 3/6] Add support for the new SQLite storage Resolve DB_PATH, db-path.php, or a legacy .ht.sqlite database at runtime, retaining FQDB compatibility for older integration plugin versions. Export and table listing check that the database exists before opening it. Import uses the configured location and initializes secret-path storage only when no location has been recorded. Report invalid plugin database settings as command errors. Keep storage initialization out of the plugin loader and cover the storage behavior with Behat scenarios. https://github.com/WordPress/sqlite-database-integration/pull/502 https://github.com/WordPress/sqlite-database-integration/pull/512 --- features/bootstrap/SQLiteFeatureContext.php | 7 +- features/sqlite-storage.feature | 142 ++++++++++++++++++++ phpstan/stubs.php | 6 + src/Import.php | 2 +- src/SQLiteDatabaseIntegrationLoader.php | 11 +- src/SQLiteDriverFactory.php | 57 +++++++- 6 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 features/sqlite-storage.feature diff --git a/features/bootstrap/SQLiteFeatureContext.php b/features/bootstrap/SQLiteFeatureContext.php index a83dbc9..d543dfa 100644 --- a/features/bootstrap/SQLiteFeatureContext.php +++ b/features/bootstrap/SQLiteFeatureContext.php @@ -71,8 +71,11 @@ public function theFileShouldExist( $filename ) { private function connectToDatabase() { if ( ! $this->db ) { - $run_dir = $this->variables['RUN_DIR']; - $db_file = $run_dir . '/wp-content/database/.ht.sqlite'; + $result = $this->proc( 'wp eval \'echo defined( "DB_PATH" ) ? DB_PATH : FQDB;\'' )->run_check(); + $db_file = trim( $result->stdout ); + if ( ! is_file( $db_file ) ) { + throw new Exception( 'The WordPress SQLite database does not exist.' ); + } $this->db = new PDO( 'sqlite:' . $db_file ); $this->db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); } diff --git a/features/sqlite-storage.feature b/features/sqlite-storage.feature new file mode 100644 index 0000000..d306943 --- /dev/null +++ b/features/sqlite-storage.feature @@ -0,0 +1,142 @@ +@require-sqlite +Feature: SQLite database storage + Commands use the same database as WordPress before its database drop-in loads. + + Background: + Given a WP installation + + Scenario: Use an existing legacy database without migrating storage + Given a SQL dump file named "test_import.sql" with content: + """ + CREATE TABLE test_table (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO test_table VALUES (1, 'Imported data'); + """ + When I run `wp eval 'echo defined( "DB_PATH" ) ? DB_PATH : FQDB;'` + Then save STDOUT as {DATABASE_PATH} + When I run `cp "{DATABASE_PATH}" original.sqlite` + And I run `rm -r wp-content/database` + And I run `mkdir wp-content/database` + And I run `mv original.sqlite wp-content/database/.ht.sqlite` + And I run `wp sqlite export backup.sql` + Then the backup.sql file should contain: + """ + WP CLI Site + """ + When I run `wp sqlite import test_import.sql` + And I run `wp sqlite export -` + Then STDOUT should contain: + """ + Imported data + """ + And the wp-content/database/.ht.sqlite file should exist + And the wp-content/database/db-path.php file should not exist + + Scenario: Only import initializes fresh default storage + When I run `wp sqlite export backup.sql` + And I run `rm -r wp-content/database` + And I try `wp sqlite export missing.sql` + Then the return code should be 1 + And the missing.sql file should not exist + When I try `wp sqlite tables` + Then the return code should be 1 + And the wp-content/database directory should not exist + When I run `mkdir wp-content/database` + And I run `wp sqlite import backup.sql` + Then STDOUT should contain: + """ + Success: Imported from 'backup.sql'. + """ + When I run `wp sqlite tables` + Then STDOUT should contain: + """ + wp_options + """ + When I run `wp eval 'echo get_option( "blogname" );'` + Then STDOUT should be: + """ + WP CLI Site + """ + + Scenario: Use DB_PATH without changing existing storage + When I run `wp eval 'echo defined( "DB_PATH" ) ? DB_PATH : FQDB;'` + Then save STDOUT as {DATABASE_PATH} + When I run `mkdir custom-database` + And I run `cp "{DATABASE_PATH}" 'custom-database/custom;database.sqlite'` + And I run `wp config set DB_PATH "dirname( __FILE__ ) . '/custom-database/custom;database.sqlite'" --raw` + And I run `wp sqlite export backup.sql` + And I run `wp sqlite import backup.sql` + Then the custom-database/db-path.php file should not exist + And the custom-database/.htaccess file should not exist + And the custom-database/.ht.sqlite.lock file should not exist + When I run `wp sqlite export -` + Then STDOUT should contain: + """ + WP CLI Site + """ + + Scenario: Only import creates a missing explicit database + Given a SQL dump file named "test_import.sql" with content: + """ + CREATE TABLE test_table (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO test_table VALUES (1, 'Imported data'); + """ + When I run `wp config set DB_PATH '{RUN_DIR}/new.sqlite'` + And I try `wp sqlite export backup.sql` + Then the return code should be 1 + And STDERR should contain: + """ + The SQLite database does not exist. + """ + And the new.sqlite file should not exist + And the backup.sql file should not exist + When I try `wp sqlite tables` + Then the return code should be 1 + And the new.sqlite file should not exist + When I run `wp sqlite import test_import.sql` + And I run `wp sqlite tables` + Then STDOUT should contain: + """ + test_table + """ + When I run `wp sqlite export -` + Then STDOUT should contain: + """ + Imported data + """ + + Scenario: Use the legacy FQDB override + When I run `wp eval 'echo defined( "DB_PATH" ) ? DB_PATH : FQDB;'` + Then save STDOUT as {DB_PATH} + When I run `cp "{DB_PATH}" custom.sqlite` + And I run `wp config set FQDB '{RUN_DIR}/custom.sqlite'` + And I run `wp sqlite export backup.sql` + And I run `wp sqlite import backup.sql` + And I run `wp eval 'echo get_option( "blogname" );'` + Then STDOUT should be: + """ + WP CLI Site + """ + + Scenario: Reject an invalid DB_PATH without falling back to existing storage + Given a SQL dump file named "test_import.sql" with content: + """ + CREATE TABLE test_table (id INTEGER PRIMARY KEY); + """ + When I run `wp config set DB_PATH null --raw` + And I try `wp sqlite import test_import.sql` + Then the return code should be 1 + And STDERR should contain: + """ + Error: Could not open the SQLite database: + """ + When I try `wp sqlite export backup.sql` + Then the return code should be 1 + And the backup.sql file should not exist + When I try `wp sqlite tables` + Then the return code should be 1 + When I run `wp config delete DB_PATH` + And I run `wp sqlite tables` + Then STDOUT should not contain: + """ + test_table + """ diff --git a/phpstan/stubs.php b/phpstan/stubs.php index 51777ed..7d5d730 100644 --- a/phpstan/stubs.php +++ b/phpstan/stubs.php @@ -34,3 +34,9 @@ public function __construct() {} public function query( string $sql ) {} public function get_pdo(): PDO {} } + +class WP_SQLite_Storage { + public static function with_secret_path( string $root ): self {} + public function initialize(): string {} + private function __construct() {} +} diff --git a/src/Import.php b/src/Import.php index e312611..a4fa387 100644 --- a/src/Import.php +++ b/src/Import.php @@ -20,7 +20,7 @@ class Import { public function __construct() { SQLiteDatabaseIntegrationLoader::load_plugin(); - $this->driver = SQLiteDriverFactory::create_driver(); + $this->driver = SQLiteDriverFactory::create_driver( true ); } /** diff --git a/src/SQLiteDatabaseIntegrationLoader.php b/src/SQLiteDatabaseIntegrationLoader.php index f235a64..a639302 100644 --- a/src/SQLiteDatabaseIntegrationLoader.php +++ b/src/SQLiteDatabaseIntegrationLoader.php @@ -86,7 +86,16 @@ public static function load_plugin() { if ( $old_structure ) { require_once $plugin_directory . '/php-polyfills.php'; } - require_once $plugin_directory . '/constants.php'; + try { + require_once $plugin_directory . '/constants.php'; + } catch ( \Throwable $exception ) { + // Newer plugin releases reject invalid database settings. + WP_CLI::error( 'Could not open the SQLite database: ' . $exception->getMessage() ); + } + $storage_file = $plugin_directory . '/wp-includes/sqlite/class-wp-sqlite-storage.php'; + if ( file_exists( $storage_file ) ) { + require_once $storage_file; + } $mysql_on_sqlite_class_file = $plugin_directory . '/wp-includes/database/sqlite/class-wp-mysql-on-sqlite.php'; $mysql_on_sqlite_loader_file = $plugin_directory . '/wp-includes/database/load.php'; diff --git a/src/SQLiteDriverFactory.php b/src/SQLiteDriverFactory.php index acb8129..e0abc6c 100644 --- a/src/SQLiteDriverFactory.php +++ b/src/SQLiteDriverFactory.php @@ -3,24 +3,38 @@ namespace Automattic\WP_CLI\SQLite; use PDO; +use RuntimeException; +use WP_CLI; use WP_MySQL_On_SQLite; use WP_SQLite_Connection; use WP_SQLite_Driver; +use WP_SQLite_Storage; use WP_SQLite_Translator; class SQLiteDriverFactory { /** * Create an instance of the SQLite driver. * + * @param bool $create_database_if_missing Allow imports to create a database when missing. + * * @return WP_MySQL_On_SQLite|WP_SQLite_Driver|WP_SQLite_Translator */ - public static function create_driver() { + public static function create_driver( $create_database_if_missing = false ) { + try { + $database_path = self::get_database_path( $create_database_if_missing ); + } catch ( \Throwable $exception ) { + WP_CLI::error( 'Could not open the SQLite database: ' . $exception->getMessage() ); + } + if ( ! $create_database_if_missing && ! is_file( $database_path ) ) { + WP_CLI::error( 'The SQLite database does not exist.' ); + } + $db_name = defined( 'DB_NAME' ) && '' !== DB_NAME ? DB_NAME : 'database_name_here'; if ( class_exists( WP_MySQL_On_SQLite::class ) ) { $database_dsn = sprintf( 'mysql-on-sqlite:path=%s;dbname=%s', - str_replace( ';', ';;', FQDB ), + str_replace( ';', ';;', $database_path ), str_replace( ';', ';;', $db_name ) ); $driver = new WP_MySQL_On_SQLite( $database_dsn ); @@ -35,9 +49,46 @@ public static function create_driver() { $connection = new WP_SQLite_Connection( array( - 'path' => FQDB, + 'path' => $database_path, ) ); return new WP_SQLite_Driver( $connection, $db_name ); } + + /** + * Resolve configuration without initializing existing storage. + * + * @param bool $create_database_if_missing Allow initialization when no secret path is recorded. + * @return string + */ + private static function get_database_path( $create_database_if_missing ) { + if ( defined( 'DB_PATH' ) ) { + $database_path = DB_PATH; + } elseif ( defined( 'FQDB' ) ) { + // Older plugin releases and explicit legacy settings use FQDB. + $database_path = FQDB; + } else { + $path_file = rtrim( FQDBDIR, '/\\' ) . '/db-path.php'; + $legacy_path = rtrim( FQDBDIR, '/\\' ) . '/.ht.sqlite'; + if ( file_exists( $path_file ) ) { + // Use include so unreadable files can be handled on PHP 7. + // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Failure is checked below. + $database_path = @include $path_file; + if ( false === $database_path ) { + throw new RuntimeException( 'Failed to read the SQLite database path file.' ); + } + } elseif ( is_file( $legacy_path ) ) { + $database_path = $legacy_path; + } elseif ( $create_database_if_missing && class_exists( WP_SQLite_Storage::class ) ) { + $database_path = WP_SQLite_Storage::with_secret_path( FQDBDIR )->initialize(); + } else { + throw new RuntimeException( 'No SQLite database path is configured.' ); + } + } + + if ( ! is_string( $database_path ) || '' === $database_path || false !== strpos( $database_path, "\0" ) ) { + throw new RuntimeException( 'The SQLite database path is invalid.' ); + } + return $database_path; + } } From 5c08fcf8804c5542246f01c23a4a3e748f42ab21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 30 Sep 2026 18:21:46 +0200 Subject: [PATCH 4/6] Reject in-memory SQLite databases An in-memory database is discarded when the command exits. Import reported success without keeping any data, and export and table listing reported a missing database. --- features/sqlite-storage.feature | 26 ++++++++++++++++++++++++++ src/SQLiteDriverFactory.php | 3 +++ 2 files changed, 29 insertions(+) diff --git a/features/sqlite-storage.feature b/features/sqlite-storage.feature index d306943..bb92374 100644 --- a/features/sqlite-storage.feature +++ b/features/sqlite-storage.feature @@ -140,3 +140,29 @@ Feature: SQLite database storage """ test_table """ + + Scenario: Reject an in-memory database + Given a SQL dump file named "test_import.sql" with content: + """ + CREATE TABLE test_table (id INTEGER PRIMARY KEY); + """ + When I run `wp config set DB_PATH ':memory:'` + And I try `wp sqlite import test_import.sql` + Then the return code should be 1 + And STDERR should contain: + """ + In-memory databases are not supported. + """ + When I try `wp sqlite export backup.sql` + Then the return code should be 1 + And STDERR should contain: + """ + In-memory databases are not supported. + """ + And the backup.sql file should not exist + When I try `wp sqlite tables` + Then the return code should be 1 + And STDERR should contain: + """ + In-memory databases are not supported. + """ diff --git a/src/SQLiteDriverFactory.php b/src/SQLiteDriverFactory.php index e0abc6c..93e2dae 100644 --- a/src/SQLiteDriverFactory.php +++ b/src/SQLiteDriverFactory.php @@ -89,6 +89,9 @@ private static function get_database_path( $create_database_if_missing ) { if ( ! is_string( $database_path ) || '' === $database_path || false !== strpos( $database_path, "\0" ) ) { throw new RuntimeException( 'The SQLite database path is invalid.' ); } + if ( ':memory:' === $database_path ) { + throw new RuntimeException( 'In-memory databases are not supported.' ); + } return $database_path; } } From 678060329e64708e57ecb8f11a1412bf62695981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 7 Oct 2026 14:31:35 +0200 Subject: [PATCH 5/6] Report SQLite driver errors as command errors Opening the database can fail, for example when the database directory does not exist. Show the reason as a WP-CLI error instead of an uncaught exception with a stack trace. --- features/sqlite-storage.feature | 13 +++++++ src/SQLiteDriverFactory.php | 61 ++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/features/sqlite-storage.feature b/features/sqlite-storage.feature index bb92374..79d0f5c 100644 --- a/features/sqlite-storage.feature +++ b/features/sqlite-storage.feature @@ -166,3 +166,16 @@ Feature: SQLite database storage """ In-memory databases are not supported. """ + + Scenario: Report a database that cannot be opened + Given a SQL dump file named "test_import.sql" with content: + """ + CREATE TABLE test_table (id INTEGER PRIMARY KEY); + """ + When I run `wp config set DB_PATH '{RUN_DIR}/missing-directory/database.sqlite'` + And I try `wp sqlite import test_import.sql` + Then the return code should be 1 + And STDERR should contain: + """ + Error: Could not open the SQLite database: + """ diff --git a/src/SQLiteDriverFactory.php b/src/SQLiteDriverFactory.php index 93e2dae..7e8de01 100644 --- a/src/SQLiteDriverFactory.php +++ b/src/SQLiteDriverFactory.php @@ -29,30 +29,12 @@ public static function create_driver( $create_database_if_missing = false ) { WP_CLI::error( 'The SQLite database does not exist.' ); } - $db_name = defined( 'DB_NAME' ) && '' !== DB_NAME ? DB_NAME : 'database_name_here'; - - if ( class_exists( WP_MySQL_On_SQLite::class ) ) { - $database_dsn = sprintf( - 'mysql-on-sqlite:path=%s;dbname=%s', - str_replace( ';', ';;', $database_path ), - str_replace( ';', ';;', $db_name ) - ); - $driver = new WP_MySQL_On_SQLite( $database_dsn ); - $driver->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, true ); - return $driver; - } - - $new_driver_enabled = defined( 'WP_SQLITE_AST_DRIVER' ) && WP_SQLITE_AST_DRIVER; - if ( ! $new_driver_enabled ) { - return new WP_SQLite_Translator(); + try { + $driver = self::open_driver( $database_path ); + } catch ( \Throwable $exception ) { + WP_CLI::error( 'Could not open the SQLite database: ' . $exception->getMessage() ); } - - $connection = new WP_SQLite_Connection( - array( - 'path' => $database_path, - ) - ); - return new WP_SQLite_Driver( $connection, $db_name ); + return $driver; } /** @@ -94,4 +76,37 @@ private static function get_database_path( $create_database_if_missing ) { } return $database_path; } + + /** + * Open the SQLite driver for a database path. + * + * @param string $database_path The SQLite database path. + * @return WP_MySQL_On_SQLite|WP_SQLite_Driver|WP_SQLite_Translator + */ + private static function open_driver( $database_path ) { + $db_name = defined( 'DB_NAME' ) && '' !== DB_NAME ? DB_NAME : 'database_name_here'; + + if ( class_exists( WP_MySQL_On_SQLite::class ) ) { + $database_dsn = sprintf( + 'mysql-on-sqlite:path=%s;dbname=%s', + str_replace( ';', ';;', $database_path ), + str_replace( ';', ';;', $db_name ) + ); + $driver = new WP_MySQL_On_SQLite( $database_dsn ); + $driver->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, true ); + return $driver; + } + + $new_driver_enabled = defined( 'WP_SQLITE_AST_DRIVER' ) && WP_SQLITE_AST_DRIVER; + if ( ! $new_driver_enabled ) { + return new WP_SQLite_Translator(); + } + + $connection = new WP_SQLite_Connection( + array( + 'path' => $database_path, + ) + ); + return new WP_SQLite_Driver( $connection, $db_name ); + } } From 211877f1a9fab147c52dd4fe4797a00e76c330f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 7 Oct 2026 14:33:54 +0200 Subject: [PATCH 6/6] Open the import file before the database A missing or unreadable dump file no longer creates or initializes the database before the import fails. --- features/sqlite-storage.feature | 14 ++++++++++++++ src/Import.php | 30 ++++++++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/features/sqlite-storage.feature b/features/sqlite-storage.feature index 79d0f5c..02d6bf5 100644 --- a/features/sqlite-storage.feature +++ b/features/sqlite-storage.feature @@ -40,6 +40,13 @@ Feature: SQLite database storage When I try `wp sqlite tables` Then the return code should be 1 And the wp-content/database directory should not exist + When I try `wp sqlite import missing.sql` + Then the return code should be 1 + And STDERR should contain: + """ + Unable to open file: missing.sql + """ + And the wp-content/database directory should not exist When I run `mkdir wp-content/database` And I run `wp sqlite import backup.sql` Then STDOUT should contain: @@ -92,6 +99,13 @@ Feature: SQLite database storage When I try `wp sqlite tables` Then the return code should be 1 And the new.sqlite file should not exist + When I try `wp sqlite import missing.sql` + Then the return code should be 1 + And STDERR should contain: + """ + Unable to open file: missing.sql + """ + And the new.sqlite file should not exist When I run `wp sqlite import test_import.sql` And I run `wp sqlite tables` Then STDOUT should contain: diff --git a/src/Import.php b/src/Import.php index a4fa387..aaf6286 100644 --- a/src/Import.php +++ b/src/Import.php @@ -20,7 +20,6 @@ class Import { public function __construct() { SQLiteDatabaseIntegrationLoader::load_plugin(); - $this->driver = SQLiteDriverFactory::create_driver( true ); } /** @@ -36,6 +35,13 @@ public function run( $sql_file_path, $args ) { $is_stdin = '-' === $sql_file_path; $import_file = $is_stdin ? 'php://stdin' : $sql_file_path; + $handle = fopen( $import_file, 'r' ); + if ( ! $handle ) { + WP_CLI::error( "Unable to open file: $import_file" ); + } + + // Create the driver after opening the input, so a missing file doesn't create a database. + $this->driver = SQLiteDriverFactory::create_driver( true ); /* * Set default SQL mode and other options as per the "mysqldump" command. @@ -61,7 +67,8 @@ public function run( $sql_file_path, $args ) { */ $this->driver->execute_sqlite_query( 'PRAGMA foreign_keys = OFF' ); - $this->execute_statements( $import_file ); + $this->execute_statements( $handle ); + fclose( $handle ); /* * Re-enable foreign key constraints and verify integrity. @@ -83,13 +90,13 @@ public function run( $sql_file_path, $args ) { /** * Execute SQL statements from an SQL dump file. * - * @param $import_file + * @param resource $handle The SQL dump file handle. * * @return void * @throws Exception */ - protected function execute_statements( $import_file ) { - foreach ( $this->parse_statements( $import_file ) as $statement ) { + protected function execute_statements( $handle ) { + foreach ( $this->parse_statements( $handle ) as $statement ) { try { $this->driver->query( $statement ); } catch ( Exception $e ) { @@ -114,18 +121,11 @@ protected function execute_statements( $import_file ) { /** * Parse SQL statements from an SQL dump file. - * @param string $sql_file_path The path to the SQL dump file. + * @param resource $handle The SQL dump file handle. * * @return Generator A generator that yields SQL statements. */ - public function parse_statements( $sql_file_path ) { - - $handle = fopen( $sql_file_path, 'r' ); - - if ( ! $handle ) { - WP_CLI::error( "Unable to open file: $sql_file_path" ); - } - + public function parse_statements( $handle ) { $starting_quote = null; $in_comment = false; $buffer = ''; @@ -202,7 +202,5 @@ public function parse_statements( $sql_file_path ) { if ( ! empty( $buffer ) ) { yield $buffer; } - - fclose( $handle ); } }