Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
#1 04/01/2010 11:54:09
- mich30
- Membre
trigger
Bonjour
1) 1ere question
J'aimerez dans la table emp_audit creer un champ marequete de type text
et lorsque j'insere un enregistrement exemple insert into values emp ('hubert',12)
dans ma table emp_audit j'ai
operation I ok
tampon heure courante ok
id_utilisateur postgres ok
nom_employe hubert ok,
salaire 12
marequete ici "insert into values emp ('hubert',12)" possible ?
Merci et bonne année a tous
CREATE TABLE emp (
nom_employe text NOT NULL,
salaire integer
);
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
tampon timestamp NOT NULL,
id_utilisateur text NOT NULL,
nom_employe text NOT NULL,
salaire integer,
marequete text
);
CREATE OR REPLACE FUNCTION audit_employe() RETURNS TRIGGER AS $emp_audit$
BEGIN
--
-- Ajoute une ligne dans emp_audit pour refléter l'opération réalisée
-- sur emp,
-- utilise la variable spéciale TG_OP pour cette opération.
--
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; -- le résultat est ignoré car il s'agit d'un trigger AFTER
END;
$emp_audit$ language plpgsql;
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE audit_employe();
Hors ligne
#2 04/01/2010 12:16:18
- Marc Cousin
- Membre
Re : trigger
Il y a au moins cette solution là pour récupérer l'ordre SQL ayant appelé la fonction :
CREATE OR REPLACE FUNCTION fonction_test()
RETURNS text AS
$BODY$DECLARE
pa text;
BEGIN
SELECT current_query INTO pa from pg_stat_get_activity(pg_backend_pid());
RETURN pa;
END$BODY$
LANGUAGE 'plpgsql' VOLATILE;
Attention, le current_query est de taille limitée (1024 caractères jusqu'à 8.3, spécifié par track_activity_query_size à partir de 8.4)
Dernière modification par Marc Cousin (04/01/2010 12:16:58)
Marc.
Hors ligne
#3 04/01/2010 12:21:58
- wilka
- Membre
Re : trigger
Bonjour,
Pour cela il faut que vous recreez la requete.
en testant et concatenant les differentes valeurs contenues dans NEW et OLD.
si old.nom_employe est null alors il s'agit d'un INSERT
si new.nom_employee alors c'est un DELETE
pour les autres cas UPDATE
Apres vous reconstituez l'instruction, le probleme c'est que vous ne recuperez pas le where surtout si cela touche plusieurs records avec une seule requete, donc pas tres utilisable.
Le mieux est de stocker les anciennes valeurs (OLD) et les nouvelles (NEW) pour chaque lignes impactées par la requete
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
tampon timestamp NOT NULL,
id_utilisateur text NOT NULL,
nom_employe_old text ,
salaire_old integer,
nom_employe_new text ,
salaire_new integer
);
Hors ligne
#4 04/01/2010 12:25:05
- mich30
- Membre
Re : trigger
je vais mieux formuler ma demande ce n'est pas clair
est ce possible de concatener tous les paramétres OLD.*,new.* lors d'un insert ou update ou delete
et de les mettre dans un champ de type text tous_parametre dans la table emp_audit ?
OLD.* et NEW.* sont des record donc surement je peux patiner ce record pour recuperer
tous les enregistrements :
exemple si je fais insert into emp values ('hubert',12);
dans tous_parametre =' hubert,12'
Merci
CREATE TABLE emp (
nom_employe text NOT NULL,
salaire integer
);
drop TABLE emp_audit;
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
tampon timestamp NOT NULL,
id_utilisateur text NOT NULL,
nom_employe text NOT NULL,
salaire integer,
NOM_TABLE text,
tous_parametre TEXT,
);
CREATE OR REPLACE FUNCTION audit_employe() RETURNS TRIGGER AS $emp_audit$
BEGIN
--
-- Ajoute une ligne dans emp_audit pour refléter l'opération réalisée
-- sur emp,
-- utilise la variable spéciale TG_OP pour cette opération.
--
IF (TG_OP = 'DELETE') THEN
INSERT INTO emp_audit SELECT 'D', now(), user, OLD.*,TG_RELNAME;
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO emp_audit SELECT 'U', now(), user, NEW.*,TG_RELNAME;
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*,TG_RELNAME;
RETURN NEW;
END IF;
RETURN NULL; -- le résultat est ignoré car il s'agit d'un trigger AFTER
END;
$emp_audit$ language plpgsql;
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE audit_employe();
drop TRIGGER emp_audit on emp;
Hors ligne
#5 04/01/2010 12:27:03
- mich30
- Membre
Re : trigger
ok les posts sont arrivés avant mon dernier message j'y reflechis
la methode de marc je vais la tester
et wilka merci j'y reflechis
Hors ligne
#6 04/01/2010 12:32:58
- wilka
- Membre
Re : trigger
soit en utilsant la table que j'ai écris precedement
INSERT INTO emp_audit SELECT 'U', now(), user, OLD.nom_employe,OLD.salaire,NEW.nom_employe,NEW.salaire
Apres vous pouvez adapter en concatenant les valeurs (si c'est vraiment votre besoin), mais cela peut etre moins pratique pour les recherche
INSERT INTO emp_audit SELECT 'D', now(), user, OLD.nom_employe||';'||OLD.salaire::text,NEW.nom_employe||';'||NEW.salaire::text
avec cette table
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
tampon timestamp NOT NULL,
id_utilisateur text NOT NULL,
employe_old text ,
employe_new text
);
edit: petit oubli ^^
en testant les valeurs null sinon la concatenation avec du null, ce n'est pas terrible
case when OLD.nom_employe is null then '(null)' else OLD.nom_employe end||';'||case when OLD.salaire is null then '(null)'::text else OLD.salaire::text end
même chose a faire pour le new
Dernière modification par wilka (04/01/2010 12:40:26)
Hors ligne
#7 04/01/2010 12:37:21
- mich30
- Membre
Re : trigger
merci marc encore super
pour le trigger genre drop table create table create role le gere t'il
ou comment faut t'il contourner
merci
Hors ligne
#8 04/01/2010 12:42:36
- gleu
- Administrateur
Re : trigger
Il n'existe pas de moyen de récupérer les ordres de modification de structures.
Guillaume.
Hors ligne
#9 04/01/2010 12:45:15
- Marc Cousin
- Membre
Re : trigger
Pas de triggers sur les ordresDDL, pas de chance
Le mieux c'est d'interdire purement et simplement ces ordres aux utilisateurs.
Marc.
Hors ligne
#10 04/01/2010 15:14:39
- mich30
- Membre
Re : trigger
c'est ok
lorsque j'insere il y a un enregistrements dans la table audit ok
et lorsque je fait un update il y a 2 enregistrements update dans la table audit
c'est pas FOR EACH ROW du trigger ?
merci
CREATE OR REPLACE FUNCTION FCT_RECUP_REQUETE()
RETURNS text AS
$BODY$DECLARE
pa text;
BEGIN
SELECT current_query into pa from pg_stat_get_activity(pg_backend_pid());
RETURN pa;
END$BODY$
LANGUAGE 'plpgsql' VOLATILE;
CREATE OR REPLACE FUNCTION FCT_RECUP_CLIENT_ADDR()
RETURNS text AS
$BODY$DECLARE
pa text;
BEGIN
SELECT client_addr from into pa pg_stat_get_activity(pg_backend_pid());
RETURN pa;
END$BODY$
LANGUAGE 'plpgsql' VOLATILE;
/* test
insert into emp values ('mich',12);
update emp set libelle= 15;
select * from emp;
CREATE TABLE emp(
id text,
libelle integer
);
CREATE TABLE audit(
typ_operation char(1) NOT NULL,
Date_Systeme timestamp NOT NULL,
id_utilisateur text NOT NULL,
Nom_table text,
requete text,
client_addr text
);
CREATE OR REPLACE FUNCTION fct_audit() RETURNS TRIGGER AS $audit$
BEGIN
--
-- Ajoute une ligne dans emp_audit pour refléter l'opération réalisée
-- sur emp,
-- utilise la variable spéciale TG_OP pour cette opération.
--
IF (TG_OP = 'DELETE') THEN
INSERT INTO audit SELECT 'D', now(), user,TG_RELNAME,FCT_RECUP_REQUETE(),FCT_RECUP_CLIENT_ADDR();
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO audit SELECT 'U', now(), user,TG_RELNAME,FCT_RECUP_REQUETE(),FCT_RECUP_CLIENT_ADDR();
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO audit SELECT 'I', now(), user,TG_RELNAME,FCT_RECUP_REQUETE(),FCT_RECUP_CLIENT_ADDR();
RETURN NEW;
END IF;
RETURN NULL; -- le résultat est ignoré car il s'agit d'un trigger AFTER
END;
$audit$ language plpgsql;
CREATE TRIGGER trg_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE fct_audit();
Hors ligne
#11 04/01/2010 15:31:59
- gleu
- Administrateur
Re : trigger
« FOR EACH ROW » veut dire que le trigger s'exécute pour chaque ligne impactée. Donc si vous faites un UPDATE qui impacte deux lignes, le trigger se déclenchera pour chacune des lignes, donc deux fois.
Guillaume.
Hors ligne
#12 04/01/2010 15:34:14
- mich30
- Membre
Re : trigger
c'est bizarre je fais un insert dans emp je fais un update dans emp
dans la table audit j'ai un insert puis 2 lignes updates !!!
Hors ligne
#13 04/01/2010 15:42:46
- gleu
- Administrateur
Re : trigger
Une seule raison, il y avait déjà une ligne dans la table.
Guillaume.
Hors ligne
#14 04/01/2010 16:08:02
- mich30
- Membre
Re : trigger
non non il y avez juste un insert
Hors ligne
#15 04/01/2010 16:17:16
- gleu
- Administrateur
Re : trigger
Ce n'est pas possible avec le code que vous nous avez fourni ci-dessus. D'ailleurs, un test sur mon serveur donne ceci :
mich30=# insert into emp values ('mich',12);
INSERT 0 1
mich30=# update emp set libelle= 15;
UPDATE 1
mich30=# select * from emp;
id | libelle
------+---------
mich | 15
(1 ligne)
mich30=# select * from audit;
typ_operation | date_systeme | id_utilisateur | nom_table | requete | client_addr
---------------+----------------------------+----------------+-----------+-------------------------------------+-------------
I | 2010-01-04 15:16:27.387123 | guillaume | emp | insert into emp values ('mich',12); |
U | 2010-01-04 15:16:27.393092 | guillaume | emp | update emp set libelle= 15; |
(2 lignes)
Autrement dit, fonctionnel pour moi.
Guillaume.
Hors ligne
#16 04/01/2010 16:40:17
- mich30
- Membre
Re : trigger
zut !!! je reteste pas possible !!!
Hors ligne
#17 04/01/2010 16:51:47
- mich30
- Membre
Re : trigger
fait encore un insert puis un update tu verras il ya a 2 updates a la suite
merci
Hors ligne
#18 04/01/2010 16:57:11
- gleu
- Administrateur
Re : trigger
Même pas besoin de faire le test pour le savoir. Deux lignes dans la table, un UPDATE sur la table entière, donc deux lignes d'UPDATE dans la table d'audit. Rien que du logique.
Guillaume.
Hors ligne
#19 04/01/2010 17:03:07
- mich30
- Membre
Re : trigger
Guillaume,
ok merci ca m'embete un peu j'aurez aimé qui il y 'ai un update
si tu as 1000 enregistrements , et que je demande un update sur ces lignes
il va me mettre 1000 ligne updates alors que 1 update aurez suffit
FOR EACH STATEMENT serez pas mieux ?
merci
Hors ligne
#20 04/01/2010 17:05:58
- gleu
- Administrateur
Re : trigger
S'il ne faut qu'une insertion dans audit par instruction, il faut « EACH statement ». Mais vous ne pouvez plus regarder le contenu de OLD et de NEW dans ce cas... mais vu la fonction trigger, cela n'a pas d'importance actuellement.
Guillaume.
Hors ligne
#21 04/01/2010 17:10:40
- mich30
- Membre
Re : trigger
oui ca n'a pas d'importance ,
je viens de faire les tests c'est OK
je te remercie beaucoup
ce forum est super !!
A bientot pour de nouvelles avntures postgres
Mich
Hors ligne
#22 04/01/2010 18:20:56
- mich30
- Membre
Re : trigger
pour la 8.4 ca marche
Code:
CREATE OR REPLACE FUNCTION fonction_test()
RETURNS text AS
$BODY$DECLARE
pa text;
BEGIN
SELECT current_query INTO pa from pg_stat_get_activity(pg_backend_pid());
RETURN pa;
END$BODY$
LANGUAGE 'plpgsql' VOLATILE;
mais sur la 8.2 cette fonction ne marche pas
ERROR: function pg_stat_get_activity(integer) does not exist
LINE 1: SELECT current_query from pg_stat_get_activity(pg_backend_pid(...
j'ai pg_stat_activity mais pas le champ current query ? comme faire merci
Hors ligne
#23 04/01/2010 18:25:46
- mich30
- Membre
Re : trigger
je l'ai sur la 8.2
SELECT current_query from pg_stat_activity;
mais comment je gere le (pg_backend_pid());
merci
Hors ligne
#24 04/01/2010 18:35:30
- gleu
- Administrateur
Re : trigger
SELECT current_query from pg_stat_activity WHERE procpid=pg_backend_pid();
Guillaume.
Hors ligne
#25 07/01/2010 14:24:53
- mich30
- Membre
Re : trigger
merci gleu !!
Hors ligne