postgresql/src/backend/commands/trigger.c

837 lines
22 KiB
C
Raw Normal View History

1997-08-31 13:40:13 +02:00
/*-------------------------------------------------------------------------
*
* trigger.c--
* PostgreSQL TRIGGERs support code.
1997-08-31 13:40:13 +02:00
*
*-------------------------------------------------------------------------
*/
#include <string.h>
1997-08-31 13:40:13 +02:00
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/valid.h"
#include "access/xact.h"
1997-09-04 15:19:01 +02:00
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
1997-08-31 13:40:13 +02:00
#include "catalog/pg_trigger.h"
#include "commands/trigger.h"
#include "fmgr.h"
#include "nodes/memnodes.h"
#include "nodes/parsenodes.h"
1997-09-04 15:19:01 +02:00
#include "storage/lmgr.h"
#include "storage/bufmgr.h"
1997-09-04 15:19:01 +02:00
#include "utils/mcxt.h"
#include "utils/inval.h"
1997-08-31 13:40:13 +02:00
#include "utils/builtins.h"
#include "utils/syscache.h"
1997-08-31 13:40:13 +02:00
1997-09-04 15:19:01 +02:00
#ifndef NO_SECURITY
#include "miscadmin.h"
#include "utils/acl.h"
#endif
TriggerData *CurrentTriggerData = NULL;
1997-09-04 15:19:01 +02:00
void RelationBuildTriggers(Relation relation);
void FreeTriggerDesc(Relation relation);
static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
static HeapTuple GetTupleForTrigger(Relation relation, ItemPointer tid,
1997-09-11 09:24:37 +02:00
bool before);
1997-09-04 15:19:01 +02:00
extern GlobalMemory CacheCxt;
1997-08-31 13:40:13 +02:00
void
CreateTrigger(CreateTrigStmt *stmt)
1997-08-31 13:40:13 +02:00
{
int16 tgtype;
int16 tgattr[8] = {0};
Datum values[Natts_pg_trigger];
char nulls[Natts_pg_trigger];
Relation rel;
Relation tgrel;
HeapScanDesc tgscan;
ScanKeyData key;
1998-09-01 05:29:17 +02:00
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 (IsSystemRelationName(stmt->relname))
elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
1997-08-31 13:40:13 +02:00
1997-09-04 15:19:01 +02:00
#ifndef NO_SECURITY
if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
1997-09-04 15:19:01 +02:00
#endif
rel = heap_openr(stmt->relname);
if (!RelationIsValid(rel))
elog(ERROR, "CreateTrigger: there is no relation %s", stmt->relname);
RelationSetLockForWrite(rel);
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);
RelationSetLockForWrite(tgrel);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ, RelationGetRelid(rel));
1998-07-27 21:38:40 +02:00
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);
1997-09-18 22:22:58 +02:00
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))->prorettype != 0 ||
((Form_pg_proc) GETSTRUCT(tuple))->pronargs != 0)
elog(ERROR, "CreateTrigger: function %s () does not exist", 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");
}
1997-09-18 22:22:58 +02:00
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));
1998-11-27 20:52:36 +01:00
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++)
1997-10-02 15:52:29 +02:00
{
if (*ar == '\\')
len++;
}
}
args = (char *) palloc(len + 1);
args[0] = 0;
foreach(le, stmt->args)
1997-10-02 15:52:29 +02:00
{
char *s = (char *) lfirst(le);
char *d = args + strlen(args);
1997-10-02 15:52:29 +02:00
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);
RelationUnsetLockForWrite(tgrel);
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);
1998-09-01 05:29:17 +02:00
pgrel = heap_openr(RelationRelationName);
((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
1998-09-01 05:29:17 +02:00
RelationInvalidateHeapTuple(pgrel, tuple);
1998-11-27 20:52:36 +01:00
heap_replace(pgrel, &tuple->t_self, tuple);
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
1998-09-01 05:29:17 +02:00
CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
CatalogCloseIndices(Num_pg_class_indices, ridescs);
pfree(tuple);
1998-09-01 05:29:17 +02:00
heap_close(pgrel);
CommandCounterIncrement();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
FreeTriggerDesc(rel);
rel->rd_rel->reltriggers = found + 1;
RelationBuildTriggers(rel);
MemoryContextSwitchTo(oldcxt);
heap_close(rel);
return;
1997-08-31 13:40:13 +02:00
}
void
DropTrigger(DropTrigStmt *stmt)
1997-08-31 13:40:13 +02:00
{
Relation rel;
Relation tgrel;
HeapScanDesc tgscan;
ScanKeyData key;
1998-09-01 05:29:17 +02:00
Relation pgrel;
HeapTuple tuple;
Relation ridescs[Num_pg_class_indices];
MemoryContext oldcxt;
int found = 0;
int tgfound = 0;
1997-09-04 15:19:01 +02:00
#ifndef NO_SECURITY
if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
1997-09-04 15:19:01 +02:00
#endif
rel = heap_openr(stmt->relname);
if (!RelationIsValid(rel))
elog(ERROR, "DropTrigger: there is no relation %s", stmt->relname);
RelationSetLockForWrite(rel);
tgrel = heap_openr(TriggerRelationName);
RelationSetLockForWrite(tgrel);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ, RelationGetRelid(rel));
1998-07-27 21:38:40 +02:00
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)
{
1998-11-27 20:52:36 +01:00
heap_delete(tgrel, &tuple->t_self);
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);
RelationUnsetLockForWrite(tgrel);
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 */
1998-09-01 05:29:17 +02:00
pgrel = heap_openr(RelationRelationName);
((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
1998-09-01 05:29:17 +02:00
RelationInvalidateHeapTuple(pgrel, tuple);
1998-11-27 20:52:36 +01:00
heap_replace(pgrel, &tuple->t_self, tuple);
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
1998-09-01 05:29:17 +02:00
CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
CatalogCloseIndices(Num_pg_class_indices, ridescs);
pfree(tuple);
1998-09-01 05:29:17 +02:00
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;
1997-08-31 13:40:13 +02:00
}
void
RelationRemoveTriggers(Relation rel)
1997-09-04 15:19:01 +02:00
{
Relation tgrel;
HeapScanDesc tgscan;
ScanKeyData key;
HeapTuple tup;
tgrel = heap_openr(TriggerRelationName);
RelationSetLockForWrite(tgrel);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ, RelationGetRelid(rel));
1998-07-27 21:38:40 +02:00
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
1998-11-27 20:52:36 +01:00
heap_delete(tgrel, &tup->t_self);
heap_endscan(tgscan);
RelationUnsetLockForWrite(tgrel);
heap_close(tgrel);
1997-09-04 15:19:01 +02:00
}
void
RelationBuildTriggers(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;
1998-11-27 20:52:36 +01:00
HeapTupleData tuple;
IndexScanDesc sd;
RetrieveIndexResult indexRes;
Buffer buffer;
struct varlena *val;
bool isnull;
int found;
1997-09-18 22:22:58 +02:00
MemSet(trigdesc, 0, sizeof(TriggerDesc));
ScanKeyEntryInitialize(&skey,
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
tgrel = heap_openr(TriggerRelationName);
RelationSetLockForRead(tgrel);
irel = index_openr(TriggerRelidIndex);
sd = index_beginscan(irel, false, 1, &skey);
for (found = 0;;)
{
indexRes = index_getnext(sd, ForwardScanDirection);
if (!indexRes)
break;
1998-11-27 20:52:36 +01:00
tuple.t_self = indexRes->heap_iptr;
heap_fetch(tgrel, SnapshotNow, &tuple, &buffer);
pfree(indexRes);
1998-11-27 20:52:36 +01:00
if (!tuple.t_data)
continue;
if (found == ntrigs)
elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %.*s",
NAMEDATALEN, relation->rd_rel->relname.data);
1998-11-27 20:52:36 +01:00
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));
1998-11-27 20:52:36 +01:00
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;
1998-11-27 20:52:36 +01:00
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,
NAMEDATALEN, relation->rd_rel->relname.data);
index_endscan(sd);
pfree(sd);
index_close(irel);
RelationUnsetLockForRead(tgrel);
heap_close(tgrel);
/* Build trigdesc */
trigdesc->triggers = triggers;
for (found = 0; found < ntrigs; found++)
{
build = &(triggers[found]);
DescribeTrigger(trigdesc, build);
}
relation->trigdesc = trigdesc;
1997-09-04 15:19:01 +02:00
}
void
FreeTriggerDesc(Relation relation)
1997-09-04 15:19:01 +02:00
{
TriggerDesc *trigdesc = relation->trigdesc;
Trigger ***t;
Trigger *trigger;
int i;
if (trigdesc == NULL)
return;
t = trigdesc->tg_before_statement;
for (i = 0; i < 3; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_before_row;
for (i = 0; i < 3; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_after_row;
for (i = 0; i < 3; i++)
if (t[i] != NULL)
pfree(t[i]);
t = trigdesc->tg_after_statement;
for (i = 0; i < 3; i++)
if (t[i] != NULL)
pfree(t[i]);
trigger = trigdesc->triggers;
for (i = 0; i < relation->rd_rel->reltriggers; i++)
{
pfree(trigger->tgname);
if (trigger->tgnargs > 0)
{
while (--(trigger->tgnargs) >= 0)
pfree(trigger->tgargs[trigger->tgnargs]);
pfree(trigger->tgargs);
}
trigger++;
}
pfree(trigdesc->triggers);
pfree(trigdesc);
relation->trigdesc = NULL;
return;
1997-09-04 15:19:01 +02:00
}
static void
DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
1997-09-04 15:19:01 +02:00
{
uint16 *n;
Trigger ***t,
***tp;
if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
* trigger */
{
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_row;
t = trigdesc->tg_before_row;
}
else
{
n = trigdesc->n_after_row;
t = trigdesc->tg_after_row;
}
}
else
/* STATEMENT (NI) */
{
if (TRIGGER_FOR_BEFORE(trigger->tgtype))
{
n = trigdesc->n_before_statement;
t = trigdesc->tg_before_statement;
}
else
{
n = trigdesc->n_after_statement;
t = trigdesc->tg_after_statement;
}
}
if (TRIGGER_FOR_INSERT(trigger->tgtype))
{
tp = &(t[TRIGGER_EVENT_INSERT]);
if (*tp == NULL)
*tp = (Trigger **) palloc(sizeof(Trigger *));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
sizeof(Trigger *));
(*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
(n[TRIGGER_EVENT_INSERT])++;
}
if (TRIGGER_FOR_DELETE(trigger->tgtype))
{
tp = &(t[TRIGGER_EVENT_DELETE]);
if (*tp == NULL)
*tp = (Trigger **) palloc(sizeof(Trigger *));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
sizeof(Trigger *));
(*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
(n[TRIGGER_EVENT_DELETE])++;
}
if (TRIGGER_FOR_UPDATE(trigger->tgtype))
{
tp = &(t[TRIGGER_EVENT_UPDATE]);
if (*tp == NULL)
*tp = (Trigger **) palloc(sizeof(Trigger *));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
sizeof(Trigger *));
(*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
(n[TRIGGER_EVENT_UPDATE])++;
}
}
static HeapTuple
ExecCallTriggerFunc(Trigger *trigger)
{
if (trigger->tgfunc.fn_addr == NULL)
fmgr_info(trigger->tgfoid, &trigger->tgfunc);
if (trigger->tgfunc.fn_plhandler != NULL)
{
return (HeapTuple) (*(trigger->tgfunc.fn_plhandler))
(&trigger->tgfunc);
}
return (HeapTuple) ((*fmgr_faddr(&trigger->tgfunc)) ());
}
HeapTuple
1997-09-11 09:24:37 +02:00
ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
{
1997-09-11 09:24:37 +02:00
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
1997-09-11 09:24:37 +02:00
HeapTuple newtuple = trigtuple;
HeapTuple oldtuple;
int i;
1997-09-11 09:24:37 +02:00
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event =
TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
SaveTriggerData->tg_relation = rel;
SaveTriggerData->tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
1997-09-11 09:24:37 +02:00
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = oldtuple = newtuple;
CurrentTriggerData->tg_trigger = trigger[i];
newtuple = ExecCallTriggerFunc(trigger[i]);
if (newtuple == NULL)
break;
1997-09-11 09:24:37 +02:00
else if (oldtuple != newtuple && oldtuple != trigtuple)
pfree(oldtuple);
}
CurrentTriggerData = NULL;
1997-09-11 09:24:37 +02:00
pfree(SaveTriggerData);
1998-09-01 05:29:17 +02:00
return newtuple;
}
void
1997-09-11 09:24:37 +02:00
ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
{
1997-09-11 09:24:37 +02:00
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT];
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_INSERT];
int i;
1997-09-11 09:24:37 +02:00
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
SaveTriggerData->tg_relation = rel;
SaveTriggerData->tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_trigger = trigger[i];
ExecCallTriggerFunc(trigger[i]);
1997-09-11 09:24:37 +02:00
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
return;
}
bool
ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
{
1997-09-11 09:24:37 +02:00
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
HeapTuple trigtuple;
HeapTuple newtuple = NULL;
int i;
trigtuple = GetTupleForTrigger(rel, tupleid, true);
if (trigtuple == NULL)
1998-09-01 05:29:17 +02:00
return false;
1997-09-11 09:24:37 +02:00
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event =
TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
SaveTriggerData->tg_relation = rel;
SaveTriggerData->tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_trigger = trigger[i];
newtuple = ExecCallTriggerFunc(trigger[i]);
1997-09-11 09:24:37 +02:00
if (newtuple == NULL)
break;
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
pfree(trigtuple);
1998-09-01 05:29:17 +02:00
return (newtuple == NULL) ? false : true;
}
void
ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
{
1997-09-11 09:24:37 +02:00
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE];
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE];
HeapTuple trigtuple;
int i;
1997-09-11 09:24:37 +02:00
trigtuple = GetTupleForTrigger(rel, tupleid, false);
Assert(trigtuple != NULL);
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event =
TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW;
SaveTriggerData->tg_relation = rel;
SaveTriggerData->tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
{
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_trigger = trigger[i];
ExecCallTriggerFunc(trigger[i]);
1997-09-11 09:24:37 +02:00
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
pfree(trigtuple);
return;
}
HeapTuple
1997-09-11 09:24:37 +02:00
ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
{
1997-09-11 09:24:37 +02:00
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
HeapTuple trigtuple;
HeapTuple oldtuple;
HeapTuple intuple = newtuple;
int i;
1997-09-11 09:24:37 +02:00
trigtuple = GetTupleForTrigger(rel, tupleid, true);
if (trigtuple == NULL)
1998-09-01 05:29:17 +02:00
return NULL;
1997-09-11 09:24:37 +02:00
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event =
TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
SaveTriggerData->tg_relation = rel;
for (i = 0; i < ntrigs; i++)
{
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_newtuple = oldtuple = newtuple;
CurrentTriggerData->tg_trigger = trigger[i];
newtuple = ExecCallTriggerFunc(trigger[i]);
1997-09-11 09:24:37 +02:00
if (newtuple == NULL)
break;
else if (oldtuple != newtuple && oldtuple != intuple)
pfree(oldtuple);
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
pfree(trigtuple);
1998-09-01 05:29:17 +02:00
return newtuple;
}
void
1997-09-11 09:24:37 +02:00
ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple)
{
1997-09-11 09:24:37 +02:00
TriggerData *SaveTriggerData;
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE];
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE];
HeapTuple trigtuple;
int i;
trigtuple = GetTupleForTrigger(rel, tupleid, false);
Assert(trigtuple != NULL);
1997-09-11 09:24:37 +02:00
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event =
TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW;
SaveTriggerData->tg_relation = rel;
for (i = 0; i < ntrigs; i++)
{
CurrentTriggerData = SaveTriggerData;
CurrentTriggerData->tg_trigtuple = trigtuple;
CurrentTriggerData->tg_newtuple = newtuple;
CurrentTriggerData->tg_trigger = trigger[i];
ExecCallTriggerFunc(trigger[i]);
1997-09-11 09:24:37 +02:00
}
CurrentTriggerData = NULL;
pfree(SaveTriggerData);
pfree(trigtuple);
return;
}
1997-09-11 09:24:37 +02:00
static HeapTuple
GetTupleForTrigger(Relation relation, ItemPointer tid, bool before)
{
1998-11-27 20:52:36 +01:00
ItemId lp;
HeapTupleData tuple;
HeapTuple result;
PageHeader dp;
Buffer b;
1997-09-11 09:24:37 +02:00
b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
if (!BufferIsValid(b))
elog(ERROR, "GetTupleForTrigger: failed ReadBuffer");
1997-09-11 09:24:37 +02:00
dp = (PageHeader) BufferGetPage(b);
lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
Assert(ItemIdIsUsed(lp));
1998-11-27 20:52:36 +01:00
tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
tuple.t_len = ItemIdGetLength(lp);
tuple.t_self = *tid;
1997-09-11 09:24:37 +02:00
if (before)
{
1998-11-27 20:52:36 +01:00
if (TupleUpdatedByCurXactAndCmd(&tuple))
1997-09-11 09:24:37 +02:00
{
elog(NOTICE, "GetTupleForTrigger: Non-functional delete/update");
ReleaseBuffer(b);
1998-09-01 05:29:17 +02:00
return NULL;
1997-09-11 09:24:37 +02:00
}
1998-11-27 20:52:36 +01:00
HeapTupleSatisfies(&tuple, relation, b, dp,
false, 0, (ScanKey) NULL);
if (!tuple.t_data)
1997-09-11 09:24:37 +02:00
{
ReleaseBuffer(b);
elog(ERROR, "GetTupleForTrigger: (am)invalid tid");
1997-09-11 09:24:37 +02:00
}
}
1998-11-27 20:52:36 +01:00
result = heap_copytuple(&tuple);
1997-09-11 09:24:37 +02:00
ReleaseBuffer(b);
1998-11-27 20:52:36 +01:00
return result;
1997-09-11 09:24:37 +02:00
}