PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 16/07/2012 10:44:46

leTaz
Membre

le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Bonjour à tous.

Je me suis basé sur l'exemple donné dans la doc (postgreSQL 9.1.4) pour créer une table partitionnée avec un trigger. La table est partitionnée sur l'année, la fonction appelée par le trigger crée la table partitionnée si elle n'existe pas et insère l'occurrence dans celle-ci.

Le problème est dans l'instruction : EXECUTE 'INSERT INTO ' || v_table || ' VALUES (' NEW.* ')';
Le NEW.* ne renvoie pas les chaînes de caractères entourées de quotes, ce qui fait planter l'INSERT.

Auriez-vous une solution ? Merci d'avance.

Voici le code :

CREATE OR REPLACE FUNCTION cvae_insert_trigger() RETURNS TRIGGER AS $$
DECLARE
    v_nombre SMALLINT;
    v_annee SMALLINT;
    v_table VARCHAR;
BEGIN
    v_annee := NEW.annee;
    v_table := 'cvae' || v_annee;
   
    SELECT count(*) INTO v_nombre FROM pg_tables WHERE pg_tables.tablename = v_table;
    IF ( v_nombre = 0 ) THEN
        -- Creation de la partition si elle n'existe pas
        EXECUTE 'CREATE TABLE ' || v_table || '( '
        || 'PRIMARY KEY (annee, idcvae), '
        || 'CONSTRAINT ' || v_table || '_annee_check CHECK (annee =  ' || v_annee  || '), '
        || 'CONSTRAINT ' || v_table || '_commune_fkey FOREIGN KEY (codecommunedpt) REFERENCES commune(codecommunedpt), '
        || 'CONSTRAINT ' || v_table || '_sousclasse_fkey FOREIGN KEY (codesousclasse) REFERENCES naf_sous_classe(codesousclasse), '
        || 'CONSTRAINT ' || v_table || '_voie_fkey FOREIGN KEY (codevoie, codecommunedpt) REFERENCES voie(codevoie, codecommunedpt), '
        || 'CONSTRAINT ' || v_table || '_formejuridique_fkey FOREIGN KEY (idformejuridique) REFERENCES forme_juridique(idformejuridique), '
        || 'CONSTRAINT ' || v_table || '_zone_fkey FOREIGN KEY (idzonage, idzone) REFERENCES zone(idzonage, idzone), '
        || 'CONSTRAINT ' || v_table || '_entreprise_fk FOREIGN KEY (siren) REFERENCES entreprise(siren), '
        || 'CONSTRAINT ' || v_table || '_etablissement_fkey FOREIGN KEY (siren, nic) REFERENCES etablissement(siren, nic)) '
        || 'INHERITS (cvae)';
   
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_commune ON ' || v_table || ' (CodeCommuneDpt)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_voie ON ' || v_table || ' (CodeVoie, CodeCommuneDpt)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_formejuridique ON ' || v_table || ' (IdFormeJuridique)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_entreprise ON ' || v_table || ' (SIREN)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_etablissement ON ' || v_table || ' (SIREN, NIC)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_nafsousclasse ON ' || v_table || ' (CodeSousClasse)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_zone ON ' || v_table || ' (IdZonage, IdZone)';
        EXECUTE 'CREATE INDEX i_' || v_table || '_denomination ON ' || v_table || ' (Denomination)';
    END IF;

    EXECUTE 'INSERT INTO ' || v_table || ' VALUES (' NEW.* ')';
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER cvae_insert_trigger
    BEFORE INSERT ON cvae
    FOR EACH ROW EXECUTE PROCEDURE cvae_insert_trigger();

