postgres insert triggers and/or 可以在不插入的情况下检查 运行
Can postgres insert triggers and/or check be ran without inserting
我希望能够使用数据库的现有约束(引发异常和检查的触发器)来验证代表 table 行的对象,而无需将它们实际插入到数据库中。
目前有没有一种方法可以在 postgres 中做到这一点?至少对于 BEFORE INSERT
触发器和 CHECK
,我认为它对于 AFTER INSERT
触发器没有意义。
我能想到或现在最简单的方法是:
- 锁定table
- 插入一个新行
- 如果异常引发 API / 否则删除该行并将其称为有效
- 解锁
但我可以看到几个问题。
更简单的方法是在事务中插入而不提交:
BEGIN;
INSERT INTO tbl(...) VALUES (...);
-- see effects ...
ROLLBACK;
无需额外锁定。该行对于具有默认事务隔离级别 READ COMMITTED
的任何其他事务永远不可见。 (您可能会停止与测试行冲突的并发写入。)
Notable side-effect:即使 INSERT
从未提交,serial
或 IDENTITY
列的序列也会被推进。但无论如何,序列号之间的差距是可以预料的,无需担心。
警惕 side-effect 的触发器。所有“事务性”SQL 效果都会回滚,甚至大多数 DDL 命令也是如此。但一些特殊操作(如推进序列)永远不会回滚。
此外,DEFERRED
约束不会生效。The manual:
DEFERRED
constraints are not checked until transaction commit.
如果您经常需要它,请使用您的 table 甚至您的数据库的副本。
严格来说,虽然允许任何触发器/约束/并发事件,但除了将它们插入实际目标数据库中的实际目标 table 之外,没有其他方法可以“验证对象”时间点。触发器、约束,甚至默认值,都可以与整个数据库的当前状态交互。排除的可能性越多,要求越低,我们模拟测试的选项就越多。
CREATE FUNCTION validate_function ( )
RETURNS trigger LANGUAGE plpgsql
AS $function$
DECLARE
valid_flag boolean := 't';
BEGIN
--Validation code
if valid_flag = 'f' then
RAISE EXCEPTION 'This record is not valid id %', id
USING HINT = 'Please enter valid record';
RETURN NULL;
else
RETURN NEW;
end if;
END;
$function$
CREATE TRIGGER validate_rec BEFORE INSERT OR UPDATE ON some_tbl
FOR EACH ROW EXECUTE FUNCTION validate_function();
使用此函数和触发器,您可以在触发器内部进行验证。如果新记录验证失败,则将 valid_flag
设置为 false
,然后使用它来引发异常。 RETURN NULL;
可能是多余的,我不确定是否会到达,但如果是,它也会中止插入或更新。如果记录有效,那么您 RETURN NEW
并且 insert/update 完成。
我希望能够使用数据库的现有约束(引发异常和检查的触发器)来验证代表 table 行的对象,而无需将它们实际插入到数据库中。
目前有没有一种方法可以在 postgres 中做到这一点?至少对于 BEFORE INSERT
触发器和 CHECK
,我认为它对于 AFTER INSERT
触发器没有意义。
我能想到或现在最简单的方法是:
- 锁定table
- 插入一个新行
- 如果异常引发 API / 否则删除该行并将其称为有效
- 解锁
但我可以看到几个问题。
更简单的方法是在事务中插入而不提交:
BEGIN;
INSERT INTO tbl(...) VALUES (...);
-- see effects ...
ROLLBACK;
无需额外锁定。该行对于具有默认事务隔离级别 READ COMMITTED
的任何其他事务永远不可见。 (您可能会停止与测试行冲突的并发写入。)
Notable side-effect:即使 INSERT
从未提交,serial
或 IDENTITY
列的序列也会被推进。但无论如何,序列号之间的差距是可以预料的,无需担心。
警惕 side-effect 的触发器。所有“事务性”SQL 效果都会回滚,甚至大多数 DDL 命令也是如此。但一些特殊操作(如推进序列)永远不会回滚。
此外,DEFERRED
约束不会生效。The manual:
DEFERRED
constraints are not checked until transaction commit.
如果您经常需要它,请使用您的 table 甚至您的数据库的副本。
严格来说,虽然允许任何触发器/约束/并发事件,但除了将它们插入实际目标数据库中的实际目标 table 之外,没有其他方法可以“验证对象”时间点。触发器、约束,甚至默认值,都可以与整个数据库的当前状态交互。排除的可能性越多,要求越低,我们模拟测试的选项就越多。
CREATE FUNCTION validate_function ( )
RETURNS trigger LANGUAGE plpgsql
AS $function$
DECLARE
valid_flag boolean := 't';
BEGIN
--Validation code
if valid_flag = 'f' then
RAISE EXCEPTION 'This record is not valid id %', id
USING HINT = 'Please enter valid record';
RETURN NULL;
else
RETURN NEW;
end if;
END;
$function$
CREATE TRIGGER validate_rec BEFORE INSERT OR UPDATE ON some_tbl
FOR EACH ROW EXECUTE FUNCTION validate_function();
使用此函数和触发器,您可以在触发器内部进行验证。如果新记录验证失败,则将 valid_flag
设置为 false
,然后使用它来引发异常。 RETURN NULL;
可能是多余的,我不确定是否会到达,但如果是,它也会中止插入或更新。如果记录有效,那么您 RETURN NEW
并且 insert/update 完成。