Skip to content

Commit 4268dea

Browse files
committed
Support ORDER BY disambiguation also for parenthesised column names
1 parent f872535 commit 4268dea

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

tests/WP_SQLite_Driver_Translation_Tests.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,18 @@ public function testSelectOrderByAmbiguousColumnResolution(): void {
13621362
'SELECT ta.name FROM (SELECT t2.name FROM t1 JOIN t2 ON t2.id = t1.id ORDER BY name) ta ORDER BY name'
13631363
);
13641364

1365+
// When the SELECT item is nested in a simple parentheses expression, the disambiguation still works.
1366+
$this->assertQuery(
1367+
'SELECT ( ( ( `t1`.`name` ) ) ) AS `(((t1.name)))` FROM `t1` JOIN `t2` ON `t2`.`id` = `t1`.`id` ORDER BY `t1`.`name`',
1368+
'SELECT (((t1.name))) FROM t1 JOIN t2 ON t2.id = t1.id ORDER BY name'
1369+
);
1370+
1371+
// When the SELECT item is nested in a complex expression, the column is not disambiguated (like in MySQL).
1372+
$this->assertQuery(
1373+
"SELECT (`t1`.`name` || 'test') AS `CONCAT(t1.name, 'test')` FROM `t1` JOIN `t2` ON `t2`.`id` = `t1`.`id` ORDER BY `name`",
1374+
"SELECT CONCAT(t1.name, 'test') FROM t1 JOIN t2 ON t2.id = t1.id ORDER BY name"
1375+
);
1376+
13651377
// When the SELECT list item uses an alias, the column is not disambiguated (like in MySQL).
13661378
$this->assertQuery(
13671379
'SELECT `t1`.`name` AS `t1_name` FROM `t1` JOIN `t2` ON `t2`.`id` = `t1`.`id` ORDER BY `name` DESC',

wp-includes/sqlite-ast/class-wp-sqlite-driver.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,7 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
29592959
continue;
29602960
}
29612961

2962+
$select_item_expr = $this->unnest_parenthesized_expression( $select_item_expr );
29622963
$select_column_ref = $select_item->get_first_descendant_node( 'columnRef' );
29632964
if (
29642965
$select_column_ref
@@ -3024,6 +3025,46 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
30243025
return $this->translate_sequence( $node->get_children() );
30253026
}
30263027

3028+
/**
3029+
* Unnest parenthesized MySQL expression node.
3030+
*
3031+
* In MySQL, extra parentheses around simple expressions are not considered.
3032+
*
3033+
* For example, the "SELECT (((id)))" clause is equivalent to "SELECT id".
3034+
* This means that the "(((id)))" part will behave as a column name rather
3035+
* than as an expression, and the resulting column name will be just "id".
3036+
*
3037+
* @param WP_Parser_Node $node The expression AST node.
3038+
* @return WP_Parser_Node The unnested expression.
3039+
*/
3040+
private function unnest_parenthesized_expression( WP_Parser_Node $node ): WP_Parser_Node {
3041+
$children = $node->get_children();
3042+
3043+
// Descend the "expr -> boolPri -> predicate -> bitExpr -> simpleExpr" tree,
3044+
// when on each level we have only a single child node (expression nesting).
3045+
if (
3046+
1 === count( $children )
3047+
&& $children[0] instanceof WP_Parser_Node
3048+
&& in_array( $children[0]->rule_name, array( 'expr', 'boolPri', 'predicate', 'bitExpr', 'simpleExpr' ), true )
3049+
) {
3050+
$unnested = $this->unnest_parenthesized_expression( $children[0] );
3051+
return $unnested === $children[0] ? $node : $unnested;
3052+
}
3053+
3054+
// Unnest "OPEN_PAR_SYMBOL exprList CLOSE_PAR_SYMBOL" to "exprList".
3055+
if (
3056+
count( $children ) === 3
3057+
&& $children[0] instanceof WP_MySQL_Token && WP_MySQL_Lexer::OPEN_PAR_SYMBOL === $children[0]->id
3058+
&& $children[1] instanceof WP_Parser_Node && 'exprList' === $children[1]->rule_name
3059+
&& $children[2] instanceof WP_MySQL_Token && WP_MySQL_Lexer::CLOSE_PAR_SYMBOL === $children[2]->id
3060+
&& 1 === count( $children[1]->get_children() )
3061+
) {
3062+
return $this->unnest_parenthesized_expression( $children[1] );
3063+
}
3064+
3065+
return $node;
3066+
}
3067+
30273068
/**
30283069
* Translate a MySQL simple expression to SQLite.
30293070
*

0 commit comments

Comments
 (0)