Esta sección describe los detalles de bajo nivel de la interfaz para una función de disparo. Esta información sólo se necesita cuando se escriben funciones de disparo en C. Si estás utilizando un lenguaje de nivel superior, estos detalles se manejan por ti. En la mayoría de los casos, deberías considerar el uso de un lenguaje procedimental antes de escribir tus disparadores en C. La documentación de cada lenguaje procedimental explica cómo escribir un disparador en ese lenguaje.
Las funciones de disparo deben utilizar la interfaz del gestor de funciones “versión 1”.
Cuando una función es llamada por el administrador de disparadores, no se le pasan argumentos normales,
sino que se le pasa un puntero de “contexto” que apunta a una estructura
TriggerData. Las funciones en C pueden verificar si fueron llamadas desde el
administrador de disparadores o no ejecutando la macro:
CALLED_AS_TRIGGER(fcinfo)
que se expande a:
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
Si esto devuelve true, entonces es seguro convertir fcinfo->context al
tipo TriggerData * y hacer uso de la estructura TriggerData
a la que apunta. La función no debe alterar la estructura
TriggerData ni ninguno de los datos a los que apunta.
La estructura struct TriggerData está definida en
commands/trigger.h:
typedef struct TriggerData
{
NodeTag type;
TriggerEvent tg_event;
Relation tg_relation;
HeapTuple tg_trigtuple;
HeapTuple tg_newtuple;
Trigger *tg_trigger;
TupleTableSlot *tg_trigslot;
TupleTableSlot *tg_newslot;
Tuplestorestate *tg_oldtable;
Tuplestorestate *tg_newtable;
const Bitmapset *tg_updatedcols;
} TriggerData;
donde los miembros se definen de la siguiente manera:
type
Siempre T_TriggerData.
tg_event
Describe el evento para el cual se llama a la función. Puedes utilizar las siguientes macros
para examinar tg_event:
TRIGGER_FIRED_BEFORE(tg_event)Devuelve true si el disparador se activó antes de la operación.
TRIGGER_FIRED_AFTER(tg_event)Devuelve true si el disparador se activó después de la operación.
TRIGGER_FIRED_INSTEAD(tg_event)Devuelve true si el disparador se activó en lugar de la operación.
TRIGGER_FIRED_FOR_ROW(tg_event)Devuelve true si el disparador se activó para un evento a nivel de fila.
TRIGGER_FIRED_FOR_STATEMENT(tg_event)Devuelve true si el disparador se activó para un evento a nivel de sentencia.
TRIGGER_FIRED_BY_INSERT(tg_event)
Devuelve true si el disparador fue activado por un comando INSERT.
TRIGGER_FIRED_BY_UPDATE(tg_event)
Devuelve true si el disparador fue activado por un comando UPDATE.
TRIGGER_FIRED_BY_DELETE(tg_event)
Devuelve true si el disparador fue activado por un comando DELETE.
TRIGGER_FIRED_BY_TRUNCATE(tg_event)
Devuelve true si el disparador fue activado por un comando TRUNCATE.
tg_relation
Un puntero a una estructura que describe la relación para la cual se activó el disparador.
Consulta utils/rel.h para obtener detalles sobre esta estructura.
Lo más interesante es tg_relation->rd_att (descriptor de las tuplas de la relación)
y tg_relation->rd_rel->relname (nombre de la relación; el tipo no es
char* sino NameData; utiliza SPI_getrelname(tg_relation)
para obtener un char* si necesitas una copia del nombre).
tg_trigtuple
Un puntero a la fila para la cual se activó el disparador. Esta es la fila que se está insertando,
actualizando o eliminando. Si este disparador se activó para un INSERT o un
DELETE, esto es lo que debes devolver de la función si no deseas reemplazar
la fila con una diferente (en el caso de INSERT) o saltarte la operación.
Para disparadores en tablas foráneas, los valores de las columnas del sistema aquí no están especificados.
tg_newtuple
Un puntero a la nueva versión de la fila, si el disparador se activó para un UPDATE,
y NULL si es para un INSERT o un DELETE.
Esto es lo que debes devolver de la función si el evento es un UPDATE y no deseas
reemplazar esta fila por una diferente o saltarte la operación. Para disparadores en tablas foráneas,
los valores de las columnas del sistema aquí no están especificados.
tg_trigger
Un puntero a una estructura de tipo Trigger,
definida en utils/reltrigger.h:
typedef struct Trigger
{
Oid tgoid;
char *tgname;
Oid tgfoid;
int16 tgtype;
char tgenabled;
bool tgisinternal;
bool tgisclone;
Oid tgconstrrelid;
Oid tgconstrindid;
Oid tgconstraint;
bool tgdeferrable;
bool tginitdeferred;
int16 tgnargs;
int16 tgnattr;
int16 *tgattr;
char **tgargs;
char *tgqual;
char *tgoldtable;
char *tgnewtable;
} Trigger;
donde tgname es el nombre del disparador,
tgnargs es el número de argumentos en
tgargs, y tgargs es una matriz de
punteros a los argumentos especificados en la sentencia CREATE TRIGGER.
Los otros miembros son sólo para uso interno.
tg_trigslot
La ranura (slot) que contiene tg_trigtuple,
o un puntero NULL si no hay tal tupla.
tg_newslot
La ranura (slot) que contiene tg_newtuple,
o un puntero NULL si no hay tal tupla.
tg_oldtable
Un puntero a una estructura de tipo Tuplestorestate
que contiene cero o más filas en el formato especificado por
tg_relation, o un puntero NULL
if there is no OLD TABLE transition relation.
tg_newtable
Un puntero a una estructura de tipo Tuplestorestate
que contiene cero o más filas en el formato especificado por
tg_relation, o un puntero NULL
si no hay una relación de transición NEW TABLE.
tg_updatedcols
Para disparadores UPDATE, un conjunto de mapa de bits (bitmap)
que indica las columnas que fueron actualizadas por el comando que activó el disparador.
Las funciones de disparo genéricas pueden usar esto para optimizar acciones al no tener que
lidiar con columnas que no fueron modificadas.
Como ejemplo, para determinar si una columna con número de atributo
attnum (basado en 1) es miembro de este conjunto de mapa de bits,
llama a bms_is_member(attnum -
FirstLowInvalidHeapAttributeNumber,
trigdata->tg_updatedcols)).
Para disparadores que no sean de UPDATE, esto será
NULL.
Para permitir que las consultas emitidas a través de SPI hagan referencia a las tablas de transición, consulta SPI_register_trigger_data.
Una función de disparo debe devolver un puntero HeapTuple o un puntero
NULL (no un valor nulo de SQL, es decir, no establezcas
isNull en true). Asegúrate de devolver tg_trigtuple
o tg_newtuple, según corresponda, si no deseas modificar la fila
sobre la que se está operando.