* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.71 2000/06/30 07:04:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.72 2000/07/03 03:57:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TupleTableSlot **newSlot);
static HeapTuple ExecCallTriggerFunc(Trigger *trigger,
TriggerData *trigdata);
-
static void DeferredTriggerSaveEvent(Relation rel, int event,
HeapTuple oldtup, HeapTuple newtup);
Relation idescs[Num_pg_trigger_indices];
Relation ridescs[Num_pg_class_indices];
Oid fargtypes[FUNC_MAX_ARGS];
+ Oid funcoid;
Oid funclang;
int found = 0;
int i;
char constrtrigname[NAMEDATALEN];
char *constrname = "";
- Oid constrrelid = 0;
+ Oid constrrelid = InvalidOid;
if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
{
constrname = stmt->trigname;
stmt->trigname = constrtrigname;
- sprintf(constrtrigname, "RI_ConstraintTrigger_%d", newoid());
+ sprintf(constrtrigname, "RI_ConstraintTrigger_%u", newoid());
if (strcmp(stmt->constrrelname, "") == 0)
- constrrelid = 0;
+ constrrelid = InvalidOid;
else
{
+ /* NoLock is probably sufficient here, since we're only
+ * interested in getting the relation's OID...
+ */
rel = heap_openr(stmt->constrrelname, NoLock);
if (rel == NULL)
elog(ERROR, "table \"%s\" does not exist",
}
}
- /* Scan pg_trigger */
+ /*
+ * Scan pg_trigger for existing triggers on relation. NOTE that this
+ * is cool only because we have AccessExclusiveLock on the relation,
+ * so the trigger set won't be changing underneath us.
+ */
tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ, RelationGetRelid(rel));
if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
stmt->trigname, stmt->relname);
- else
- found++;
+ found++;
}
heap_endscan(tgscan);
+ /*
+ * Find and validate the trigger function.
+ */
MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
tuple = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(stmt->funcname),
if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
stmt->funcname);
+ funcoid = tuple->t_data->t_oid;
funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
if (funclang != ClanguageId &&
funclang != NEWClanguageId &&
elog(ERROR, "CreateTrigger: only builtin, C and PL functions are supported");
}
+ /*
+ * Build the new pg_trigger tuple.
+ */
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_tgfoid - 1] = ObjectIdGetDatum(funcoid);
values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
-
- values[Anum_pg_trigger_tgenabled - 1] = true;
- values[Anum_pg_trigger_tgisconstraint - 1] = stmt->isconstraint;
- values[Anum_pg_trigger_tgconstrname - 1] = PointerGetDatum(constrname);;
- values[Anum_pg_trigger_tgconstrrelid - 1] = constrrelid;
- values[Anum_pg_trigger_tgdeferrable - 1] = stmt->deferrable;
- values[Anum_pg_trigger_tginitdeferred - 1] = stmt->initdeferred;
+ values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
+ values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
+ values[Anum_pg_trigger_tgconstrname - 1] = PointerGetDatum(constrname);
+ values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
+ values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
+ values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
if (stmt->args)
{
{
char *ar = (char *) lfirst(le);
- len += strlen(ar) + VARHDRSZ;
+ len += strlen(ar) + 4;
for (; *ar; ar++)
{
if (*ar == '\\')
values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
tuple = heap_formtuple(tgrel->rd_att, values, nulls);
+
+ /*
+ * Insert tuple into pg_trigger.
+ */
heap_insert(tgrel, tuple);
CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
- /* update pg_class */
+ /*
+ * Update relation's pg_class entry. Crucial side-effect: other
+ * backends (and this one too!) are sent SI message to make them
+ * rebuild relcache entries.
+ */
pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
tuple = SearchSysCacheTupleCopy(RELNAME,
PointerGetDatum(stmt->relname),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
+ elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
+ stmt->relname);
((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
- RelationInvalidateHeapTuple(pgrel, tuple);
heap_update(pgrel, &tuple->t_self, tuple, NULL);
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
* fairly pointless since it will happen as a byproduct of the
* upcoming CommandCounterIncrement...
*/
+
/* Keep lock on target rel until end of xact */
heap_close(rel, NoLock);
}
rel = heap_openr(stmt->relname, AccessExclusiveLock);
+ /*
+ * Search pg_trigger, delete target trigger, count remaining triggers
+ * for relation. Note this is OK only because we have
+ * AccessExclusiveLock on the rel, so no one else is creating/deleting
+ * triggers on this rel at the same time.
+ */
tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ, RelationGetRelid(rel));
heap_delete(tgrel, &tuple->t_self, NULL);
tgfound++;
-
}
else
found++;
heap_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
- /* update pg_class */
+ /*
+ * Update relation's pg_class entry. Crucial side-effect: other
+ * backends (and this one too!) are sent SI message to make them
+ * rebuild relcache entries.
+ */
pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
tuple = SearchSysCacheTupleCopy(RELNAME,
PointerGetDatum(stmt->relname),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "DropTrigger: relation %s not found in pg_class", stmt->relname);
+ elog(ERROR, "DropTrigger: relation %s not found in pg_class",
+ stmt->relname);
((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
- RelationInvalidateHeapTuple(pgrel, tuple);
heap_update(pgrel, &tuple->t_self, tuple, NULL);
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
* fairly pointless since it will happen as a byproduct of the
* upcoming CommandCounterIncrement...
*/
+
/* Keep lock on target rel until end of xact */
heap_close(rel, NoLock);
}
+/*
+ * Remove all triggers for a relation that's being deleted.
+ */
void
RelationRemoveTriggers(Relation rel)
{
DeleteComments(tup->t_data->t_oid);
heap_delete(tgrel, &tup->t_self, NULL);
-
}
heap_endscan(tgscan);
* deferredTriggerAddEvent()
*
* Add a new trigger event to the queue.
+ * Caller must have switched into appropriate memory context!
* ----------
*/
static void
{
deftrig_events = lappend(deftrig_events, event);
deftrig_n_events++;
-
- return;
}
ReleaseBuffer(newbuffer);
heap_close(rel, NoLock);
-
- return;
}
DeferredTriggerStatus stat;
if (deftrig_cxt != NULL)
- elog(FATAL,
- "DeferredTriggerBeginXact() called while inside transaction");
+ elog(ERROR,
+ "DeferredTriggerBeginXact() called while inside transaction");
/* ----------
* Create the per transaction memory context and copy all states
Relation irel = (Relation) NULL;
List *l;
List *ls;
- List *lnext;
List *loid = NIL;
MemoryContext oldcxt;
bool found;
{
/* ----------
* ... outside of a transaction block
- * ----------
- */
- oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
-
- /* ----------
+ *
* Drop all information about individual trigger states per
* session.
* ----------
l = deftrig_dfl_trigstates;
while (l != NIL)
{
- lnext = lnext(l);
+ List *next = lnext(l);
+
pfree(lfirst(l));
pfree(l);
- l = lnext;
+ l = next;
}
deftrig_dfl_trigstates = NIL;
deftrig_dfl_all_isset = true;
deftrig_dfl_all_isdeferred = stmt->deferred;
- MemoryContextSwitchTo(oldcxt);
-
return;
}
else
{
/* ----------
* ... inside of a transaction block
- * ----------
- */
- oldcxt = MemoryContextSwitchTo(deftrig_cxt);
-
- /* ----------
+ *
* Drop all information about individual trigger states per
* transaction.
* ----------
l = deftrig_trigstates;
while (l != NIL)
{
- lnext = lnext(l);
+ List *next = lnext(l);
+
pfree(lfirst(l));
pfree(l);
- l = lnext;
+ l = next;
}
deftrig_trigstates = NIL;
deftrig_all_isset = true;
deftrig_all_isdeferred = stmt->deferred;
- MemoryContextSwitchTo(oldcxt);
-
return;
}
}
(char *) lfirst(l));
constr_oid = htup->t_data->t_oid;
- loid = lappend(loid, (Node *) constr_oid);
+ loid = lappendi(loid, constr_oid);
found = true;
if (hasindex)
index_close(irel);
heap_close(tgrel, AccessShareLock);
-
if (!IsTransactionBlock())
{
/* ----------
foreach(ls, deftrig_dfl_trigstates)
{
state = (DeferredTriggerStatus) lfirst(ls);
- if (state->dts_tgoid == (Oid) lfirst(l))
+ if (state->dts_tgoid == (Oid) lfirsti(l))
{
state->dts_tgisdeferred = stmt->deferred;
found = true;
{
state = (DeferredTriggerStatus)
palloc(sizeof(DeferredTriggerStatusData));
- state->dts_tgoid = (Oid) lfirst(l);
+ state->dts_tgoid = (Oid) lfirsti(l);
state->dts_tgisdeferred = stmt->deferred;
deftrig_dfl_trigstates =
foreach(ls, deftrig_trigstates)
{
state = (DeferredTriggerStatus) lfirst(ls);
- if (state->dts_tgoid == (Oid) lfirst(l))
+ if (state->dts_tgoid == (Oid) lfirsti(l))
{
state->dts_tgisdeferred = stmt->deferred;
found = true;
{
state = (DeferredTriggerStatus)
palloc(sizeof(DeferredTriggerStatusData));
- state->dts_tgoid = (Oid) lfirst(l);
+ state->dts_tgoid = (Oid) lfirsti(l);
state->dts_tgisdeferred = stmt->deferred;
deftrig_trigstates =
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
deferredTriggerAddEvent(new_event);
MemoryContextSwitchTo(oldcxt);
-
- return;
}