Spring ScriptUtils - PostgreSQL 中未终止的美元报价
Spring ScriptUtils - Unterminated dollar quote in PostgreSQL
我将以下 Java 代码用于 运行 SQL 脚本:
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
DataSource ds;
@Value("classpath:test.sql")
Resource resource;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
try {
@Cleanup
Connection c = ds.getConnection();
ScriptUtils.executeSqlScript(c, resource);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我使用的 Spring 引导版本是 2.1.7.RELEASE 和 PostgreSQL 在本地 docker 镜像中是 运行ning via:
docker run --rm --name pg-docker -e POSTGRES_PASSWORD=PASSWORD -d -p 5432:5432 -v postgresql:/var/lib/postgresql/data postgres:11.3
我使用的SQL脚本是:
CREATE OR REPLACE FUNCTION totalRecords ()
RETURNS integer AS $total$
declare
total integer;
BEGIN
SELECT count(*) into total FROM COMPANY;
RETURN total;
END;
$total$ LANGUAGE plpgsql;
在我看来这是完全有效的并且 运行在 PgAdmin 中没问题。
不幸的是,我从 Java 收到以下异常:
Caused by: org.postgresql.util.PSQLException: Unterminated dollar quote started at position 62 in SQL CREATE OR REPLACE FUNCTION totalRecords () RETURNS integer AS $total$ declare total integer. Expected terminating $$
at org.postgresql.core.Parser.checkParsePosition(Parser.java:1274)
at org.postgresql.core.Parser.parseSql(Parser.java:1173)
at org.postgresql.core.Parser.replaceProcessing(Parser.java:1125)
at org.postgresql.core.CachedQueryCreateAction.create(CachedQueryCreateAction.java:41)
at org.postgresql.core.QueryExecutorBase.createQueryByKey(QueryExecutorBase.java:314)
at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:289)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:274)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:269)
at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95)
at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java)
at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:488)
... 9 more
怎么了?请问我该如何解决?或者如果 ScriptUtils 无法这样做,如何从 Java 可靠地 运行 PostgreSQL 脚本?
终于自己解决了。不确定我的解决方案是否是最好的想法。问题出在 ScriptUtils 中 - 它通过 ScriptUtils.DEFAULT_STATEMENT_SEPARATOR 确定语句结束,即“;”。不幸的是,FUNCTION 命令包含各种“;”这是声明本身的一部分。所以解决方案是声明并使用另一个不干扰 PostgreSQL 语法的分隔符。在我的例子中,我使用了两个分号——“;;”。所以我的陈述看起来像:
CREATE OR REPLACE FUNCTION totalRecords ()
RETURNS integer AS $total$
declare
total integer;
BEGIN
SELECT count(*) into total FROM COMPANY;
RETURN total;
END;
$total$ LANGUAGE plpgsql;;
并且 Java 调用它的代码更改为:
ScriptUtils.executeSqlScript(c, new EncodedResource(resource, "UTF-8"), false, false, ScriptUtils.DEFAULT_COMMENT_PREFIX, ";;",
ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER);
如 所述,hibernate 在解析时似乎是问题所在。将 $total$ 替换为 ',它应该可以工作:
CREATE OR REPLACE FUNCTION totalRecords ()
RETURNS integer AS '
declare
total integer;
BEGIN
SELECT count(*) into total FROM COMPANY;
RETURN total;
END;
' LANGUAGE plpgsql;
我将以下 Java 代码用于 运行 SQL 脚本:
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
DataSource ds;
@Value("classpath:test.sql")
Resource resource;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
try {
@Cleanup
Connection c = ds.getConnection();
ScriptUtils.executeSqlScript(c, resource);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我使用的 Spring 引导版本是 2.1.7.RELEASE 和 PostgreSQL 在本地 docker 镜像中是 运行ning via:
docker run --rm --name pg-docker -e POSTGRES_PASSWORD=PASSWORD -d -p 5432:5432 -v postgresql:/var/lib/postgresql/data postgres:11.3
我使用的SQL脚本是:
CREATE OR REPLACE FUNCTION totalRecords ()
RETURNS integer AS $total$
declare
total integer;
BEGIN
SELECT count(*) into total FROM COMPANY;
RETURN total;
END;
$total$ LANGUAGE plpgsql;
在我看来这是完全有效的并且 运行在 PgAdmin 中没问题。
不幸的是,我从 Java 收到以下异常:
Caused by: org.postgresql.util.PSQLException: Unterminated dollar quote started at position 62 in SQL CREATE OR REPLACE FUNCTION totalRecords () RETURNS integer AS $total$ declare total integer. Expected terminating $$
at org.postgresql.core.Parser.checkParsePosition(Parser.java:1274)
at org.postgresql.core.Parser.parseSql(Parser.java:1173)
at org.postgresql.core.Parser.replaceProcessing(Parser.java:1125)
at org.postgresql.core.CachedQueryCreateAction.create(CachedQueryCreateAction.java:41)
at org.postgresql.core.QueryExecutorBase.createQueryByKey(QueryExecutorBase.java:314)
at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:289)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:274)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:269)
at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95)
at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java)
at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:488)
... 9 more
怎么了?请问我该如何解决?或者如果 ScriptUtils 无法这样做,如何从 Java 可靠地 运行 PostgreSQL 脚本?
终于自己解决了。不确定我的解决方案是否是最好的想法。问题出在 ScriptUtils 中 - 它通过 ScriptUtils.DEFAULT_STATEMENT_SEPARATOR 确定语句结束,即“;”。不幸的是,FUNCTION 命令包含各种“;”这是声明本身的一部分。所以解决方案是声明并使用另一个不干扰 PostgreSQL 语法的分隔符。在我的例子中,我使用了两个分号——“;;”。所以我的陈述看起来像:
CREATE OR REPLACE FUNCTION totalRecords ()
RETURNS integer AS $total$
declare
total integer;
BEGIN
SELECT count(*) into total FROM COMPANY;
RETURN total;
END;
$total$ LANGUAGE plpgsql;;
并且 Java 调用它的代码更改为:
ScriptUtils.executeSqlScript(c, new EncodedResource(resource, "UTF-8"), false, false, ScriptUtils.DEFAULT_COMMENT_PREFIX, ";;",
ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER);
如
CREATE OR REPLACE FUNCTION totalRecords ()
RETURNS integer AS '
declare
total integer;
BEGIN
SELECT count(*) into total FROM COMPANY;
RETURN total;
END;
' LANGUAGE plpgsql;