我最近在使用jOOQ解析包含Oracle DUAL表的SQL查询时遇到了一个解析问题. 下面是查询的简化版本,它再现了问题:

private Pair<String, String> getPerEchDate(Connection dbConn) throws Exception {
        String query="select  'dtPrEch' as lib , to_char(add_months(sysdate,12),'dd/mm/yyyy') as val from dual tab";
        Pair<String, String> rtn =null;
        try (final PreparedStatement pStmt = dbConn.prepareStatement(query); ResultSet rs= pStmt.executeQuery()) {
            while(rs.next()){
                rtn= Pair.of(rs.getString(1), rs.getString(2));
            }
            return rtn;
        } catch (SQLException | ParserException e1) {
            throw new Exception(e1);
        }
    }

jOOQ Settings:

private Settings createSettings() {
        Settings settings = new Settings()
                .withParseDialect(SQLDialect.ORACLE)
                .withParseUnknownFunctions(ParseUnknownFunctions.IGNORE)
                .withTransformTableListsToAnsiJoin(true) // transform (+) to left outer join
                .withTransformUnneededArithmeticExpressions(TransformUnneededArithmeticExpressions.ALWAYS)
                .withTransformRownum(Transformation.ALWAYS)
                .withParamType(ParamType.INLINED)
                .withParamCastMode(ParamCastMode.DEFAULT)
                .withRenderOptionalAsKeywordForFieldAliases(RenderOptionalKeyword.ON)
                .withRenderOptionalAsKeywordForTableAliases(RenderOptionalKeyword.ON)
                .withRenderQuotedNames(RenderQuotedNames.EXPLICIT_DEFAULT_UNQUOTED)
                .withRenderNameCase(RenderNameCase.UPPER)
                // Oracle reads empty strings as NULLs, while PostgreSQL treats them as empty.
                // Concatenating NULL values with non-NULL characters results in that character in Oracle, but NULL in PostgreSQL.
                // So this parameter whenever there's a concat it applies coalesce(x ,'')
                .withRenderCoalesceToEmptyStringInConcat(true);
        return settings;
    }

为了提供更多的上下文,以下是我使用的相关jOOQ设置:

  1. Database Configuration:
    Database source dialect: Oracle
    Destination dialect: PostgreSQL
  2. jOOQ version:3.19.6.
  3. jOOQ edition:开源

有趣的是,当忽略DUAL表的别名时,查询工作得非常好.但是,一旦一个别名,如tab添加到DUAL,解析失败,导致错误relation "dual" does not exist.

我期望jOOQ能够成功地解析查询(Oracle方言)并生成相应的jOOQ表示(PostgreSQL).但是,我遇到了一个与DUAL表别名相关的解析错误.我试着调整查询并删除别名,在这些情况下,jOOQ能够毫无问题地解析查询.

我正在寻求关于为什么jOOQ难以用别名解析DUAL以及如何解决或解决这个问题的建议或见解.任何帮助、解决方案或建议将不胜感激.谢谢

推荐答案

从jOOQ 3.19开始,jOOQ解析器目前只识别单个、无别名的DUAL个表,例如:

SELECT 1 FROM dual

它不识别别名的DUAL个表或JOIN个表达式中的DUAL个表,或表列表,例如.

SELECT 1 FROM dual a;
SELECT 1 FROM dual, dual;

我创建了一个问题来解决这个问题:

如果使用解析器API,

如果你直接使用the Parser API,你可以通过Query Object Model (QOM) API对解析过的Select对象进行后处理来解决这个问题.

// There are various ways to do this:
Query query = parser.parseQuery(sql);
if (query instanceof Select<?> s && s.$from().stream().anyMatch(...)) {
    query = ...;
}

Workaround if using the ParsingConnection

如果您使用的是ParsingConnection,给出您的问题中的示例,那么您可能可以实现ParseListener,它拦截所有表的解析.以这种方式从查询中删除DUAL表并不容易,但至少可以将其转换为等价的表,如(SELECT 'X' DUMMY) AS DUAL

DSLContext ctx = DSL.using(connection);
Configuration configuration = ctx.configuration();

configuration.set(ParseListener.onParseTable(c -> {
    if (c.parseKeywordIf("DUAL"))
        return select(DSL.inline("DUMMY").as("X")).asTable("DUAL");

    return null;
}));

try (Connection c = ctx.parsingConnection();
    Statement s = c.createStatement();
    ResultSet rs = s.executeQuery("select 1 from dual t, dual")
) {
    while (rs.next())
        System.out.println(rs.getString(1));
}

从日志(log)中可以看到:

Translating from : select 1 from dual t, dual                
Translating to   : select 1 from (select 'DUMMY' "X") t, (select 'DUMMY' "X") "DUAL"

Java相关问答推荐

使用标记时,场景大纲不在多个线程上运行

所有 case 一起输入时输出错误,而单独放置时输出正确

Java 21虚拟线程执行器的性能比池化操作系统线程的执行器差?

在运行MVN测试时,为什么构建失败,并显示了java.lang.ClassNotFoundException:java.net.http.HttpResponse?

Java编译器抛出可能未正确初始化的错误?

如何正确创建序列图?

与不同顺序的组进行匹配,不重复组但分开

我如何知道MediaDiscoverer何时完成发现介质?

@Rollback @ Transmission在验收测试中不工作

Java Telnet客户端重复的IAC符号

对从Spring Boot 3.1.5升级到3.2.0的方法的查询验证失败

在一行中检索字符分隔字符串的第n个值

基于Java中mm/dd/yy格式的最近日期对数组列表进行排序

JPA无手术同品种器械可能吗?

无法在IntStream上应用Collectors.groupingBy

在Java中比较同一多维数组的两个不同的字符串元素

从字节数组切换到JakartaMail org.springframework.mail.javamail.JavaMailSender InputStreamResource

Java方法参数:括号中的类型声明?

带有提取器的JavaFXObservableList会根据侦听器的存在而改变行为

ANTLR 接受特殊字符,例如 .标识符或表达式中的(点)和 ,(逗号)