42.6. Funciones de disparo (Triggers) en PL/Tcl #

Las funciones de disparo se pueden escribir en PL/Tcl. PostgreSQL requiere que una función que se va a llamar como disparador se declare como una función sin argumentos y con un tipo de retorno de trigger.

La información del gestor de disparadores se pasa al cuerpo de la función en las siguientes variables:

$TG_name

El nombre del disparador de la sentencia CREATE TRIGGER.

$TG_relid

El ID de objeto de la tabla que causó la invocación de la función de disparo.

$TG_table_name

El nombre de la tabla que causó la invocación de la función de disparo.

$TG_table_schema

El esquema de la tabla que causó la invocación de la función de disparo.

$TG_relatts

Una lista de Tcl con los nombres de las columnas de la tabla, con un elemento de lista vacío como prefijo. De modo que buscar un nombre de columna en la lista con el comando lsearch de Tcl devuelve el número del elemento comenzando con 1 para la primera columna, de la misma manera que las columnas se numeran habitualmente en PostgreSQL. (Los elementos de lista vacíos también aparecen en las posiciones de las columnas que han sido eliminadas, de modo que la numeración de atributos es correcta para las columnas a su derecha).

$TG_when

La cadena BEFORE, AFTER o INSTEAD OF, según el tipo de evento del disparador.

$TG_level

La cadena ROW o STATEMENT, según el tipo de evento del disparador.

$TG_op

La cadena INSERT, UPDATE, DELETE o TRUNCATE, según el tipo de evento del disparador.

$NEW

Un array asociativo que contiene los valores de la nueva fila de la tabla para las acciones INSERT o UPDATE, o vacío para DELETE. El array está indexado por el nombre de la columna. Las columnas que son null no aparecerán en el array. Esto no se establece para los disparadores a nivel de sentencia.

$OLD

Un array asociativo que contiene los valores de la antigua fila de la tabla para las acciones UPDATE o DELETE, o vacío para INSERT. El array está indexado por el nombre de la columna. Las columnas que son null no aparecerán en el array. Esto no se establece para los disparadores a nivel de sentencia.

$args

Una lista de Tcl con los argumentos de la función tal como se proporcionan en la sentencia CREATE TRIGGER. Estos argumentos también son accesibles como $1 ... $n en el cuerpo de la función.

El valor de retorno de una función de disparo puede ser una de las cadenas OK o SKIP, o una lista de pares nombre/valor de columna. Si el valor de retorno es OK, la operación (INSERT/UPDATE/DELETE) que activó el disparador continuará normalmente. SKIP le dice al gestor de disparadores que suprima silenciosamente la operación para esta fila. Si se devuelve una lista, le dice a PL/Tcl que devuelva una fila modificada al gestor de disparadores; los contenidos de la fila modificada se especifican mediante los nombres de las columnas y los valores en la lista. Cualquier columna no mencionada en la lista se establece en null. Devolver una fila modificada solo es significativo para disparadores a nivel de fila BEFORE INSERT o UPDATE, para los cuales la fila modificada se insertará en lugar de la proporcionada en $NEW; o para disparadores a nivel de fila INSTEAD OF INSERT o UPDATE donde la fila devuelta se utiliza como datos de origen para las cláusulas INSERT RETURNING o UPDATE RETURNING. En disparadores a nivel de fila BEFORE DELETE o INSTEAD OF DELETE, devolver una fila modificada tiene el mismo efecto que devolver OK, es decir, la operación continúa. El valor de retorno del disparador se ignora para todos los demás tipos de disparadores.

Tip

La lista de resultados se puede crear a partir de una representación en array de la tupla modificada con el comando Tcl array get.

Aquí tienes un pequeño ejemplo de función de disparo que fuerza a un valor entero en una tabla a realizar un seguimiento del número de actualizaciones que se realizan en la fila. Para las nuevas filas insertadas, el valor se inicializa a 0 y luego se incrementa en cada operación de actualización.

CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS $$
    switch $TG_op {
        INSERT {
            set NEW($1) 0
        }
        UPDATE {
            set NEW($1) $OLD($1)
            incr NEW($1)
        }
        default {
            return OK
        }
    }
    return [array get NEW]
$$ LANGUAGE pltcl;

CREATE TABLE mytab (num integer, description text, modcnt integer);

CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
    FOR EACH ROW EXECUTE FUNCTION trigfunc_modcount('modcnt');

Observa que la función de disparo en sí no conoce el nombre de la columna; se proporciona a partir de los argumentos del disparador. Esto permite que la función de disparo se reutilice con diferentes tablas.