Se uma "fonte" não "enviar um identificador", a coluna não será alterada. Então você não pode detectar se o
UPDATE
atual foi feito pela mesma fonte que a última ou por uma fonte que não alterou em nada a coluna. Em outras palavras:isso não funciona corretamente. Se a "fonte" for identificável por qualquer função de informação de sessão, você pode trabalhar com isso. Como:
NEW.column = session_user;
Incondicionalmente para cada atualização.
Solução geral
Eu encontrei uma maneira de resolver o problema original. A coluna será definida como um valor padrão em qualquer update onde a coluna está não atualizada (não no
SET
lista de UPDATE
). O elemento-chave é um acionador por coluna introduzido no PostgreSQL 9.0 - um gatilho específico de coluna usando o
UPDATE OF
column_name
cláusula.
O gatilho só será acionado se pelo menos uma das colunas listadas for mencionada como destino doUPDATE
comando.
Essa é a única maneira simples que encontrei para distinguir se uma coluna foi atualizada com um novo valor idêntico ao antigo ou não atualizado.
Um poderia também analisa o texto retornado por
current_query()
. Mas isso parece complicado e não confiável. Funções de gatilho
Eu assumo uma coluna
col
definido NOT NULL
. Etapa 1: Definir
col
para NULL
se inalterado: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;
Etapa 2: Reverter para o valor antigo. O acionador só será acionado se o valor for realmente atualizado (ver abaixo):
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;
Etapa 3: Agora podemos identificar a atualização que falta e definir um valor padrão:
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;
Acionadores
O acionador da Etapa 2 é disparado por coluna!
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();
Nomes dos acionadores são relevantes, porque são disparados em ordem alfabética (todos sendo
BEFORE UPDATE
)! O procedimento pode ser simplificado com algo como "gatilhos por não-coluna" ou qualquer outra maneira de verificar a lista de destino de um
UPDATE
em um gatilho. Mas não vejo alça para isso. Se
col
pode ser NULL
, use qualquer outro valor intermediário "impossível" e verifique se há NULL
adicionalmente na função de disparo 1:IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
NEW.col := '#impossible_value#';
END IF;
Adapte o resto de acordo.