Professional Documents
Culture Documents
Pgina 1 de 2
Siguiente
Triggers (disparadores)
Postgres tiene algunas interfaces cliente como Perl, Tcl, Python y C, as como dos Lenguajes Procedurales (PL). Tambin es posible llamar a funciones C como acciones trigger. Notar que los eventos trigger a nivel STATEMENT no estn soportados en la versin actual. Actualmente es posible especificar BEFORE o AFTER en los INSERT, DELETE o UPDATE de un registro como un evento trigger.
Creacin de Triggers
Si un evento trigger ocurre, el administrador de triggers (llamado Ejecutor) inicializa la estructura global TriggerData *CurrentTriggerData (descrita ms abajo) y llama a la funcin trigger para procesar el evento. La funcin trigger debe ser creada antes que el trigger, y debe hacerse como una funcin sin argumentos, y cdigos de retorno opacos. La sintaxis para la creacin de triggers es la siguiente:
CREATE TRIGGER <trigger name> <BEFORE|AFTER> <INSERT|DELETE|UPDATE> ON <relation name> FOR EACH <ROW|STATEMENT> EXECUTE PROCEDURE <procedure name> (<function args>);
El nombre del trigger se usar si se desea eliminar el trigger. Se usa como argumento del comando DROP TRIGGER. La palabra siguiente determina si la funcin debe ser llamada antes (BEFORE) o despus (AFTER) del evento. El siguiente elemento del comando determina en que evento/s ser llamada la funcin. Es posible especificar mltiples eventos utilizado el operador OR. El nombre de la relacin (relation name) determinar la tabla afectada por el evento. La instruccin FOR EACH determina si el trigger se ejecutar para cada fila afectada o bien antes (o despus) de que la secuencia se haya completado. El nombre del procedimiento (procedure name) es la funcin C llamada. Los argumentos son pasados a la funcin en la estructura CurrentTriggerData. El propsito de pasar los argumentos a la funcin es permitir a triggers diferentes con requisitos similares llamar a la misma funcin. Adems, la funcin puede ser utilizada para disparar distintas relaciones (estas funciones son llamadas "general trigger funcions"). Como ejemplo de utilizacin de lo descrito, se puede hacer una funci n general que toma como argumentos dos nombres de campo e inserta el nombre del usuario y la fecha (timestamp) actuales en ellos. Esto permite, por ejemplo, utilizar los triggers en los eventos INSERT para realizar un http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/triggers.html 20/10/2002
Triggers (disparadores)
Pgina 2 de 2
seguimiento automtico de la creacin de registros en una tabla de transacciones. Se podra utilizar tambin para registrar actualizaciones si es utilizado en un evento UPDATE. Las funciones trigger retornan un rea de tuplas (HeapTuple) al ejecutor. Esto es ignorado para trigger lanzados tras (AFTER) una operacin INSERT, DELETE o UPDATE, pero permite lo siguiente a los triggers BEFORE: - retornar NULL e ignorar la operacin para la tupla actual (y de este modo la tupla no ser insertada/actualizada/borrada); - devolver un puntero a otra tupla (solo en eventos INSERT y UPDATE) que sern insertados (como la nueva versin de la tupla actualizada en caso de UPDATE) en lugar de la tupla original. Notar que no hay inicializacin por parte del CREATE TRIGGER handler. Esto ser cambiado en el futuro. Adems, si m s de un trigger es definido para el mismo evento en la misma relacin, el orden de ejecucin de los triggers es impredecible. Esto puede ser cambiado en el futuro. Si una funcin trigger ejecuta consultas SQL (utilizando SPI) entonces estas funciones pueden disparar nuevos triggers. Esto es conocido como triggers en cascada. No hay ninguna limitacin explicita en cuanto al nmero de niveles de cascada. Si un trigger es lanzado por un INSERT e inserta una nueva tupla en la misma relacin, el trigger ser llamado de nuevo (por el nuevo INSERT). Actualmente, no se proporciona ningn mecanismo de sincronizacin (etc) para estos casos pero esto puede cambiar. Por el momento, existe una funcin llamada funny_dup17() en los tests de regresin que utiliza algunas tcnicas para parar la recursividad (cascada) en si misma... Anterior SunOS 4.x, Solaris 2.x y HP-UX Inicio Siguiente Interaccin con el Trigger Manager
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/triggers.html
20/10/2002
Interaccin con el Trigger Manager Guia del Programador de PostgreSQL Triggers (disparadores)
Pgina 1 de 2
Anterior
Siguiente
es disparado el trigger, esto es, la INSERT), borrando (DELETE) o lo que se debe devolver al Ejecutor si otra (INSERT) o ignorar la operacin.
tg_newtuple es un puntero a la nueva tupla en caso de UPDATE y NULL si es para un INSERT o un DELETE. Esto es lo que debe devolverse al Ejecutor en el caso de un UPDATE si no se desea reemplazar la tupla por otra o ignorar la operacin. tg_trigger es un puntero a la estructura Trigger definida en src/include/utils/rel.h: typedef struct Trigger {
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2014.html
20/10/2002
Pgina 2 de 2
tgname es el nombre del trigger, tgnargs es el nmero de argumentos en tgargs, tgargs es un array de punteros a los argumentos especificados en el CREATE TRIGGER. Otros miembros son exclusivamente para uso interno.
Inicio Subir
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2014.html
20/10/2002
Pgina 1 de 1
Anterior
Siguiente
las tuplas insertadas son invisibles para el propio SELECT. En efecto, esto duplica la tabla dentro de s misma (sujeto a las reglas de ndice nico, por supuesto) sin recursividad. Pero hay que recordar esto sobre visibilidad en la documentacin de SPI:
Los cambios hechos por la consulta Q son visibles por las consultas que empiezan tras la consulta Q, no importa si son iniciados desde Q (durante su ejecucin) o una vez ha acabado.
Esto es vlido tambin para los triggers, as mientras se inserta una tupla (tg_trigtuple) no es visible a las consultas en un trigger BEFORE, mientras que esta tupla (recin insertada) es visible a las consultas de un trigger AFTER, y para las consultas en triggers BEFORE/AFTER lanzados con posterioridad! Anterior Interaccin con el Trigger Manager Inicio Subir Siguiente Ejemplos
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2020.html
20/10/2002
Pgina 1 de 4
Anterior
Siguiente
Ejemplos
Hay ejemplos ms complejos en src/test/regress/regress.c y en contrig/spi. He aqu un ejemplo muy sencillo sobre el uso de triggers. La funcin trigf devuelve el nmero de tuplas en la relacin ttest e ignora la operaci n si la consulta intenta insertar NULL en x (i.e - acta como una restriccin NOT NULL pero no aborta la transaccin).
#include "executor/spi.h" #include "commands/trigger.h" HeapTuple HeapTuple trigf() { TupleDesc HeapTuple char bool bool int /* Necesario para trabajar con SPI */ /* -"- y triggers */
trigf(void);
if (!CurrentTriggerData) elog(WARN, "trigf: triggers sin inicializar"); /* tupla para devolver al Ejecutor */ if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event)) rettuple = CurrentTriggerData->tg_newtuple; else rettuple = CurrentTriggerData->tg_trigtuple; /* comprobar NULLs ? */ if (!TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event) && TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event)) checknull = true; if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event)) when = "antes "; else when = "despus "; tupdesc = CurrentTriggerData->tg_relation->rd_att; CurrentTriggerData = NULL; /* Conexin al gestor SPI */ if ((ret = SPI_connect()) < 0) elog(WARN, "trigf (lanzado %s): SPI_connect devolvi %d", when, ret); /* Obtiene el nmero de tuplas en la relacin */ ret = SPI_exec("select count(*) from ttest", 0); if (ret < 0) elog(WARN, "trigf (lanzado %s): SPI_exec devolvi %d", when, ret); i = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull); elog (NOTICE, "trigf (lanzado %s): hay %d tuplas en ttest", when, i);
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2028.html
20/10/2002
Ejemplos
Pgina 2 de 4
SPI_finish(); if (checknull) { i = SPI_getbinval(rettuple, tupdesc, 1, &isnull); if (isnull) rettuple = NULL; } return (rettuple); }
Ahora, compila y create table ttest (x int4); create function trigf () returns opaque as '...path_to_so' language 'c';
vac=> create for each row CREATE vac=> create for each row CREATE vac=> insert NOTICE:trigf INSERT 0 0 trigger tbefore before insert or update or delete on ttest execute procedure trigf(); trigger tafter after insert or update or delete on ttest execute procedure trigf(); into ttest values (null); (fired before): there are 0 tuples in ttest
-- Insertion skipped and AFTER trigger is not fired vac=> select * from ttest; x (0 rows) vac=> insert into ttest values (1); NOTICE:trigf (fired before): there are 0 tuples in ttest NOTICE:trigf (fired after ): there are 1 tuples in ttest ^^^^^^^^ remember what we said about visibility. INSERT 167793 1 vac=> select * from ttest; x 1 (1 row) vac=> insert into ttest select x * 2 from ttest; NOTICE:trigf (fired before): there are 1 tuples in ttest NOTICE:trigf (fired after ): there are 2 tuples in ttest ^^^^^^^^ remember what we said about visibility. INSERT 167794 1 vac=> select * from ttest; x 1 2 (2 rows) vac=> update NOTICE:trigf UPDATE 0 vac=> update NOTICE:trigf NOTICE:trigf ttest set x = null where x = 2; (fired before): there are 2 tuples in ttest ttest set x = 4 where x = 2; (fired before): there are 2 tuples in ttest (fired after ): there are 2 tuples in ttest
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2028.html
20/10/2002
Ejemplos
UPDATE 1 vac=> select * from ttest; x 1 4 (2 rows) vac=> delete NOTICE:trigf NOTICE:trigf NOTICE:trigf NOTICE:trigf from ttest; (fired before): (fired after ): (fired before): (fired after ):
Pgina 3 de 4
Nota
Aportacin del traductor.Manuel Mart nez Valls En la version 6.4 ya existian los triggers, lo que eran triggers para tuplos, (FOR EACH ROW) pero no para sentencias (FOR STATEMENT), por eso creo que es importante poner disparadores para sentencias, no disparadores solo. Los trigger son parte de lo que se conoce como "elementos activos" de una BD. Asi como lo son las constraints tales como NOT NULL, FOREIGN KEY, PRIMARY KEY, CHECK. Una vez definidas ellas "se activaran" solo al ocurrir un evento que las viole, un valor nulo en un campo con NOT NULL, etc Por que entonces llamar triggers a los triggers? ;Con ellos se quizo dar mas control al programador sobre los eventos que desencadenan un elemento activo, se le conoce en ingles como ECA rules o event-condition-action rule. Es por ello que los triggers tienen una clausula BEFORE, AFTER o INSTEAD (por cierto pgsql no tiene INSTEAD) y bajo que evento (INSERT, UPDATE, DELETE) pero de esta forma el trigger se ejecutara para tuplo (o fila) sometido al evento (clausula FOR EACH ROW) pero el standard (que pgsql no cubre completamente) dice que puede ser tambien FOR EACH SENTENCE. Esto provoca que se ejecute el trigger para toda la relacion (o tabla) para la cual se define (clausula ON). La diferencia para los que lo han programado, por ejemplo en plpgsql, queda clara entonces: cuando es FOR EACH ROW en la funcion pgsql que implementa el trigger se tiene un objeto NEW y uno OLD que se refiere a la tupla completa, en el trigger de STATEMENT tiene un objeto NEW y OLD que son la relacion (o tabla) completa Esta claro entonces que es un poco mas dificil implementar un trigger para statement que para fila (todavia pgsql no lo tiene). Finalmente este es un buen ejemplo de que por que pgsql dice que "implementa un subconjunto extendido de SQL92", no hay trigger en SQL92, son del SQL3.
Anterior
Inicio
Siguiente
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2028.html
20/10/2002
http://lucas.hispalinux.es/Postgresql-es/web/navegable/programmer/x2028.html
20/10/2002