ОШИБКА: неопределенная строка в кавычках или рядом - PullRequest
36 голосов
/ 17 августа 2010

При выполнении показанного ниже кода триггера с использованием 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;

Ответы [ 8 ]

47 голосов
/ 24 февраля 2014

Я столкнулся с этой ошибкой в ​​ 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 за указание на это).

26 голосов
/ 27 декабря 2010

У меня была такая же проблема с драйвером JDBC, используемым Liquibase.

Кажется, что драйвер взрывает каждую строку, оканчивающуюся точкой с запятой, и запускает ее как отдельную команду 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;

Кроме того, вы можете поместить все определение в одну строку.

3 голосов
/ 15 октября 2014

Я использую клиент HeidiSQL, и это было решено путем размещения DELIMITER // перед оператором CREATE OR REPLACE. В HeidiSQL также есть опция «Отправить пакет за один раз», которая, по сути, достигает того же самого.

1 голос
/ 24 января 2017

Этот пример работал для меня с 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 голос
/ 28 сентября 2012

У меня была такая же проблема с Zeos и C ++ Builder.Решение в моем случае:
Измените разделитель свойства (обычно «;») на другой компонент (класс), который я использовал.

dm->ZSQLProcessor1->DelimiterType=sdGo;

Возможно, у Муравья есть нечто подобное.

1 голос
/ 18 марта 2012

Эта ошибка возникает как взаимодействие между конкретным клиентом, используемым для подключения к серверу, и формой функции.Для иллюстрации:

Следующий код будет работать без сбоев в 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 начинается сразу после цитируемого символа $string.

Следующий код остановит всех вышеперечисленных клиентов, кроме 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-файл, который пытается реализовать сеансы или пространства имен.Хотя это не решение, я надеюсь, что это поможет.

0 голосов
/ 03 мая 2016

Я знаю, что этот вопрос задавался очень давно, но у меня была такая же проблема со скриптом Postgresql (запущенным из Jenkins) с использованием Ant-задачи SQL.

Я попытался запустить этот 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 Я нашел ответ:

Муравей ест дважды - $$ как часть своей переменной обработки. Вы должны использовать $ 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"
/>
0 голосов
/ 03 марта 2015

Я получил ту же ошибку, потому что у меня была точка с запятой в новой строке, например:

WHERE colA is NULL
;

Убедитесь, что они в одной строке как

WHERE colA is NULL;
...