Написание триггерных функций на языке C
Эта страница переведена при помощи нейросети GigaChat.
В этом разделе описаны низкоуровневые детали интерфейса триггерных функций. Эта информация необходима только при написании функций триггеров на языке C. Если используется язык более высокого уровня, то эти детали обрабатываются сами. В большинстве случаев перед написанием триггеров на языке C следует рассмотреть возможность использования процедурного языка. Документация каждого процедурного языка объясняет, как написать триггер на этом языке.
Триггерные функции должны использовать интерфейс диспетчера функций «версия 1».
Когда функция вызывается диспетчером триггеров, ей не передаются стандартные аргументы, но предоставляется указатель «контекст», который указывает на структуру 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;
const Bitmapset *tg_updatedcols;
} TriggerData;
Компоненты структуры определены следующим образом:
-
type
– всегдаT_TriggerData
; -
tg_event
– описывает событие, для которого вызывается функция. Можно использовать следующие макросы для изученияtg_event
:TRIGGER_FIRED_BEFORE(tg_event)
– возвращаетtrue
, если триггер сработал до операции.TRIGGER_FIRED_AFTER(tg_event)
– возвращаетtrue
, если триггер сработал после операции.TRIGGER_FIRED_INSTEAD(tg_event)
– возвращаетtrue
, если триггер сработал вместо операции.TRIGGER_FIRED_FOR_ROW(tg_event)
– возвращаетtrue
, если триггер сработал для события уровня строки.TRIGGER_FIRED_FOR_STATEMENT(tg_event)
– возвращаетtrue
, если триггер сработал для события уровня оператора.TRIGGER_FIRED_BY_INSERT(tg_event)
– возвращаетtrue
, если триггер вызвал командуINSERT
.TRIGGER_FIRED_BY_UPDATE(tg_event)
– возвращаетtrue
, если триггер вызвал командуUPDATE
.TRIGGER_FIRED_BY_DELETE(tg_event)
– возвращаетtrue
, если триггер вызвал командуDELETE
.TRIGGER_FIRED_BY_TRUNCATE(tg_event)
– возвращаетtrue
, если триггер вызвал командуTRUNCATE
.
-
tg_relation
– указатель на структуру, описывающую отношение, для которого сработал триггер. Посмотрите наutils/rel.h
для получения подробной информации об этой структуре. Наиболее интересными вещами являютсяtg_relation->rd_att
(дескриптор кортежей отношения) иtg_relation->rd_rel->relname
(имя отношения; тип не являетсяchar*
, аNameData
; используйте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;
bool tgisclone;
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
. -
tg_updatedcols
– для триггеровUPDATE
это битовая карта, указывающая столбцы, которые были обновлены командой запуска. Общие триггерные функции могут использовать это для оптимизации действий путем отказа от работы со столбцами, которые не изменились.Например, чтобы проверить, является ли столбец с номером атрибута
attnum
(нумерация начинается с единицы) членом этой битовой карты, вызовитеbms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols))
.Для триггеров, отличных от триггеров
UPDATE
, это поле будетNULL
.
Чтобы запросы, отправляемые через SPI, могли обращаться к таблицам переходов, обратитесь к документации SPI_register_trigger_data.
Функция триггера должна возвращать либо указатель HeapTuple
, либо указатель NULL
(не значение SQL null, то есть не устанавливайте в true). Будьте осторожны, чтобы вернуть либо , либо isNull
, если не хотите изменять строку, над которой выполняется операция.