How to get update statement in trigger function or when condition

时间:2016-02-03 03:19:38

标签: postgresql triggers

CREATE TABLE accounts (
 id SERIAL PRIMARY KEY,
 email TEXT,
 verified BOOLEAN DEFAULT FALSE,
 ...
);

CREATE OR REPLACE FUNCTION fn_reset_verified() RETURNS TRIGGER AS $$
BEGIN 
IF (
    OLD.email != NEW.email -- do nothing if no change
) THEN
    RAISE NOTICE 'UPDATE';
    UPDATE users SET verified=FALSE WHERE id=NEW.id;
END IF;
RETURN NEW;
END; $$ language 'plpgsql';

CREATE TRIGGER reset_verified AFTER UPDATE OF email ON accounts
FOR EACH ROW
WHEN (OLD.email != NEW.email) -- only when email changed
EXECUTE PROCEDURE fn_reset_verified();

Based on above schema, I wish to create trigger to automatic update verified to false if user change email. It work well for below statement:

UPDATE accounts SET email='newemail@email.com' WHERE id=1;

My problem come in when I intend update the email and set verified to TRUE at same time like below statement:

UPDATE accounts SET email='verified@email.com', verified=TRUE WHERE id=1;

If verified is been set in update statement, I should skip the function. Maybe condition as below:

WHEN (OLD.email != NEW.email AND STATEMENT.verified IS NULL)

So is there any way I can get the update statement or involved column?

1 个答案:

答案 0 :(得分:0)

首先,您不应该在该表的更新触发器中的表上调用UPDATE。有可能你将无限循环(不是在这种特殊情况下,但无论如何),通常有更好的方法来实现同样的事情。

在您的情况下,您会在电子邮件地址更改时触发BEFORE UPDATE触发器,并检查/修改该触发器中的verified列:

CREATE OR REPLACE FUNCTION fn_reset_verified() RETURNS TRIGGER AS $$
BEGIN 
    -- Below condition does not have to be checked because of WHEN clause in trigger
IF (
    OLD.email != NEW.email -- do nothing if no change
) THEN
    RAISE NOTICE 'UPDATE';
    NEW.verified := ...;
END IF;
    RETURN NEW;
END; $$ language 'plpgsql';

CREATE TRIGGER reset_verified BEFORE UPDATE OF email ON accounts
FOR EACH ROW
WHEN (OLD.email != NEW.email) -- only when email changed
EXECUTE PROCEDURE fn_reset_verified();

但是,没有逻辑可以确定在触发器内设置NEW.verified的内容。问题是,NEW变量在设置具有新值的列之后保存新行的所有列的值,而不仅仅是由命令修改的那些值。因此,如果NEW.verified = true无法知道调用触发器的命令是否为:

UPDATE accounts SET email = 'newemail@email.com', verified = true WHERE id = 1;

UPDATE accounts SET email = 'newemail@email.com' WHERE id = 1;

因此NEW.verified可以引用旧的电子邮件地址或新的电子邮件地址,该地址在UPDATE命令中专门标记为已验证。

您唯一的选择是更改您的逻辑:如果电子邮件地址发生变化,则需要在之后进行验证,因此NEW.verified = false