#6720·druid

[BUG] SQLBinaryOpExpr does not parenthesize lower-precedence OR operand, producing semantically wrong SQL

Author: 632485071-cryptoCreated Sep 16, 2026Updated Sep 16, 2026

Database Type

该问题与具体数据库方言无关,对通用 boolean 表达式输出均成立)

Database Version

复现不依赖具体数据库版本,纯 AST 序列化问题

Druid Version

1.2.23 - 1.2.28 均存在该问题

JDK Version

OpenJDK 21(同时验证 OpenJDK 8 编译运行,结果一致;该问题与 JDK 版本无关)

Error SQL

Error SQL

colA = 1 AND colB = 2 AND col1 = 1 OR col2 = 2

期望(语义正确):
colA = 1 AND colB = 2 AND (col1 = 1 OR col2 = 2)

Testcase Code

import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;

import org.junit.jupiter.api.Test;

class DruidBinaryOpExprParenBugTest {

@Test
void testAndWithOrOperandMissingParentheses() {
    // 1) Build two operands by parsing.
    SQLExpr andExpr = SQLUtils.toSQLExpr("colA = 1 and colB = 2");
    SQLExpr orExpr  = SQLUtils.toSQLExpr("col1 = 1 or col2 = 2");

    // 2) Programmatically combine them with AND:
    //    intended semantics = (colA = 1 AND colB = 2) AND (col1 = 1 OR col2 = 2)
    SQLBinaryOpExpr top =
            new SQLBinaryOpExpr(andExpr, SQLBinaryOperator.BooleanAnd, orExpr);

    // 3) Serialize and re-parse to compare semantics.
    String generated = SQLUtils.toSQLString(top);
    System.out.println("generated SQL: " + generated);

    SQLExpr reparsed = SQLUtils.toSQLExpr(generated);
    System.out.println("reparsed     : " + reparsed.toString().replaceAll("\\s+", " ").tr
}

}

Stacktrace Info

No response

Error Info

当通过构造器 new SQLBinaryOpExpr(left, SQLBinaryOperator.BooleanAnd, right) 组合两个布尔表达式,且 right 是一个 OR 表达式(SQLBinaryOperator.BooleanOr)时,序列化阶段未对低优先级的 OR 子表达式加括号。由于 SQL 中 AND 的优先级高于 OR,缺失括号会使生成的 SQL 被重新解析为完全不同的语义。