diff --git a/AGENTS.md b/AGENTS.md index 6d6296140..fc62f7abe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,15 +14,15 @@ This project implements SQLite database support for MySQL-based projects. It is a monorepo that includes the following components: - **MySQL lexer** — A fast MySQL lexer with multi-version support. - **MySQL parser** — An exhaustive MySQL parser with multi-version support. -- **SQLite driver** — A MySQL emulation layer on top of SQLite with a PDO-compatible API. +- **MySQL on SQLite** — A MySQL emulation layer on top of SQLite with a PDO-compatible API. - **MySQL proxy** — A MySQL binary protocol implementation to support MySQL-based projects beyond PHP. - **WordPress plugin** — A plugin that adds SQLite support to WordPress. - **Test suites** — A set of extensive test suites to cover MySQL syntax and functionality. The monorepo packages are placed under the `packages` directory. -The WordPress plugin links the SQLite driver using a symlink. The build script -replaces the symlink with a copy of the driver for release. +The WordPress plugin links the MySQL on SQLite package using a symlink. The build +script replaces the symlink with a copy of the package for release. The codebase is pure PHP with zero dependencies. It supports PHP 7.2 through 8.5, MySQL syntax from version 5.7 onward, and requires SQLite 3.37.0 or newer @@ -37,9 +37,9 @@ composer install # Install dependencies composer run check-cs # Check coding standards (PHPCS) composer run fix-cs # Auto-fix coding standards (PHPCBF) composer run build-sqlite-plugin-zip # Build the plugin zip -composer run prepare-release # Prepare a new release +composer run prepare-release # Prepare a new release -# SQLite driver tests (under packages/mysql-on-sqlite) +# MySQL on SQLite tests (under packages/mysql-on-sqlite) cd packages/mysql-on-sqlite composer run test # Run unit tests composer run test tests/SomeTest.php # Run specific unit test file @@ -70,7 +70,7 @@ Release is streamlined with a local preparation script and GitHub Actions: ``` The script will: - Bump version numbers and generate a changelog from merged PRs. - - Create a `release/` branch with a preparation commit. + - Create a `release/v` branch with a preparation commit. - Push the branch and create a PR. 2. **Review the PR.** @@ -84,19 +84,19 @@ Release is streamlined with a local preparation script and GitHub Actions: ## Architecture The project consists of multiple components providing different APIs that funnel -into the SQLite driver to support diverse use cases both inside and outside the +into MySQL on SQLite to support diverse use cases both inside and outside the PHP ecosystem. ### Component overview The following diagrams show how different types of applications can be supported using components from this project. -**PHP applications** are supported through a PDO\MySQL-compatible API: +**PHP applications** are supported through an API compatible with the PDO MySQL driver: ``` PHP applications, Adminer, phpMyAdmin - ↓ PDO\MySQL API -SQLite driver - ↓ PDO\SQLite + ↓ PDO MySQL API +MySQL on SQLite + ↓ PDO SQLite SQLite ``` @@ -105,9 +105,9 @@ SQLite WordPress + plugins, WordPress Playground, WordPress Studio, wp-env ↓ wpdb wpdb drop-in - ↓ PDO\MySQL API -SQLite driver - ↓ PDO\SQLite + ↓ PDO MySQL API +MySQL on SQLite + ↓ PDO SQLite SQLite ``` @@ -116,9 +116,9 @@ SQLite MySQL CLI, Desktop clients ↓ MySQL binary protocol v10 MySQL proxy - ↓ PDO\MySQL API -SQLite driver - ↓ PDO\SQLite + ↓ PDO MySQL API +MySQL on SQLite + ↓ PDO SQLite SQLite ``` @@ -174,7 +174,7 @@ the public APIs responsibly, following semantic versioning practices. In particular: - **Public APIs:** It's possible to evolve the public API, but this must always be surfaced to the developer so versioning decisions can be made. -- **PDO API:** The SQLite driver must follow PDO\MySQL API as closely as possible. +- **PDO API:** MySQL on SQLite must match the PDO MySQL driver API as closely as possible. - **MySQL binary protocol:** The MySQL proxy must follow the MySQL binary protocol as closely as possible. - **PHP version support:** All PHP versions starting from **PHP 7.2** must be supported. diff --git a/README.md b/README.md index a2bf39923..c16dda7c9 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,15 @@ This project implements SQLite database support for MySQL-based projects. It is a monorepo that includes the following components: - **MySQL lexer** — A fast MySQL lexer with multi-version support. - **MySQL parser** — An exhaustive MySQL parser with multi-version support. -- **SQLite driver** — A MySQL emulation layer on top of SQLite with a PDO-compatible API. -- **MySQL proxy** — A MySQL binary protocol implementation to support MySQL-based projects beyond PHP. +- [**MySQL on SQLite**](packages/mysql-on-sqlite/) — A MySQL emulation layer on top of SQLite with a PDO-compatible API. +- [**MySQL proxy**](packages/mysql-proxy/) — A MySQL binary protocol implementation to support MySQL-based projects beyond PHP. - **WordPress plugin** — A plugin that adds SQLite support to WordPress. - **Test suites** — A set of extensive test suites to cover MySQL syntax and functionality. The monorepo packages are placed under the `packages` directory. -The WordPress plugin links the SQLite driver using a symlink. The build script -replaces the symlink with a copy of the driver for release. +The WordPress plugin links the MySQL on SQLite package using a symlink. The build +script replaces the symlink with a copy of the package for release. The codebase is pure PHP with zero dependencies. It supports PHP 7.2 through 8.5, MySQL syntax from version 5.7 onward, and requires SQLite 3.37.0 or newer @@ -35,9 +35,9 @@ composer install # Install dependencies composer run check-cs # Check coding standards (PHPCS) composer run fix-cs # Auto-fix coding standards (PHPCBF) composer run build-sqlite-plugin-zip # Build the plugin zip -composer run prepare-release # Prepare a new release +composer run prepare-release # Prepare a new release -# SQLite driver tests (under packages/mysql-on-sqlite) +# MySQL on SQLite tests (under packages/mysql-on-sqlite) cd packages/mysql-on-sqlite composer run test # Run unit tests composer run test tests/SomeTest.php # Run specific unit test file @@ -61,7 +61,7 @@ composer run wp-test-clean # Clean up WordPress environment (Docker ## Optional: Native MySQL Parser Extension -The default code path is pure PHP. For environments that can load PHP extensions, the optional `wp_mysql_parser` extension accelerates the MySQL lexer/parser used by the SQLite driver. +The default code path is pure PHP. For environments that can load PHP extensions, the optional `wp_mysql_parser` extension accelerates the MySQL lexer/parser used by MySQL on SQLite. - [Published WASM release list, manifest links, Playground links, and native extension overview](https://wordpress.github.io/sqlite-database-integration/) - [Build, load, and benchmark docs](packages/php-ext-wp-mysql-parser/README.md) @@ -77,7 +77,7 @@ Release is streamlined with a local preparation script and GitHub Actions: ``` The script will: - Bump version numbers and generate a changelog from merged PRs. - - Create a `release/` branch with a preparation commit. + - Create a `release/v` branch with a preparation commit. - Push the branch and create a PR. 2. **Review the PR.** @@ -91,7 +91,7 @@ Release is streamlined with a local preparation script and GitHub Actions: ## Architecture The project consists of multiple components providing different APIs that funnel -into the SQLite driver to support diverse use cases both inside and outside the +into MySQL on SQLite to support diverse use cases both inside and outside the PHP ecosystem. ### Component overview @@ -104,10 +104,10 @@ using components from this project: │ Adminer, phpMyAdmin │──────────────────────────┐ └──────────────────────┘ │ │ -┌──────────────────────┐ wpdb API │ PDO\MySQL API PDO\SQLite -│ WordPress + plugins │ │ ╔══════════════╗ │ │ ╔═══════════════╗ │ ┌────────┐ -│ WordPress Playground │───┴──→║ wpdb drop-in ║───┼───┴──→║ SQLite driver ║───┴──→│ SQLite │ -│ Studio, wp-env │ ╚══════════════╝ │ ╚═══════════════╝ └────────┘ +┌──────────────────────┐ wpdb API │ PDO MySQL API PDO SQLite +│ WordPress + plugins │ │ ╔══════════════╗ │ │ ╔═════════════════╗ │ ┌────────┐ +│ WordPress Playground │───┴──→║ wpdb drop-in ║───┼───┴──→║ MySQL on SQLite ║───┴──→│ SQLite │ +│ Studio, wp-env │ ╚══════════════╝ │ ╚═════════════════╝ └────────┘ └──────────────────────┘ │ MySQL binary protocol │ ┌──────────────────────┐ │ ╔══════════════╗ │ diff --git a/grammar-tools/MySQLParser.g4 b/grammar-tools/MySQLParser.g4 index 8c1b0b255..453f16d39 100644 --- a/grammar-tools/MySQLParser.g4 +++ b/grammar-tools/MySQLParser.g4 @@ -1902,7 +1902,7 @@ filterStringList: ; filterWildDbTableString: - textStringNoLinebreak // sql_yacc.yy checks for the existance of at least one dot char in the string. + textStringNoLinebreak // sql_yacc.yy checks for the existence of at least one dot char in the string. ; filterDbPairList: @@ -3844,7 +3844,7 @@ dataType: // type in sql_yacc.yy | type = NATIONAL_SYMBOL CHAR_SYMBOL VARYING_SYMBOL | type = NCHAR_SYMBOL VARYING_SYMBOL ) fieldLength BINARY_SYMBOL? - /* @CHANGED: Moved "nchar fieldLength? BINARY_SYMBOL?" after othe nchar definitions to solve conflicts. */ + /* @CHANGED: Moved "nchar fieldLength? BINARY_SYMBOL?" after the other nchar definitions to solve conflicts. */ | nchar fieldLength? BINARY_SYMBOL? | type = VARBINARY_SYMBOL fieldLength | type = YEAR_SYMBOL fieldLength? fieldOptions? diff --git a/packages/mysql-on-sqlite/README.md b/packages/mysql-on-sqlite/README.md new file mode 100644 index 000000000..0cfc38801 --- /dev/null +++ b/packages/mysql-on-sqlite/README.md @@ -0,0 +1,140 @@ +# MySQL on SQLite + +A **PDO MySQL drop-in** for running MySQL-based PHP applications on SQLite. + +## Overview + +**MySQL on SQLite** is a pure-PHP database driver that exposes SQLite through +an API compatible with the PDO MySQL driver. + +At a glance: + +- **MySQL compatibility:** Broad coverage of MySQL syntax, semantics, types, and metadata. +- **PDO MySQL drop-in:** Extensive PDO API coverage with MySQL behavior emulation. +- **Pure PHP:** No third-party runtime dependencies. +- **Lean runtime:** Small footprint, low overhead, and efficient query processing. +- **Extensive validation:** Comprehensive test suites covering real-world patterns. + +## Usage + +Load the package and create a connection using a `mysql-on-sqlite` DSN: + +```php +// Use a PDO-like constructor. +$pdo = new WP_MySQL_On_SQLite( + 'mysql-on-sqlite:path=/path/to/database.sqlite;dbname=app' +); + +// Use the PDO API to talk to the database as with the PDO MySQL driver. +$statement = $pdo->query( 'SELECT * FROM users' ); +$users = $statement->fetchAll( PDO::FETCH_ASSOC ); +``` + +Switching an existing application from the PDO MySQL driver to MySQL on SQLite +can be as simple as: + +```diff +-$pdo = new PDO( 'mysql:host=localhost;dbname=app', $username, $password ); ++$pdo = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:path=database.sqlite;dbname=app' ); +``` + +## Configuration + +The driver is configured through the standard PDO API, closely mirroring the +PDO MySQL driver while providing additional SQLite-specific options. + +### DSN + +The DSN has the following format: + +```text +mysql-on-sqlite:path=;dbname= +``` + +| Field | Description | Default | +| --- | --- | --- | +| `path` | SQLite database path or `:memory:` | `:memory:` | +| `dbname` | Logical MySQL database name | `sqlite_database` | + +Use `;;` to include a literal semicolon in either value. + +### PDO options + +The constructor follows the PDO signature and accepts most common attributes +supported by the PDO MySQL driver in its fourth argument. Its `username` and +`password` arguments are accepted for compatibility and ignored. MySQL-specific +PDO attributes are currently not supported. + +#### Driver options + +The fourth argument accepts additional options for selecting the emulated MySQL +version and configuring the SQLite connection: + +| Option | Description | Default | +| --- | --- | --- | +| `mysql_version` | MySQL version to emulate, represented as an integer | `80038` | +| `pdo` | Existing PDO SQLite connection | A new connection for `path` | +| `journal_mode` | SQLite journal mode | `WAL` | +| `synchronous` | SQLite synchronous setting | `NORMAL` in WAL mode; otherwise the SQLite default | + +## Compatibility + +The driver covers extensive MySQL functionality behind an API compatible with +the PDO MySQL driver. + +### MySQL + +Supported areas include: + +- **Queries:** Joins, subqueries, CTEs, unions, grouping, `HAVING`, ordering, + limits, and more. +- **Data manipulation:** `INSERT`, `UPDATE`, `DELETE`, and `REPLACE`, including + MySQL-specific forms such as `INSERT IGNORE`, `ON DUPLICATE KEY UPDATE`, and + joined updates. +- **Schema definition:** Creating, altering, dropping, and truncating tables, + including temporary tables and complex column definitions. +- **Indexes and constraints:** Index definitions and primary, unique, + foreign-key, and check constraints. +- **Data types:** Numeric, character, binary, temporal, `ENUM`, `SET`, `JSON`, + and spatial type declarations, plus character sets and collations. +- **Value semantics:** MySQL-style casting, coercion, defaults, auto-increment + values, and date and time behavior. +- **Expressions and functions:** MySQL operators and string, numeric, date/time, + aggregate, regular-expression, conversion, and utility functions. +- **Metadata:** `INFORMATION_SCHEMA`, `SHOW`, `DESCRIBE`, and database selection + with `USE`. +- **Session state:** SQL modes and system and user variables. +- **Transactions and locking:** Transactions, savepoints, and locks. + +### PDO + +The driver broadly supports the PDO API and aims for full compatibility with the +PDO MySQL driver. Some APIs, such as prepared statements, parameter binding, +and multi-statement queries, are not yet supported. + +## Development + +Install the development dependencies and run the tests from this directory: + +```bash +composer install +composer run test +``` + +Run an individual test file or test method with: + +```bash +composer run test tests/SomeTest.php +composer run test -- --filter testName +``` + +## Requirements + +- **PHP:** 7.2+ +- **PHP extensions:** `pdo`, `pdo_sqlite`, `pcre` +- **SQLite:** 3.37.0+ + +## License + +MySQL on SQLite is licensed under the +[GNU General Public License v2 or later](../../LICENSE). diff --git a/packages/mysql-on-sqlite/src/load.php b/packages/mysql-on-sqlite/src/load.php index 8ef704366..a1f8e67b8 100644 --- a/packages/mysql-on-sqlite/src/load.php +++ b/packages/mysql-on-sqlite/src/load.php @@ -3,7 +3,7 @@ define( 'WP_MYSQL_ON_SQLITE_LOADER_PATH', __FILE__ ); /** - * Load the PDO MySQL-on-SQLite driver and its dependencies. + * Load the MySQL on SQLite driver and its dependencies. */ require_once __DIR__ . '/php-polyfills.php'; require_once __DIR__ . '/version.php'; diff --git a/packages/mysql-on-sqlite/src/parser/class-wp-parser.php b/packages/mysql-on-sqlite/src/parser/class-wp-parser.php index 9953f1a58..72f4ed886 100644 --- a/packages/mysql-on-sqlite/src/parser/class-wp-parser.php +++ b/packages/mysql-on-sqlite/src/parser/class-wp-parser.php @@ -51,7 +51,7 @@ private function parse_recursive( $rule_id ) { return false; } - // Bale out from processing the current branch if none of its rules can + // Bail out from processing the current branch if none of its rules can // possibly match the current token. if ( isset( $this->grammar->lookahead_is_match_possible[ $rule_id ] ) ) { $token_id = $this->tokens[ $this->position ]->id; diff --git a/packages/mysql-on-sqlite/src/php-polyfills.php b/packages/mysql-on-sqlite/src/php-polyfills.php index b3ab8ed67..6158a90e5 100644 --- a/packages/mysql-on-sqlite/src/php-polyfills.php +++ b/packages/mysql-on-sqlite/src/php-polyfills.php @@ -5,8 +5,6 @@ * Implementation follows the Symfony polyfill-php80 package. * * @see https://github.com/symfony/polyfill-php80 - * - * @package wp-sqlite-integration */ if ( ! function_exists( 'str_starts_with' ) ) { diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-exception.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-exception.php index 72112c16e..9e961c0fe 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-exception.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-exception.php @@ -5,6 +5,12 @@ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase */ +/** + * Exception raised by the MySQL-on-SQLite driver. + * + * Provides PDO-style error information and access to the driver that originated + * the exception. + */ class WP_MySQL_On_SQLite_Exception extends PDOException { /** * The MySQL-on-SQLite driver that originated the exception. @@ -35,6 +41,11 @@ public function __construct( $this->errorInfo = $error_info ?? $this->create_error_info( $message, $code, $previous ); } + /** + * Get the MySQL-on-SQLite driver that originated the exception. + * + * @return WP_MySQL_On_SQLite The originating driver. + */ public function get_driver(): WP_MySQL_On_SQLite { return $this->driver; } diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-statement.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-statement.php index 7e01766be..c7c35b638 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-statement.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite-statement.php @@ -141,7 +141,7 @@ public function getColumnMeta( int $column ) { * - PDO::FETCH_KEY_PAIR: key-value pair * - PDO::FETCH_OBJ: object (stdClass) * - PDO::FETCH_CLASS: object (custom class) [1-2 extra args] - * - PDO::FETCH_INTO: update an exisisting object, can't be used with fetchAll() [1 extra arg] + * - PDO::FETCH_INTO: update an existing object, can't be used with fetchAll() [1 extra arg] * - PDO::FETCH_LAZY: lazy fetch via PDORow, can't be used with fetchAll() * - PDO::FETCH_BOUND: bind values to PHP variables, can't be used with fetchAll() * - PDO::FETCH_FUNC: custom function, only works with fetchAll(), can't be default [1 extra arg] @@ -292,7 +292,7 @@ public function errorCode(): ?string { * 2: Driver-specific error message. */ public function errorInfo(): array { - // Normalize successful results. PDO_SQLite may retain stale driver-specific fields on PHP < 8.0. + // Normalize successful results. PDO SQLite may retain stale driver-specific fields on PHP < 8.0. if ( '00000' === $this->statement->errorCode() ) { return array( '00000', null, null ); } @@ -391,7 +391,7 @@ public function bindValue( $param, $value, $type = PDO::PARAM_STR ): bool { /** * Dump information about the statement. * - * Dupms the SQL query and parameters information. + * Dumps the SQL query and parameter information. * * @return bool|null Returns null, or false on failure. */ diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php index 3f769fe97..3bfad72b6 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php @@ -770,7 +770,7 @@ class WP_MySQL_On_SQLite extends PDO { * Driver-specific PDO options are not supported. * * @type int $mysql_version Optional. MySQL version to emulate. Default 80038. - * @type PDO|null $pdo Optional. Existing SQLite PDO connection. + * @type PDO|null $pdo Optional. Existing PDO SQLite connection. * @type string|null $journal_mode Optional. SQLite journal mode. Default 'WAL'. * @type string|int|null $synchronous Optional. SQLite synchronous setting. * } @@ -886,7 +886,7 @@ function ( $key ) { * with SQLite versions < 3.37.0 when "PRAGMA writable_schema" is * set to "ON", which also enables error-tolerant schema parsing. * - * This is an unsafe opt-in feature for special back compatibility + * This is an unsafe opt-in feature for special backward compatibility * use cases, as it can corrupt the database by allowing incorrect * types into STRICT tables. Additionally, depending on the legacy * SQLite version used, there is no guarantee that all features of @@ -1255,7 +1255,7 @@ public function errorInfo(): array { */ #[ReturnTypeWillChange] public function quote( $string, $type = PDO::PARAM_STR ) { - // Mirror PDO\MySQL::quote() value validation. + // Mirror value validation from the PDO MySQL driver. if ( is_array( $string ) || is_resource( $string ) @@ -1377,8 +1377,8 @@ public function inTransaction(): bool { /** * PDO API: Set a PDO attribute. * - * TODO: Evaluate whether we should pass all PDO attributes to the PDO SQLite - * instance, or whether some of them require special handling. + * TODO: Evaluate whether we should pass all PDO attributes to the underlying + * PDO instance, or whether some of them require special handling. * See: https://github.com/php/php-src/blob/b391c28f903536e3bc6a0021ae0976ddbc2745f8/ext/pdo/php_pdo_driver.h#L103 * * @param int $attribute The attribute to set. @@ -1414,8 +1414,8 @@ public function setAttribute( $attribute, $value ): bool { /** * PDO API: Get a PDO attribute. * - * TODO: Evaluate whether we should get all PDO attributes from the PDO SQLite - * instance, or whether some of them require special handling. + * TODO: Evaluate whether we should get all PDO attributes from the underlying + * PDO instance, or whether some of them require special handling. * See: https://github.com/php/php-src/blob/b391c28f903536e3bc6a0021ae0976ddbc2745f8/ext/pdo/php_pdo_driver.h#L103 * * @param int $attribute The attribute to get. @@ -1435,14 +1435,12 @@ public function getAttribute( $attribute ) { } /** - * Get the underlying SQLite PDO instance. + * Get the underlying PDO SQLite instance. * - * Exposes the SQLite PDO for advanced use, bypassing MySQL emulation. + * Exposes the PDO SQLite connection for advanced use, bypassing MySQL emulation. * Do not retain it across reconnections or modify driver-owned state. * - * @since 3.0.0 - * - * @return PDO The underlying SQLite PDO instance. + * @return PDO The underlying PDO SQLite instance. */ public function get_sqlite_pdo(): PDO { return $this->connection->get_pdo(); @@ -2340,7 +2338,7 @@ private function execute_insert_or_replace_statement( WP_Parser_Node $node ): vo * ON CONFLICT clause differently, and at this stage, we only * save the translated update list to a variable. * - * See bellow at "Handle ON CONFLICT clause for SQLite < 3.35.0". + * See below at "Handle ON CONFLICT clause for SQLite < 3.35.0". */ $sqlite_version = $this->get_sqlite_version(); if ( version_compare( $sqlite_version, '3.35.0', '<' ) ) { @@ -3914,7 +3912,7 @@ private function execute_set_system_variable_statement( /* * Handle ON/OFF values. They are accepted as both strings and keywords. * - * @TODO: This is actually variable-specific and depends on the its type. + * @TODO: This is actually variable-specific and depends on its type. * For example: * SET autocommit = OFF; SELECT @@autocommit; -> 0 * SET autocommit = false; SELECT @@autocommit; -> 0 @@ -4821,7 +4819,7 @@ private function translate_simple_expr_body( WP_Parser_Node $node ): string { return $this->translate_cast_expr( $expr, $cast_type ); } else { // CONVERT(expr USING charset): Keep "expr" as is (no SQLite support). - // TODO: Consider rejecting UTF-8-incompatible charasets. + // TODO: Consider rejecting UTF-8-incompatible charsets. return $this->translate( $expr ); } } diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-connection.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-connection.php index 60792103b..78461f1b1 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-connection.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-connection.php @@ -93,9 +93,9 @@ public function __construct( array $options ) { $this->pdo = $options['pdo']; } else { if ( ! isset( $options['path'] ) || ! is_string( $options['path'] ) ) { - throw new InvalidArgumentException( 'Option "path" is required when "connection" is not provided.' ); + throw new InvalidArgumentException( 'Option "path" is required when "pdo" is not provided.' ); } - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo_options = $options['pdo_options'] ?? array(); // Internal driver operations require exceptions regardless of the @@ -148,7 +148,7 @@ public function __construct( array $options ) { * * The synchronous=NORMAL setting provides the best balance between * performance and safety for most applications running in WAL mode. - * You lose durability across power lose with synchronous NORMAL in WAL + * You lose durability across power loss with synchronous NORMAL in WAL * mode, but that is not important for most applications. Transactions * are still atomic, consistent, and isolated, which are the most * important characteristics in most use cases. diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-driver.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-driver.php index dacb0c759..c8b07174b 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-driver.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-driver.php @@ -9,7 +9,7 @@ */ /** - * For back compatibility with dependencies that use their own loader scripts + * For backward compatibility with dependencies that use their own loader scripts * (e.g., WP CLI SQLite Command), ensure the PDO-based classes are loaded. */ require_once __DIR__ . '/class-wp-mysql-on-sqlite.php'; @@ -261,7 +261,7 @@ public function beginTransaction(): void { } /** - * A temporary alias for back compatibility. + * A temporary alias for backward compatibility. * * @see self::beginTransaction() */ diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-reconstructor.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-reconstructor.php index bc860c571..a29a405a2 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-reconstructor.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-reconstructor.php @@ -6,12 +6,12 @@ */ /** - * SQLite information schema recconstructor for MySQL. + * SQLite information schema reconstructor for MySQL. * * This class checks and reconstructs the MySQL INFORMATION_SCHEMA data in SQLite * when it becomes out of sync with the actual SQLite database schema. * - * Currently, it reconstructs schema infromation for missing tables, and removes + * Currently, it reconstructs schema information for missing tables, and removes * stale data for tables that no longer exist. When used with WordPress, it uses * the "wp_get_db_schema()" function to reconstruct WordPress table information. * @@ -768,7 +768,7 @@ private function get_mysql_column_type( string $column_type ): string { * See WP_MySQL_On_SQLite::quote_mysql_utf8_string_literal(). * * TODO: This is a copy of WP_MySQL_On_SQLite::quote_mysql_utf8_string_literal(). - * We may consider extracing it to reusable MySQL helpers. + * We may consider extracting it to reusable MySQL helpers. * * @param string $utf8_literal The UTF-8 string literal to escape. * @return string The escaped string literal. diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-pdo-user-defined-functions.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-pdo-user-defined-functions.php index 54dfae7fa..656d67d70 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-pdo-user-defined-functions.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-pdo-user-defined-functions.php @@ -1,39 +1,28 @@ - * new WP_SQLite_PDO_User_Defined_Functions(ref_to_pdo_obj); - * - * - * This automatically enables ref_to_pdo_obj to replace the function in the SQL statement - * to the ones defined here. + * Each callback implements a MySQL SQL function that SQLite does not provide. * * @access private */ class WP_SQLite_PDO_User_Defined_Functions { /** - * Registers the user defined functions for SQLite to a PDO instance. + * Register the user-defined SQLite functions on a PDO connection. + * * The functions are registered using PDO::sqliteCreateFunction(). * - * @param PDO|PDO\SQLite $pdo The PDO object. + * @param PDO|Pdo\Sqlite $pdo The PDO object. */ public static function register_for( $pdo ): self { $instance = new self(); foreach ( $instance->functions as $f => $t ) { - if ( $pdo instanceof PDO\SQLite ) { + if ( $pdo instanceof Pdo\Sqlite ) { $pdo->createFunction( $f, array( $instance, $t ) ); } else { $pdo->sqliteCreateFunction( $f, array( $instance, $t ) ); @@ -955,7 +944,7 @@ public function reverse( $str ) { } /** - * A helper to covert LIKE pattern to a GLOB pattern for "LIKE BINARY" support. + * A helper to convert a LIKE pattern to a GLOB pattern for "LIKE BINARY" support. * @TODO: Some of the MySQL string specifics described below are likely to * affect also other patterns than just "LIKE BINARY". We should diff --git a/packages/mysql-on-sqlite/src/sqlite/trait-wp-mysql-on-sqlite-pdo-compat-php-84.php b/packages/mysql-on-sqlite/src/sqlite/trait-wp-mysql-on-sqlite-pdo-compat-php-84.php index f59d71322..9a4bc1f15 100644 --- a/packages/mysql-on-sqlite/src/sqlite/trait-wp-mysql-on-sqlite-pdo-compat-php-84.php +++ b/packages/mysql-on-sqlite/src/sqlite/trait-wp-mysql-on-sqlite-pdo-compat-php-84.php @@ -12,7 +12,7 @@ */ trait WP_MySQL_On_SQLite_PDO_Compat { /** - * Create a MySQL-on-SQLite PDO connection. + * Create a PDO connection to MySQL on SQLite. * * @param string $dsn MySQL-on-SQLite data source name. * @param string|null $username Optional. Ignored by this driver. diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Concurrency_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Concurrency_Tests.php index 684bd2c49..2128d497c 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Concurrency_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Concurrency_Tests.php @@ -166,7 +166,7 @@ private function assertReadOnlyQuerySucceedsUnderWriteLock( string $query ): voi } private function create_in_memory_driver(): WP_MySQL_On_SQLite { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo = new $pdo_class( 'sqlite::memory:' ); $connection = new WP_SQLite_Connection( array( 'pdo' => $pdo ) ); return $this->create_driver( $connection ); diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php index 0116246de..242d59899 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php @@ -14,7 +14,7 @@ class WP_MySQL_On_SQLite_Metadata_Tests extends TestCase { // Before each test, we create a new database public function setUp(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $this->sqlite = new $pdo_class( 'sqlite::memory:' ); $this->engine = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:dbname=wp', diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_PDO_API_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_PDO_API_Tests.php index 185bb84bd..d434b5e48 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_PDO_API_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_PDO_API_Tests.php @@ -135,7 +135,7 @@ public function test_constructor_reports_stringify_fetches_from_injected_pdo(): $this->markTestSkipped( 'PDO SQLite cannot report PDO::ATTR_STRINGIFY_FETCHES before PHP 8.2.' ); } - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo = new $pdo_class( 'sqlite::memory:' ); $pdo->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, true ); $driver = new WP_MySQL_On_SQLite( @@ -182,7 +182,7 @@ public function test_emulated_driver_exception_exposes_mysql_error_information() } public function test_exposes_underlying_sqlite_pdo(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo = new $pdo_class( 'sqlite::memory:' ); $driver = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:dbname=wp', @@ -403,7 +403,7 @@ public function test_statement_error_information(): void { } public function test_statement_error_information_discards_stale_sqlite_error(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo = new $pdo_class( 'sqlite::memory:' ); $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); $pdo->query( 'SELECT * FROM missing_table' ); diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Query_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Query_Tests.php index fc2fbe9da..5c7e13aab 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Query_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Query_Tests.php @@ -107,7 +107,7 @@ public function setUp(): void { global $tables; $queries = explode( ';', $tables ); - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $this->sqlite = new $pdo_class( 'sqlite::memory:' ); $this->engine = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:dbname=wp', diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php index f39b9da0f..c8f500242 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php @@ -30,7 +30,7 @@ class WP_MySQL_On_SQLite_Tests extends TestCase { // Before each test, we create a new database public function setUp(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $this->sqlite = new $pdo_class( 'sqlite::memory:' ); $this->engine = new WP_MySQL_On_SQLite( @@ -7306,7 +7306,7 @@ public function testComplexInformationSchemaQueries(): void { } public function testDatabaseNameEmpty(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo = new $pdo_class( 'sqlite::memory:' ); $this->expectException( WP_MySQL_On_SQLite_Exception::class ); $this->expectExceptionMessage( 'The database name cannot be empty.' ); diff --git a/packages/mysql-on-sqlite/tests/WP_SQLite_DB_Tests.php b/packages/mysql-on-sqlite/tests/WP_SQLite_DB_Tests.php index c2ba0b8e1..13219937e 100644 --- a/packages/mysql-on-sqlite/tests/WP_SQLite_DB_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_SQLite_DB_Tests.php @@ -10,7 +10,7 @@ class WP_SQLite_DB_Tests extends TestCase { private $driver; public function setUp(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $pdo = new $pdo_class( 'sqlite::memory:' ); $this->driver = new WP_MySQL_On_SQLite( diff --git a/packages/mysql-on-sqlite/tests/WP_SQLite_Driver_Compatibility_Tests.php b/packages/mysql-on-sqlite/tests/WP_SQLite_Driver_Compatibility_Tests.php index fe25e6604..bdbc3b90b 100644 --- a/packages/mysql-on-sqlite/tests/WP_SQLite_Driver_Compatibility_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_SQLite_Driver_Compatibility_Tests.php @@ -10,7 +10,7 @@ class WP_SQLite_Driver_Compatibility_Tests extends TestCase { private $sqlite; public function setUp(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $this->sqlite = new $pdo_class( 'sqlite::memory:' ); $this->driver = new WP_SQLite_Driver( new WP_SQLite_Connection( array( 'pdo' => $this->sqlite ) ), diff --git a/packages/mysql-on-sqlite/tests/WP_SQLite_Information_Schema_Reconstructor_Tests.php b/packages/mysql-on-sqlite/tests/WP_SQLite_Information_Schema_Reconstructor_Tests.php index 6ff39c7f5..a7924861d 100644 --- a/packages/mysql-on-sqlite/tests/WP_SQLite_Information_Schema_Reconstructor_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_SQLite_Information_Schema_Reconstructor_Tests.php @@ -41,7 +41,7 @@ function wp_get_db_schema() { // Before each test, we create a new database public function setUp(): void { - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\SQLite::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Sqlite::class : PDO::class; $this->sqlite = new $pdo_class( 'sqlite::memory:' ); $this->engine = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:dbname=wp', diff --git a/packages/mysql-on-sqlite/tests/bootstrap.php b/packages/mysql-on-sqlite/tests/bootstrap.php index 424d09aec..dc438597b 100644 --- a/packages/mysql-on-sqlite/tests/bootstrap.php +++ b/packages/mysql-on-sqlite/tests/bootstrap.php @@ -3,7 +3,7 @@ require_once __DIR__ . '/wp-sqlite-schema.php'; require_once __DIR__ . '/../src/load.php'; -// When on an older SQLite version, enable unsafe back compatibility. +// When on an older SQLite version, enable unsafe backward compatibility. $sqlite_version = ( new PDO( 'sqlite::memory:' ) )->query( 'SELECT SQLITE_VERSION();' )->fetch()[0]; if ( version_compare( $sqlite_version, WP_MySQL_On_SQLite::MINIMUM_SQLITE_VERSION, '<' ) ) { define( 'WP_SQLITE_UNSAFE_ENABLE_UNSUPPORTED_VERSIONS', true ); diff --git a/packages/mysql-proxy/README.md b/packages/mysql-proxy/README.md index b50f6a2c6..d9550d91f 100644 --- a/packages/mysql-proxy/README.md +++ b/packages/mysql-proxy/README.md @@ -1,4 +1,8 @@ -# WP MySQL Proxy +# MySQL proxy + +> [!WARNING] +> This package is experimental. Use it at your own risk. + A MySQL proxy that bridges the MySQL wire protocol to a PDO-like interface. This is a zero-dependency, pure PHP implementation of a MySQL proxy that acts as @@ -6,8 +10,8 @@ a MySQL server, accepts MySQL-native commands, and executes them using a configu PDO-like driver. This allows MySQL-compatible clients to connect and run queries against alternative database backends over the MySQL wire protocol. -Combined with the **WP SQLite Driver**, this allows MySQL-based projects to run -on SQLite. +Combined with [**MySQL on SQLite**](../mysql-on-sqlite/), this allows +MySQL-based projects to run on SQLite. ## Usage diff --git a/packages/mysql-proxy/src/class-mysql-protocol.php b/packages/mysql-proxy/src/class-mysql-protocol.php index 8423394ab..0e37ec1d3 100644 --- a/packages/mysql-proxy/src/class-mysql-protocol.php +++ b/packages/mysql-proxy/src/class-mysql-protocol.php @@ -22,7 +22,7 @@ class MySQL_Protocol { const CLIENT_LONG_PASSWORD = 1 << 0; // [NOT USED] Use improved version of old authentication. const CLIENT_FOUND_ROWS = 1 << 1; // Send found rows instead of affected rows in EOF packet. const CLIENT_LONG_FLAG = 1 << 2; // Get all column flags. - const CLIENT_CONNECT_WITH_DB = 1 << 3; // Database can be specified in handshake reponse packet. + const CLIENT_CONNECT_WITH_DB = 1 << 3; // Database can be specified in handshake response packet. const CLIENT_NO_SCHEMA = 1 << 4; // [DEPRECATED] Don't allow "database.table.column". const CLIENT_COMPRESS = 1 << 5; // Compression protocol supported. const CLIENT_ODBC = 1 << 6; // Special handling of ODBC behavior. None since 3.22. diff --git a/packages/mysql-proxy/src/class-mysql-session.php b/packages/mysql-proxy/src/class-mysql-session.php index 70d5a18bc..b370e0bbe 100644 --- a/packages/mysql-proxy/src/class-mysql-session.php +++ b/packages/mysql-proxy/src/class-mysql-session.php @@ -10,7 +10,7 @@ */ class MySQL_Session { /** - * Client capabilites that are supported by the server. + * Client capabilities that are supported by the server. */ const CAPABILITIES = ( MySQL_Protocol::CLIENT_PROTOCOL_41 diff --git a/packages/mysql-proxy/tests/WP_MySQL_Proxy_PDO_Test.php b/packages/mysql-proxy/tests/WP_MySQL_Proxy_PDO_Test.php index cb9d6a8fa..f88a9a3fb 100644 --- a/packages/mysql-proxy/tests/WP_MySQL_Proxy_PDO_Test.php +++ b/packages/mysql-proxy/tests/WP_MySQL_Proxy_PDO_Test.php @@ -7,7 +7,7 @@ class WP_MySQL_Proxy_PDO_Test extends WP_MySQL_Proxy_Test { public function setUp(): void { parent::setUp(); - $pdo_class = PHP_VERSION_ID >= 80400 ? PDO\MySQL::class : PDO::class; + $pdo_class = PHP_VERSION_ID >= 80400 ? Pdo\Mysql::class : PDO::class; $this->pdo = new $pdo_class( sprintf( 'mysql:host=127.0.0.1;port=%d', $this->port ), 'user', diff --git a/packages/plugin-sqlite-database-integration/activate.php b/packages/plugin-sqlite-database-integration/activate.php index fc6cd91d1..2274dd1c6 100644 --- a/packages/plugin-sqlite-database-integration/activate.php +++ b/packages/plugin-sqlite-database-integration/activate.php @@ -1,16 +1,11 @@

