用触发器函数替换删除:如何 return 影响行数?
Replace delete with trigger function: how to return affected row count?
标准delete from foo_history where id = 123;
return正文:
DELETE 1
我创建了一个触发器过程来替换删除触发器,而不是删除,设置一个存档标志:
CREATE FUNCTION archive()
RETURNS trigger AS $$
DECLARE
command text := '" SET timeEnd = current_timestamp WHERE id = ';
BEGIN
EXECUTE 'UPDATE "' || TG_TABLE_NAME || command USING OLD.id;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
然后为 foo_history
table 创建了一个名为 foo
:
的视图
CREATE VIEW foo AS
SELECT id, timeStart from foo_history WHERE timeEnd IS NULL;
并向视图添加触发器:
CREATE TRIGGER foo_archive INSTEAD OF DELETE ON foo FOR EACH ROW EXECUTE PROCEDURE archive();
换句话说,当删除 foo
记录时,改为设置 timeEnd
列 - 这样,foo
视图仅显示未设置 timeEnd
的记录。
这个效果很好:
delete from foo where id = 123
确实设置了 timeEnd
列。但是,此输出是:
DELETE 0
而我真的很想说:
DELETE 1
作为一名 SQL 新手和 Postgres 新手,我不确定如何更改存档功能来执行此操作。
我确实尝试将其更改为:
RETURN 1
但是我得到一个错误,关于我需要 return 一个复合材料(无论那意味着什么)。
当然,第二个我 post 这个,我有一个似乎可行的想法..
而不是RETURN NULL
,使用RETURN OLD
对不起...
您已经发现您需要 RETURN OLD
在 INSTEAD OF
触发器中进行 DELETE
操作以使行 count 在返回的 命令标记 中。手册:
A row-level INSTEAD OF
trigger should either return NULL
to indicate
that it did not modify any data from the view's underlying base
tables, or it should return the view row that was passed in (the NEW
row for INSERT
and UPDATE
operations, or the OLD
row for DELETE
operations). A nonnull return value is used to signal that the trigger
performed the necessary data modifications in the view. This will
cause the count of the number of rows affected by the command to be incremented.
大胆强调我的。
但是您的当前触发器中也有一个偷偷摸摸的 SQL 注入错误。 TG_TABLE_NAME
是没有引号的裸名。标识符必须被视为用户输入 - 并且在任何情况下都必须根据需要引用。在动态 SQL 语句中正确引用 table 名称(否则您可能会遭受后果)。一种方法是使用 format()
:
CREATE OR REPLACE FUNCTION archive()
RETURNS trigger AS
$func$
BEGIN
EXECUTE format('UPDATE %I SET time_end = current_timestamp WHERE id = ', TG_TABLE_NAME)
USING OLD.id;
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
相关:
- INSERT with dynamic table name in trigger function
- SQL injection in Postgres functions vs prepared queries
我还使用 time_end
而不是 timeEnd
,因为我的长期建议是避免在 Postgres 中使用 CaMeL 大小写标识符。相关:
- Are PostgreSQL column names case-sensitive?
标准delete from foo_history where id = 123;
return正文:
DELETE 1
我创建了一个触发器过程来替换删除触发器,而不是删除,设置一个存档标志:
CREATE FUNCTION archive()
RETURNS trigger AS $$
DECLARE
command text := '" SET timeEnd = current_timestamp WHERE id = ';
BEGIN
EXECUTE 'UPDATE "' || TG_TABLE_NAME || command USING OLD.id;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
然后为 foo_history
table 创建了一个名为 foo
:
CREATE VIEW foo AS
SELECT id, timeStart from foo_history WHERE timeEnd IS NULL;
并向视图添加触发器:
CREATE TRIGGER foo_archive INSTEAD OF DELETE ON foo FOR EACH ROW EXECUTE PROCEDURE archive();
换句话说,当删除 foo
记录时,改为设置 timeEnd
列 - 这样,foo
视图仅显示未设置 timeEnd
的记录。
这个效果很好:
delete from foo where id = 123
确实设置了 timeEnd
列。但是,此输出是:
DELETE 0
而我真的很想说:
DELETE 1
作为一名 SQL 新手和 Postgres 新手,我不确定如何更改存档功能来执行此操作。
我确实尝试将其更改为:
RETURN 1
但是我得到一个错误,关于我需要 return 一个复合材料(无论那意味着什么)。
当然,第二个我 post 这个,我有一个似乎可行的想法..
而不是RETURN NULL
,使用RETURN OLD
对不起...
您已经发现您需要 RETURN OLD
在 INSTEAD OF
触发器中进行 DELETE
操作以使行 count 在返回的 命令标记 中。手册:
A row-level
INSTEAD OF
trigger should either returnNULL
to indicate that it did not modify any data from the view's underlying base tables, or it should return the view row that was passed in (theNEW
row forINSERT
andUPDATE
operations, or theOLD
row forDELETE
operations). A nonnull return value is used to signal that the trigger performed the necessary data modifications in the view. This will cause the count of the number of rows affected by the command to be incremented.
大胆强调我的。
但是您的当前触发器中也有一个偷偷摸摸的 SQL 注入错误。 TG_TABLE_NAME
是没有引号的裸名。标识符必须被视为用户输入 - 并且在任何情况下都必须根据需要引用。在动态 SQL 语句中正确引用 table 名称(否则您可能会遭受后果)。一种方法是使用 format()
:
CREATE OR REPLACE FUNCTION archive()
RETURNS trigger AS
$func$
BEGIN
EXECUTE format('UPDATE %I SET time_end = current_timestamp WHERE id = ', TG_TABLE_NAME)
USING OLD.id;
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
相关:
- INSERT with dynamic table name in trigger function
- SQL injection in Postgres functions vs prepared queries
我还使用 time_end
而不是 timeEnd
,因为我的长期建议是避免在 Postgres 中使用 CaMeL 大小写标识符。相关:
- Are PostgreSQL column names case-sensitive?