PostgreSQL
La base de données la plus sophistiquée au monde.

Ouverture de session

Navigation

Contactez-nous

Administration du site :
"equipe chez postgresqlfr point org"

Contact presse :
"fr chez postgresql point org"

Contact association :
"bureau chez postgresqlfr point org"

Questions PostgreSQL :
 IRC :
  serveur irc.freenode.net
  canal #postgresqlfr

Recherche

Accéder aux archives

« Octobre 2008  
Lun Mar Mer Jeu Ven Sam Dim
  2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31  

Syndication

Flux XML

Sondage

Quelle est la version de PostgreSQL la plus répandue sur vos serveurs ?
8.3
10%
8.2
42%
8.1
40%
8.0
2%
7.4
6%
7.3 ou antérieure
0%
Nombre de votes: 48

[plpgSQL][Déclencheur / Trigger en cascade] perte / changement de NEW

Technique - Langages Procéduraux (PL) | [plpgSQL][Déclencheur / Trigger en cascade] perte / changement de NEW

Par mesange le 28/07/2008 - 16:13

Bonjour,

Voilà dans l'exemple suivant quand je rentre dans le if de la fonction "function_update_pds_salles_valide_before()", et alors qu'aucune modification n'est apporté à NEW dans la fonction, si NEW.valide était égale à 1 au début de la fonction celui-ci est égale à 0 au moment du return avant le END IF; et inversement si il était égale à 0 celui-ci est égale à 1 à la fin...
Donc si je cherche à faire un update du champs valide d'un enregistrement de pds_salles celui n'est pas modifié... --> "La requête a été exécutée avec succés : 0 lignes modifiées. La requête a été exécutée en 1453594 ms."

J'ai eu beau chercher je ne trouve pas d'explication... please help ;-)

le seul trigger de pds_salles :

----------------------------------------------------------------
CREATE TRIGGER update_pds_salles_valide_before
BEFORE UPDATE
ON pds_salles
FOR EACH ROW
EXECUTE PROCEDURE function_update_pds_salles_valide_before();
----------------------------------------------------------------

sa fonction associé :

---------------------------------------------------------------------
CREATE OR REPLACE FUNCTION function_update_pds_salles_valide_before()
RETURNS trigger AS
$BODY$DECLARE
new_valide INTEGER;
old_valide INTEGER;
old_id INTEGER;

BEGIN
new_valide := NEW.valide;
old_valide := OLD.valide;
old_id := OLD.id;
IF (old_valide <> new_valide) THEN
BEGIN
UPDATE pds_tables SET valide = new_valide WHERE id IN (SELECT id_table FROM relations_tables_salle WHERE id_salle = old_id);
UPDATE pds_murs SET valide = new_valide WHERE id IN (SELECT id_mur FROM relations_murs_salle WHERE id_salle = old_id);
END;
RETURN NEW;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION function_update_pds_salles_valide_before() OWNER TO mesange;
----------------------------------------------------------------------------

Les deux triggers sur pds_tables :
---------------------------------------------------------
CREATE TRIGGER update_pds_tables_after
AFTER UPDATE
ON pds_tables
FOR EACH ROW
EXECUTE PROCEDURE function_update_pds_tables_after();
---------------------------------------------------------

---------------------------------------------------------------
CREATE TRIGGER update_pds_tables_valide_before
BEFORE UPDATE
ON pds_tables
FOR EACH ROW
EXECUTE PROCEDURE function_update_pds_tables_valide_before();
----------------------------------------------------------------

Et les deux fonctions associés :
-----------------------------------------------------------------
CREATE OR REPLACE FUNCTION function_update_pds_tables_after()
RETURNS trigger AS
$BODY$DECLARE
BEGIN
UPDATE pds_salles SET nbcvt = (SELECT SUM(nbcvt) FROM pds_tables WHERE id IN (SELECT id_table FROM relations_tables_salle WHERE id_salle = pds_salles.id)) WHERE id = (SELECT id_salle FROM relations_tables_salle WHERE id_table = NEW.id);
RETURN NULL;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION function_update_pds_tables_after() OWNER TO mesange;
---------------------------------------------------------------------

