Ant Sql Target无法创建Postgresql函数

时间:2014-04-27 16:24:00

标签: ant

我在名为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

它创建函数就好了。我已经尝试过建议herehere的解决方案,这听起来像是同样的问题,但它们对我没有用。

1 个答案:

答案 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),那么我们就会看到一个关于未终止字符串的错误(即函数体的前半部分)。

我们可以通过使用不同的分隔符并通过delimiterdelimitertype参数告诉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之前将其删除。