%s

', - esc_html__( 'The SQLite Integration plugin is active, but the PDO SQLite extension is missing from your server. Please make sure that PDO SQLite is enabled in your PHP installation.', 'sqlite-database-integration' ) + esc_html__( 'The SQLite Integration plugin is active, but the pdo_sqlite extension is missing from your server. Please make sure that pdo_sqlite is enabled in your PHP installation.', 'sqlite-database-integration' ) ); return; } diff --git a/packages/plugin-sqlite-database-integration/admin-page.php b/packages/plugin-sqlite-database-integration/admin-page.php index a6e3c4569..8f833f496 100644 --- a/packages/plugin-sqlite-database-integration/admin-page.php +++ b/packages/plugin-sqlite-database-integration/admin-page.php @@ -1,15 +1,10 @@ dbh = $dbh; /** - * Exposes the SQLite PDO instance for backward compatibility. + * Exposes the underlying PDO SQLite connection for backward compatibility. * * @deprecated 3.0.0 Use WP_SQLite_DB::get_driver() with * WP_MySQL_On_SQLite::get_sqlite_pdo() instead. diff --git a/packages/plugin-sqlite-database-integration/wp-includes/sqlite/db.php b/packages/plugin-sqlite-database-integration/wp-includes/sqlite/db.php index 7ede214af..1fa76de06 100644 --- a/packages/plugin-sqlite-database-integration/wp-includes/sqlite/db.php +++ b/packages/plugin-sqlite-database-integration/wp-includes/sqlite/db.php @@ -1,9 +1,6 @@