Написание триггерных функций на языке 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, если не предусмотрено внесение изменений в строку, участвующую в операции.