45 votes

ERREUR : chaîne citée non terminée à ou près de

En exécutant le code de déclenchement ci-dessous à l'aide de ANT, j'obtiens l'erreur suivante

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

Je suis en mesure d'exécuter avec succès le code ci-dessous via PGADmin (fourni par postgres) et l'utilitaire de ligne de commande "psql" et la fonction de déclenchement est ajoutée, mais lors de l'exécution via ANT, il échoue à chaque fois.

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;

59voto

Corve Points 95

J'ai rencontré cette erreur dans liquibase et cette page a été l'un des premiers résultats de recherche. Je pense donc que je dois partager ma solution sur cette page :

Vous pouvez mettre votre sql complet dans un fichier séparé et l'inclure dans le changeset. Il est important de mettre le splitStatements option pour false .

L'ensemble du jeu de modifications ressemblerait alors à

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

J'aime toujours avoir ces grosses parties SQL (comme les mises à jour de fonctions et autres) dans des fichiers séparés. De cette façon, vous obtenez une coloration syntaxique appropriée lorsque vous ouvrez le fichier SQL et vous ne devez pas mélanger XML et SQL dans un seul fichier.


Modifier comme mentionné dans les commentaires, il convient de noter que le site sql changement soutient le splitStatements (merci à AndreyT de l'avoir signalé).

31voto

manRo Points 787

J'ai eu le même problème avec le pilote JDBC utilisé par Liquibase.

Il semble que le pilote explose chaque ligne terminée par un point-virgule et l'exécute comme une commande SQL distincte. C'est pourquoi le code ci-dessous sera exécuté par le pilote JDBC dans la séquence suivante :

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

Bien entendu, il s'agit d'un SQL invalide qui entraîne l'erreur suivante :

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

Pour corriger cela, vous devez utiliser des antislashes après chaque ligne terminée par un point-virgule :

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

Vous pouvez également placer toute la définition sur une seule ligne.

8voto

user3328634 Points 81

J'utilise le client HeidiSQL et le problème a été résolu en plaçant DELIMITER // avant l'instruction CREATE OR REPLACE. Il existe également une option "Envoyer un lot en une seule fois" dans HeidiSQL qui permet d'obtenir la même chose.

1voto

huphos Points 11

Cette erreur est due à une interaction entre le client particulier utilisé pour se connecter au serveur et la forme de la fonction. Pour illustrer :

Le code suivant s'exécutera sans dommage dans Netbeans 7, Squirrel, DbSchema et 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;

Veuillez noter que l'instruction "begin" vient immédiatement après la chaîne de caractères citée "$".

Le code suivant arrêtera tous les clients ci-dessus sauf 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;

La différence essentielle dans le deuxième exemple est la section "declare". L'utilisation de barres obliques inversées provoque une erreur dans PgAdmin3.

En résumé, je suggère d'essayer différents outils. Certains outils, même s'ils sont censés écrire des fichiers texte, insèrent des éléments invisibles dans le texte. C'est notamment le cas de la nomenclature Unicode, qui bloque tout fichier php qui tente d'implémenter des sessions ou des espaces de noms. Bien que ce ne soit pas une solution, j'espère que cela vous aidera.

1voto

lisben Points 11

Je sais que cette question a été posée il y a longtemps mais j'ai eu un peu le même problème avec un Postgresql script (exécuté depuis Jenkins) en utilisant la tâche SQL de Ant.

J'ai essayé d'exécuter ce SQL (enregistré dans un fichier nommé 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
;

mais j'ai obtenu l'erreur "unterminated dollar-quoted string". Aucun problème pour l'exécuter depuis pgAdmin.

J'ai découvert que ce n'est pas le pilote qui divise le script à chaque " ;" mais plutôt Ant.

Sur http://grokbase.com/t/postgresql/pgsql-jdbc/06cjx3s3y0/ant-sql-tag-for-dollar-quoting J'ai trouvé la réponse :

La fourmi mange le double-$$ dans le cadre de son traitement des variables. Vous devez utiliser $BODY$ (ou similaire) dans les procs stockés, et mettre le délimiteur sur sa propre propre ligne (avec delimitertype="row"). Ant coopérera alors.

Mon script Ant SQL ressemble à ceci et il fonctionne :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X