Si una "fuente" no "envía un identificador", la columna permanecerá sin cambios. Entonces no puede detectar si el UPDATE
actual fue realizada por la misma fuente que la última o por una fuente que no cambió la columna en absoluto. En otras palabras:esto no funciona correctamente.
Si la "fuente" es identificable por cualquier función de información de sesión, puede trabajar con eso. Me gusta:
NEW.column = session_user;
Incondicionalmente para cada actualización.
Solución general
Encontré una manera de resolver el problema original. La columna se establecerá en un valor predeterminado en cualquiera actualizar donde la columna no está actualizada (no en el SET
lista de UPDATE
).
El elemento clave es un gatillo por columna introducido en PostgreSQL 9.0:un disparador específico de columna que usa UPDATE OF
column_name
cláusula.
El activador solo se activará si al menos una de las columnas enumeradas se menciona como objetivo de la UPDATE
comando.
Esa es la única forma sencilla que encontré para distinguir si una columna se actualizó con un nuevo valor idéntico al anterior o si no se actualizó en absoluto.
Uno podría también analiza el texto devuelto por current_query()
. Pero eso parece engañoso y poco confiable.
Funciones de activación
Asumo una columna col
definido NOT NULL
.
col
a NULL
si no cambia:
CREATE OR REPLACE FUNCTION trg_tbl_upbef_step1()
RETURNS trigger AS
$func$
BEGIN
IF OLD.col = NEW.col THEN
NEW.col := NULL; -- "impossible" value
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION trg_tbl_upbef_step2()
RETURNS trigger AS
$func$
BEGIN
IF NEW.col IS NULL THEN
NEW.col := OLD.col;
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Paso 3: Ahora podemos identificar la actualización que falta y establecer un valor predeterminado en su lugar:
CREATE OR REPLACE FUNCTION trg_tbl_upbef_step3()
RETURNS trigger AS
$func$
BEGIN
IF NEW.col IS NULL THEN
NEW.col := 'default value';
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Disparadores
El desencadenante del Paso 2 se dispara por columna!
CREATE TRIGGER upbef_step1
BEFORE UPDATE ON tbl
FOR EACH ROW
EXECUTE PROCEDURE trg_tbl_upbef_step1();
CREATE TRIGGER upbef_step2
BEFORE UPDATE OF col ON tbl -- key element!
FOR EACH ROW
EXECUTE PROCEDURE trg_tbl_upbef_step2();
CREATE TRIGGER upbef_step3
BEFORE UPDATE ON tbl
FOR EACH ROW
EXECUTE PROCEDURE trg_tbl_upbef_step3();
Nombres de activadores son relevantes, porque se activan en orden alfabético (todos son BEFORE UPDATE
)!
El procedimiento podría simplificarse con algo como "disparadores por columna" o cualquier otra forma de verificar la lista de objetivos de un UPDATE
en un gatillo. Pero no veo ningún mango para esto.
Si col
puede ser NULL
, use cualquier otro valor intermedio "imposible" y busque NULL
adicionalmente en la función de activación 1:
IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
NEW.col := '#impossible_value#';
END IF;
Adapte el resto en consecuencia.