PostgreSQL / JPA - импортировать функции в файл import.sql? - PullRequest
0 голосов
/ 08 мая 2018

Я пытаюсь определить некоторые функции и триггеры PostgreSQL в моем файле JPA import.sql. Я использую Hibernate 5.x в качестве основного поставщика JPA. Поскольку в моем файле import.sql есть команды, состоящие из нескольких строк, в моем файле persistence.xml установлено это свойство:

<property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />

Оттуда я пытаюсь определить свои функции в import.sql. Они выглядят примерно так:

DROP FUNCTION IF EXISTS update_total_feedback_count() CASCADE;
CREATE FUNCTION update_total_feedback_count() RETURNS TRIGGER AS
$$
DECLARE
  application_version_id BIGINT := 0;
  app_version_metadata_id BIGINT:= 0;
  application_id BIGINT := 0;
  app_metadata_id BIGINT := 0;
BEGIN
    IF (TG_OP = 'INSERT') THEN
        SELECT INTO application_version_id tbl_application_version.id
            FROM tbl_application_version
            INNER JOIN tbl_feedback ON tbl_feedback.application_version_id = tbl_application_version.id
            WHERE tbl_feedback.id = NEW.id;

        SELECT INTO app_version_metadata_id tbl_application_version.application_version_metadata_id
            FROM tbl_application_version
            WHERE id = application_version_id;

        SELECT INTO app_metadata_id registered_application_metadata_id
            FROM tbl_registered_application
            INNER JOIN tbl_application_version ON tbl_application_version.registered_application_id = tbl_registered_application.id
            WHERE tbl_application_version.id = application_version_id;

        UPDATE tbl_registered_application_metadata SET feedbackcount = (feedbackcount + 1), lastfeedbackdate = NEW.createddate WHERE id = app_metadata_id;
        UPDATE tbl_application_version_metadata SET feedbackcount = (feedbackcount + 1), lastfeedbackdate = NEW.createddate WHERE id = app_version_metadata_id;

        RETURN NEW;
    ELSIF (TG_OP = 'DELETE') THEN
        -- IMPLEMENT THIS TRIGGER

        RETURN NULL;
    END IF;
END;
$$
LANGUAGE 'plpgsql';
ALTER FUNCTION update_total_feedback_count() OWNER TO feedback_tracker;

Однако, когда я развертываю свой WAR-файл, я получаю сообщение об ошибке, наподобие этого:

Неопределенная котировка доллара началась с позиции 65 в SQL CREATE FUNCTION my_function () ВОЗВРАЩАЕТСЯ TRIGGER AS $$

Итак, очевидно, что он умирает от $$ в моем объявлении функции. Это можно обойти? Должен ли я объявить свою функцию / триггер по-другому? Есть ли в моем файле persistence.xml свойство, которое можно обойти?

1 Ответ

0 голосов
/ 17 мая 2018

проблема с реализацией SqlStatementParser по умолчанию в hibernate, которая используется в многострочном экстракторе команд sql.

если вы посмотрите на определение грамматики hibernate-core/src/main/antlr/sql-stmt.g, есть определение оператора End:

STMT_END
    : ';' ( '\t' | ' ' | '\r' | '\n' )*
    ;

NOT_STMT_END
    : ~( ';' )
    ;

Это говорит о том, что конец оператора - это точка с запятой, за которой следуют символы «пробел», «табуляция», «возврат карреты» или «новая строка».

ТАМ: РЕАЛИЗАЦИЯ ПО УМОЛЧАНИЮ В HIBERNATE НЕ ПОДДЕРЖИВАЕТ КВАЛИФИКАЦИЮ ДОЛЛАРОВ.

Если вы не хотите реализовывать пользовательский парсер hibernate, вы можете переписать все функции без долларовых кавычек, используя простые ' кавычки. Но вам нужно будет тщательно избегать ' символов.

ОБНОВЛЕНИЕ: вы можете создать свой собственный ImportSqlCommandExtractor. Например: разделите ваши команды с помощью --****** (6 звездных символов в комментарии, просто чтобы сделать ваш файл правильным файлом SQL, но с пользовательским разделением команд в комментариях, или выберите любую безумную комбинацию, которая вам нравится), а затем разделите их на простые реализация

public class ImportSqlCE implements ImportSqlCommandExtractor {

    private static final Logger log = LoggerFactory.getLogger(ImportSqlCE.class);

    @Override
    public String[] extractCommands(Reader reader) {
        try {
            String allCommands = IOUtils.toString(reader);

            return allCommands.split("--******");
        } catch (IOException e) {
            log.error("error reading import commands", e);
            log.info("sengind default empty command set");
            return new String[0];
        }
    }
}

, а затем настройте спящий режим для его использования <property name="hibernate.hbm2ddl.import_files_sql_extractor" value="example.ImportSqlCE" />

с этим ваш import.sql будет поддерживать котировки доллара (то есть он просто игнорирует любую осведомленность sql о происходящем).

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