Функция не найдена при генерации кода с использованием базы данных DDL — jooq

#spring-boot #h2 #jooq

#spring-boot #h2 #jooq

Вопрос:

У меня есть проект spring boot gradle с базой данных mysql. Ранее в версии jooq 3.13.6 мой sql анализировался без ошибок. При обновлении до более высокой версии jooq (3.14.X и 3.15.X) и генерации / анализе миграций с помощью jooq я получаю следующий результат:

СЕРЬЕЗНАЯ ошибка базы данных DDLD: ваша строка SQL не может быть проанализирована или интерпретирована. Это может иметь множество причин, в том числе:

  • Анализатор jOOQ не понимает ваш SQL
  • Логика моделирования jOOQ DDL (перевод в H2) не может имитировать ваш SQL

org.h2.jdbc.JdbcSQLSyntaxErrorException: функция «coalesce» не найдена;

Ниже приведен базовый пример sql, в котором возникает ошибка. Синтаксический анализ того же представления работал с jooq 3.13.6.

 DROP VIEW IF EXISTS view1;
CREATE VIEW view1 AS
SELECT COALESCE(SUM(table1.col1), 0)   AS 'sum'
FROM table1;
 

В настоящее время я здесь потерян. Я не вижу никаких связанных изменений в журнале изменений jooq.

Любая помощь или указания для дальнейшего изучения приветствуются.

Расширенная трассировка стека:

 11:10:30 SEVERE DDLDatabase Error        : Your SQL string could not be parsed or interpreted. This may have a variety of reasons, including:
- The jOOQ parser doesn't understand your SQL
- The jOOQ DDL simulation logic (translating to H2) cannot simulate your SQL

If you think this is a bug or a feature worth requesting, please report it here: https://github.com/jOOQ/jOOQ/issues/new/choose

As a workaround, you can use the Settings.parseIgnoreComments syntax documented here:
https://www.jooq.org/doc/latest/manual/sql-building/dsl-context/custom-settings/settings-parser/
11:10:30 SEVERE Error while loading file: /Users/axel/projects/service/./src/main/resources/db/migration/V5__create_view1.sql
11:10:30 SEVERE Error in file: /Users/axel/projects/service/build/tmp/generateJooq/config.xml. Error : Error while exporting schema
org.jooq.exception.DataAccessException: Error while exporting schema
        at org.jooq.meta.extensions.AbstractInterpretingDatabase.connection(AbstractInterpretingDatabase.java:103)
        at org.jooq.meta.extensions.AbstractInterpretingDatabase.create0(AbstractInterpretingDatabase.java:77)
        at org.jooq.meta.AbstractDatabase.create(AbstractDatabase.java:332)
        at org.jooq.meta.AbstractDatabase.create(AbstractDatabase.java:322)
        at org.jooq.meta.AbstractDatabase.setConnection(AbstractDatabase.java:312)
        at org.jooq.codegen.GenerationTool.run0(GenerationTool.java:531)
        at org.jooq.codegen.GenerationTool.run(GenerationTool.java:237)
        at org.jooq.codegen.GenerationTool.generate(GenerationTool.java:232)
        at org.jooq.codegen.GenerationTool.main(GenerationTool.java:204)
