【问题标题】:PostgreSQL/JPA - Import functions in import.sql file?PostgreSQL/JPA - 在 import.sql 文件中导入函数?
【发布时间】:2018-05-17 06:07:02
【问题描述】:

我正在尝试在我的 JPA import.sql 文件中定义一些 PostgreSQL 函数和触发器。我使用 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 文件时,我收到如下错误消息:

未终止的美元报价开始于 SQL CREATE 中的第 65 位 函数 my_function() 返回触发器为 $$

所以,很明显它在我的函数声明中的$$ 上死了。有没有解决的办法?我应该以不同的方式声明我的函数/触发器吗?我可以在我的persistence.xml 文件中设置一个可以解决此问题的属性吗?

【问题讨论】:

  • 未终止意味着您有偶数个$$。所以你开始引用某处但没有完成。如果您发布完整的功能 bidy,我会告诉您确切的错误
  • FWIW JPA API 没有这样的“import.sql”文件。您指的是 Hibernate 专有的东西。 JPA 能够通过脚本加载数据库,但您忽略了该机制
  • @VaoTsun 我已经用 SQL 函数源更新了这个问题。对于它的价值,我可以使用此代码手动执行 CREATE FUNCTION 并且没有问题。只是在 import.sql 执行期间尝试执行此操作时失败。
  • hm - 简单的解决方法是将$$ 更改为$uniq_name$
  • 相同类型的错误:未终止的美元报价开始于 SQL $uniq_name$ 中的位置 0

标签: postgresql hibernate function jpa triggers


【解决方案1】:

hibernate 默认的 SqlStatementParser 实现的问题,它用于多行 sql 命令提取器。

如果你看语法定义hibernate-core/src/main/antlr/sql-stmt.g有语句结束的定义:

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

NOT_STMT_END
    : ~( ';' )
    ;

这告诉语句结束是分号符号,后跟“空格”“制表符”“回车符”或“换行符”符号。

因此:休眠中的默认实现不支持美元报价。

如果您不想实现自定义 hibernate 的解析器,您可以使用简单的' 引号重写所有函数而不使用美元引号。但是您需要小心地转义 ' 字符。

更新:您可以创建自定义 ImportSqlCommandExtractor。例如:用--****** 分隔您的命令(注释中的6 个星号,只是为了使您的文件成为正确的SQL 文件,但在cmets 中使用自定义命令分隔,或者选择您喜欢的任何疯狂组合)然后将它们拆分为简单实现

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];
        }
    }
}

然后配置hibernate使用&lt;property name="hibernate.hbm2ddl.import_files_sql_extractor" value="example.ImportSqlCE" /&gt;

这样,您的 import.sql 将支持美元报价(即它会简单地忽略任何对正在发生的事情的 sql 意识。)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多