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でこのエラーが発生しました。このページは最初の検索結果の 1 つだったので、このページで解決策を共有していると思います。

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

変更セット全体は次のようになります

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

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


編集:コメントで述べたようにsql変更がオプションもサポートしていることは注目に値しsplitStatementsます(それを指摘してくれたAndreyTにthx)。

于 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;

または、定義全体を 1 行に入れることもできます。

于 2010-12-27T20:28:23.627 に答える
9

私は HeidiSQL クライアントを使用していますが、これは CREATE OR REPLACE ステートメントの前に DELIMITER // を配置することで解決されました。HeidiSQL には、基本的に同じことを実現する「一度にバッチを送信する」オプションもあります。

于 2014-10-15T08:22:36.237 に答える
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が協力してくれます。

私の 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

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

dm->ZSQLProcessor1->DelimiterType=sdGo;

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

于 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;

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

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

于 2012-03-18T10:27:50.483 に答える
0

次のような新しい行にセミコロンがあるため、同じエラーが発生しました。

WHERE colA is NULL
;

それらが一行にあることを確認してください

WHERE colA is NULL;
于 2015-03-03T12:40:04.897 に答える