This is an automated email from the ASF dual-hosted git repository.

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 1a40be57d95 Fix MySQL OR and XOR operator precedence (#40329)
1a40be57d95 is described below

commit 1a40be57d95c63383a7cce0a557951e522b8d07b
Author: Rain. <[email protected]>
AuthorDate: Thu Oct 22 21:08:03 2026 +0800

    Fix MySQL OR and XOR operator precedence (#40329)
    
    * Fix MySQL OR and XOR operator precedence
    
    MySQL's operator precedence table ranks XOR above OR (AND > XOR > OR), but 
the
    MySQL grammar listed the `expr orOperator expr` alternative ahead of
    `expr XOR expr`. ANTLR4 resolves the alternatives of a directly 
left-recursive
    rule by their order, with the earlier alternative binding tighter, so OR
    outranked XOR:
    
      1 OR 1 XOR 1  ->  (1 OR 1) XOR 1     (wrong)
      1 XOR 1 OR 1  ->  1 XOR (1 OR 1)     (wrong)
    
    Swapping the two alternatives restores the MySQL precedence:
    
      1 OR 1 XOR 1  ->  1 OR (1 XOR 1)
      1 XOR 1 OR 1  ->  (1 XOR 1) OR 1
    
    AND stays above both alternatives, so the AND/OR groupings are unchanged.
    No visitor change is needed: MySQLStatementVisitor#visitExpr discriminates 
on
    ctx.XOR() / ctx.andOperator() / ctx.orOperator(), which are mutually 
exclusive.
    
    Covered by the Parser IT case select_where_with_expr_with_xor_or.
    
    * Fix MySQL OR and XOR operator precedence
    
    MySQL evaluates `AND` tighter than `XOR`, and `XOR` tighter than `OR`.
    In ANTLR4 a directly left-recursive rule assigns precedence by the order
    of its alternatives, so `expr` had to list `XOR` before `orOperator`.
    It listed them the other way around, grouping `1 OR 1 XOR 1` as
    `(1 OR 1) XOR 1`.
    
    Apply the same reordering to the Doris grammar, which keeps its own copy
    of this shared rule. Doris documents the same precedence (`AND, &&` = 9,
    `XOR` = 10, `OR` = 11), so both dialects now match their vendors.
    
    Cover both dialects with one Parser IT case; its expected AST carries no
    `db-types`, so MySQL and Doris assert the same tree from the same SQL.
    
    Reported in #40295. Reverting either grammar alone reproduces the
    failures in the corresponding `Internal*ParserIT`.
---
 .../src/main/antlr4/imports/doris/BaseRule.g4      |  2 +-
 .../src/main/antlr4/imports/mysql/BaseRule.g4      |  2 +-
 .../main/resources/case/dml/select-expression.xml  | 62 ++++++++++++++++++++++
 .../sql/supported/dml/select-expression.xml        |  1 +
 4 files changed, 65 insertions(+), 2 deletions(-)

diff --git 
a/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/BaseRule.g4 
b/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/BaseRule.g4
index 43b4f83b849..7b6313ac1fb 100644
--- a/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/BaseRule.g4
+++ b/parser/sql/engine/dialect/doris/src/main/antlr4/imports/doris/BaseRule.g4
@@ -970,8 +970,8 @@ triggerOrder
 expr
     : booleanPrimary
     | expr andOperator expr
-    | expr orOperator expr
     | expr XOR expr
+    | expr orOperator expr
     | notOperator expr
     ;
 
diff --git 
a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4 
b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
index 1cf48417601..324023a12ac 100644
--- a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
+++ b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
@@ -392,8 +392,8 @@ triggerOrder
 expr
     : booleanPrimary
     | expr andOperator expr
-    | expr orOperator expr
     | expr XOR expr
+    | expr orOperator expr
     | notOperator expr
     ;
 
diff --git a/test/it/parser/src/main/resources/case/dml/select-expression.xml 
b/test/it/parser/src/main/resources/case/dml/select-expression.xml
index 465f75de876..de4cb82a28d 100644
--- a/test/it/parser/src/main/resources/case/dml/select-expression.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-expression.xml
@@ -1097,6 +1097,68 @@
             </expr>
         </where>
     </select>
+    <select sql-case-id="select_where_with_expr_with_xor_or" 
parameters="1,2,3">
+        <from start-index="14" stop-index="20">
+            <simple-table name="t_order" start-index="14" stop-index="20" />
+        </from>
+        <projections distinct-row="false" start-index="7" stop-index="7">
+            <shorthand-projection start-index="7" stop-index="7" />
+        </projections>
+        <where start-index="22" stop-index="96">
+            <expr>
+                <binary-operation-expression start-index="28" stop-index="96">
+                    <left>
+                        <binary-operation-expression start-index="28" 
stop-index="72">
+                            <left>
+                                <binary-operation-expression start-index="28" 
stop-index="47">
+                                    <left>
+                                        <column name="order_id" 
start-index="28" stop-index="43">
+                                            <owner name="t_order" 
start-index="28" stop-index="34" />
+                                        </column>
+                                    </left>
+                                    <operator>=</operator>
+                                    <right>
+                                        <literal-expression value="1" 
start-index="47" stop-index="47" />
+                                        <parameter-marker-expression 
parameter-index="0" start-index="47" stop-index="47" />
+                                    </right>
+                                </binary-operation-expression>
+                            </left>
+                            <operator>XOR</operator>
+                            <right>
+                                <binary-operation-expression start-index="53" 
stop-index="72">
+                                    <left>
+                                        <literal-expression value="2" 
start-index="53" stop-index="53" />
+                                        <parameter-marker-expression 
parameter-index="1" start-index="53" stop-index="53" />
+                                    </left>
+                                    <operator>=</operator>
+                                    <right>
+                                        <column name="order_id" 
start-index="57" stop-index="72">
+                                            <owner name="t_order" 
start-index="57" stop-index="63" />
+                                        </column>
+                                    </right>
+                                </binary-operation-expression>
+                            </right>
+                        </binary-operation-expression>
+                    </left>
+                    <operator>OR</operator>
+                    <right>
+                        <binary-operation-expression start-index="77" 
stop-index="96">
+                            <left>
+                                <literal-expression value="3" start-index="77" 
stop-index="77" />
+                                <parameter-marker-expression 
parameter-index="2" start-index="77" stop-index="77" />
+                            </left>
+                            <operator>=</operator>
+                            <right>
+                                <column name="order_id" start-index="81" 
stop-index="96">
+                                    <owner name="t_order" start-index="81" 
stop-index="87" />
+                                </column>
+                            </right>
+                        </binary-operation-expression>
+                    </right>
+                </binary-operation-expression>
+            </expr>
+        </where>
+    </select>
 
     <select sql-case-id="select_where_with_expr_with_and" parameters="1,2">
         <from start-index="14" stop-index="20">
diff --git 
a/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml 
b/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml
index de991a052a0..69a49cf033a 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml
@@ -58,6 +58,7 @@
     <sql-case id="select_where_with_expr_with_or_sign" value="SELECT * FROM 
t_order WHERE t_order.order_id = ? || ? = t_order.order_id" db-types="MySQL" />
     <sql-case id="select_concat_pipe_with_table" value="SELECT 'a' || 'b' FROM 
t_order" db-types="MySQL" />
     <sql-case id="select_where_with_expr_with_xor" value="SELECT * FROM 
t_order WHERE t_order.order_id = ? XOR ? = t_order.order_id" 
db-types="MySQL,Presto,Doris" />
+    <sql-case id="select_where_with_expr_with_xor_or" value="SELECT * FROM 
t_order WHERE t_order.order_id = ? XOR ? = t_order.order_id OR ? = 
t_order.order_id" db-types="MySQL,Doris" />
     <sql-case id="select_where_with_expr_with_and" value="SELECT * FROM 
t_order WHERE t_order.order_id = ? AND ? = t_order.order_id" db-types="MySQL" />
     <sql-case id="select_where_with_expr_with_and_or" value="SELECT * FROM 
t_order WHERE t_order.order_id = ? AND ? = t_order.order_id OR t_order.status = 
'failed' AND ? = t_order.order_id" />
     <sql-case id="select_where_with_expr_with_and_sign" value="SELECT * FROM 
t_order WHERE t_order.order_id = ? &amp;&amp; ? = t_order.order_id" 
db-types="MySQL" />

Reply via email to