aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c263
1 files changed, 104 insertions, 159 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index cc97c569ba5..d386fe5665f 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.125 2002/08/13 17:22:08 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.126 2002/08/17 12:15:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1266,12 +1266,10 @@ static MemoryContext deftrig_cxt = NULL;
* state IMMEDIATE or DEFERRED.
* ----------
*/
-static bool deftrig_dfl_all_isset = false;
-static bool deftrig_dfl_all_isdeferred = false;
static List *deftrig_dfl_trigstates = NIL;
-static bool deftrig_all_isset;
-static bool deftrig_all_isdeferred;
+static bool deftrig_all_isset = false;
+static bool deftrig_all_isdeferred = false;
static List *deftrig_trigstates;
/* ----------
@@ -1702,8 +1700,11 @@ DeferredTriggerBeginXact(void)
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
- deftrig_all_isset = deftrig_dfl_all_isset;
- deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
+ deftrig_all_isset = false;
+ /*
+ * If unspecified, constraints default to IMMEDIATE, per SQL
+ */
+ deftrig_all_isdeferred = false;
deftrig_trigstates = NIL;
foreach(l, deftrig_dfl_trigstates)
@@ -1793,189 +1794,125 @@ DeferredTriggerAbortXact(void)
/* ----------
* DeferredTriggerSetState()
*
- * Called for the users SET CONSTRAINTS ... utility command.
+ * Called for the SET CONSTRAINTS ... utility command.
* ----------
*/
void
DeferredTriggerSetState(ConstraintsSetStmt *stmt)
{
- Relation tgrel;
List *l;
- List *ls;
- List *loid = NIL;
- MemoryContext oldcxt;
- bool found;
- DeferredTriggerStatus state;
+
+ /*
+ * If called outside a transaction block, we can safely return: this
+ * command cannot effect any subsequent transactions, and there
+ * are no "session-level" trigger settings.
+ */
+ if (!IsTransactionBlock())
+ return;
/*
* Handle SET CONSTRAINTS ALL ...
*/
if (stmt->constraints == NIL)
{
- if (!IsTransactionBlock())
- {
- /*
- * ... outside of a transaction block
- *
- * Drop all information about individual trigger states per
- * session.
- */
- l = deftrig_dfl_trigstates;
- while (l != NIL)
- {
- List *next = lnext(l);
-
- pfree(lfirst(l));
- pfree(l);
- l = next;
- }
- deftrig_dfl_trigstates = NIL;
-
- /*
- * Set the session ALL state to known.
- */
- deftrig_dfl_all_isset = true;
- deftrig_dfl_all_isdeferred = stmt->deferred;
-
- return;
- }
- else
+ /*
+ * Drop all per-transaction information about individual trigger
+ * states.
+ */
+ l = deftrig_trigstates;
+ while (l != NIL)
{
- /*
- * ... inside of a transaction block
- *
- * Drop all information about individual trigger states per
- * transaction.
- */
- l = deftrig_trigstates;
- while (l != NIL)
- {
- List *next = lnext(l);
-
- pfree(lfirst(l));
- pfree(l);
- l = next;
- }
- deftrig_trigstates = NIL;
-
- /*
- * Set the per transaction ALL state to known.
- */
- deftrig_all_isset = true;
- deftrig_all_isdeferred = stmt->deferred;
+ List *next = lnext(l);
- return;
+ pfree(lfirst(l));
+ pfree(l);
+ l = next;
}
- }
-
- /* ----------
- * Handle SET CONSTRAINTS constraint-name [, ...]
- * First lookup all trigger Oid's for the constraint names.
- * ----------
- */
- tgrel = heap_openr(TriggerRelationName, AccessShareLock);
-
- foreach(l, stmt->constraints)
- {
- char *cname = strVal(lfirst(l));
- ScanKeyData skey;
- SysScanDesc tgscan;
- HeapTuple htup;
-
- /*
- * Check that only named constraints are set explicitly
- */
- if (strlen(cname) == 0)
- elog(ERROR, "unnamed constraints cannot be set explicitly");
+ deftrig_trigstates = NIL;
/*
- * Setup to scan pg_trigger by tgconstrname ...
+ * Set the per-transaction ALL state to known.
*/
- ScanKeyEntryInitialize(&skey,
- (bits16) 0x0,
- (AttrNumber) Anum_pg_trigger_tgconstrname,
- (RegProcedure) F_NAMEEQ,
- PointerGetDatum(cname));
-
- tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,
- SnapshotNow, 1, &skey);
-
- /*
- * ... and search for the constraint trigger row
+ deftrig_all_isset = true;
+ deftrig_all_isdeferred = stmt->deferred;
+ }
+ else
+ {
+ Relation tgrel;
+ MemoryContext oldcxt;
+ bool found;
+ DeferredTriggerStatus state;
+ List *ls;
+ List *loid = NIL;
+
+ /* ----------
+ * Handle SET CONSTRAINTS constraint-name [, ...]
+ * First lookup all trigger Oid's for the constraint names.
+ * ----------
*/
- found = false;
+ tgrel = heap_openr(TriggerRelationName, AccessShareLock);
- while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
+ foreach(l, stmt->constraints)
{
- Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
- Oid constr_oid;
+ char *cname = strVal(lfirst(l));
+ ScanKeyData skey;
+ SysScanDesc tgscan;
+ HeapTuple htup;
/*
- * If we found some, check that they fit the deferrability but
- * skip ON <event> RESTRICT ones, since they are silently
- * never deferrable.
+ * Check that only named constraints are set explicitly
*/
- if (stmt->deferred && !pg_trigger->tgdeferrable &&
- pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
- pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
- elog(ERROR, "Constraint '%s' is not deferrable",
- cname);
-
- AssertTupleDescHasOid(tgrel->rd_att);
- constr_oid = HeapTupleGetOid(htup);
- loid = lappendi(loid, constr_oid);
- found = true;
- }
-
- systable_endscan(tgscan);
+ if (strlen(cname) == 0)
+ elog(ERROR, "unnamed constraints cannot be set explicitly");
- /*
- * Not found ?
- */
- if (!found)
- elog(ERROR, "Constraint '%s' does not exist", cname);
- }
- heap_close(tgrel, AccessShareLock);
+ /*
+ * Setup to scan pg_trigger by tgconstrname ...
+ */
+ ScanKeyEntryInitialize(&skey, (bits16) 0x0,
+ (AttrNumber) Anum_pg_trigger_tgconstrname,
+ (RegProcedure) F_NAMEEQ,
+ PointerGetDatum(cname));
- if (!IsTransactionBlock())
- {
- /*
- * Outside of a transaction block set the trigger states of
- * individual triggers on session level.
- */
- oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
+ tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,
+ SnapshotNow, 1, &skey);
- foreach(l, loid)
- {
+ /*
+ * ... and search for the constraint trigger row
+ */
found = false;
- foreach(ls, deftrig_dfl_trigstates)
- {
- state = (DeferredTriggerStatus) lfirst(ls);
- if (state->dts_tgoid == (Oid) lfirsti(l))
- {
- state->dts_tgisdeferred = stmt->deferred;
- found = true;
- break;
- }
- }
- if (!found)
+
+ while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{
- state = (DeferredTriggerStatus)
- palloc(sizeof(DeferredTriggerStatusData));
- state->dts_tgoid = (Oid) lfirsti(l);
- state->dts_tgisdeferred = stmt->deferred;
+ Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
+ Oid constr_oid;
- deftrig_dfl_trigstates =
- lappend(deftrig_dfl_trigstates, state);
+ /*
+ * If we found some, check that they fit the deferrability but
+ * skip ON <event> RESTRICT ones, since they are silently
+ * never deferrable.
+ */
+ if (stmt->deferred && !pg_trigger->tgdeferrable &&
+ pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
+ pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
+ elog(ERROR, "Constraint '%s' is not deferrable",
+ cname);
+
+ AssertTupleDescHasOid(tgrel->rd_att);
+ constr_oid = HeapTupleGetOid(htup);
+ loid = lappendi(loid, constr_oid);
+ found = true;
}
- }
- MemoryContextSwitchTo(oldcxt);
+ systable_endscan(tgscan);
+
+ /*
+ * Not found ?
+ */
+ if (!found)
+ elog(ERROR, "Constraint '%s' does not exist", cname);
+ }
+ heap_close(tgrel, AccessShareLock);
- return;
- }
- else
- {
/*
* Inside of a transaction block set the trigger states of
* individual triggers on transaction level.
@@ -2008,9 +1945,17 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
}
MemoryContextSwitchTo(oldcxt);
-
- return;
}
+
+ /*
+ * SQL99 requires that when a constraint is set to IMMEDIATE, any
+ * deferred checks against that constraint must be made when the
+ * SET CONSTRAINTS command is executed -- i.e. the effects of the
+ * SET CONSTRAINTS command applies retroactively. This happens "for
+ * free" since we have already made the necessary modifications to
+ * the constraints, and deferredTriggerEndQuery() is called by
+ * finish_xact_command().
+ */
}