37.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;
const Bitmapset *tg_updatedcols;
} 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; 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(ÑÑиÑÐ°Ñ Ñ 1), можно Ñак:bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols)).ÐÐ»Ñ Ð²ÑÐµÑ Ð¾ÑÑалÑнÑÑ ÑÑиггеÑов ÑодеÑжиÑ
NULL.
ЧÑÐ¾Ð±Ñ Ð¾Ð±ÑаÑаÑÑÑÑ Ðº пеÑÐµÑ Ð¾Ð´Ð½Ñм ÑаблиÑам в запÑоÑÐ°Ñ , вÑполнÑемÑÑ ÑеÑез SPI, иÑполÑзÑйÑе SPI_register_trigger_data.
ТÑиггеÑÐ½Ð°Ñ ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° возвÑаÑаÑÑ ÑказаÑÐµÐ»Ñ HeapTuple или ÑказаÑÐµÐ»Ñ NULL (но не SQL знаÑение null, Ñо еÑÑÑ Ð½Ðµ нÑжно ÑÑÑанавливаÑÑ isNull в иÑÑинÑ). Ðе забÑдÑÑе, ÑÑо еÑли не планиÑÑеÑе менÑÑÑ Ð¾Ð±ÑабаÑÑваемÑÑ ÑÑиггеÑом ÑÑÑокÑ, Ñо нÑжно веÑнÑÑÑ Ð»Ð¸Ð±Ð¾ tg_trigtuple, либо tg_newtuple.