ОШИБКА: неиспользуемая строка с титром или рядом
Выполняя приведенный ниже код запуска с помощью 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;
Ответы
Ответ 1
Я столкнулся с этой ошибкой в 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 для указания этого).
Ответ 2
У меня была та же проблема с драйвером JDBC, используемым Liquibase.
Кажется, что драйвер взрывает каждую строку, заканчивающуюся точкой с запятой, и запускает ее как отдельную команду SQL. Вот почему приведенный ниже код будет выполняться драйвером JDBC в следующей последовательности:
-
CREATE OR REPLACE FUNCTION test(text) RETURNS VOID AS ' DECLARE tmp text
-
BEGIN tmp := "test"
-
END;
-
' 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
Эта ошибка возникает как взаимодействие между конкретным клиентом, используемым для подключения к серверу, и формой функции. Чтобы проиллюстрировать:
Следующий код будет работать без потерь в 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, которая остановит любой php файл, который пытается реализовать сеансы или пространства имен.
Хотя это не решение, я надеюсь, что это поможет.
Ответ 4
У меня была такая же проблема с zeos и С++ builder.
Решение в моем случае:
Измените разделитель свойств (обычно ";" ) на другой в компоненте (классе), который я использовал.
dm->ZSQLProcessor1->DelimiterType=sdGo;
Возможно, Ant имеет что-то подобное.
Ответ 5
Я использую клиент HeidiSQL, и это было решено, поставив DELIMITER//перед оператором CREATE OR REPLACE. В HeidiSQL есть опция "Отправить пакет за один раз", которая по сути достигает того же.
Ответ 6
Этот пример работал у меня с 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();
Ответ 7
Я получал ту же ошибку, потому что у меня была точка с запятой в новой строке:
WHERE colA is NULL
;
Убедитесь, что они находятся в одной строке как
WHERE colA is NULL;
Ответ 8
Я знаю, что этот вопрос задавался давно, но у меня была такая же проблема с Postgresql script (выполняется от Jenkins) с помощью Ant SQL Task.
Я попытался запустить этот 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
;
но получил ошибку "unterminated knot-quoted string". Нет проблем с запуском его из pgAdmin.
Я узнал, что это не драйвер, который разбивает script на каждом ";" а скорее Ant.
В http://grokbase.com/t/postgresql/pgsql-jdbc/06cjx3s3y0/ant-sql-tag-for-dollar-quoting Я нашел ответ:
Ant ест двойной - $$ как часть обработки переменной. Вы должны использовать $BODY $(или аналогичный) в хранимых процедурах и помещает разделитель на свой собственной линией (с delimitertype = "row" ). Ant будет сотрудничать тогда.
Мой Ant SQL script выглядит так: он работает:
<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"
/>