45

在使用 ANT 执行下面显示的触发代码时,我收到了错误

org.postgresql.util.PSQLException: ERROR: unterminated quoted string at or near "' DECLARE timeout integer"
Position: 57

我能够通过 PGADmin(由 postgres 提供)和命令行实用程序“psql”成功执行以下代码,并添加了触发功能,但是在通过 ANT 执行时,每次都失败

BEGIN TRANSACTION;

CREATE OR REPLACE FUNCTION sweeper() RETURNS trigger as '
    DECLARE
    timeout integer;
    BEGIN
    timeout = 30 * 24 * 60 * 60 ;
        DELETE FROM diagnosticdata WHERE current_timestamp - teststarttime  > (timeout * ''1 sec''::interval);
        return NEW;
    END;
' LANGUAGE 'plpgsql';

-- Trigger: sweep on diagnosticdata

CREATE TRIGGER sweep
  AFTER INSERT
  ON diagnosticdata
  FOR EACH ROW
  EXECUTE PROCEDURE sweeper();

END;
4

8 回答 8

59

我在liquibase中遇到了这个错误,这个页面是第一个搜索结果之一,所以我想我在这个页面上分享了我的解决方案:

您可以将整个 sql 放在一个单独的文件中,并将其包含在变更集中。splitStatements将选项设置为 很重要false

整个变更集看起来像

<changeSet author="fgrosse" id="530b61fec3ac9">
    <sqlFile path="your_sql_file_here.sql" splitStatements="false"/>
</changeSet>

我总是喜欢将那些大的 SQL 部分(如函数更新等)放在单独的文件中。这样,您可以在打开 sql 文件时获得正确的语法突出显示,而不必在一个文件中混合 XML 和 SQL。


编辑:正如评论中提到的,值得注意的是,sql更改也支持该splitStatements选项(感谢 AndreyT 指出这一点)。

于 2014-02-24T15:33:29.497 回答
31

我对 Liquibase 使用的 JDBC 驱动程序有同样的问题。

似乎驱动程序会分解以分号结尾的每一行并将其作为单独的 SQL 命令运行。这就是为什么下面的代码将由 JDBC 驱动程序按以下顺序执行的原因:

  1. CREATE OR REPLACE FUNCTION test(text) RETURNS VOID AS ' DECLARE tmp text
  2. BEGIN tmp := "test"
  3. END;
  4. ' LANGUAGE plpgsql

当然,这是无效的 SQL,会导致以下错误:

unterminated dollar-quoted string at or near ' DECLARE tmp text

要更正此问题,您需要在每行以分号结尾后使用反斜杠:

CREATE OR REPLACE FUNCTION test(text) 
RETURNS void AS ' DECLARE tmp text; \
BEGIN 
tmp := "test"; \
END;' LANGUAGE plpgsql;

或者,您可以将整个定义放在一行中。

于 2010-12-27T20:28:23.627 回答
9

我正在使用 HeidiSQL 客户端,这是通过在 CREATE OR REPLACE 语句之前放置 DELIMITER // 解决的。HeidiSQL 中还有一个“一次性发送批处理”选项,它基本上实现了相同的目的。

于 2014-10-15T08:22:36.237 回答
1

我对 zeos 和 c++ builder 有同样的问题。在我的情况下的解决方案:在
我使用的组件(类)中将属性分隔符(通常是“;”)更改为另一个。

dm->ZSQLProcessor1->DelimiterType=sdGo;

也许蚂蚁也有类似的东西。

于 2012-09-28T11:47:33.400 回答
1

此错误是由于用于连接到服务器的特定客户端与函数形式之间的交互而出现的。为了显示:

以下代码将在 Netbeans 7、Squirrel、DbSchema、PgAdmin3 中正常运行

CREATE OR REPLACE FUNCTION author.revision_number()
  RETURNS trigger AS
$BODY$
 begin
  new.rev := new.rev + 1;
  new.revised := current_timestamp;
  return new;
 end;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

请注意,'begin' 语句紧跟在 '$' 引用的字符串之后。

下一个代码将停止除 PgAdmin3 之外的所有上述客户端。

