Skip to content

Commit 5093169

Browse files
committed
Correctly consider aliases when disambiguating ORDER BY columns
1 parent fc016f7 commit 5093169

File tree

2 files changed

+30
-17
lines changed

2 files changed

+30
-17
lines changed

tests/WP_SQLite_Driver_Translation_Tests.php

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

1401+
// When the SELECT item list is ambiguous with an alias, the ORDER BY column is not disambiguated (like in MySQL).
1402+
$this->assertQuery(
1403+
"SELECT `t1`.`name` , 'test' AS `name` FROM `t1` JOIN `t2` ON `t2`.`id` = `t1`.`id` ORDER BY `name` DESC",
1404+
"SELECT t1.name, 'test' AS `name` FROM t1 JOIN t2 ON t2.id = t1.id ORDER BY name DESC"
1405+
);
1406+
14011407
// When the ORDER BY item uses an alias, there is no ambiguity.
14021408
$this->assertQuery(
14031409
'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: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2947,7 +2947,8 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
29472947
$select_item_list = $node->get_first_descendant_node( 'selectItemList' );
29482948

29492949
// Get a list of column references used in the SELECT item list.
2950-
$select_column_refs = array();
2950+
$select_column_refs = array();
2951+
$select_alias_values = array();
29512952
foreach ( $select_item_list->get_child_nodes() as $select_item ) {
29522953
/*
29532954
* [GRAMMAR]
@@ -2961,7 +2962,9 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
29612962
}
29622963

29632964
// Skip when a SELECT item alias is used (as per MySQL behavior).
2964-
if ( $select_item->has_child_node( 'selectAlias' ) ) {
2965+
$alias = $select_item->get_first_child_node( 'selectAlias' );
2966+
if ( $alias ) {
2967+
$select_alias_values[] = $this->translate( $alias->get_first_child_node() );
29652968
continue;
29662969
}
29672970

@@ -3004,27 +3007,31 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
30043007
// Support also parenthesized ORDER BY column references (e.g. "(id)").
30053008
$order_expr = $this->unnest_parenthesized_expression( $order_expr );
30063009

3007-
// Consider only simple and parenthesized column references.
3010+
// Consider only simple and parenthesized order column references;
3011+
// skip when the ORDER BY item value matches a SELECT item alias.
30083012
$order_expr_value = $this->translate( $order_expr );
30093013
$order_column_value = $this->translate( $order_column_ref );
3014+
$matches_alias = in_array( $order_expr_value, $select_alias_values, true );
3015+
if ( $order_expr_value !== $order_column_value || $matches_alias ) {
3016+
$disambiguated_order_list[] = $this->translate( $order_item );
3017+
continue;
3018+
}
30103019

30113020
// Look for select items that match the column reference.
30123021
$select_item_matches = array();
3013-
if ( $order_expr_value === $order_column_value ) {
3014-
foreach ( $select_column_refs as $select_column_ref ) {
3015-
// Skip non-qualified column references in the SELECT item.
3016-
$dot_identifiers = $select_column_ref->get_descendant_nodes( 'dotIdentifier' );
3017-
if ( count( $dot_identifiers ) === 0 ) {
3018-
continue;
3019-
}
3022+
foreach ( $select_column_refs as $select_column_ref ) {
3023+
// Skip non-qualified column references in the SELECT item.
3024+
$dot_identifiers = $select_column_ref->get_descendant_nodes( 'dotIdentifier' );
3025+
if ( count( $dot_identifiers ) === 0 ) {
3026+
continue;
3027+
}
30203028

3021-
// Compare only the column names (last "dotIdentifier" node).
3022-
$last_dot_identifier = end( $dot_identifiers );
3023-
$select_column_name = $this->translate( $last_dot_identifier->get_first_child_node() );
3024-
$order_column_name = $this->translate( $order_column_ref );
3025-
if ( $select_column_name === $order_column_name ) {
3026-
$select_item_matches[] = $this->translate( $select_column_ref );
3027-
}
3029+
// Compare only the column names (last "dotIdentifier" node).
3030+
$last_dot_identifier = end( $dot_identifiers );
3031+
$select_column_name = $this->translate( $last_dot_identifier->get_first_child_node() );
3032+
$order_column_name = $this->translate( $order_column_ref );
3033+
if ( $select_column_name === $order_column_name ) {
3034+
$select_item_matches[] = $this->translate( $select_column_ref );
30283035
}
30293036
}
30303037

0 commit comments

Comments
 (0)