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