CREATE OR REPLACE FUNCTION author.word_count()
  RETURNS trigger AS 
$BODY$
   declare
    wordcount integer := 0; -- counter for words
    indexer integer := 1;  -- position in the whole string
    charac char(1);  -- the first character of the word
    prevcharac char(1);
   begin

    while indexer <= length(new.blab) loop
      charac := substring(new.blab,indexer,1); -- first character of string

      if indexer = 1 then
        prevcharac := ' '; -- absolute start of counting
      else
        prevcharac := substring(new.blab, indexer - 1, 1); -- indexer has increased
      end if;

     if prevcharac = ' ' and charac != ' ' then
       wordcount := wordcount + 1;
     end if;

     indexer := indexer + 1;
   end loop;
  new.words := wordcount;
  return new;
  end;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

第二个示例的关键区别在于“声明”部分。使用反斜杠的策略会引发 PgAdmin3 错误。

总之,我建议尝试不同的工具。一些工具即使它们应该编写文本文件,也会将不可见的东西放入文本中。众所周知,Unicode BOM 会停止任何试图实现会话或命名空间的 php 文件。虽然这不是解决方案,但我希望它有所帮助。

于 2012-03-18T10:27:50.483 回答
1

我知道很久以前有人问过这个问题,但是我在使用 Ant 的 SQL 任务的 Postgresql 脚本(从 Jenkins 运行)时遇到了同样的问题。

我尝试运行此 SQL(保存在名为 audit.sql 的文件中):

DROP SCHEMA IF EXISTS audit CASCADE
;
CREATE SCHEMA IF NOT EXISTS audit AUTHORIZATION faktum
;
CREATE FUNCTION audit.extract_interval_trigger () 
RETURNS trigger AS $extractintervaltrigger$
BEGIN
        NEW."last_change_ts" := current_timestamp;
        NEW."last_change_by" := current_user;
        RETURN NEW;
END;
$extractintervaltrigger$ LANGUAGE plpgsql
;

但收到错误“未终止的美元引号字符串”。从 pgAdmin 运行它没问题。

我发现不是驱动程序在每个“;”处拆分脚本 而是蚂蚁。

http://grokbase.com/t/postgresql/pgsql-jdbc/06cjx3s3y0/ant-sql-tag-for-dollar-quoting我找到了答案:

Ant 吃掉 double-$$ 作为其变量处理的一部分。您必须在存储的过程中使用 $BODY$ (或类似的),并将分隔符放在自己的行上(使用 delimitertype="row")。届时蚂蚁将合作。

我的 Ant SQL 脚本看起来像这样,它可以工作:

<sql
    driver="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/jenkins"
    userid="user" password="*****"
    keepformat="true"
    autocommit="true"
    delimitertype="row"
    encoding="utf-8"
    src="audit.sql"
/>
于 2016-05-03T18:45:08.330 回答
1

此示例适用于 PostgreSQL 14.1 和 HeidiSQL 9.4.0.5125

DROP TABLE IF EXISTS emp;
CREATE TABLE emp (
    empname           text NOT NULL,
    salary            integer
);

DROP TABLE IF EXISTS EMP_AUDIT;
CREATE TABLE emp_audit(
    operation         char(1)   NOT NULL,
    stamp             timestamp NOT NULL,
    userid            text      NOT NULL,
    empname           text      NOT NULL,
    salary integer
);

DELIMITER //
CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $$
    BEGIN
        --
        -- Create a row in emp_audit to reflect the operation performed on emp,
        -- make use of the special variable TG_OP to work out the operation.
        --
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO emp_audit SELECT 'D', now(), user, OLD.*;
            RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO emp_audit SELECT 'U', now(), user, NEW.*;
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*;
            RETURN NEW;
        END IF;
        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS emp_audit ON emp;
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
    FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();
于 2017-01-24T03:34:46.233 回答
0

我收到了同样的错误,因为我的分号在新行中,如下所示:

WHERE colA is NULL
;

确保它们在一行中

WHERE colA is NULL;
于 2015-03-03T12:40:04.897 回答