Sync with upstream trunk (8 commits) - #5
Merged
Merged
Conversation
## Summary This PR improves SQL mode handling and adds **`ANSI_QUOTES`** and **`ANSII`** support. This includes: - **SQL mode storage:** SQL modes use MySQL's native bitmap and canonical order. - **Validation:** Named and numeric assignments are validated with MySQL-compatible errors. - **ANSI_QUOTES:** `ANSI_QUOTES` is supported by the driver, standalone parser, and native lexer. - **ANSI** Composite `ANSI` SQL mode is expanded into its component modes. - **Quoted identifiers:** Fixed backslash behavior in quoted identifiers. - **Native builds:** Lexer constants are regenerated, and the generator's monorepo path is fixed. ## Why The `ANSI_QUOTES` SQL mode support keeps reappearing in our recent performance optimization and parser experiments. This PR extracts and completes that functionality. Additionally, the driver stored arbitrary mode names, accepted invalid assignments, always treated double quotes as string delimiters, did not expand did not expand composite SQL modes, and applied string escaping to quoted identifiers. The standalone parser and native lexer lacked equivalent quoted-identifier handling.
## Summary > [!NOTE] > The commits reflect the logical sequence of changes, so the PR is best reviewed by commit. This prepares the **3.0 API surface** by removing obsolete and broken compatibility paths, narrowing implementation APIs, and aligning exposed class names with `WP_MySQL_On_SQLite`. This includes: - Remove the obsolete **`DATABASE_ENGINE` input alias** in favor of `DB_ENGINE`. - Remove the broken development-only **crosscheck instrumentation** from the plugin and release package. - Remove test-only access to private **legacy driver state**. - Make self-contained constant maps and self-only translation helpers **private**. - Mark parser, native bridge, connection, schema, diagnostic, and compatibility implementation APIs with WordPress Core-style **`@access private` annotations**. - **Deprecate `WP_SQLite_Driver`** in favor of `WP_MySQL_On_SQLite`. - Remove the obsolete **Performance Lab SQLite migration**, upgrade UI, and notice compatibility. The migration had been broken since 2023 because it used `$wp_filesystem` without initializing the `WP_Filesystem` class. - **Stop accepting the `@pdo` global as connection input.** Expose the active driver through `WP_SQLite_DB::get_driver()` and its underlying SQLite PDO through `WP_MySQL_On_SQLite::get_sqlite_pdo()`, while retaining the global temporarily as a deprecated output alias. - Rename `WP_SQLite_Driver_Exception` to `WP_MySQL_On_SQLite_Exception`. - Rename `WP_PDO_Proxy_Statement` to `WP_MySQL_On_SQLite_Statement`.
## Summary Stacked on WordPress#469. > [!NOTE] > The commits reflect the logical sequence of changes, so the PR is best reviewed by commit. This expands **PDO compatibility** for `WP_MySQL_On_SQLite` before the 3.0 release: - Implement **`lastInsertId()`, `errorCode()`, and `errorInfo()`** without relying on uninitialized parent PDO state. - **Isolate the public last insert ID** from internal information-schema writes. - **Reset operation state via `flush()`** for direct transaction methods. - Honor numeric **PDO constructor options**, improve PDO attribute handling. - Initialize **`PDOStatement::$queryString`** on PHP 8.1+ (on older PHP versions, it's unfortunately not writable). - **Delegate safe result statement methods**, including iteration, `closeCursor()`, `bindColumn()`, and diagnostics. - Snapshot result **column metadata** into each statement; implement `getColumnMeta()` with its `array|false` contract. - Populate **`PDOException::$errorInfo`** with native SQLite or emulated MySQL diagnostics. - Override **`PDO::connect()` on PHP 8.4+** so it creates the emulated connection. - Report **`prepare()` as unsupported** for now. Created follow-up tickets related to this PR: - WordPress#473 - WordPress#474 - WordPress#475
## Summary This PR prepares the repository's documentation and non-functional metadata for the 3.0 release: - **Driver documentation:** Adds a focused package README covering the overview, requirements, usage, DSN format, connection options, compatibility limits, and development workflow. It also documents the public exception and driver accessor in source. - **Package status and naming:** Marks the MySQL proxy as experimental and replaces the stale "WP SQLite Driver" name with "MySQL on SQLite." - **Release and source documentation:** Corrects the release command and branch naming, outdated option and drop-in metadata, inaccurate class documentation, and spelling and grammar errors. - **Obsolete annotations:** Removes `@since` and `@package` annotations throughout the repository. ## Why Version 3.0 establishes a well-defined PDO-compatible API. Documenting its entry points, connection format, configuration, and limitations makes that contract discoverable outside source docblocks, while the remaining cleanup removes stale or misleading information before the release is tagged. These changes do not alter runtime behavior.
## Summary This PR is stacked on WordPress#477. This PR makes the configured **MySQL version** the single source of truth for parsing and version reporting. It also makes the driver consistently identify itself as **MySQL on SQLite** instead of exposing SQLite details through MySQL-facing APIs. The changes are: - **Version handling:** Validate `mysql_version`, unify its usage, and fix formatting. - **Server identity:** Report the driver name and consistent server, client, SQL, and WordPress version information. - **System variables:** Report `version` and `version_comment` through both `@@` variables and `SHOW VARIABLES`. ## Why The parser previously used a hard-coded MySQL version, while different public APIs could report conflicting MySQL and SQLite identities. The version and server identity reporting was messy and unfinished. ## Reported values With the default `mysql_version` (`80038`) and current driver version (`3.0.0-rc.8`), the APIs report: The MariaDB reference values were measured with MariaDB 10.11.15 from the official container and PHP 8.5.9 with mysqlnd. Distribution and client suffixes can vary. | Interface | MySQL on SQLite | MariaDB reference | | --- | --- | --- | | `PDO::ATTR_DRIVER_NAME` | `mysql` | `mysql` | | `PDO::ATTR_SERVER_VERSION` | `8.0.38-mysql-on-sqlite-3.0.0-rc.8` | `10.11.15-MariaDB-ubu2204` | | `PDO::ATTR_CLIENT_VERSION` | `mysqlnd 8.0.38-mysql-on-sqlite-3.0.0-rc.8` | `mysqlnd 8.5.9` | | `VERSION()` | `8.0.38-mysql-on-sqlite-3.0.0-rc.8` | `10.11.15-MariaDB-ubu2204` | | `@@version`<br>`@@GLOBAL.version`<br>`SHOW VARIABLES: version` | `8.0.38-mysql-on-sqlite-3.0.0-rc.8` | `10.11.15-MariaDB-ubu2204` | | `@@version_comment`<br>`@@GLOBAL.version_comment`<br>`SHOW VARIABLES: version_comment` | `MySQL on SQLite` | `mariadb.org binary distribution` | | `WP_SQLite_DB::db_version()` | `8.0.38` | `10.11.15` | | `WP_SQLite_DB::db_server_info()` | `8.0.38-mysql-on-sqlite-3.0.0-rc.8` | `10.11.15-MariaDB-ubu2204` | | `WP_MySQL_On_SQLite::$client_info` | `mysqlnd 8.0.38-mysql-on-sqlite-3.0.0-rc.8` | `mysqlnd 8.5.9` | ## Accepted WordPress test failures Reporting MySQL 8.0.38 causes WordPress to apply MySQL 8 behavior when interpreting database metadata. This exposes three existing compatibility gaps: - `Tests_DB_Charset::test_get_column_charset` data sets `#5` and `#6`, because the driver still reports `utf8` instead of the modern `utf8mb3` alias. - `Tests_DB_dbDelta::test_column_type_change`, because the driver still reports integer display widths that MySQL 8.0.19 and later omit. These cases are tracked as expected failures in this PR. Version-dependent metadata reporting will be addressed separately in a follow-up.
## Summary Rename the SQLite-specific `WP_MySQL_On_SQLite` constructor options so their ownership is explicit: - `pdo` → `sqlite_pdo` - `journal_mode` → `sqlite_journal_mode` - `synchronous` → `sqlite_synchronous` The documentation, internal callers, and tests now use the prefixed names. ## Rationale `WP_MySQL_On_SQLite` accepts standard numeric PDO constructor options alongside its own string-keyed options. The generic names did not clearly distinguish SQLite connection configuration from PDO attributes or other driver configuration. The `sqlite_` prefix makes that boundary explicit.
## Summary This completes four API and compatibility refinements before 3.0: - Prevents `PDOStatement::execute()` from bypassing MySQL emulation. Marking it not implemented for now. - Normalizes missing table failures to the MySQL-compatible SQLSTATE, error code, and message. - Marks the legacy database constants as deprecated. - Removes `ext-filter` dependency when reconstructing hexadecimal defaults.
…ess#484) ## Summary Restore `WP_SQLite_DB::db_version()` and remove the redundant implementation from the unit-test `wpdb` stub. ## Why WordPress 5.4 and older do not provide `wpdb::db_server_info()`. Their inherited `db_version()` asks the MySQL extension for server information directly, which does not work with the SQLite-backed connection used by Playground. Defining the method on the drop-in makes these releases read the emulated MySQL version through the driver API. Fixes WordPress/wordpress-playground#4256
Resolve the drift between the fork's D1 backend and the upstream 3.0 API
refinements, and adopt the upstream changes in the D1-specific code.
Conflict resolutions:
- Keep the connection interface as the driver's single access path.
Upstream reintroduced direct `get_pdo()` calls in `setAttribute()`,
`getAttribute()` and the user-defined function registration; these now
go through `set_attribute()` / `get_attribute()` / `create_function()`
so the D1 connection keeps working, while upstream's new behavior
(driver-specific attribute rejection, caller error mode tracking,
stringify-fetches reporting) is preserved in full.
- Keep `WP_PDO_Array_Statement` for composed result sets. Upstream builds
them from a connection-private TEMP table, which a remote backend has
no way to provide. The in-memory statement is backend-agnostic and
avoids the write lock the TEMP table exists to dodge, so the now-unused
`EMPTY_RESULT_TABLE_NAME` constant is dropped.
- Follow upstream's rename of the statement class and of
`WP_SQLite_Driver_Exception` to `WP_MySQL_On_SQLite_Exception`.
- Keep both sides where upstream and the fork added different methods
to the same place.
Adopted upstream changes:
- Rename the connection injection option to `sqlite_connection`, matching
the upstream convention of prefixing SQLite-specific options (WordPress#481), and
document it in the driver README.
- Give the D1 connection an error mode attribute, so upstream's new
caller-visible `PDO::ATTR_ERRMODE` handling works on that backend
instead of failing every set.
- Report `PDO::ATTR_STRINGIFY_FETCHES` from PDO itself on PHP 8.2+. The
locally tracked value could not see the initial state of an injected
PDO instance.
Also fix a latent bug in the D1 fake transport: it restored the handle's
stringification setting before fetching rows rather than after, and PDO
SQLite applies that attribute at fetch time. Every value therefore arrived
as a string and the fake never reproduced D1's native JSON types. This
surfaced through upstream's new numeric `sql_mode` bitmaps (WordPress#452), which
depend on `getColumnMeta()` reporting a native type.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🤖 Lexer benchmarkChanges to lexer-related files were detected and triggered a benchmark:
Note: Hosted runners are noisy, and absolute numbers vary. Treat the results with caution and verify them locally. To reproduce locally: |
The MySQL functions that the D1 backend rewrites instead of emulating with
PHP callbacks used SQLite features newer than the project's floor of SQLite
3.37.0. They only ever ran against whatever SQLite the D1 job happened to
have, so this went unnoticed until the full version matrix ran:
- IF() is a reserved word, so it parses as a runtime function call and
never reached the rewrite at all. It survived only because SQLite 3.48
added an "if" alias for IIF(). It now compiles to a CASE expression,
which every version understands and which selects the "else" branch for
a NULL condition, as MySQL does.
- WEEK() mode 0 used the "%U" strftime specifier (SQLite 3.46+). It now
computes the same value the way "%U" is defined. Verified against "%U"
for every date in 2020-2027.
- UNIX_TIMESTAMP() used UNIXEPOCH() (SQLite 3.38+), now STRFTIME('%s').
- LOCATE() with an offset used IIF() (SQLite 3.32+), now a CASE expression.
- LOG() uses LN(), which is a math function: SQLite 3.35+ and only when
compiled with SQLITE_ENABLE_MATH_FUNCTIONS. Constant arguments are now
evaluated in PHP, matching LN() including its NULL results for
out-of-domain values; other arguments still compile to LN().
Scope the oracle tests to the versions their oracle can serve:
- WP_PDO_Array_Statement_Tests compares against PDO SQLite, which before
PHP 8.1 has different value semantics entirely: it always stringifies,
and does so from SQLite's text rendering rather than from a PHP value,
so a float reads as "1230.0" and every column reports PDO::PARAM_STR.
The array statement implements the current semantics, so there is
nothing to compare against on older versions.
- The D1 fake transport reads its values from PDO SQLite and inherits the
same limitation, which the driver's numeric sql_mode handling depends
on. Those five tests are skipped below PHP 8.1 with that reason. Only
the test double is affected: json_decode() yields native types on every
supported PHP version, so the real transports carry them as D1 does.
These failures all predate the upstream merge; they are fixed here because
the merge is the first change to run the full PHP and SQLite matrix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated sync of
WordPress/sqlite-database-integration@trunkintod1-support.This pull request tracks every upstream commit that has not landed on
d1-supportyet.It is updated in place as upstream moves, and merges itself once the merge is clean and
every check is green. While it is open, it needs a person.
Upstream commits (8)
Branch shape:
merged. Maintained byupstream-sync.yml. Closing this pull request is not permanent — the next scheduled run reopens it. Disable the workflow to stop the sync.