From a5ee8ddc3888681750df3342785f9c6bbb0d724a Mon Sep 17 00:00:00 2001 From: Jan Jakes Date: Wed, 17 Sep 2025 09:23:37 +0200 Subject: [PATCH] Add support for all binary and hexadecimal literal syntaxes --- tests/WP_SQLite_Driver_Tests.php | 22 ++++++++++++ tests/WP_SQLite_Driver_Translation_Tests.php | 34 +++++++++++++++++++ .../sqlite-ast/class-wp-sqlite-driver.php | 25 ++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/tests/WP_SQLite_Driver_Tests.php b/tests/WP_SQLite_Driver_Tests.php index 3a0d0a68..68ba9242 100644 --- a/tests/WP_SQLite_Driver_Tests.php +++ b/tests/WP_SQLite_Driver_Tests.php @@ -6873,4 +6873,26 @@ public function testUpdateWithJoinComplexQuery(): void { SET claim_id = 37, last_attempt_gmt = '2025-09-03 12:23:55', last_attempt_local = '2025-09-03 12:23:55'" ); } + + public function testBinaryLiterals(): void { + $result = $this->assertQuery( 'SELECT 0b0100000101111010' ); + $this->assertEquals( array( (object) array( '0b0100000101111010' => 'Az' ) ), $result ); + + $result = $this->assertQuery( "SELECT b'0100000101111010'" ); + $this->assertEquals( array( (object) array( "b'0100000101111010'" => 'Az' ) ), $result ); + + $result = $this->assertQuery( "SELECT B'0100000101111010'" ); + $this->assertEquals( array( (object) array( "B'0100000101111010'" => 'Az' ) ), $result ); + } + + public function testHexadecimalLiterals(): void { + $result = $this->assertQuery( 'SELECT 0x417a' ); + $this->assertEquals( array( (object) array( '0x417a' => 'Az' ) ), $result ); + + $result = $this->assertQuery( "SELECT x'417a'" ); + $this->assertEquals( array( (object) array( "x'417a'" => 'Az' ) ), $result ); + + $result = $this->assertQuery( "SELECT X'417a'" ); + $this->assertEquals( array( (object) array( "X'417a'" => 'Az' ) ), $result ); + } } diff --git a/tests/WP_SQLite_Driver_Translation_Tests.php b/tests/WP_SQLite_Driver_Translation_Tests.php index b249e235..07fddb8f 100644 --- a/tests/WP_SQLite_Driver_Translation_Tests.php +++ b/tests/WP_SQLite_Driver_Translation_Tests.php @@ -1328,6 +1328,40 @@ public function testSerialDataTypes(): void { ); } + public function testBinaryLiterals(): void { + // All binary literal syntaxes need to be converted to HEX strings. + $this->assertQuery( + "SELECT x'417a' AS `b'0100000101111010'`", + "SELECT b'0100000101111010'" + ); + $this->assertQuery( + "SELECT x'417a' AS `B'0100000101111010'`", + "SELECT B'0100000101111010'" + ); + $this->assertQuery( + "SELECT x'417a' AS `0b0100000101111010`", + 'SELECT 0b0100000101111010' + ); + } + + public function testHexadecimalLiterals(): void { + // The x'...' and X'...' syntax should be preserved as is. + $this->assertQuery( + "SELECT x'417a'", + "SELECT x'417a'" + ); + $this->assertQuery( + "SELECT X'417a'", + "SELECT X'417a'" + ); + + // The 0x... syntax needs to be translated to x'...'. + $this->assertQuery( + "SELECT x'417a' AS `0x417a`", + 'SELECT 0x417a' + ); + } + public function testSystemVariables(): void { $this->assertQuery( "SELECT 'ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES' AS `@@sql_mode`", diff --git a/wp-includes/sqlite-ast/class-wp-sqlite-driver.php b/wp-includes/sqlite-ast/class-wp-sqlite-driver.php index 08e2f966..2945b7e5 100644 --- a/wp-includes/sqlite-ast/class-wp-sqlite-driver.php +++ b/wp-includes/sqlite-ast/class-wp-sqlite-driver.php @@ -2860,6 +2860,31 @@ private function translate_token( WP_MySQL_Token $token ): ?string { switch ( $token->id ) { case WP_MySQL_Lexer::EOF: return null; + case WP_MySQL_Lexer::BIN_NUMBER: + /* + * There are no binary literals in SQLite. We need to convert all + * MySQL binary string values to HEX strings in SQLite (x'...'). + */ + $value = $token->get_value(); + if ( '0' === $value[0] ) { + // 0b... + $value = substr( $value, 2 ); + } else { + // b'...' or B'...' + $value = substr( $value, 2, -1 ); + } + return sprintf( "x'%s'", base_convert( $value, 2, 16 ) ); + case WP_MySQL_Lexer::HEX_NUMBER: + /* + * In MySQL, "0x" prefixed values represent binary literal values, + * while in SQLite, that would be a hexadecimal number. Therefore, + * we need to convert the 0x... syntax to x'...'. + */ + $value = $token->get_value(); + if ( '0' === $value[0] && 'x' === $value[1] ) { + return sprintf( "x'%s'", substr( $value, 2 ) ); + } + return $value; case WP_MySQL_Lexer::AUTO_INCREMENT_SYMBOL: return 'AUTOINCREMENT'; case WP_MySQL_Lexer::BINARY_SYMBOL: