Skip to content

Commit f53ebed

Browse files
committed
Translate MySQL BINARY operator via SQLite COLLATE BINARY
'BINARY expr' is now emitted as 'expr COLLATE BINARY', which matches MySQL's byte-by-byte comparison semantics and overrides declared column collations like NOCASE. Refs #31.
1 parent bd461a2 commit f53ebed

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

packages/mysql-on-sqlite/src/sqlite/class-wp-pdo-mysql-on-sqlite.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3924,9 +3924,9 @@ private function translate_token( WP_MySQL_Token $token ): ?string {
39243924
return 'AUTOINCREMENT';
39253925
case WP_MySQL_Lexer::BINARY_SYMBOL:
39263926
/*
3927-
* There is no "BINARY expr" equivalent in SQLite. We look for the
3928-
* keyword from a higher level to respect it in particular cases
3929-
* (REGEXP, LIKE, etc.) and then remove it from the output here.
3927+
* "BINARY expr" is translated in "translate_simple_expr_body()".
3928+
* Returning null here is a safety net for any unhandled context
3929+
* where a bare BINARY token would otherwise leak into the output.
39303930
*/
39313931
return null;
39323932
case WP_MySQL_Lexer::SQL_CALC_FOUND_ROWS_SYMBOL:
@@ -4274,6 +4274,19 @@ private function translate_simple_expr_body( WP_Parser_Node $node ): string {
42744274
);
42754275
}
42764276

4277+
/*
4278+
* Translate "BINARY expr" to "expr COLLATE BINARY".
4279+
*
4280+
* The MySQL BINARY operator enforces byte-by-byte string comparison.
4281+
* In SQLite, COLLATE BINARY is equivalent in comparison contexts.
4282+
*/
4283+
if ( null !== $token && WP_MySQL_Lexer::BINARY_SYMBOL === $token->id ) {
4284+
return sprintf(
4285+
'%s COLLATE BINARY',
4286+
$this->translate( $node->get_first_child_node( 'simpleExpr' ) )
4287+
);
4288+
}
4289+
42774290
/**
42784291
* Translate MySQL CONVERT() expression.
42794292
*

packages/mysql-on-sqlite/tests/WP_SQLite_Driver_Translation_Tests.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,44 @@ public function testConvert(): void {
136136
);
137137
}
138138

139+
public function testBinary(): void {
140+
// "BINARY expr" on the left side of comparison
141+
$this->assertQuery(
142+
'SELECT `a` COLLATE BINARY = `b` AS `BINARY a = b` FROM `t`',
143+
'SELECT BINARY a = b FROM t'
144+
);
145+
146+
// "BINARY expr" on the right side of comparison
147+
$this->assertQuery(
148+
'SELECT `a` = `b` COLLATE BINARY AS `a = BINARY b` FROM `t`',
149+
'SELECT a = BINARY b FROM t'
150+
);
151+
152+
// "BINARY literal"
153+
$this->assertQuery(
154+
"SELECT 'abc' COLLATE BINARY AS `BINARY 'abc'`",
155+
"SELECT BINARY 'abc'"
156+
);
157+
158+
// "BINARY expr" in ORDER BY
159+
$this->assertQuery(
160+
'SELECT `a` FROM `t` ORDER BY `a` COLLATE BINARY',
161+
'SELECT a FROM t ORDER BY BINARY a'
162+
);
163+
164+
// "BINARY expr" in GROUP BY
165+
$this->assertQuery(
166+
'SELECT `a` FROM `t` GROUP BY `a` COLLATE BINARY',
167+
'SELECT a FROM t GROUP BY BINARY a'
168+
);
169+
170+
// "BINARY expr" wrapping a parenthesized expression
171+
$this->assertQuery(
172+
"SELECT ( `a` || `b` ) COLLATE BINARY = 'x' AS `BINARY (a || b) = 'x'` FROM `t`",
173+
"SELECT BINARY (a || b) = 'x' FROM t"
174+
);
175+
}
176+
139177
public function testInsert(): void {
140178
$this->driver->query( 'CREATE TABLE t (c INT, c1 INT, c2 INT)' );
141179
$this->driver->query( 'CREATE TABLE t1 (c1 INT, c2 INT)' );

0 commit comments

Comments
 (0)