alibaba / druid

阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池
https://github.com/alibaba/druid/wiki
Apache License 2.0
27.88k stars 8.57k forks source link

[BUG] 特殊join语法解析多个连接条件出错 #6061

Open Icarus124 opened 1 month ago

Icarus124 commented 1 month ago

Database Type

MySQL

Database Version

MySQL 5.7

Druid Version

1.2.23

JDK Version

jdk8

Error SQL

select t1.id,t3.num23 from t1 left join t2 right join t3 on t2.id = t3.id on t1.id = t2.id;

Testcase Code

    String sql = "select t1.id,t3.num23 from t1 left join t2 right join t3 on t2.id = t3.id on t1.id = t2.id;";
    MySqlStatementParser parser = new MySqlStatementParser(sql);
    SQLStatement statement = parser.parseStatement();
    System.out.println(SQLUtils.toMySqlString(statement));

Stacktrace Info

打印结果: SELECT t1.id, t3.num23 FROM t1 LEFT JOIN t2 RIGHT JOIN t3 ON t2.id = t3.id AND t1.id = t2.id

Error Info

连接条件里的on t2.id = t3.id on t1.id = t2.id的第二个on被换成了and,解析完statement转回sql发到mysql里会报语法错误

Icarus124 commented 1 month ago

问题根因是在SQLSelectParser.java中的protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource)方法里

if (lexer.token == Token.ON) {
                lexer.nextToken();
                SQLExpr joinOn = expr();
                join.setCondition(joinOn);

                while (lexer.token == Token.ON
                        && dbType == DbType.mysql) {
                    lexer.nextToken();

                    SQLExpr joinOn2 = expr();
                    join.addCondition(joinOn2);
                }

这里循环解析所有的on连接条件,用addCondition串起来所有的连接条件:

    public void addCondition(SQLExpr condition) {
        if (this.condition == null) {
            this.condition = condition;
            setImplicitJoinToCross();
            return;
        }

        this.condition = SQLBinaryOpExpr.and(this.condition, condition);
    }

这里是用的AND连接的条件,是不是考虑换成ON来连接?暂时没有想到更好的做法