Ограничения внешнего ключа в настоящее время реализуются с помощью специальных внутренних триггеров. Все они запущены FOR EACH ROW.
Обратите внимание, что это детали реализации, которые могут измениться, поэтому не полагайтесь на это. Но основы не изменились за последние пару основных версий, поэтому серьезные изменения маловероятны.
Я провел быстрый тест с простым ограничением FK от tblдо tbltype. Простой FK реализован с четырьмя простыми внутренними триггерами FOR EACH ROWв моем тесте на стр. 9.4.
Вот краткое изложение того, как исследовать:
SELECT oid -- 74791
FROM pg_constraint
WHERE conrelid = 'tbl'::regclass
AND contype = 'f';
SELECT objid, classid::regclass -- 74792,74793,74794,74795 / 'pg_trigger'
FROM pg_depend
WHERE refobjid = 74791
AND deptype = 'i'
SELECT tgrelid::regclass, tgname, tgfoid, tgtype FROM pg_trigger
WHERE oid IN (74792,74793,74794,74795) ORDER BY tgfoid;
'tbl' ;'RI_ConstraintTrigger_c_74794';1644;5
'tbl' ;'RI_ConstraintTrigger_c_74795';1645;17
'tbltype';'RI_ConstraintTrigger_a_74792';1654;9
'tbltype';'RI_ConstraintTrigger_a_74793';1655;17
SELECT oid, proname FROM pg_proc
WHERE oid IN (1654,1655,1644,1645);
1644;'RI_FKey_check_ins'
1645;'RI_FKey_check_upd'
1654;'RI_FKey_noaction_del'
1655;'RI_FKey_noaction_upd'
Два внутренних «noaction» запускаются tbltype.
Два внутренних «проверки» запускаются tbl.
Все они запускаются FOR EACH ROW, как указано нечетными числами в tgtype.
2 байта Postgres tgtype smallintпредставляют int16исходный код на C, где кодируется младший значащий бит TRIGGER_TYPE_ROW. Подробное объяснение здесь:
Вы можете легко проверить это с парой идентичных триггеров, где вы только меняете FOR ROW/ STATEMENT...