SQL解析器监听器
适用于 ❌ 开源版 ✅ Express 版 ✅ 专业版 ✅ 企业版
为了实现自定义的解析器行为,可以为你的 Configuration 提供一组自定义的 org.jooq.ParseListener 实现。
当前的 SPI 提供了 3 种类型的语法元素解析的钩子(另请参阅 解析器语法)
-
term用于解析org.jooq.Field表达式 -
predicate用于解析org.jooq.Condition表达式 -
tableFactor用于解析org.jooq.Table表达式
以及这两个生命周期事件
- 解析调用开始之前
- 解析调用结束之后
这个想法是,你提供给解析器的任何监听器实现都可以解析函数、顶级优先级运算符等,而无需处理所有较低级别的优先级运算符,例如 AND、OR、NOT、+、- 等。
例如,假设你想添加对逻辑 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));
反馈
你对此页面有任何反馈吗? 我们很乐意听到!