?? trigger.c
字號:
/*------------------------------------------------------------------------- * * trigger.c * PostgreSQL TRIGGERs support code. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/catname.h"#include "catalog/indexing.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "catalog/pg_trigger.h"#include "commands/trigger.h"#include "executor/executor.h"#include "miscadmin.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/inval.h"#include "utils/syscache.h"DLLIMPORT TriggerData *CurrentTriggerData = NULL;void RelationBuildTriggers(Relation relation);void FreeTriggerDesc(Relation relation);static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot);extern GlobalMemory CacheCxt;voidCreateTrigger(CreateTrigStmt *stmt){ int16 tgtype; int16 tgattr[8] = {0}; Datum values[Natts_pg_trigger]; char nulls[Natts_pg_trigger]; Relation rel; Relation tgrel; HeapScanDesc tgscan; ScanKeyData key; Relation pgrel; HeapTuple tuple; Relation idescs[Num_pg_trigger_indices]; Relation ridescs[Num_pg_class_indices]; MemoryContext oldcxt; Oid fargtypes[8]; int found = 0; int i; if (!allowSystemTableMods && IsSystemRelationName(stmt->relname)) elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);#ifndef NO_SECURITY if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME)) elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);#endif rel = heap_openr(stmt->relname); if (!RelationIsValid(rel)) elog(ERROR, "CreateTrigger: there is no relation %s", stmt->relname); LockRelation(rel, AccessExclusiveLock); TRIGGER_CLEAR_TYPE(tgtype); if (stmt->before) TRIGGER_SETT_BEFORE(tgtype); if (stmt->row) TRIGGER_SETT_ROW(tgtype); else elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet"); for (i = 0; i < 3 && stmt->actions[i]; i++) { switch (stmt->actions[i]) { case 'i': if (TRIGGER_FOR_INSERT(tgtype)) elog(ERROR, "CreateTrigger: double INSERT event specified"); TRIGGER_SETT_INSERT(tgtype); break; case 'd': if (TRIGGER_FOR_DELETE(tgtype)) elog(ERROR, "CreateTrigger: double DELETE event specified"); TRIGGER_SETT_DELETE(tgtype); break; case 'u': if (TRIGGER_FOR_UPDATE(tgtype)) elog(ERROR, "CreateTrigger: double UPDATE event specified"); TRIGGER_SETT_UPDATE(tgtype); break; default: elog(ERROR, "CreateTrigger: unknown event specified"); break; } } /* Scan pg_trigger */ tgrel = heap_openr(TriggerRelationName); LockRelation(tgrel, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, F_OIDEQ, RelationGetRelid(rel)); tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0))) { Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0) elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s", stmt->trigname, stmt->relname); else found++; } heap_endscan(tgscan); MemSet(fargtypes, 0, 8 * sizeof(Oid)); tuple = SearchSysCacheTuple(PRONAME, PointerGetDatum(stmt->funcname), Int32GetDatum(0), PointerGetDatum(fargtypes), 0); if (!HeapTupleIsValid(tuple) || ((Form_pg_proc) GETSTRUCT(tuple))->pronargs != 0) elog(ERROR, "CreateTrigger: function %s() does not exist", stmt->funcname); if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0) elog(ERROR, "CreateTrigger: function %s() must return OPAQUE", stmt->funcname); if (((Form_pg_proc) GETSTRUCT(tuple))->prolang != ClanguageId) { HeapTuple langTup; langTup = SearchSysCacheTuple(LANOID, ObjectIdGetDatum(((Form_pg_proc) GETSTRUCT(tuple))->prolang), 0, 0, 0); if (!HeapTupleIsValid(langTup)) elog(ERROR, "CreateTrigger: cache lookup for PL failed"); if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false) elog(ERROR, "CreateTrigger: only C and PL functions are supported"); } MemSet(nulls, ' ', Natts_pg_trigger * sizeof(char)); values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel)); values[Anum_pg_trigger_tgname - 1] = NameGetDatum(namein(stmt->trigname)); values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(tuple->t_data->t_oid); values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype); if (stmt->args) { List *le; char *args; int16 nargs = length(stmt->args); int len = 0; foreach(le, stmt->args) { char *ar = (char *) lfirst(le); len += strlen(ar) + VARHDRSZ; for (; *ar; ar++) { if (*ar == '\\') len++; } } args = (char *) palloc(len + 1); args[0] = 0; foreach(le, stmt->args) { char *s = (char *) lfirst(le); char *d = args + strlen(args); while (*s) { if (*s == '\\') *d++ = '\\'; *d++ = *s++; } *d = 0; strcat(args, "\\000"); } values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs); values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(args)); } else { values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0); values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain("")); } values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr); tuple = heap_formtuple(tgrel->rd_att, values, nulls); heap_insert(tgrel, tuple); CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs); CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple); CatalogCloseIndices(Num_pg_trigger_indices, idescs); pfree(tuple); UnlockRelation(tgrel, AccessExclusiveLock); heap_close(tgrel); pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1])); pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1])); /* update pg_class */ tuple = SearchSysCacheTupleCopy(RELNAME, PointerGetDatum(stmt->relname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "CreateTrigger: relation %s not found in pg_class", stmt->relname); pgrel = heap_openr(RelationRelationName); ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1; RelationInvalidateHeapTuple(pgrel, tuple); heap_replace(pgrel, &tuple->t_self, tuple, NULL); CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs); CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple); CatalogCloseIndices(Num_pg_class_indices, ridescs); pfree(tuple); heap_close(pgrel); CommandCounterIncrement(); oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); FreeTriggerDesc(rel); rel->rd_rel->reltriggers = found + 1; RelationBuildTriggers(rel); MemoryContextSwitchTo(oldcxt); heap_close(rel); return;}voidDropTrigger(DropTrigStmt *stmt){ Relation rel; Relation tgrel; HeapScanDesc tgscan; ScanKeyData key; Relation pgrel; HeapTuple tuple; Relation ridescs[Num_pg_class_indices]; MemoryContext oldcxt; int found = 0; int tgfound = 0;#ifndef NO_SECURITY if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME)) elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);#endif rel = heap_openr(stmt->relname); if (!RelationIsValid(rel)) elog(ERROR, "DropTrigger: there is no relation %s", stmt->relname); LockRelation(rel, AccessExclusiveLock); tgrel = heap_openr(TriggerRelationName); LockRelation(tgrel, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, F_OIDEQ, RelationGetRelid(rel)); tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0))) { Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0) { heap_delete(tgrel, &tuple->t_self, NULL); tgfound++; } else found++; } if (tgfound == 0) elog(ERROR, "DropTrigger: there is no trigger %s on relation %s", stmt->trigname, stmt->relname); if (tgfound > 1) elog(NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s", tgfound, stmt->trigname, stmt->relname); heap_endscan(tgscan); UnlockRelation(tgrel, AccessExclusiveLock); heap_close(tgrel); tuple = SearchSysCacheTupleCopy(RELNAME, PointerGetDatum(stmt->relname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "DropTrigger: relation %s not found in pg_class", stmt->relname); /* update pg_class */ pgrel = heap_openr(RelationRelationName); ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found; RelationInvalidateHeapTuple(pgrel, tuple); heap_replace(pgrel, &tuple->t_self, tuple, NULL); CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs); CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple); CatalogCloseIndices(Num_pg_class_indices, ridescs); pfree(tuple); heap_close(pgrel); CommandCounterIncrement(); oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); FreeTriggerDesc(rel); rel->rd_rel->reltriggers = found; if (found > 0) RelationBuildTriggers(rel); MemoryContextSwitchTo(oldcxt); heap_close(rel); return;}voidRelationRemoveTriggers(Relation rel){ Relation tgrel; HeapScanDesc tgscan; ScanKeyData key; HeapTuple tup; tgrel = heap_openr(TriggerRelationName); LockRelation(tgrel, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, F_OIDEQ, RelationGetRelid(rel)); tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0))) heap_delete(tgrel, &tup->t_self, NULL); heap_endscan(tgscan); UnlockRelation(tgrel, AccessExclusiveLock); heap_close(tgrel);}voidRelationBuildTriggers(Relation relation){ TriggerDesc *trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc)); int ntrigs = relation->rd_rel->reltriggers; Trigger *triggers = NULL; Trigger *build; Relation tgrel; Form_pg_trigger pg_trigger; Relation irel; ScanKeyData skey; HeapTupleData tuple; IndexScanDesc sd; RetrieveIndexResult indexRes; Buffer buffer; struct varlena *val; bool isnull; int found; MemSet(trigdesc, 0, sizeof(TriggerDesc)); ScanKeyEntryInitialize(&skey, (bits16) 0x0, (AttrNumber) 1, (RegProcedure) F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); tgrel = heap_openr(TriggerRelationName); irel = index_openr(TriggerRelidIndex); sd = index_beginscan(irel, false, 1, &skey); for (found = 0;;) { indexRes = index_getnext(sd, ForwardScanDirection); if (!indexRes) break; tuple.t_self = indexRes->heap_iptr; heap_fetch(tgrel, SnapshotNow, &tuple, &buffer); pfree(indexRes); if (!tuple.t_data) continue; if (found == ntrigs) elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %.*s", NAMEDATALEN, relation->rd_rel->relname.data); pg_trigger = (Form_pg_trigger) GETSTRUCT(&tuple); if (triggers == NULL) triggers = (Trigger *) palloc(sizeof(Trigger)); else triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger)); build = &(triggers[found]); build->tgname = nameout(&(pg_trigger->tgname)); build->tgfoid = pg_trigger->tgfoid; build->tgfunc.fn_addr = NULL; build->tgtype = pg_trigger->tgtype; build->tgnargs = pg_trigger->tgnargs; memcpy(build->tgattr, &(pg_trigger->tgattr), 8 * sizeof(int16)); val = (struct varlena *) fastgetattr(&tuple, Anum_pg_trigger_tgargs, tgrel->rd_att, &isnull); if (isnull) elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %.*s", NAMEDATALEN, relation->rd_rel->relname.data); if (build->tgnargs > 0) { char *p; int i; val = (struct varlena *) fastgetattr(&tuple, Anum_pg_trigger_tgargs, tgrel->rd_att, &isnull); if (isnull) elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %.*s", NAMEDATALEN, relation->rd_rel->relname.data); p = (char *) VARDATA(val); build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *)); for (i = 0; i < build->tgnargs; i++) { build->tgargs[i] = (char *) palloc(strlen(p) + 1); strcpy(build->tgargs[i], p); p += strlen(p) + 1; } } else build->tgargs = NULL; found++; ReleaseBuffer(buffer); } if (found < ntrigs) elog(ERROR, "RelationBuildTriggers: %d record not found for rel %.*s", ntrigs - found,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -