可用版本:Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15

SQL解析器监听器

适用于 ❌ 开源版   ✅ Express 版   ✅ 专业版   ✅ 企业版

为了实现自定义的解析器行为,可以为你的 Configuration 提供一组自定义的 org.jooq.ParseListener 实现。

当前的 SPI 提供了 3 种类型的语法元素解析的钩子(另请参阅 解析器语法

以及这两个生命周期事件

  • 解析调用开始之前
  • 解析调用结束之后

这个想法是,你提供给解析器的任何监听器实现都可以解析函数、顶级优先级运算符等,而无需处理所有较低级别的优先级运算符,例如 ANDORNOT+- 等。

例如,假设你想添加对逻辑 LOGICAL_XOR 运算符作为函数的支持

Query query = configuration
    .derive(ParseListener.onParseCondition(ctx -> {
        if (ctx.parseFunctionNameIf("LOGICAL_XOR")) {
            ctx.parse('(');
            Condition c1 = ctx.parseCondition();
            ctx.parse(',');
            Condition c2 = ctx.parseCondition();
            ctx.parse(')');

            return c1.andNot(c2).or(c2.andNot(c1));
        }

        // Let the parser take over if we don't know the token
        return null;
    })
    .dsl()
    .parser()
    .parseQuery("select * from t where logical_xor(t.a = 1, t.b = 2)");

以上只是将便利函数 LOGICAL_XOR(c1, c2) 转换为其正式定义 c1 AND NOT c2 OR c2 AND NOT c1。 但是我们可以做得更好。 如果某种方言具有原生 XOR 支持,为什么不支持它呢?

Query query = configuration
    .derive(ParseListener.onParseCondition(ctx -> {
        if (ctx.parseFunctionNameIf("LOGICAL_XOR")) {
            ctx.parse('(');
            Condition c1 = ctx.parseCondition();
            ctx.parse(',');
            Condition c2 = ctx.parseCondition();
            ctx.parse(')');

            return CustomCondition.of(c -> {
                switch (c.family()) {
                    case MARIADB:
                    case MYSQL:
                        c.visit(condition("{0} xor {1}", c1, c2));
                        break;
                    default:
                        c.visit(c1.andNot(c2).or(c2.andNot(c1)));
                        break;
                }
            });
        }

        // Let the parser take over if we don't know the token
        return null;
    }))
    .dsl()
    .parser()
    .parseQuery("select * from t where logical_xor(t.a = 1, t.b = 2)");

System.out.println(DSL.using(SQLDialect.MYSQL).render(query));
System.out.println(DSL.using(SQLDialect.ORACLE).render(query));

上面的输出现在是

-- MYSQL:
select * from t where (t.a = 1 xor t.b = 2);

-- ORACLE:
select * from t where (t.a = 1 and not (t.b = 2)) or (t.b = 2 and not (t.a = 1));

这样,通过适度的努力,你可以解析和/或翻译任意 列表达式表表达式条件表达式,这些是 jOOQ 本身不支持的,或者覆盖此区域中解析器的默认行为。

反馈

你对此页面有任何反馈吗? 我们很乐意听到!

The jOOQ Logo