web-dev-qa-db-ja.com

エラー:またはその付近の終了文字列

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;
37
Anuj

liquibaseでこのエラーが発生し、このページは最初の検索結果の1つであったため、このページでソリューションを共有すると思います。

Sql全体を別のファイルに入れて、これを変更セットに含めることができます。 splitStatementsオプションをfalseに設定することが重要です。

チェンジセット全体は次のようになります

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

私はいつも、それらの大きなSQL部分(関数の更新など)を別々のファイルに入れたいです。この方法により、SQLファイルを開くときに適切な構文の強調表示が得られ、XMLとSQLを1つのファイルに混在させる必要がなくなります。


Edit:コメントで述べたように、 sql changesplitStatementsオプション(AndreyTにそれを指摘するためのthx)も。

47

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;

または、定義全体を1行に配置できます。

26
manRo

私はHeidiSQLクライアントを使用していますが、これはCREATE OR REPLACEステートメントの前にDELIMITER //を配置することで解決しました。 。

3
user3328634

このエラーは、サーバーへの接続に使用される特定のクライアントと関数の形式との間の相互作用として発生します。説明する:

次のコードは、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;

2番目の例の決定的な違いは、「宣言」セクションです。バックスラッシュを使用すると、PgAdmin3でエラーが発生します。

要約すると、さまざまなツールを試すことをお勧めします。一部のツールは、テキストファイルを記述することになっているにもかかわらず、目に見えないものをテキストに入れます。残念ながら、これはセッションまたは名前空間を実装しようとするphpファイルを停止するUnicode BOMで発生します。これは解決策ではありませんが、役立つことを願っています。

1
huphos

Zeosとc ++ builderでも同じ問題がありました。私の場合の解決策:
プロパティ区切り文字(通常は「;」)を、使用したコンポーネント(クラス)の別の区切り文字に変更します。

dm->ZSQLProcessor1->DelimiterType=sdGo;

おそらく、Antには似たようなものがあります。

1
fvel

この例は、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();
1
David

私はこの質問がずっと前に尋ねられたことを知っていますが、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はそれから協力します。

私の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"
/>
0
lisben

次のような新しい行にセミコロンがあったため、同じエラーが表示されました。

WHERE colA is NULL
;

それらが1行になっていることを確認してください

WHERE colA is NULL;
0
masoodg