PostgreSQL触发器函数必须返回TRIGGER类型,因内核依赖该返回值控制执行流;RETURNS VOID会导致CREATE TRIGGER报错,RETURN非TRIGGER值在BEFORE中被视作NULL致行丢失,RETURN NEW/OLD/NULL分别表示修改行、确认删除、跳过当前行,AFTER中RETURN无效且不可修改NEW/OLD。

PostgreSQL触发器函数必须返回TRIGGER类型,不是语法强制,而是运行时契约——数据库内核靠这个返回值决定是否继续执行、是否跳过当前行、甚至是否中止事务。
为什么不能用VOID或TEXT代替TRIGGER?
PL/pgSQL函数声明为RETURNS TRIGGER,本质是告诉PostgreSQL:“我准备处理NEW、OLD、TG_OP这些隐式变量,并按规则返回控制流信号”。如果写成RETURNS VOID:
- 函数可能编译通过,但
CREATE TRIGGER会直接报错:ERROR: function ... must return type "trigger" - 即使绕过检查(比如用
event_trigger误配),运行时找不到TriggerData上下文,会崩溃或静默失败 -
RETURN 'hello'这类非TRIGGER兼容值,在BEFORE行级触发器里会被当作NULL处理,导致整行被丢弃(不报错,但数据消失)
RETURN NEW、RETURN OLD、RETURN NULL的实际效果差异
返回值不是“返回数据”,而是向执行引擎发指令:
-
RETURN NEW:仅用于INSERT或UPDATE的BEFORE触发器;把修改后的NEW行交还给主操作,后续INSERT/UPDATE照常进行 -
RETURN OLD:仅用于DELETE的BEFORE触发器;表示“确认删除这行”,等价于RETURN NULL(但语义更清晰) -
RETURN NULL:在BEFORE行级触发器中 = “跳过当前行”;在AFTER触发器中无意义,建议统一写RETURN NULL避免混淆 - 任何其他返回值(如
RETURN 42)会被强制转为NULL,等效于跳过
常见错误:在AFTER触发器里修改NEW并RETURN NEW
AFTER触发器的NEW和OLD是只读快照,修改它们无效;且RETURN值不会影响已提交的数据:
- 写了
NEW.updated_at := now()+RETURN NEW→ 无任何效果,字段不会更新 - 想改数据,必须用
BEFORE触发器,或者在触发器里显式执行UPDATE语句(注意循环触发风险) - 若误在
AFTER里RAISE EXCEPTION,事务会回滚,但触发器本身已执行完毕,日志类副作用无法撤回
最易被忽略的一点:触发器函数体里哪怕只有一行RAISE NOTICE,也必须以RETURN结尾——否则函数实际返回NULL,在BEFORE场景下等于悄悄删掉整行。写完务必检查最后是不是明确的RETURN NEW、RETURN OLD或RETURN NULL。

















