Skip to content

Commit 0e90582

Browse files
committed
Improve readability and docs
1 parent a229fb2 commit 0e90582

File tree

2 files changed

+51
-14
lines changed

2 files changed

+51
-14
lines changed

tests/WP_SQLite_Driver_Translation_Tests.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,12 @@ public function testSelectOrderByAmbiguousColumnResolution(): void {
13801380
'SELECT t1.name AS t1_name FROM t1 JOIN t2 ON t2.id = t1.id ORDER BY name DESC'
13811381
);
13821382

1383+
// When the SELECT item list is ambiguous, the ORDER BY column is not disambiguated (like in MySQL).
1384+
$this->assertQuery(
1385+
'SELECT `t1`.`name` , `t2`.`name` FROM `t1` JOIN `t2` ON `t2`.`id` = `t1`.`id` ORDER BY `name` DESC',
1386+
'SELECT t1.name, t2.name FROM t1 JOIN t2 ON t2.id = t1.id ORDER BY name DESC'
1387+
);
1388+
13831389
// When the ORDER BY item uses an alias, there is no ambiguity.
13841390
$this->assertQuery(
13851391
'SELECT `t1`.`name` AS `t1_name` FROM `t1` JOIN `t2` ON `t2`.`t1_id` = `t1`.`id` ORDER BY `t1_name` DESC',

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

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2949,44 +2949,73 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
29492949
// Get a list of column references used in the SELECT item list.
29502950
$select_column_refs = array();
29512951
foreach ( $select_item_list->get_child_nodes() as $select_item ) {
2952-
// When the SELECT item uses an alias, the column is not disambiguated.
2952+
/*
2953+
* [GRAMMAR]
2954+
* selectItem: tableWild | (expr selectAlias?)
2955+
*/
2956+
2957+
// Skip when a "tableWild" node is used (no "expr" node).
2958+
$select_item_expr = $select_item->get_first_child_node( 'expr' );
2959+
if ( ! $select_item_expr ) {
2960+
continue;
2961+
}
2962+
2963+
// Skip when a SELECT item alias is used (as per MySQL behavior).
29532964
if ( $select_item->has_child_node( 'selectAlias' ) ) {
29542965
continue;
29552966
}
29562967

2957-
$select_item_expr = $select_item->get_first_child_node( 'expr' );
2958-
if ( ! $select_item_expr ) {
2968+
// Skip when there is no column listed (no "columnRef" node).
2969+
$select_column_ref = $select_item_expr->get_first_descendant_node( 'columnRef' );
2970+
if ( ! $select_column_ref ) {
29592971
continue;
29602972
}
29612973

2962-
$select_item_expr = $this->unnest_parenthesized_expression( $select_item_expr );
2963-
$select_column_ref = $select_item->get_first_descendant_node( 'columnRef' );
2964-
if (
2965-
$select_column_ref
2966-
&& $this->translate( $select_item_expr ) === $this->translate( $select_column_ref )
2967-
) {
2974+
// Support also parenthesized column references (e.g. "(t.id)").
2975+
$select_item_expr = $this->unnest_parenthesized_expression( $select_item_expr );
2976+
2977+
// Consider only simple and parenthesized column references.
2978+
$expr_value = $this->translate( $select_item_expr );
2979+
$column_value = $this->translate( $select_column_ref );
2980+
if ( $expr_value === $column_value ) {
29682981
$select_column_refs[] = $select_column_ref;
29692982
}
29702983
}
29712984

29722985
// For each ORDER BY item, try to find a corresponding SELECT item.
29732986
foreach ( $order_list->get_child_nodes() as $order_item ) {
2987+
/*
2988+
* [GRAMMAR]
2989+
* orderExpression: expr direction?
2990+
*/
29742991
$order_expr = $order_item->get_first_child_node( 'expr' );
29752992
$order_column_ref = $order_expr->get_first_descendant_node( 'columnRef' );
29762993

2977-
$select_item_matches = array();
2994+
// Skip when there is no column in the ORDER BY item (no "columnRef"
2995+
// node), or when the item is qualified (has a "dotIdentifier" node).
29782996
if (
2979-
$order_column_ref
2980-
&& $this->translate( $order_column_ref ) === $this->translate( $order_expr )
2981-
&& null === $order_column_ref->get_first_descendant_node( 'dotIdentifier' )
2997+
! $order_column_ref
2998+
|| null !== $order_column_ref->get_first_descendant_node( 'dotIdentifier' )
29822999
) {
2983-
// Look for select items that match the column reference.
3000+
$disambiguated_order_list[] = $this->translate( $order_item );
3001+
continue;
3002+
}
3003+
3004+
// Consider only simple and parenthesized column references.
3005+
$order_expr_value = $this->translate( $order_expr );
3006+
$order_column_value = $this->translate( $order_column_ref );
3007+
3008+
// Look for select items that match the column reference.
3009+
$select_item_matches = array();
3010+
if ( $order_expr_value === $order_column_value ) {
29843011
foreach ( $select_column_refs as $select_column_ref ) {
3012+
// Skip non-qualified column references in the SELECT item.
29853013
$dot_identifiers = $select_column_ref->get_descendant_nodes( 'dotIdentifier' );
29863014
if ( count( $dot_identifiers ) === 0 ) {
29873015
continue;
29883016
}
29893017

3018+
// Compare only the column names (last "dotIdentifier" node).
29903019
$last_dot_identifier = end( $dot_identifiers );
29913020
$select_column_name = $this->translate( $last_dot_identifier->get_first_child_node() );
29923021
$order_column_name = $this->translate( $order_column_ref );
@@ -2996,6 +3025,8 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
29963025
}
29973026
}
29983027

3028+
// When we find exactly one SELECT item, we can disambiguate the
3029+
// reference. Otherwise, fall back to the original ORDER BY item.
29993030
if ( 1 === count( $select_item_matches ) ) {
30003031
$direction = $order_item->get_first_child_node( 'direction' );
30013032
$translated_order_item = sprintf(

0 commit comments

Comments
 (0)