[BUG] SQLBinaryOpExpr does not parenthesize lower-precedence OR operand, producing semantically wrong SQL
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 被重新解析为完全不同的语义。
Source: alibaba/druid