From 902a032df1c1f4d617979dbd6c745f68d497db71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jake=C5=A1?= Date: Fri, 7 Aug 2026 10:39:45 +0000 Subject: [PATCH 1/4] Unify emulated MySQL version Use the configured MySQL version for parser version gates and report it consistently through PDO, SQL, and wpdb APIs. --- .../src/sqlite/class-wp-mysql-on-sqlite.php | 80 ++++++++++++++----- .../src/sqlite/class-wp-sqlite-driver.php | 2 +- .../WP_MySQL_On_SQLite_PDO_API_Tests.php | 66 +++++++++++++++ .../tests/WP_MySQL_On_SQLite_Tests.php | 4 +- .../tests/WP_SQLite_DB_Tests.php | 31 +++++++ .../WP_SQLite_Driver_Compatibility_Tests.php | 11 +++ .../tests/fixtures/class-wpdb-stub.php | 4 + .../wp-includes/sqlite/class-wp-sqlite-db.php | 19 +---- 8 files changed, 178 insertions(+), 39 deletions(-) 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 3bfad72b6..2bfadb115 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 @@ -45,6 +45,16 @@ class WP_MySQL_On_SQLite extends PDO { */ private const MYSQL_GRAMMAR_PATH = __DIR__ . '/../mysql/mysql-grammar.php'; + /** + * The minimum supported MySQL version. + */ + private const MINIMUM_MYSQL_VERSION = 50700; + + /** + * The default MySQL version to emulate. + */ + const DEFAULT_MYSQL_VERSION = 80038; + /** * The minimum required version of SQLite. * @@ -775,6 +785,7 @@ class WP_MySQL_On_SQLite extends PDO { * @type string|int|null $synchronous Optional. SQLite synchronous setting. * } * + * @throws InvalidArgumentException When the MySQL version is invalid. * @throws WP_MySQL_On_SQLite_Exception When the driver initialization fails. */ public function __construct( @@ -824,6 +835,16 @@ public function __construct( $path = $args['path'] ?? ':memory:'; $db_name = $args['dbname'] ?? 'sqlite_database'; + $mysql_version = $options['mysql_version'] ?? self::DEFAULT_MYSQL_VERSION; + if ( ! is_int( $mysql_version ) || $mysql_version < self::MINIMUM_MYSQL_VERSION ) { + throw new InvalidArgumentException( + sprintf( + 'The "mysql_version" option must be an integer greater than or equal to %d.', + self::MINIMUM_MYSQL_VERSION + ) + ); + } + // Create a new SQLite connection. $pdo_options = array_filter( $options, @@ -852,7 +873,7 @@ function ( $key ) { } $this->connection = new WP_SQLite_Connection( $connection_options ); - $this->mysql_version = $options['mysql_version'] ?? 80038; + $this->mysql_version = $mysql_version; $this->main_db_name = $db_name; $this->db_name = $db_name; $this->set_sql_modes( $this->get_default_sql_modes() ); @@ -1423,11 +1444,14 @@ public function setAttribute( $attribute, $value ): bool { */ #[ReturnTypeWillChange] public function getAttribute( $attribute ) { - // Return the caller's error mode instead of the exception mode used internally. - if ( PDO::ATTR_ERRMODE === $attribute ) { + if ( PDO::ATTR_CLIENT_VERSION === $attribute ) { + return 'mysqlnd ' . $this->get_mysql_server_version_string(); + } elseif ( PDO::ATTR_SERVER_VERSION === $attribute ) { + return $this->get_mysql_server_version_string(); + } elseif ( PDO::ATTR_ERRMODE === $attribute ) { + // Return the caller's error mode instead of the exception mode used internally. return $this->error_mode; - } - if ( PDO::ATTR_STRINGIFY_FETCHES === $attribute && PHP_VERSION_ID < 80200 ) { + } elseif ( PDO::ATTR_STRINGIFY_FETCHES === $attribute && PHP_VERSION_ID < 80200 ) { // PDO SQLite cannot report this attribute before PHP 8.2. return $this->stringify_fetches; } @@ -1546,7 +1570,7 @@ public function get_last_sqlite_queries(): array { public function create_parser( string $query ): WP_MySQL_Parser { $lexer = new WP_MySQL_Lexer( $query, - 80038, + $this->mysql_version, $this->get_active_sql_mode_names() ); $tokens = $lexer instanceof WP_MySQL_Native_Lexer @@ -4294,13 +4318,7 @@ private function translate( $node ): ?string { if ( 'sql_mode' === $name ) { $value = implode( ',', $this->get_active_sql_mode_names() ); } elseif ( 'version' === $name ) { - $version = (string) $this->mysql_version; - $value = sprintf( - '%d.%d.%d', - $version[0], - substr( $version, 1, 2 ), - substr( $version, 3, 2 ) - ); + $value = $this->get_mysql_server_version_string(); } elseif ( 'version_comment' === $name ) { $value = 'MySQL Community Server - GPL'; } elseif ( WP_MySQL_Lexer::SESSION_SYMBOL === $type ) { @@ -5077,19 +5095,39 @@ private function translate_function_call( WP_Parser_Node $node ): string { return 0; } case 'VERSION': - $version = (string) $this->mysql_version; - $value = sprintf( - '%d.%d.%d', - $version[0], - substr( $version, 1, 2 ), - substr( $version, 3, 2 ) - ); - return $this->quote_sqlite_value( $value ); + return $this->quote_sqlite_value( $this->get_mysql_server_version_string() ); default: return $this->translate_sequence( $node->get_children() ); } } + /** + * Get the configured MySQL version in dotted notation. + * + * @return string The MySQL version. + */ + private function get_mysql_version_string(): string { + return sprintf( + '%d.%d.%d', + intdiv( $this->mysql_version, 10000 ), + intdiv( $this->mysql_version % 10000, 100 ), + $this->mysql_version % 100 + ); + } + + /** + * Get the raw version string of the emulated MySQL server. + * + * @return string The MySQL server version. + */ + private function get_mysql_server_version_string(): string { + return sprintf( + '%s-mysql-on-sqlite-%s', + $this->get_mysql_version_string(), + SQLITE_DRIVER_VERSION + ); + } + /** * Translate a MySQL datetime literal to SQLite. * 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 c8b07174b..3b0404167 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 @@ -75,7 +75,7 @@ class WP_SQLite_Driver { public function __construct( WP_SQLite_Connection $connection, string $database, - int $mysql_version = 80038 + int $mysql_version = WP_MySQL_On_SQLite::DEFAULT_MYSQL_VERSION ) { $this->mysql_on_sqlite_driver = new WP_MySQL_On_SQLite( sprintf( 'mysql-on-sqlite:dbname=%s', str_replace( ';', ';;', $database ) ), 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 d434b5e48..ade939691 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 @@ -101,6 +101,72 @@ public function test_constructor_applies_pdo_options(): void { $this->assertSame( PDO::ERRMODE_EXCEPTION, $driver->get_sqlite_pdo()->getAttribute( PDO::ATTR_ERRMODE ) ); } + public function test_configured_mysql_version_controls_reporting_and_parsing(): void { + $driver = new WP_MySQL_On_SQLite( + 'mysql-on-sqlite:path=:memory:;dbname=WordPress;', + null, + null, + array( 'mysql_version' => 50744 ) + ); + $server_version = '5.7.44-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION; + + $this->assertSame( $server_version, $driver->getAttribute( PDO::ATTR_SERVER_VERSION ) ); + $this->assertSame( 'mysqlnd ' . $server_version, $driver->getAttribute( PDO::ATTR_CLIENT_VERSION ) ); + $this->assertSame( $server_version, $driver->query( 'SELECT VERSION()' )->fetchColumn() ); + $this->assertSame( $server_version, $driver->query( 'SELECT @@version' )->fetchColumn() ); + $this->assertEquals( 1, $driver->query( 'SELECT 1 /*!80000 + 1 */' )->fetchColumn() ); + } + + public function test_formats_six_digit_mysql_version(): void { + $driver = new WP_MySQL_On_SQLite( + 'mysql-on-sqlite:path=:memory:;dbname=WordPress;', + null, + null, + array( 'mysql_version' => 100000 ) + ); + $server_version = '10.0.0-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION; + + $this->assertSame( $server_version, $driver->getAttribute( PDO::ATTR_SERVER_VERSION ) ); + $this->assertSame( 'mysqlnd ' . $server_version, $driver->getAttribute( PDO::ATTR_CLIENT_VERSION ) ); + $this->assertSame( $server_version, $driver->query( 'SELECT VERSION()' )->fetchColumn() ); + $this->assertSame( $server_version, $driver->query( 'SELECT @@version' )->fetchColumn() ); + } + + /** + * @dataProvider data_invalid_mysql_versions + */ + public function test_rejects_invalid_mysql_version( $mysql_version ): void { + $this->expectException( InvalidArgumentException::class ); + $this->expectExceptionMessage( + 'The "mysql_version" option must be an integer greater than or equal to 50700.' + ); + + new WP_MySQL_On_SQLite( + 'mysql-on-sqlite:path=:memory:;dbname=WordPress;', + null, + null, + array( 'mysql_version' => $mysql_version ) + ); + } + + public function data_invalid_mysql_versions(): array { + return array( + 'string' => array( '80038' ), + 'float' => array( 80038.0 ), + 'boolean' => array( true ), + 'array' => array( array( 80038 ) ), + 'below minimum' => array( 50699 ), + 'zero' => array( 0 ), + 'negative' => array( -80038 ), + ); + } + + public function test_uses_shared_default_mysql_version(): void { + $this->assertSame( 80038, WP_MySQL_On_SQLite::DEFAULT_MYSQL_VERSION ); + $this->assertSame( '8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $this->driver->getAttribute( PDO::ATTR_SERVER_VERSION ) ); + $this->assertSame( 'mysqlnd 8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $this->driver->getAttribute( PDO::ATTR_CLIENT_VERSION ) ); + } + public function test_constructor_applies_fetch_column_default(): void { $driver = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:path=:memory:;dbname=WordPress;', 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 c8f500242..8802f3b6d 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 @@ -7363,7 +7363,7 @@ public function testSetStatement(): void { public function testBuiltInSystemVariables(): void { $result = $this->assertQuery( 'SELECT @@version' ); - $this->assertSame( '8.0.38', $result[0]->{'@@version'} ); + $this->assertSame( '8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $result[0]->{'@@version'} ); $result = $this->assertQuery( 'SELECT @@version_comment' ); $this->assertSame( 'MySQL Community Server - GPL', $result[0]->{'@@version_comment'} ); @@ -12681,7 +12681,7 @@ public function testUpdateErrorsInNonStrictMode(): void { public function testVersionFunction(): void { $result = $this->query( 'SELECT VERSION()' ); - $this->assertSame( '8.0.38', $result[0]->{'VERSION()'} ); + $this->assertSame( '8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $result[0]->{'VERSION()'} ); } public function testFromBase64Function(): void { 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 13219937e..e112d8911 100644 --- a/packages/mysql-on-sqlite/tests/WP_SQLite_DB_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_SQLite_DB_Tests.php @@ -31,6 +31,37 @@ public function __construct( WP_MySQL_On_SQLite $driver ) { $this->assertSame( $this->driver, $wpdb->get_driver() ); } + public function test_reports_emulated_mysql_version(): void { + $driver = new WP_MySQL_On_SQLite( + 'mysql-on-sqlite:dbname=wp', + null, + null, + array( + 'pdo' => $this->driver->get_sqlite_pdo(), + 'mysql_version' => 50744, + ) + ); + $wpdb = new class( $driver ) extends WP_SQLite_DB { + public function __construct( WP_MySQL_On_SQLite $driver ) { + $this->dbh = $driver; + } + }; + + $this->assertSame( '5.7.44', $wpdb->db_version() ); + $this->assertSame( '5.7.44-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $wpdb->db_server_info() ); + } + + public function test_reports_empty_version_without_database_connection(): void { + $wpdb = new class() extends WP_SQLite_DB { + public function __construct() { + $this->dbh = null; + } + }; + + $this->assertSame( '', $wpdb->db_version() ); + $this->assertSame( '', $wpdb->db_server_info() ); + } + public function test_rejects_driver_access_without_database_connection(): void { $wpdb = new class() extends WP_SQLite_DB { public function __construct() { 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 bdbc3b90b..96d9a51c6 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 @@ -69,6 +69,17 @@ public function test_delegates_diagnostics_and_native_queries(): void { $this->assertSame( '42', $this->driver->execute_sqlite_query( 'SELECT 42' )->fetchColumn() ); } + public function test_preserves_configured_mysql_version(): void { + $driver = new WP_SQLite_Driver( + new WP_SQLite_Connection( array( 'pdo' => $this->sqlite ) ), + 'wp', + 50744 + ); + + $this->assertSame( '5.7.44-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $driver->query( 'SELECT VERSION()' )[0]->{'VERSION()'} ); + $this->assertSame( '1', $driver->query( 'SELECT 1 /*!80000 + 1 */' )[0]->{'1'} ); + } + public function test_preserves_transaction_method_aliases(): void { $this->driver->begin_transaction(); $this->driver->query( "INSERT INTO t (value) VALUES ('rolled back')" ); diff --git a/packages/mysql-on-sqlite/tests/fixtures/class-wpdb-stub.php b/packages/mysql-on-sqlite/tests/fixtures/class-wpdb-stub.php index 8b2b8f44e..a030c8544 100644 --- a/packages/mysql-on-sqlite/tests/fixtures/class-wpdb-stub.php +++ b/packages/mysql-on-sqlite/tests/fixtures/class-wpdb-stub.php @@ -4,6 +4,10 @@ class WPDB_Stub { public function add_placeholder_escape( $query ) { return $query; } + + public function db_version() { + return preg_replace( '/[^0-9.].*/', '', $this->db_server_info() ); + } } class_alias( WPDB_Stub::class, 'wpdb' ); diff --git a/packages/plugin-sqlite-database-integration/wp-includes/sqlite/class-wp-sqlite-db.php b/packages/plugin-sqlite-database-integration/wp-includes/sqlite/class-wp-sqlite-db.php index 17223a39d..7aca1db00 100644 --- a/packages/plugin-sqlite-database-integration/wp-includes/sqlite/class-wp-sqlite-db.php +++ b/packages/plugin-sqlite-database-integration/wp-includes/sqlite/class-wp-sqlite-db.php @@ -746,29 +746,18 @@ public function has_cap( $db_cap ) { } /** - * Method to return database version number. + * Returns the raw version string of the emulated MySQL server. * - * This overrides wpdb::db_version() to avoid using MySQL function. - * It returns mysql version number, but it means nothing for SQLite. - * So it return the newest mysql version. + * @see wpdb::db_server_info() * - * @see wpdb::db_version() - */ - public function db_version() { - return '8.0'; - } - - /** - * Returns the version of the SQLite engine. - * - * @return string SQLite engine version, or an empty string while disconnected. + * @return string Emulated MySQL server version, or an empty string while disconnected. */ public function db_server_info() { if ( ! $this->dbh ) { return ''; } - return $this->dbh->get_sqlite_version(); + return $this->dbh->getAttribute( PDO::ATTR_SERVER_VERSION ); // phpcs:ignore WordPress.DB.RestrictedClasses.mysql__PDO } /** From 0aa38ebf8a7dae0447808c730589e3e7a8fbd4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jake=C5=A1?= Date: Fri, 7 Aug 2026 12:02:18 +0000 Subject: [PATCH 2/4] Report emulated MySQL identity Expose the MySQL PDO driver name while identifying the implementation as MySQL on SQLite through @@version_comment. --- .../src/sqlite/class-wp-mysql-on-sqlite.php | 21 ++++++++++++++----- .../src/sqlite/class-wp-sqlite-driver.php | 2 +- .../WP_MySQL_On_SQLite_PDO_API_Tests.php | 6 ++++++ .../tests/WP_MySQL_On_SQLite_Tests.php | 2 +- .../WP_SQLite_Driver_Compatibility_Tests.php | 5 ++++- 5 files changed, 28 insertions(+), 8 deletions(-) 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 2bfadb115..b809bf616 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 @@ -498,7 +498,7 @@ class WP_MySQL_On_SQLite extends PDO { private $mysql_version; /** - * The SQLite engine version. + * The emulated MySQL client library version. * * This is a mysqli-like property that is needed to avoid a PHP warning in * the WordPress health info. The "WP_Debug_Data::get_wp_database()" method @@ -930,8 +930,8 @@ function ( $key ) { } } - // Load SQLite version to a property used by WordPress health info. - $this->client_info = $sqlite_version; + // Load MySQL client information to a property used by WordPress health info. + $this->client_info = $this->getAttribute( PDO::ATTR_CLIENT_VERSION ); // Enable foreign keys. By default, they are off. $this->connection->query( 'PRAGMA foreign_keys = ON' ); @@ -1444,7 +1444,9 @@ public function setAttribute( $attribute, $value ): bool { */ #[ReturnTypeWillChange] public function getAttribute( $attribute ) { - if ( PDO::ATTR_CLIENT_VERSION === $attribute ) { + if ( PDO::ATTR_DRIVER_NAME === $attribute ) { + return 'mysql'; + } elseif ( PDO::ATTR_CLIENT_VERSION === $attribute ) { return 'mysqlnd ' . $this->get_mysql_server_version_string(); } elseif ( PDO::ATTR_SERVER_VERSION === $attribute ) { return $this->get_mysql_server_version_string(); @@ -4320,7 +4322,7 @@ private function translate( $node ): ?string { } elseif ( 'version' === $name ) { $value = $this->get_mysql_server_version_string(); } elseif ( 'version_comment' === $name ) { - $value = 'MySQL Community Server - GPL'; + $value = $this->get_mysql_server_version_comment(); } elseif ( WP_MySQL_Lexer::SESSION_SYMBOL === $type ) { $value = $this->session_system_variables[ $name ] ?? null; } else { @@ -5128,6 +5130,15 @@ private function get_mysql_server_version_string(): string { ); } + /** + * Get the comment identifying the emulated MySQL server implementation. + * + * @return string The MySQL server version comment. + */ + private function get_mysql_server_version_comment(): string { + return 'MySQL on SQLite'; + } + /** * Translate a MySQL datetime literal to SQLite. * 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 3b0404167..34d90d97a 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 @@ -25,7 +25,7 @@ */ class WP_SQLite_Driver { /** - * The SQLite engine version. + * The emulated MySQL client library version. * * This is a mysqli-like property that is needed to avoid a PHP warning in * the WordPress health info. The "WP_Debug_Data::get_wp_database()" method 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 ade939691..d049fd1ae 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 @@ -101,6 +101,11 @@ public function test_constructor_applies_pdo_options(): void { $this->assertSame( PDO::ERRMODE_EXCEPTION, $driver->get_sqlite_pdo()->getAttribute( PDO::ATTR_ERRMODE ) ); } + public function test_reports_mysql_driver_name(): void { + $this->assertSame( 'mysql', $this->driver->getAttribute( PDO::ATTR_DRIVER_NAME ) ); + $this->assertSame( 'sqlite', $this->driver->get_sqlite_pdo()->getAttribute( PDO::ATTR_DRIVER_NAME ) ); + } + public function test_configured_mysql_version_controls_reporting_and_parsing(): void { $driver = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:path=:memory:;dbname=WordPress;', @@ -112,6 +117,7 @@ public function test_configured_mysql_version_controls_reporting_and_parsing(): $this->assertSame( $server_version, $driver->getAttribute( PDO::ATTR_SERVER_VERSION ) ); $this->assertSame( 'mysqlnd ' . $server_version, $driver->getAttribute( PDO::ATTR_CLIENT_VERSION ) ); + $this->assertSame( 'mysqlnd ' . $server_version, $driver->client_info ); $this->assertSame( $server_version, $driver->query( 'SELECT VERSION()' )->fetchColumn() ); $this->assertSame( $server_version, $driver->query( 'SELECT @@version' )->fetchColumn() ); $this->assertEquals( 1, $driver->query( 'SELECT 1 /*!80000 + 1 */' )->fetchColumn() ); 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 8802f3b6d..bc5c2bd37 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 @@ -7366,7 +7366,7 @@ public function testBuiltInSystemVariables(): void { $this->assertSame( '8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $result[0]->{'@@version'} ); $result = $this->assertQuery( 'SELECT @@version_comment' ); - $this->assertSame( 'MySQL Community Server - GPL', $result[0]->{'@@version_comment'} ); + $this->assertSame( 'MySQL on SQLite', $result[0]->{'@@version_comment'} ); } public function testSessionSystemVariables(): void { 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 96d9a51c6..6860ba2b5 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 @@ -33,7 +33,10 @@ function () { $this->assertInstanceOf( WP_MySQL_On_SQLite::class, $mysql_on_sqlite_driver ); $this->assertTrue( $mysql_on_sqlite_driver->getAttribute( PDO::ATTR_STRINGIFY_FETCHES ) ); $this->assertSame( $this->sqlite, $this->driver->get_connection()->get_pdo() ); - $this->assertSame( $this->driver->get_sqlite_version(), $this->driver->client_info ); + $this->assertSame( + 'mysqlnd 8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, + $this->driver->client_info + ); $this->assertSame( SQLITE_DRIVER_VERSION, $this->driver->get_saved_driver_version() ); $this->assertTrue( $this->driver->is_sql_mode_active( 'STRICT_TRANS_TABLES' ) ); } From 5464beec644aef9cc3bd06c1ea9f23751a3f9741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jake=C5=A1?= Date: Fri, 7 Aug 2026 12:34:37 +0000 Subject: [PATCH 3/4] Report version through SHOW VARIABLES --- .../src/sqlite/class-wp-mysql-on-sqlite.php | 59 +++++++++++-------- .../tests/WP_MySQL_On_SQLite_Tests.php | 9 ++- 2 files changed, 42 insertions(+), 26 deletions(-) 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 b809bf616..95bb0cdd3 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 @@ -3273,31 +3273,7 @@ private function execute_show_statement( WP_Parser_Node $node ): void { $this->execute_show_tables_statement( $node ); return; case WP_MySQL_Lexer::VARIABLES_SYMBOL: - $this->last_column_meta = array( - array( - 'native_type' => 'STRING', - 'pdo_type' => PDO::PARAM_STR, - 'flags' => array( 'not_null' ), - 'table' => 'session_variables', - 'name' => 'Variable_name', - 'len' => 256, - 'precision' => 0, - ), - array( - 'native_type' => 'STRING', - 'pdo_type' => PDO::PARAM_STR, - 'flags' => array(), - 'table' => 'session_variables', - 'name' => 'Value', - 'len' => 4096, - 'precision' => 0, - ), - ); - $this->last_result_statement = $this->create_result_statement_from_data( - array_column( $this->last_column_meta, 'name' ), - array() - ); - $this->found_rows = 0; + $this->execute_show_variables_statement( $node ); return; } @@ -3310,6 +3286,39 @@ private function execute_show_statement( WP_Parser_Node $node ): void { ); } + /** + * Translate and execute a MySQL SHOW VARIABLES statement in SQLite. + * + * @param WP_Parser_Node $node The "showStatement" AST node. + */ + private function execute_show_variables_statement( WP_Parser_Node $node ): void { + $like_or_where = $node->get_first_child_node( 'likeOrWhere' ); + if ( null !== $like_or_where ) { + $condition = $this->translate_show_like_or_where_condition( $like_or_where, 'Variable_name' ); + } + + $query = sprintf( + "SELECT column1 AS `Variable_name`, column2 AS `Value` + FROM ( + VALUES + ('version', ?), + ('version_comment', ?) + ) + WHERE TRUE %s + ORDER BY column1", + $condition ?? '' + ); + $params = array( + $this->get_mysql_server_version_string(), + $this->get_mysql_server_version_comment(), + ); + + $stmt = $this->execute_sqlite_query( $query, $params ); + $this->store_last_column_meta_from_statement( $stmt ); + $this->last_result_statement = $stmt; + $this->found_rows = array( $query, $params ); + } + /** * Translate and execute a MySQL SHOW COLLATION statement in SQLite. * 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 bc5c2bd37..17fa613db 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 @@ -3895,7 +3895,14 @@ public function testShowIndex() { public function testShowVarianles(): void { $this->assertQuery( 'SHOW VARIABLES' ); $this->assertQuery( "SHOW VARIABLES LIKE 'version'" ); + $this->assertSame( 'version', $this->last_result[0]->Variable_name ); + $this->assertSame( '8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $this->last_result[0]->Value ); + $this->assertQuery( "SHOW VARIABLES LIKE 'version_comment'" ); + $this->assertSame( 'version_comment', $this->last_result[0]->Variable_name ); + $this->assertSame( 'MySQL on SQLite', $this->last_result[0]->Value ); $this->assertQuery( "SHOW VARIABLES WHERE Variable_name = 'version'" ); + $this->assertSame( 'version', $this->last_result[0]->Variable_name ); + $this->assertSame( '8.0.38-mysql-on-sqlite-' . SQLITE_DRIVER_VERSION, $this->last_result[0]->Value ); $this->assertQuery( 'SHOW GLOBAL VARIABLES' ); $this->assertQuery( 'SHOW SESSION VARIABLES' ); } @@ -4058,7 +4065,7 @@ public function testFoundRowsWithoutSqlCalcFoundRows(): void { // SHOW VARIABLES $this->assertQuery( 'SHOW VARIABLES' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '0', $result[0]->{'FOUND_ROWS()'} ); + $this->assertSame( '2', $result[0]->{'FOUND_ROWS()'} ); } public function testComplexSelectBasedOnDates() { From f82e47485bd04ef9f030d67f600415a613374943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jake=C5=A1?= Date: Fri, 7 Aug 2026 16:02:44 +0000 Subject: [PATCH 4/4] Accept MySQL version-related WordPress test failures Reporting MySQL 8.0.38 exposes existing differences in utf8mb3 metadata and integer display-width reporting. Track the three affected WordPress tests as expected failures and remove the spatial-index case that now passes. --- .github/workflows/wp-tests-phpunit-run.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wp-tests-phpunit-run.js b/.github/workflows/wp-tests-phpunit-run.js index 934d3c571..efb7d2b7a 100644 --- a/.github/workflows/wp-tests-phpunit-run.js +++ b/.github/workflows/wp-tests-phpunit-run.js @@ -22,6 +22,8 @@ const expectedFailures = [ 'Tests_Comment_CheckComment::test_should_return_false_when_comment_previously_approved_is_enabled_and_author_does_not_have_approved_comment', 'Tests_Comment_CheckComment::test_should_return_true_when_comment_previously_approved_is_enabled_and_author_has_approved_comment', 'Tests_Comment_CheckComment::test_should_return_false_when_comment_previously_approved_is_enabled_and_user_does_not_have_a_previously_approved_comment_with_any_email', + 'Tests_DB_Charset::test_get_column_charset with data set #5', + 'Tests_DB_Charset::test_get_column_charset with data set #6', 'Tests_DB_Charset::test_get_column_charset_is_mysql_undefined with data set #1', 'Tests_DB_Charset::test_get_column_charset_is_mysql_undefined with data set #2', 'Tests_DB_Charset::test_get_column_charset_is_mysql_undefined with data set #3', @@ -52,7 +54,7 @@ const expectedFailures = [ 'Tests_DB_Charset::test_strip_invalid_text with data set #39', 'Tests_DB_Charset::test_strip_invalid_text with data set #40', 'Tests_DB_Charset::test_strip_invalid_text with data set #41', - 'Tests_DB_dbDelta::test_spatial_indices', + 'Tests_DB_dbDelta::test_column_type_change', 'Tests_DB::test_mysqli_flush_sync', 'Tests_DB::test_query_value_contains_invalid_chars', 'Tests_DB::test_replace',