38.3. Триггерные функции на языке C
В этом разделе описываются низкоуровневые детали интерфейса для триггерных функций. Эта информация необходима только при разработке триггерных функций на языке C. При использовании языка более высокого уровня эти детали обрабатываются не видны. В большинстве случаев стоит рассмотреть возможность использования процедурного языка, прежде чем начать разрабатывать триггеры на C. В документации по каждому процедурному языку объясняется, как создавать триггеры на этом языке.
Триггерные функции должны использовать интерфейс функций «версии 1».
Когда функция вызывается диспетчером триггеров, ей не передаются обычные аргументы, но передаётся указатель «context», ссылающийся на структуру TriggerData. Функции на C могут проверить, вызваны ли они диспетчером триггеров или нет, выполнив макрос:
CALLED_AS_TRIGGER(fcinfo)
который разворачивается в:
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
Если возвращается истина, то fcinfo->context можно безопасно привести к типу TriggerData * и использовать указатель на структуру TriggerData. Функция не должна изменять структуру TriggerData или любые данные, которые на неё указывают.
struct TriggerData определяется в commands/trigger.h:
typedef struct TriggerData
{
NodeTag type;
TriggerEvent tg_event;
Relation tg_relation;
HeapTuple tg_trigtuple;
HeapTuple tg_newtuple;
Trigger *tg_trigger;
TupleTableSlot *tg_trigslot;
TupleTableSlot *tg_newslot;
Tuplestorestate *tg_oldtable;
Tuplestorestate *tg_newtable;
} TriggerData;где элементы определяются следующим образом:
typeВсегда
T_TriggerData.tg_eventОписывает событие, для которого вызывается функция. Можно использовать следующие макросы для получения информации о
tg_event:TRIGGER_FIRED_BEFORE(tg_event)Возвращает истину, если триггер сработал до операции.
TRIGGER_FIRED_AFTER(tg_event)Возвращает истину, если триггер сработал после операции.
TRIGGER_FIRED_INSTEAD(tg_event)Возвращает истину, если триггер сработал вместо операции.
TRIGGER_FIRED_FOR_ROW(tg_event)Возвращает истину, если триггер сработал на уровне строки.
TRIGGER_FIRED_FOR_STATEMENT(tg_event)Возвращает истину, если триггер сработал на уровне оператора.
TRIGGER_FIRED_BY_INSERT(tg_event)Возвращает истину, если триггер сработал для операции
INSERT.TRIGGER_FIRED_BY_UPDATE(tg_event)Возвращает истину, если триггер сработал для операции
UPDATE.TRIGGER_FIRED_BY_DELETE(tg_event)Возвращает истину, если триггер сработал для операции
DELETE.TRIGGER_FIRED_BY_TRUNCATE(tg_event)Возвращает истину, если триггер сработал для операции
TRUNCATE.
tg_relationУказатель на структуру, описывающую таблицу, для которой сработал триггер. Подробнее об этой структуре в
utils/rel.h. Самое интересное здесь этоtg_relation->rd_att(дескриптор записей таблицы) иtg_relation->rd_rel->relname(имя таблицы; имеет типNameData, а неchar*; используйтеSPI_getrelname(tg_relation), чтобы получить типchar*если потребуется копия имени).tg_trigtupleУказатель на строку, для которой сработал триггер. Это строка, которая вставляется, обновляется или удаляется. При срабатывании триггера для
INSERTилиDELETEэто значение нужно вернуть из функции, только если не планируется изменять строку (в случаеINSERT) или пропускать операцию для этой строки.tg_newtupleДля триггера на
UPDATEэто указатель на новую версию строки либоNULL, если триггер наINSERTилиDELETE. Это значение нужно вернуть из функции в случаеUPDATE, если не планируется изменять строку или пропускать операцию для этой строки.tg_triggerУказатель на структуру с типом
Trigger, определённую вutils/reltrigger.h:typedef struct Trigger { Oid tgoid; char *tgname; Oid tgfoid; int16 tgtype; char tgenabled; bool tgisinternal; Oid tgconstrrelid; Oid tgconstrindid; Oid tgconstraint; bool tgdeferrable; bool tginitdeferred; int16 tgnargs; int16 tgnattr; int16 *tgattr; char **tgargs; char *tgqual; char *tgoldtable; char *tgnewtable; } Trigger;где
tgname— имя триггера,tgnargs— количество аргументов вtgargs, иtgargs— массив указателей на аргументы, указанные в командеCREATE TRIGGER. Остальные члены структуры предназначены для внутреннего использования.tg_trigslotСлот, содержащий
tg_trigtuple, или указательNULL, если такой строки нет.tg_newslotСлот, содержащий
tg_newtuple, или указательNULL, если такой строки нет.tg_oldtableУказатель на структуру типа
Tuplestorestate, содержащую ноль или несколько строк в формате, определяемом содержимымtg_relation, или указательNULL, если переходное отношениеOLD TABLEотсутствует.tg_newtableУказатель на структуру типа
Tuplestorestate, содержащую ноль или несколько строк в формате, определяемом содержимымtg_relation, или указательNULL, если переходное отношениеNEW TABLEотсутствует.
Чтобы обращаться к переходным таблицам в запросах, выполняемых через SPI, используйте SPI_register_trigger_data.
Триггерная функция должна возвращать указатель HeapTuple или указатель NULL (но не SQL значение null, то есть не нужно устанавливать isNull в истину). Не забудьте, что если не планируете менять обрабатываемую триггером строку, то нужно вернуть либо tg_trigtuple, либо tg_newtuple.