2010-08-17 34 views
30

Trong khi thực thi mã kích hoạt bên dưới hiển thị bằng ANT Tôi nhận được lỗiLỖI: chuỗi trích dẫn unterminated tại hoặc gần

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

tôi có thể thành công thực thi mã bên dưới thông qua pgAdmin (cung cấp bởi postgres) và dòng lệnh tiện ích "psql" và chức năng kích hoạt được thêm vào nhưng trong khi thực hiện thông qua ANT nó không thành công mỗi lần

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; 

Trả lời

25

Tôi đã có cùng một vấn đề với trình điều khiển JDBC được sử dụng bởi Liquibase.

Dường như trình điều khiển phát nổ mỗi dòng đã kết thúc bằng dấu chấm phẩy và chạy nó dưới dạng lệnh SQL riêng biệt. Đó là lý do tại sao đoạn code dưới đây sẽ được thực hiện bởi các trình điều khiển JDBC trong dãy sau:

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

Tất nhiên, đây là SQL hợp lệ và gây ra lỗi sau:

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

Để khắc phục điều này, bạn cần phải sử dụng những dấu xồ nguợc sau mỗi dòng kết thúc bằng dấu chấm phẩy:

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

Ngoài ra, bạn có thể đặt toàn bộ định nghĩa trong một dòng.

+17

Nếu sử dụng tệp SQL được định dạng LiquiBase, hãy thử thêm nhận xét này vào tệp proc/function của bạn e splitStatements: sai. Điều đó đã đánh lừa tôi. – Kuberchaun

+0

hi, cảm ơn câu trả lời này. nó đã giúp tôi với một lỗi tương tự. tuy nhiên, tôi muốn thêm rằng công việc của bạn xung quanh (thêm các dấu gạch chéo ngược) chỉ hoạt động trong một số trường hợp. việc tách thành các câu lệnh riêng biệt được thực hiện bởi một mức cao hơn jdbc, vì vậy chính xác những gì được lấy làm một dòng và những gì không phụ thuộc vào phần mềm khác trong ngăn xếp.trong trường hợp của tôi, bằng cách sử dụng mùa xuân, dấu gạch chéo ngược không hoạt động, nhưng có thể chỉ định một dấu tách khác nhau. –

+1

@andrewcooke Xin vui lòng, làm thế nào để bạn chỉ định một dấu phân cách khác nhau để giải quyết vấn đề? –

1

Lỗi này phát sinh dưới dạng tương tác giữa ứng dụng khách cụ thể được sử dụng để kết nối với máy chủ và biểu mẫu của hàm. Để minh họa:

Các mã sau sẽ chạy mà không có thương vong trong 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; 

Xin lưu ý rằng 'bắt đầu' tuyên bố đến ngay sau khi '$' trích dẫn chuỗi.

Mã tiếp theo sẽ tạm dừng tất cả các ứng dụng khách trên trừ 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; 

Sự khác biệt quan trọng trong ví dụ thứ hai là phần 'khai báo'. Các mưu đồ của việc sử dụng dấu gạch chéo ngược làm tăng một lỗi với PgAdmin3.

Tóm lại, tôi khuyên bạn nên thử các công cụ khác nhau. Một số công cụ mặc dù họ có nghĩa vụ phải viết các tập tin văn bản đặt công cụ vô hình vào văn bản. Notoriously điều này xảy ra với Unicode BOM mà sẽ ngăn chặn bất kỳ tập tin php mà cố gắng để thực hiện phiên hoặc không gian tên. Trong khi điều này là không có giải pháp tôi hy vọng nó sẽ giúp.

+0

Cả hai định nghĩa hàm của bạn không chạy trong SQuirreL (3.5.3) đối với cơ sở dữ liệu PostgreSQL 9.3.4. – zb226

1

Tôi gặp vấn đề tương tự với trình tạo zeos và C++. Giải pháp trong trường hợp của tôi:
Thay đổi dấu phân cách thuộc tính (thường là ";") thành một dấu phân cách khác trong thành phần (lớp) mà tôi đã sử dụng.

dm->ZSQLProcessor1->DelimiterType=sdGo; 

Có lẽ Ant có nội dung tương tự.

33

tôi gặp phải lỗi này trong liquibase và trang này là một trong những kết quả tìm kiếm đầu tiên vì vậy tôi đoán tôi chia sẻ giải pháp của tôi tại trang này:

Bạn có thể đặt toàn bộ sql của bạn trong một file riêng biệt và bao gồm này trong changeset. Điều quan trọng là đặt tùy chọn splitStatements thành false.

Toàn bộ changeset sau đó sẽ như thế nào

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

Tôi luôn luôn muốn có những bộ phận SQL lớn (như cập nhật chức năng và như vậy) trong tập tin riêng biệt. Bằng cách này bạn sẽ có được cú pháp tô sáng thích hợp khi mở tệp sql và không phải xen lẫn XML và SQL trong một tệp.


Sửa: như đã đề cập trong các ý kiến ​​giá trị của nó lưu ý rằng the sql change hỗ trợ các tùy chọn splitStatements cũng (thx để AndreyT đã chỉ mà ra).

+7

Tôi nghĩ rằng cần phải đề cập đến, những gì 'sql' hỗ trợ' splitStatements = "false" 'quá. [doc] (http://www.liquibase.org/documentation/changes/sql.html) – AndreyT

1

Tôi đang sử dụng ứng dụng khách HeidiSQL và điều này đã được giải quyết bằng cách đặt DELIMITER // trước câu lệnh CREATE OR REPLACE. Ngoài ra còn có một tùy chọn 'Gửi hàng loạt trong một lần' trong HeidiSQL về cơ bản đạt được điều tương tự.

0

tôi đã nhận được báo lỗi tương tự vì tôi đã có dấu chấm phẩy của tôi trong một dòng sản phẩm mới như thế này:

WHERE colA is NULL 
; 

Hãy chắc chắn rằng họ đang ở trong một dòng duy nhất là

WHERE colA is NULL; 
+0

Đó phải là một vấn đề với khách hàng của bạn, bởi vì nó không liên quan đến Postgres. –

0

Tôi biết câu hỏi này là đã hỏi một thời gian dài trước đây nhưng tôi đã có loại vấn đề tương tự với một kịch bản Postgresql (chạy từ Jenkins) bằng cách sử dụng tác vụ SQL của Ant.

Tôi cố gắng để chạy SQL này (được lưu trong một file có tên 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 
; 

nhưng đã nhận lỗi "chuỗi unterminated đô la-ngoặc kép". Không có vấn đề gì khi chạy nó từ pgAdmin.

Tôi phát hiện ra rằng nó không phải là trình điều khiển phân chia tập lệnh ở mọi ";" mà đúng hơn là Ant.

Tại http://grokbase.com/t/postgresql/pgsql-jdbc/06cjx3s3y0/ant-sql-tag-for-dollar-quoting Tôi tìm thấy câu trả lời:

Ant eats double-$$ as part of its variable processing. You have to use $BODY$ (or similar) in the stored procs, and put the delimiter on its own line (with delimitertype="row"). Ant will cooperate then.

kịch bản SQL Ant của tôi trông như thế này và nó hoạt động:

<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" 
/> 
1

Ví dụ này làm việc cho tôi với PostgreSQL 14.1 và 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(); 
Các vấn đề liên quan