----------------------------------------------------------------------
CREATE OR REPLACE FUNCTION function_update_pds_tables_valide_before()
RETURNS trigger AS
$BODY$
BEGIN
IF (NEW.valide <> 1) THEN
UPDATE pds_tables SET id_table_next = -1 WHERE id_table_next = NEW.id;
UPDATE pds_tables SET id_table_prev = -1 WHERE id_table_prev = NEW.id;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION function_update_pds_tables_valide_before() OWNER TO mesange;
-----------------------------------------------------------------------------

Il n'y a pas de trigger sur pds_murs.

Version de postgresql : PostgreSQL 8.3.1

En espérant avoir été clair...

merci d'avance ;-)

Options d'affichage des commentaires

Sélectionnez la méthode d'affichage des commentaires que vous préférez, puis cliquez sur "Sauvegarder les paramètres" pour activer vos changements.

Le trigger s'appelle lui-même

SAS/ = 28 Juillet, 2008 - 17:09

Bonjour,

Il me semble que votre trigger modifie lui-même la table sur laquelle il porte. Cela introduit un énorme risque de le voir faire n'importe quoi au final.

Librement,
Stéphane Schildknecht
Dalibo
PostgreSQLFr


Merci pour votre réponse.

mesange/ = 28 Juillet, 2008 - 17:32

Merci pour votre réponse.

Le trigger de pds_tables ne modifie lui que le champs nbcvt de pds_salles et donc ne rentrera pas dans le if de la fonction du trigger de pds_salles. Et il me semblait qu'au mot clef END; les modifications de la fonction était commité sur la base donc quand on revient à la première instance de la fonction du trigger de pds_salles les modifications à nbcvt ont déjà du être faites en base... non ?

Cordialement


Relance

mesange/ = 29 Juillet, 2008 - 11:52

Personne n'aurait une explication... ?


Précision

SAS/ = 4 Août, 2008 - 17:54

Ce n'est pas parce que vous atteignez le END de votre fonction associée au trigger que la transaction est terminée, et que vos données sont dans écrites dans la table durablement.

Librement,
Stéphane Schildknecht
Dalibo
PostgreSQLFr


Une solution

mesange/ = 10 Septembre, 2008 - 17:57

J'ai réussit à me sortir de l'impasse.

Comme cela est conseillé dans la documentation officiel de Postgresql il ne faut pas mettre de requete de modification d'autres tables dans un fonction trigger à déclenchement BEFORE mais dans un trigger à déclenchement AFTER ! :
"Typiquement, les déclencheurs avant en mode ligne sont utilisés pour vérifier ou modifier les données qui seront insérées ou mises à jour. Par exemple, un déclencheur avant pourrait être utilisé pour insérer l'heure actuelle dans une colonne de type timestamp ou pour vérifier que deux éléments d'une ligne sont cohérents. Les déclencheurs après en mode ligne sont pour la plupart utilisés pour propager des mises à jour vers d'autres tables ou pour réaliser des tests de cohérence avec d'autres tables. La raison de cette division du travail est qu'un déclencheur après peut être certain qu'il voit la valeur finale de la ligne alors qu'un déclencheur avant ne l'est pas ; il pourrait exister d'autres déclencheurs avant qui seront exécutés après lui. Si vous n'avez aucune raison spéciale pour le moment du déclenchement, le cas avant est plus efficace car l'information sur l'opération n'a pas besoin d'être sauvegardée jusqu'à la fin du traitement."

Voilà maintenant ça fonctionne, même si je ne comprends pas réellement pourquoi cela ne fonctionnait pas avant...

J'espère que cela pourra aider d'autres personnes. Merci à SAS pour son aide ;-)

@ Bientôt


© PostgreSQLFr, tous droits réservés.
Site déclaré à la CNIL sous le numéro 1074678, conformément à la Loi en vigueur.