Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <version> # 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
Expand Down Expand Up @@ -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/<version>` branch with a preparation commit.
- Create a `release/v<version>` branch with a preparation commit.
- Push the branch and create a PR.

2. **Review the PR.**
Expand All @@ -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
```

Expand All @@ -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
```

Expand All @@ -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
```

Expand Down Expand Up @@ -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.
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <version> # 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
Expand All @@ -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)
Expand All @@ -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/<version>` branch with a preparation commit.
- Create a `release/v<version>` branch with a preparation commit.
- Push the branch and create a PR.

2. **Review the PR.**
Expand All @@ -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
Expand All @@ -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 │
┌──────────────────────┐ │ ╔══════════════╗ │
Expand Down
4 changes: 2 additions & 2 deletions grammar-tools/MySQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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?
Expand Down
140 changes: 140 additions & 0 deletions packages/mysql-on-sqlite/README.md
Original file line number Diff line number Diff line change
@@ -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=<sqlite-path>;dbname=<mysql-database-name>
```

| 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).
2 changes: 1 addition & 1 deletion packages/mysql-on-sqlite/src/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
2 changes: 1 addition & 1 deletion packages/mysql-on-sqlite/src/parser/class-wp-parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions packages/mysql-on-sqlite/src/php-polyfills.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Expand Down
Loading
Loading