Caused by: org.jooq.exception.DataAccessException: SQL [create view "view1" as select "coalesce"("sum"("table1"."col1"), 0) "sum" from "table1"]; Function "coalesce" not found; SQL statement:
create view "view1" as select "coalesce"("sum"("table1"."col1"), 0) "sum" from "table1" [90022-200]
        at org.jooq_3.15.5.H2.debug(Unknown Source)
        at org.jooq.impl.Tools.translate(Tools.java:2988)
        at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:639)
        at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:349)
        at org.jooq.meta.extensions.ddl.DDLDatabase.load(DDLDatabase.java:183)
        at org.jooq.meta.extensions.ddl.DDLDatabase.lambda$export$0(DDLDatabase.java:156)
        at org.jooq.FilePattern.load0(FilePattern.java:307)
        at org.jooq.FilePattern.load(FilePattern.java:287)
        at org.jooq.FilePattern.load(FilePattern.java:300)
        at org.jooq.FilePattern.load(FilePattern.java:251)
        at org.jooq.meta.extensions.ddl.DDLDatabase.export(DDLDatabase.java:156)
        at org.jooq.meta.extensions.AbstractInterpretingDatabase.connection(AbstractInterpretingDatabase.java:100)
        ... 8 more

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "coalesce" not found; SQL statement:
create view "view1" as select "coalesce"("sum"("table1"."col1"), 0) "sum" from "table1" [90022-200]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
        at org.h2.message.DbException.get(DbException.java:205)
        at org.h2.message.DbException.get(DbException.java:181)
        at org.h2.command.Parser.readJavaFunction(Parser.java:3565)
        at org.h2.command.Parser.readFunction(Parser.java:3770)
        at org.h2.command.Parser.readTerm(Parser.java:4305)
        at org.h2.command.Parser.readFactor(Parser.java:3343)
        at org.h2.command.Parser.readSum(Parser.java:3330)
        at org.h2.command.Parser.readConcat(Parser.java:3305)
        at org.h2.command.Parser.readCondition(Parser.java:3108)
        at org.h2.command.Parser.readExpression(Parser.java:3059)
        at org.h2.command.Parser.readFunctionParameters(Parser.java:3778)
        at org.h2.command.Parser.readFunction(Parser.java:3772)
        at org.h2.command.Parser.readTerm(Parser.java:4305)
        at org.h2.command.Parser.readFactor(Parser.java:3343)
        at org.h2.command.Parser.readSum(Parser.java:3330)
        at org.h2.command.Parser.readConcat(Parser.java:3305)
        at org.h2.command.Parser.readCondition(Parser.java:3108)
        at org.h2.command.Parser.readExpression(Parser.java:3059)
        at org.h2.command.Parser.parseSelectExpressions(Parser.java:2931)
        at org.h2.command.Parser.parseSelect(Parser.java:2952)
        at org.h2.command.Parser.parseQuerySub(Parser.java:2817)
        at org.h2.command.Parser.parseSelectUnion(Parser.java:2649)
        at org.h2.command.Parser.parseQuery(Parser.java:2620)
        at org.h2.command.Parser.parseCreateView(Parser.java:6950)
        at org.h2.command.Parser.parseCreate(Parser.java:6223)
        at org.h2.command.Parser.parsePrepared(Parser.java:903)
        at org.h2.command.Parser.parse(Parser.java:843)
        at org.h2.command.Parser.parse(Parser.java:815)
        at org.h2.command.Parser.prepareCommand(Parser.java:738)
        at org.h2.engine.Session.prepareLocal(Session.java:657)
        at org.h2.engine.Session.prepareCommand(Session.java:595)
        at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235)
        at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:212)
        at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201)
        at org.jooq.tools.jdbc.DefaultStatement.execute(DefaultStatement.java:102)
        at org.jooq.impl.SettingsEnabledPreparedStatement.execute(SettingsEnabledPreparedStatement.java:227)
        at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:414)
        at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:335)
        ... 16 more


> Task :generateJooq FAILED
 

Конфигурация Jooq:

 jooq {
version = "3.15.5"
edition = JooqEdition.OSS
configurations {
    main {
        generationTool {
            generator {
                name = 'org.jooq.codegen.KotlinGenerator'
                strategy {
                    name = 'org.jooq.codegen.DefaultGeneratorStrategy'
                }
                generate {
                    relations = true
                    deprecated = false
                    records = true
                    immutablePojos = true
                    fluentSetters = true
                    daos = false
                    pojosEqualsAndHashCode = true
                    javaTimeTypes = true
                }
                target {
                    packageName = 'de.project.service.jooq'
                }
                database {
                    name = 'org.jooq.meta.extensions.ddl.DDLDatabase'
                    properties {
                        property {
                            key = 'scripts'
                            value = 'src/main/resources/db/migration/*.sql'
                        }
                        property {
                            key = 'sort'
                            value = 'semantic'
                        }
                        property {
                            key = 'unqualifiedSchema'
                            value = 'none'
                        }
                        property {
                            key = 'defaultNameCase'
                            value = 'lower'
                        }
                    }
                }
            }
        }
    }
}
 

Комментарии:

1. Можете ли вы попробовать добавить — [jooq ignore start] перед отображением и — [jooq ignore stop] после?

2. Спасибо за комментарий. Игнорирование представления помогает избежать ошибки. Тем не менее, я надеялся на решение, которое может справиться с sql из представления. В конце концов, это работало с предыдущей версией jooq.

3. Какова полная конфигурация трассировки стека и генерации кода?

4. Я обновил вопрос и добавил stacktrace и конфигурацию после обновления до версии jooq 3.15.5

5. Спасибо за обновление. Для полноты картины не могли бы вы добавить материал, который вы пропустили, где многоточие ( ... ) . Это coalesce или "coalesce" ? Если последнее, это может быть случай github.com/jOOQ/jOOQ/issues/11342

Ответ №1:

Вероятно, у вас установлена следующая конфигурация:

 <property>
    <key>defaultNameCase</key>
    <value>lower</value>
</property>
 

В jOOQ 3.15 это преобразует все идентификаторы в нижний регистр и заключает их в кавычки перед передачей инструкции SQL в H2 за кулисами для моделирования DDL, чтобы эмулировать, например, поведение PostgreSQL, где идентификаторы без кавычек имеют нижний регистр, а не верхний регистр, как во многих других СУБД.

В текущей реализации есть ошибка, которая также цитирует встроенные функции, а не только пользовательские объекты. См.:

Единственным обходным путем, который я могу придумать, было бы снова отключить это свойство и вручную указать все идентификаторы в нижнем регистре. В качестве альтернативы, вместо использования DDLDatabase , вы всегда можете подключиться к реальной базе данных, например, с помощью testcontainers . Во всяком случае, это будет намного надежнее во многих отношениях, чем DDLDatabase

В любом случае, это довольно частая проблема, поэтому я исправил это для предстоящего jOOQ 3.16. Вышеуказанный параметр больше не будет указывать «системные имена», которые являются хорошо известными идентификаторами встроенных функций