Voici l'erreur :
ERROR:  syntax error at or near ","
LINE 1: INSERT INTO cvae2012 VALUES ((2012,1,123456789,,,,toto,,,,...
                                                       ^
QUERY:  INSERT INTO cvae2012 VALUES ((2012,1,123456789,,,,toto,,,,,,,,,,,,,,,,,,,,,,))
CONTEXT:  PL/pgSQL function "cvae_insert_trigger" line 35 at EXECUTE statement

Hors ligne

#2 16/07/2012 11:18:42

gleu
Administrateur

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Le code que vous indiquez n'est pas correct syntaxiquement sur cette ligne :

EXECUTE 'INSERT INTO ' || v_table || ' VALUES (' NEW.* ')';

J'obtiens ceci :

ERROR:  syntax error at or near "."
LINE ... : EXECUTE 'INSERT INTO ' || v_table || ' VALUES (' NEW.* ')';

Donc difficile de dire d'où vient votre problème réel.

Concernant l'exemple de la documentation, il fonctionne. La seule différence entre ce code et le votre est que vous utilisez EXECUTE.


Guillaume.

Hors ligne

#3 16/07/2012 11:42:47

leTaz
Membre

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Merci pour la réponse rapide.

J'ai changé la syntaxe dans la ligne suivante (j'ai enlevé les parenthèses) mais j'ai toujours le problème :
EXECUTE 'INSERT INTO ' || v_table || ' VALUES ' || NEW.*;

ERROR:  syntax error at or near ","
LINE 1: INSERT INTO cvae2012 VALUES (2012,1,123456789,,,,toto,,,,,...
                                                                                      ^
QUERY:  INSERT INTO cvae2012 VALUES (2012,1,123456789,,,,toto,,,,,,,,,,,,,,,,,,,,,,)
CONTEXT:  PL/pgSQL function "cvae_insert_trigger" line 35 at EXECUTE statement

Après la valeur numérique 123456789, je suppose qu'il devrait y avoir ,'' (idem pour la valeur toto qui devrait être 'toto').

Hors ligne

#4 16/07/2012 12:16:35

gleu
Administrateur

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Vous arrivez à enregistrer la fonction ? parce que, moi, j'ai l'erreur de syntaxe lors du 'CREATE OR REPLACE', pas lors de 'lexécution.


Guillaume.

Hors ligne

#5 16/07/2012 12:19:46

leTaz
Membre

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

oui, la création de la fonction s'exécute bien avec ce code :

CREATE OR REPLACE FUNCTION cvae_insert_trigger() RETURNS TRIGGER AS $$
DECLARE
    v_nombre SMALLINT;
    v_annee SMALLINT;
    v_table VARCHAR;
BEGIN
    v_annee := NEW.annee;
    v_table := 'cvae' || v_annee;
   
    SELECT count(*) INTO v_nombre FROM pg_tables WHERE pg_tables.tablename = v_table;
    IF ( v_nombre = 0 ) THEN
        -- Creation de la partition si elle n'existe pas
        EXECUTE 'CREATE TABLE ' || v_table || '( '
        || 'PRIMARY KEY (annee, idcvae), '
        || 'CONSTRAINT ' || v_table || '_annee_check CHECK (annee =  ' || v_annee  || '), '
        || 'CONSTRAINT ' || v_table || '_commune_fkey FOREIGN KEY (codecommunedpt) REFERENCES commune(codecommunedpt), '
        || 'CONSTRAINT ' || v_table || '_sousclasse_fkey FOREIGN KEY (codesousclasse) REFERENCES naf_sous_classe(codesousclasse), '
        || 'CONSTRAINT ' || v_table || '_voie_fkey FOREIGN KEY (codevoie, codecommunedpt) REFERENCES voie(codevoie, codecommunedpt), '
        || 'CONSTRAINT ' || v_table || '_formejuridique_fkey FOREIGN KEY (idformejuridique) REFERENCES forme_juridique(idformejuridique), '
        || 'CONSTRAINT ' || v_table || '_zone_fkey FOREIGN KEY (idzonage, idzone) REFERENCES zone(idzonage, idzone), '
        || 'CONSTRAINT ' || v_table || '_entreprise_fk FOREIGN KEY (siren) REFERENCES entreprise(siren), '
        || 'CONSTRAINT ' || v_table || '_etablissement_fkey FOREIGN KEY (siren, nic) REFERENCES etablissement(siren, nic)) '
        || 'INHERITS (cvae)';
   
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_commune ON ' || v_table || ' (CodeCommuneDpt)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_voie ON ' || v_table || ' (CodeVoie, CodeCommuneDpt)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_formejuridique ON ' || v_table || ' (IdFormeJuridique)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_entreprise ON ' || v_table || ' (SIREN)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_etablissement ON ' || v_table || ' (SIREN, NIC)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_nafsousclasse ON ' || v_table || ' (CodeSousClasse)';
        EXECUTE 'CREATE INDEX ifk_' || v_table || '_zone ON ' || v_table || ' (IdZonage, IdZone)';
        EXECUTE 'CREATE INDEX i_' || v_table || '_denomination ON ' || v_table || ' (Denomination)';
    END IF;

    EXECUTE 'INSERT INTO ' || v_table || ' VALUES ' || NEW.*;
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

Hors ligne

#6 16/07/2012 13:47:51

gleu
Administrateur

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

OK. Là, vous demandez en fait de transformer la ligne (NEW.*) en chaîne de caractères (opérateur || pour la concaténation). Ce que fait PostgreSQL, sans mettre de guillemets, ni sans faire d'échappements. Vous ne pourrez pas aller contre ce comportement. NEW.* n'est pas utilisable dans votre cas.


Guillaume.

Hors ligne

#7 16/07/2012 14:13:24

leTaz
Membre

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Il n'y a pas moyen de contourner ce comportement pour que le NEW soit interprété comme une commande et que son résultat ne soit pas traduit en chaîne de caractères ?

Hors ligne

#8 16/07/2012 17:03:56

gleu
Administrateur

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Non.


Guillaume.

Hors ligne

#9 16/07/2012 17:10:00

leTaz
Membre

Re : le NEW.* ne quote pas les chaînes de caractères dans un EXECUTE

Tant pis, j'aurai tenté.

Merci pour les réponses.

Arnaud.

Hors ligne

Pied de page des forums