我在名为function.sql的文件中有以下内容:
CREATE FUNCTION increment(i integer) RETURNS integer AS $$
BEGIN
RETURN i + 1;
END;
$$ LANGUAGE plpgsql;
我尝试使用Ant在本地Postgres(9.3.4)数据库上执行它:
<target name = "create" >
<sql driver="org.postgresql.Driver" url="${db.url}" userid="${db.username}" password="${db.password}">
<transaction src="create/functions.sql"/>
<classpath>
<pathelement location="lib/postgresql-9.3-1101.jdbc41.jar"/>
</classpath>
</sql>
</target>
(我已经在github here上创建了一个示例项目。)
当我执行ant时,我收到错误:
BUILD FAILED
/home/paul/jobhop-workspace/AntSqlPostgresFunctions/build.xml:17: org.postgresql.util.PSQLException: ERROR: syntax error at or near "$"
Position: 58
但是如果我直接执行文件:
psql -d <mydb> functions.sql
答案 0 :(得分:2)
错误消息是因为Ant的属性扩展行为会看到$$
并在它到达PostgreSQL之前将其替换为单个$
(请参阅http://ant.apache.org/manual/properties.html, $$扩展)
我们可以通过几种方式解决这个问题。按照Ant手册中的建议,将美元字符加倍,但代价是在传递给psql
客户端时使文件不再有效。我使用$BODY$
或($whatever-you-fancy$
)代替$$
来分隔函数体,或者通过设置SQL任务expandproperties
,取得了更大的成功build.xml中的参数为false。
一旦完成,我们遇到了第二个问题:Ant任务解析您的文件 查找它提供给JDBC的语句。然而,它并不是很聪明:它只是 分裂&#39;;&#39;角色,即使它们位于身体中间 你的函数定义(参见http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/SQLExec.java?view=markup#l724),那么我们就会看到一个关于未终止字符串的错误(即函数体的前半部分)。
我们可以通过使用不同的分隔符并通过delimiter
和delimitertype
参数告诉SQL任务来解决这个问题。您项目的以下补丁
让它为我工作:
diff --git a/build.xml b/build.xml
index 7d8a990..5dbbdc5 100644
--- a/build.xml
+++ b/build.xml
@@ -14,7 +14,7 @@
</target>
<target name = "create" >
- <sql driver="org.postgresql.Driver" url="${db.url}"
userid="${db.username}" password="${db.password}">
+ <sql driver="org.postgresql.Driver" url="${db.url}"
userid="${db.username}" password="${db.password}" delimiter="/* END_STATEMENT */" delimitertype="row" >
<transaction src="create/functions.sql"/>
diff --git a/create/functions.sql b/create/functions.sql
index 3238d3e..1a8518f 100644
--- a/create/functions.sql
+++ b/create/functions.sql
@@ -1,9 +1,9 @@
-CREATE FUNCTION increment(i integer) RETURNS integer AS $$
+CREATE FUNCTION increment(i integer) RETURNS integer AS $BODY$
BEGIN
RETURN i + 1;
END;
-$$ LANGUAGE plpgsql;
-
+$BODY$ LANGUAGE plpgsql;
+/* END_STATEMENT */
我最初将语句分隔符放在-- END_STATEMENT
形式的注释中。这只会给人一种工作的错觉,因为在解析SQL时,Ant任务会在之前放弃那些注释,它会寻找分隔符。找不到分隔符它只是将文件的全部内容作为单个语句传递给PostgreSQL,它在您的简单情况下工作,但由于函数列表变得更长,因此不太理想。
相反,我使用的是由PostgreSQL识别的C风格的注释,但是(当前)没有被Ant任务的解析器识别。当然,如果更改了Ant任务的解析器,这可能会停止工作。
如果functions.sql
文件不需要在psql
工作,那么您可以考虑使用您喜欢的任何分隔符。它甚至不必是有效的SQL语法,因为Ant任务在将语句传递给PostgreSQL之前将其删除。