@@ -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