Исключение в JPA при использовании начального файла для PostgreSQL - PullRequest
0 голосов
/ 07 сентября 2018

Я использую Spring Boot 2 с JPA, и я оставляю его в Hibernate для создания моей базы данных из моих сущностей, что прекрасно работает. Теперь я хочу добавить файл data.sql, который будет заполнять мою базу данных. Я настроил JPA следующим образом:

spring.jpa.properties.hibernate.hbm2ddl.import_files=data.sql

Однако у меня есть проблема при выполнении начального SQL. В файле я определил пару функций, и в конце я их выполняю:

CREATE OR REPLACE FUNCTION insert_timeout_configuration() RETURNS bigint AS $$
  DECLARE created_id bigint;

  BEGIN
    INSERT INTO timeout_configuration (id, version, timeout)
    VALUES (nextval('my_sequence'), 0, 300)
    RETURNING id INTO created_id;
    return created_id;
  END;
$$ language plpgsql;

CREATE OR REPLACE FUNCTION insert_url_configuration() RETURNS bigint AS $$
  DECLARE created_id bigint;

  BEGIN
    INSERT INTO url_configuration (id, version, my_url)
    VALUES (nextval('my_sequence'), 0,'http://localhost:8080/')
    RETURNING id INTO created_id;
    return created_id;
  END;
$$ language plpgsql;

DO $$
      INSERT INTO global_configuration(id, version, name, timeout_configuration_id, url_configuration_id)
VALUES (nextval('my_sequence'), 0, 'My global config', insert_timeout_configuration(), insert_url_configuration());

-- do some other code 
END
$$;
drop function insert_timeout_configuration();
drop function insert_url_configuration();

Если я выполняю тот же код в консоли PostgreSQL для чтения из файла, он работает нормально. Но если я запускаю его через Spring, я получаю следующее:

org.postgresql.util.PSQLException: Unterminated dollar quote started at position 0 in SQL $$ language plpgsql. Expected terminating $$
    at org.postgresql.core.Parser.checkParsePosition(Parser.java:1273) ~    [postgresql-42.2.4.jar:42.2.4]
    at org.postgresql.core.Parser.parseSql(Parser.java:1172) ~[postgresql-    42.2.4.jar:42.2.4]
    at org.postgresql.core.Parser.replaceProcessing(Parser.java:1124) ~    [postgresql-42.2.4.jar:42.2.4]
at     org.postgresql.core.CachedQueryCreateAction.create(CachedQueryCreateAction.java:41) ~[postgresql-42.2.4.jar:42.2.4]
at org.postgresql.core.QueryExecutorBase.createQueryByKey(QueryExecutorBase.java:314) ~[postgresql-42.2.4.jar:42.2.4]
at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:285) ~[postgresql-42.2.4.jar:42.2.4]
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:270) ~    [postgresql-42.2.4.jar:42.2.4]
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:266) ~    [postgresql-42.2.4.jar:42.2.4]
    at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95) ~    [HikariCP-2.7.9.jar:?]
at         com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~    [HikariCP-2.7.9.jar:?]
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(Generat    ionTargetToDatabase.java:54) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
    ... 33 more
[DEBUG] 2018-09-07 21:09:43.325 [main] SQL - CREATE OR REPLACE FUNCTION insert_url_configuration() RETURNS bigint AS $$
Hibernate: CREATE OR REPLACE FUNCTION insert_url_configuration() RETURNS bigint AS $$
[WARN ] 2018-09-07 21:09:43.325 [main] ExceptionHandlerLoggedImpl - GenerationTarget encountered exception accepting command : Error executing DDL 
via JDBC Statement

Я использую PostgreSQL 9.5 и Spring Boot 2.0.3. Я прочитал, что разделитель $$ в определении функции не может быть проанализирован правильно, но я не могу найти, как это решить. Вместо $$ я пытался использовать его с простым '' и везде избегать одинарных кавычек, но это тоже не сработало.

1 Ответ

0 голосов
/ 08 сентября 2018

Проблема была не в синтаксисе, потому что синтаксис отлично работал с flyway или напрямую в PostgreSQL CLI. Проблема была в Hibernate, особенно с разбором файла импорта. Принцип работы Hibernate заключается в том, что он выполняет каждое выражение из файлов по отдельности, а не весь контент как единое выражение. Я попытался поместить все определения функций в одну строку, и это сработало, но не было читабельным. Таким образом, я обнаружил, что в Hibernate есть конфигурация, которая сообщает, что выражения могут быть многострочными, но разделитель $$ все еще не распознается при использовании в многострочном режиме.

Таким образом, решение состояло в том, чтобы определить команду с ' разделителем и затем экранировать одинарные кавычки, где необходимо, с дополнительным '.

Решение состоит в том, чтобы установить spring.jpa.properties.hibernate.hbm2ddl.import_files_sql_extractor для использования org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor. MultipleLinesSqlCommandExtractor извлекает выражение SQL из нескольких строк и останавливается при наличии точки с запятой. Это конец выражения. Оборачивая тело функции в строку в одинарные кавычки, Hibernate будет обрабатывать эту обертку как одну строку.

data.sql

CREATE OR REPLACE FUNCTION insert_timeout_configuration() RETURNS bigint AS '
  DECLARE created_id bigint;

  BEGIN
    INSERT INTO timeout_configuration (id, version, timeout)
    VALUES (nextval(''my_sequence''), 0, 300)
    RETURNING id INTO created_id;
    return created_id;
  END;
' language plpgsql;

CREATE OR REPLACE FUNCTION insert_url_configuration() RETURNS bigint AS '
  DECLARE created_id bigint;

  BEGIN
    INSERT INTO url_configuration (id, version, my_url)
    VALUES (nextval(''my_sequence''), 0,''http://localhost:8080/'')
    RETURNING id INTO created_id;
    return created_id;
  END;
' language plpgsql;

DO '
      INSERT INTO global_configuration(id, version, name, timeout_configuration_id, url_configuration_id)
      VALUES (nextval(''my_sequence''), 0, ''My global config'', insert_timeout_configuration(), insert_url_configuration());

-- do some other code 
END
';
drop function insert_timeout_configuration();
drop function insert_url_configuration();

Мне всегда нужно помнить, чтобы избежать выражений в выражениях, заключенных в одинарные кавычки, но теперь у меня может быть более читаемый исходный файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...