From 0f93b3d4611347db4e31241a0f7d82db048bf8e5 Mon Sep 17 00:00:00 2001 From: x-rush <78290977+x-rush@users.noreply.github.com> Date: Fri, 6 Nov 2026 02:31:16 +0800 Subject: [PATCH 1/2] Translate empty bit-value literals to an empty blob literal base_convert( '', 2, 16 ) returns '0', so the empty bit-value literal b'' was translated to the odd-length blob literal x'0', which SQLite rejects with "unrecognized token". MySQL accepts b'' and returns an empty string, like it does for the empty hex literal x''. Translate zero digits to an empty blob literal, x''. Fixes #612. --- .../src/sqlite/class-wp-mysql-on-sqlite.php | 5 ++-- .../tests/WP_MySQL_On_SQLite_Tests.php | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 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 bef1bedeb..42c9cb7ea 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 @@ -4579,8 +4579,9 @@ private function translate_token( WP_MySQL_Token $token ): ?string { $value = substr( $value, 2, -1 ); } - // Convert the binary string to HEX. - $hex = base_convert( $value, 2, 16 ); + // Convert the binary string to HEX. An empty value stays empty, + // as "base_convert()" would return "0" for it. + $hex = '' === $value ? '' : base_convert( $value, 2, 16 ); /* * The "base_convert()" function doesn't add or preserve padding. 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 4f87a3a6f..605393203 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 @@ -11997,6 +11997,31 @@ public static function oddLengthQuotedHexadecimalLiterals(): array { ); } + public function testEmptyBitLiteral(): void { + // An empty bit-value literal is an empty binary string, like an empty + // hex literal, and not the one-byte value "x'0'". See #612. + $this->assertEquals( + $this->assertQuery( "SELECT x'' AS v" ), + $this->assertQuery( "SELECT b'' AS v" ) + ); + $this->assertEquals( + array( (object) array( 'length' => '0' ) ), + $this->assertQuery( "SELECT LENGTH(b'') AS length" ) + ); + + $this->assertQuery( 'CREATE TABLE t (id INT PRIMARY KEY, data BLOB)' ); + $this->assertQuery( "INSERT INTO t (id, data) VALUES (1, b'')" ); + $this->assertEquals( + array( + (object) array( + 'id' => '1', + 'data' => '', + ), + ), + $this->assertQuery( 'SELECT id, HEX(data) AS data FROM t' ) + ); + } + public function testColumnInfo(): void { $this->assertQuery( 'CREATE TABLE t ( From d76edd1cdbeb9bfba70ecc362c3ae36ba824424f Mon Sep 17 00:00:00 2001 From: x-rush <78290977+x-rush@users.noreply.github.com> Date: Fri, 6 Nov 2026 08:03:48 +0800 Subject: [PATCH 2/2] Document the empty bit literal comparison semantics Hex and bit literals translate to blob literals, and a blob never equals a text value in SQLite, so "b'' = ''" returns false where MySQL returns true. The empty hex literal "x'' = ''" already behaves the same way on trunk, a difference tracked in #575. The empty bit literal now consistently behaves like the empty hex literal in both directions, and a test locks that in. --- .../tests/WP_MySQL_On_SQLite_Tests.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 605393203..7e6047064 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 @@ -12022,6 +12022,23 @@ public function testEmptyBitLiteral(): void { ); } + public function testEmptyBitLiteralComparesLikeEmptyHexLiteral(): void { + // Hex and bit literals translate to blob literals, and a blob never + // equals a text value in SQLite. MySQL compares the empty binary + // string equal to the empty text string, a difference tracked for + // hex literals in #575. The empty bit literal behaves like the empty + // hex literal, in both directions. + $this->assertEquals( + $this->assertQuery( "SELECT x'' = '' AS v" ), + $this->assertQuery( "SELECT b'' = '' AS v" ) + ); + + $this->assertEquals( + array( (object) array( 'v' => '1' ) ), + $this->assertQuery( "SELECT b'' = x'' AS v" ) + ); + } + public function testColumnInfo(): void { $this->assertQuery( 'CREATE TABLE t (