diff options
| author | Bruce Momjian | 2002-11-23 03:59:09 +0000 |
|---|---|---|
| committer | Bruce Momjian | 2002-11-23 03:59:09 +0000 |
| commit | 1b7f3cc02d6129b678ab651716c19d2bf8f7f6ab (patch) | |
| tree | c9929a24cffcdf4989ca67f3ef42056fe2c2f52e /src/backend | |
| parent | ea29b32758bdd293a9b932195db662209bb0ee52 (diff) | |
This patch implements FOR EACH STATEMENT triggers, per my email to
-hackers a couple days ago.
Notes/caveats:
- added regression tests for the new functionality, all
regression tests pass on my machine
- added pg_dump support
- updated PL/PgSQL to support per-statement triggers; didn't
look at the other procedural languages.
- there's (even) more code duplication in trigger.c than there
was previously. Any suggestions on how to refactor the
ExecXXXTriggers() functions to reuse more code would be
welcome -- I took a brief look at it, but couldn't see an
easy way to do it (there are several subtly-different
versions of the code in question)
- updated the documentation. I also took the liberty of
removing a big chunk of duplicated syntax documentation in
the Programmer's Guide on triggers, and moving that
information to the CREATE TRIGGER reference page.
- I also included some spelling fixes and similar small
cleanups I noticed while making the changes. If you'd like
me to split those into a separate patch, let me know.
Neil Conway
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/access/transam/xact.c | 14 | ||||
| -rw-r--r-- | src/backend/commands/copy.c | 19 | ||||
| -rw-r--r-- | src/backend/commands/tablecmds.c | 15 | ||||
| -rw-r--r-- | src/backend/commands/trigger.c | 260 | ||||
| -rw-r--r-- | src/backend/executor/execMain.c | 63 | ||||
| -rw-r--r-- | src/backend/nodes/copyfuncs.c | 10 | ||||
| -rw-r--r-- | src/backend/nodes/equalfuncs.c | 10 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 30 | ||||
| -rw-r--r-- | src/backend/utils/adt/pg_lzcompress.c | 12 |
9 files changed, 316 insertions, 117 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 607a47f124..0f30e13c84 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.139 2002/11/18 01:17:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.140 2002/11/23 03:59:06 momjian Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -901,18 +901,6 @@ StartTransaction(void) } -#ifdef NOT_USED -/* --------------- - * Tell me if we are currently in progress - * --------------- - */ -bool -CurrentXactInProgress(void) -{ - return CurrentTransactionState->state == TRANS_INPROGRESS; -} -#endif - /* -------------------------------- * CommitTransaction * -------------------------------- diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 8dbde72be4..b0dd47f945 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.180 2002/11/13 00:39:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.181 2002/11/23 03:59:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -877,6 +877,15 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, } } + /* + * Check BEFORE STATEMENT insertion triggers. It's debateable + * whether we should do this for COPY, since it's not really an + * "INSERT" statement as such. However, executing these triggers + * maintains consistency with the EACH ROW triggers that we already + * fire on COPY. + */ + ExecBSInsertTriggers(estate, resultRelInfo); + if (!binary) { file_has_oids = oids; /* must rely on user to tell us this... */ @@ -1223,8 +1232,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); /* AFTER ROW INSERT Triggers */ - if (resultRelInfo->ri_TrigDesc) - ExecARInsertTriggers(estate, resultRelInfo, tuple); + ExecARInsertTriggers(estate, resultRelInfo, tuple); } } @@ -1233,6 +1241,11 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, */ copy_lineno = 0; + /* + * Execute AFTER STATEMENT insertion triggers + */ + ExecASInsertTriggers(estate, resultRelInfo); + MemoryContextSwitchTo(oldcontext); pfree(values); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cda8687e44..e3c3d0c290 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.54 2002/11/15 02:50:05 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.55 2002/11/23 03:59:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -3321,11 +3321,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, fk_trigger->actions[0] = 'i'; fk_trigger->actions[1] = 'u'; fk_trigger->actions[2] = '\0'; - fk_trigger->lang = NULL; - fk_trigger->text = NULL; - fk_trigger->attr = NIL; - fk_trigger->when = NULL; fk_trigger->isconstraint = true; fk_trigger->deferrable = fkconstraint->deferrable; fk_trigger->initdeferred = fkconstraint->initdeferred; @@ -3374,11 +3370,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, fk_trigger->row = true; fk_trigger->actions[0] = 'd'; fk_trigger->actions[1] = '\0'; - fk_trigger->lang = NULL; - fk_trigger->text = NULL; - fk_trigger->attr = NIL; - fk_trigger->when = NULL; fk_trigger->isconstraint = true; fk_trigger->deferrable = fkconstraint->deferrable; fk_trigger->initdeferred = fkconstraint->initdeferred; @@ -3445,11 +3437,6 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, fk_trigger->row = true; fk_trigger->actions[0] = 'u'; fk_trigger->actions[1] = '\0'; - fk_trigger->lang = NULL; - fk_trigger->text = NULL; - - fk_trigger->attr = NIL; - fk_trigger->when = NULL; fk_trigger->isconstraint = true; fk_trigger->deferrable = fkconstraint->deferrable; fk_trigger->initdeferred = fkconstraint->initdeferred; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 5c56a7ccfc..c9e2d87ff9 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.139 2002/11/13 00:39:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.140 2002/11/23 03:59:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -47,7 +47,7 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, FmgrInfo *finfo, MemoryContext per_tuple_context); static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, - HeapTuple oldtup, HeapTuple newtup); + bool row_trigger, HeapTuple oldtup, HeapTuple newtup); static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno, Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo, MemoryContext per_tuple_context); @@ -147,12 +147,14 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) { /* foreign key constraint trigger */ - aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_REFERENCES); + aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), + ACL_REFERENCES); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, RelationGetRelationName(rel)); if (constrrelid != InvalidOid) { - aclresult = pg_class_aclcheck(constrrelid, GetUserId(), ACL_REFERENCES); + aclresult = pg_class_aclcheck(constrrelid, GetUserId(), + ACL_REFERENCES); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, get_rel_name(constrrelid)); } @@ -160,7 +162,8 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) else { /* real trigger */ - aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_TRIGGER); + aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), + ACL_TRIGGER); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, RelationGetRelationName(rel)); } @@ -195,10 +198,8 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) 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++) + for (i = 0; i < 2 && stmt->actions[i]; i++) { switch (stmt->actions[i]) { @@ -1131,6 +1132,64 @@ ExecCallTriggerFunc(TriggerData *trigdata, return (HeapTuple) DatumGetPointer(result); } +void +ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo) +{ + TriggerDesc *trigdesc; + int ntrigs; + int *tgindx; + int i; + TriggerData LocTriggerData; + + trigdesc = relinfo->ri_TrigDesc; + + if (trigdesc == NULL) + return; + + ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_INSERT]; + tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_INSERT]; + + if (ntrigs == 0) + return; + + /* Allocate cache space for fmgr lookup info, if not done yet */ + if (relinfo->ri_TrigFunctions == NULL) + relinfo->ri_TrigFunctions = (FmgrInfo *) + palloc0(trigdesc->numtriggers * sizeof(FmgrInfo)); + + LocTriggerData.type = T_TriggerData; + LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | + TRIGGER_EVENT_BEFORE; + LocTriggerData.tg_relation = relinfo->ri_RelationDesc; + LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigtuple = NULL; + for (i = 0; i < ntrigs; i++) + { + Trigger *trigger = &trigdesc->triggers[tgindx[i]]; + HeapTuple newtuple; + + if (!trigger->tgenabled) + continue; + LocTriggerData.tg_trigger = trigger; + newtuple = ExecCallTriggerFunc(&LocTriggerData, + relinfo->ri_TrigFunctions + tgindx[i], + GetPerTupleMemoryContext(estate)); + + if (newtuple) + elog(ERROR, "BEFORE STATEMENT trigger cannot return a value."); + } +} + +void +ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo) +{ + TriggerDesc *trigdesc = relinfo->ri_TrigDesc; + + if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_INSERT] > 0) + DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT, + false, NULL, NULL); +} + HeapTuple ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple) @@ -1149,7 +1208,9 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, palloc0(trigdesc->numtriggers * sizeof(FmgrInfo)); LocTriggerData.type = T_TriggerData; - LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; + LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | + TRIGGER_EVENT_ROW | + TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; for (i = 0; i < ntrigs; i++) @@ -1177,9 +1238,67 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0) + if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0) DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT, - NULL, trigtuple); + true, NULL, trigtuple); +} + +void +ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo) +{ + TriggerDesc *trigdesc; + int ntrigs; + int *tgindx; + int i; + TriggerData LocTriggerData; + + trigdesc = relinfo->ri_TrigDesc; + + if (trigdesc == NULL) + return; + + ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_DELETE]; + tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_DELETE]; + + if (ntrigs == 0) + return; + + /* Allocate cache space for fmgr lookup info, if not done yet */ + if (relinfo->ri_TrigFunctions == NULL) + relinfo->ri_TrigFunctions = (FmgrInfo *) + palloc0(trigdesc->numtriggers * sizeof(FmgrInfo)); + + LocTriggerData.type = T_TriggerData; + LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | + TRIGGER_EVENT_BEFORE; + LocTriggerData.tg_relation = relinfo->ri_RelationDesc; + LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigtuple = NULL; + for (i = 0; i < ntrigs; i++) + { + Trigger *trigger = &trigdesc->triggers[tgindx[i]]; + HeapTuple newtuple; + + if (!trigger->tgenabled) + continue; + LocTriggerData.tg_trigger = trigger; + newtuple = ExecCallTriggerFunc(&LocTriggerData, + relinfo->ri_TrigFunctions + tgindx[i], + GetPerTupleMemoryContext(estate)); + + if (newtuple) + elog(ERROR, "BEFORE STATEMENT trigger cannot return a value."); + } +} + +void +ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo) +{ + TriggerDesc *trigdesc = relinfo->ri_TrigDesc; + + if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_DELETE] > 0) + DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, + false, NULL, NULL); } bool @@ -1205,7 +1324,9 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, palloc0(trigdesc->numtriggers * sizeof(FmgrInfo)); LocTriggerData.type = T_TriggerData; - LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; + LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | + TRIGGER_EVENT_ROW | + TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; for (i = 0; i < ntrigs; i++) @@ -1235,17 +1356,75 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - if (trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0) + if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0) { HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, NULL); DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, - trigtuple, NULL); + true, trigtuple, NULL); heap_freetuple(trigtuple); } } +void +ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo) +{ + TriggerDesc *trigdesc; + int ntrigs; + int *tgindx; + int i; + TriggerData LocTriggerData; + + trigdesc = relinfo->ri_TrigDesc; + + if (trigdesc == NULL) + return; + + ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_UPDATE]; + tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_UPDATE]; + + if (ntrigs == 0) + return; + + /* Allocate cache space for fmgr lookup info, if not done yet */ + if (relinfo->ri_TrigFunctions == NULL) + relinfo->ri_TrigFunctions = (FmgrInfo *) + palloc0(trigdesc->numtriggers * sizeof(FmgrInfo)); + + LocTriggerData.type = T_TriggerData; + LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE | + TRIGGER_EVENT_BEFORE; + LocTriggerData.tg_relation = relinfo->ri_RelationDesc; + LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_trigtuple = NULL; + for (i = 0; i < ntrigs; i++) + { + Trigger *trigger = &trigdesc->triggers[tgindx[i]]; + HeapTuple newtuple; + + if (!trigger->tgenabled) + continue; + LocTriggerData.tg_trigger = trigger; + newtuple = ExecCallTriggerFunc(&LocTriggerData, + relinfo->ri_TrigFunctions + tgindx[i], + GetPerTupleMemoryContext(estate)); + + if (newtuple) + elog(ERROR, "BEFORE STATEMENT trigger cannot return a value."); + } +} + +void +ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo) +{ + TriggerDesc *trigdesc = relinfo->ri_TrigDesc; + + if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_UPDATE] > 0) + DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, + false, NULL, NULL); +} + HeapTuple ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple newtuple) @@ -1265,8 +1444,8 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, return NULL; /* - * In READ COMMITTED isolevel it's possible that newtuple was changed - * due to concurrent update. + * In READ COMMITTED isolation level it's possible that newtuple was + * changed due to concurrent update. */ if (newSlot != NULL) intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot); @@ -1306,13 +1485,13 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0) + if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0) { HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, NULL); DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, - trigtuple, newtuple); + true, trigtuple, newtuple); heap_freetuple(trigtuple); } } @@ -1344,7 +1523,7 @@ ltrmark:; case HeapTupleSelfUpdated: /* treat it as deleted; do not process */ ReleaseBuffer(buffer); - return (NULL); + return NULL; case HeapTupleMayBeUpdated: break; @@ -1371,12 +1550,12 @@ ltrmark:; * if tuple was deleted or PlanQual failed for updated * tuple - we have not process this tuple! */ - return (NULL); + return NULL; default: ReleaseBuffer(buffer); elog(ERROR, "Unknown status %u from heap_mark4update", test); - return (NULL); + return NULL; } } else @@ -1466,7 +1645,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate) /* * Not deferrable triggers (i.e. normal AFTER ROW triggers and - * constraints declared NOT DEFERRABLE, the state is allways false. + * constraints declared NOT DEFERRABLE, the state is always false. */ if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0) return false; @@ -1590,7 +1769,7 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno, */ LocTriggerData.type = T_TriggerData; LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) | - TRIGGER_EVENT_ROW; + (event->dte_event & TRIGGER_EVENT_ROW); LocTriggerData.tg_relation = rel; LocTriggerData.tg_trigger = NULL; @@ -2139,7 +2318,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) * ---------- */ static void -DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, +DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup) { Relation rel = relinfo->ri_RelationDesc; @@ -2152,7 +2331,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, int *tgindx; ItemPointerData oldctid; ItemPointerData newctid; - TriggerData LocTriggerData; if (deftrig_cxt == NULL) elog(ERROR, @@ -2175,14 +2353,25 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, */ oldcxt = MemoryContextSwitchTo(deftrig_cxt); - ntriggers = trigdesc->n_after_row[event]; - tgindx = trigdesc->tg_after_row[event]; + if (row_trigger) + { + ntriggers = trigdesc->n_after_row[event]; + tgindx = trigdesc->tg_after_row[event]; + } + else + { + ntriggers = trigdesc->n_after_statement[event]; + tgindx = trigdesc->tg_after_statement[event]; + } + new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + ntriggers * sizeof(DeferredTriggerEventItem); new_event = (DeferredTriggerEvent) palloc(new_size); new_event->dte_next = NULL; new_event->dte_event = event & TRIGGER_EVENT_OPMASK; + if (row_trigger) + new_event->dte_event |= TRIGGER_EVENT_ROW; new_event->dte_relid = rel->rd_id; ItemPointerCopy(&oldctid, &(new_event->dte_oldctid)); ItemPointerCopy(&newctid, &(new_event->dte_newctid)); @@ -2190,15 +2379,21 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, for (i = 0; i < ntriggers; i++) { Trigger *trigger = &trigdesc->triggers[tgindx[i]]; + DeferredTriggerEventItem *ev_item = &(new_event->dte_item[i]); - new_event->dte_item[i].dti_tgoid = trigger->tgoid; - new_event->dte_item[i].dti_state = + ev_item->dti_tgoid = trigger->tgoid; + ev_item->dti_state = ((trigger->tgdeferrable) ? TRIGGER_DEFERRED_DEFERRABLE : 0) | ((trigger->tginitdeferred) ? - TRIGGER_DEFERRED_INITDEFERRED : 0) | - ((trigdesc->n_before_row[event] > 0) ? - TRIGGER_DEFERRED_HAS_BEFORE : 0); + TRIGGER_DEFERRED_INITDEFERRED : 0); + + if (row_trigger && (trigdesc->n_before_row[event] > 0)) + ev_item->dti_state |= TRIGGER_DEFERRED_HAS_BEFORE; + else if (!row_trigger && (trigdesc->n_before_statement[event] > 0)) + { + ev_item->dti_state |= TRIGGER_DEFERRED_HAS_BEFORE; + } } MemoryContextSwitchTo(oldcxt); @@ -2219,6 +2414,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, Trigger *trigger = &trigdesc->triggers[tgindx[i]]; bool is_ri_trigger; bool key_unchanged; + TriggerData LocTriggerData; /* * We are interested in RI_FKEY triggers only. diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 65afe08203..779d44a8e0 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -13,7 +13,7 @@ * * These three procedures are the external interfaces to the executor. * In each case, the query descriptor and the execution state is required - * as arguments + * as arguments * * ExecutorStart() must be called at the beginning of any execution of any * query plan and ExecutorEnd() should always be called at the end of @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.186 2002/11/13 00:44:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.187 2002/11/23 03:59:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -908,12 +908,12 @@ ExecutePlan(EState *estate, ScanDirection direction, DestReceiver *destfunc) { - JunkFilter *junkfilter; - TupleTableSlot *slot; - ItemPointer tupleid = NULL; - ItemPointerData tuple_ctid; - long current_tuple_count; - TupleTableSlot *result; + JunkFilter *junkfilter; + TupleTableSlot *slot; + ItemPointer tupleid = NULL; + ItemPointerData tuple_ctid; + long current_tuple_count; + TupleTableSlot *result; /* * initialize local variables @@ -928,6 +928,24 @@ ExecutePlan(EState *estate, estate->es_direction = direction; /* + * Process BEFORE EACH STATEMENT triggers + */ + switch (operation) + { + case CMD_UPDATE: + ExecBSUpdateTriggers(estate, estate->es_result_relation_info); + break; + case CMD_DELETE: + ExecBSDeleteTriggers(estate, estate->es_result_relation_info); + break; + case CMD_INSERT: + ExecBSInsertTriggers(estate, estate->es_result_relation_info); + break; + default: + /* do nothing */ + } + + /* * Loop until we've processed the proper number of tuples from the * plan. */ @@ -1125,6 +1143,24 @@ lnext: ; } /* + * Process AFTER EACH STATEMENT triggers + */ + switch (operation) + { + case CMD_UPDATE: + ExecASUpdateTriggers(estate, estate->es_result_relation_info); + break; + case CMD_DELETE: + ExecASDeleteTriggers(estate, estate->es_result_relation_info); + break; + case CMD_INSERT: + ExecASInsertTriggers(estate, estate->es_result_relation_info); + break; + default: + /* do nothing */ + } + + /* * here, result is either a slot containing a tuple in the case of a * SELECT or NULL otherwise. */ @@ -1205,7 +1241,7 @@ ExecInsert(TupleTableSlot *slot, /* BEFORE ROW INSERT Triggers */ if (resultRelInfo->ri_TrigDesc && - resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) + resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) { HeapTuple newtuple; @@ -1256,8 +1292,7 @@ ExecInsert(TupleTableSlot *slot, ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); /* AFTER ROW INSERT Triggers */ - if (resultRelInfo->ri_TrigDesc) - ExecARInsertTriggers(estate, resultRelInfo, tuple); + ExecARInsertTriggers(estate, resultRelInfo, tuple); } /* ---------------------------------------------------------------- @@ -1346,8 +1381,7 @@ ldelete:; */ /* AFTER ROW DELETE Triggers */ - if (resultRelInfo->ri_TrigDesc) - ExecARDeleteTriggers(estate, resultRelInfo, tupleid); + ExecARDeleteTriggers(estate, resultRelInfo, tupleid); } /* ---------------------------------------------------------------- @@ -1498,8 +1532,7 @@ lreplace:; ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); /* AFTER ROW UPDATE Triggers */ - if (resultRelInfo->ri_TrigDesc) - ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple); + ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple); } static char * diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 2c345b9f78..eb9bbe9365 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.219 2002/11/19 23:21:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.220 2002/11/23 03:59:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2482,14 +2482,6 @@ _copyCreateTrigStmt(CreateTrigStmt *from) newnode->before = from->before; newnode->row = from->row; memcpy(newnode->actions, from->actions, sizeof(from->actions)); - if (from->lang) - newnode->lang = pstrdup(from->lang); - if (from->text) - newnode->text = pstrdup(from->text); - - Node_Copy(from, newnode, attr); - if (from->when) - newnode->when = pstrdup(from->when); newnode->isconstraint = from->isconstraint; newnode->deferrable = from->deferrable; newnode->initdeferred = from->initdeferred; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 61e314ff18..12781797c3 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.165 2002/11/19 23:21:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.166 2002/11/23 03:59:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1291,14 +1291,6 @@ _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b) return false; if (strcmp(a->actions, b->actions) != 0) return false; - if (!equalstr(a->lang, b->lang)) - return false; - if (!equalstr(a->text, b->text)) - return false; - if (!equal(a->attr, b->attr)) - return false; - if (!equalstr(a->when, b->when)) - return false; if (a->isconstraint != b->isconstraint) return false; if (a->deferrable != b->deferrable) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0b3bb279d5..29cba53f9f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.380 2002/11/18 17:12:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.381 2002/11/23 03:59:08 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1371,7 +1371,7 @@ opt_using: /***************************************************************************** * * QUERY : - * CREATE relname + * CREATE TABLE relname * *****************************************************************************/ @@ -2028,11 +2028,6 @@ CreateTrigStmt: n->before = $4; n->row = $8; memcpy (n->actions, $5, 4); - n->lang = NULL; /* unused */ - n->text = NULL; /* unused */ - n->attr = NULL; /* unused */ - n->when = NULL; /* unused */ - n->isconstraint = FALSE; n->deferrable = FALSE; n->initdeferred = FALSE; @@ -2053,11 +2048,6 @@ CreateTrigStmt: n->before = FALSE; n->row = TRUE; memcpy (n->actions, $6, 4); - n->lang = NULL; /* unused */ - n->text = NULL; /* unused */ - n->attr = NULL; /* unused */ - n->when = NULL; /* unused */ - n->isconstraint = TRUE; n->deferrable = ($10 & 1) != 0; n->initdeferred = ($10 & 2) != 0; @@ -2075,17 +2065,17 @@ TriggerActionTime: TriggerEvents: TriggerOneEvent { - char *e = palloc (4); + char *e = palloc(4); e[0] = $1; e[1] = 0; $$ = e; } | TriggerOneEvent OR TriggerOneEvent { - char *e = palloc (4); + char *e = palloc(4); e[0] = $1; e[1] = $3; e[2] = 0; $$ = e; } | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent { - char *e = palloc (4); + char *e = palloc(4); e[0] = $1; e[1] = $3; e[2] = $5; e[3] = 0; $$ = e; } @@ -2102,6 +2092,14 @@ TriggerForSpec: { $$ = $3; } + | /* EMPTY */ + { + /* + * If ROW/STATEMENT not specified, default to + * STATEMENT, per SQL + */ + $$ = FALSE; + } ; TriggerForOpt: @@ -2124,7 +2122,7 @@ TriggerFuncArg: ICONST { char buf[64]; - snprintf (buf, sizeof(buf), "%d", $1); + snprintf(buf, sizeof(buf), "%d", $1); $$ = makeString(pstrdup(buf)); } | FCONST { $$ = makeString($1); } diff --git a/src/backend/utils/adt/pg_lzcompress.c b/src/backend/utils/adt/pg_lzcompress.c index c16e59038e..a22c57cb4c 100644 --- a/src/backend/utils/adt/pg_lzcompress.c +++ b/src/backend/utils/adt/pg_lzcompress.c @@ -1,7 +1,7 @@ /* ---------- * pg_lzcompress.c - * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.15 2002/09/04 20:31:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.16 2002/11/23 03:59:08 momjian Exp $ * * This is an implementation of LZ compression for PostgreSQL. * It uses a simple history table and generates 2-3 byte tags @@ -87,7 +87,7 @@ * OOOO LLLL OOOO OOOO * * This limits the offset to 1-4095 (12 bits) and the length - * to 3-18 (4 bits) because 3 is allways added to it. To emit + * to 3-18 (4 bits) because 3 is always added to it. To emit * a tag of 2 bytes with a length of 2 only saves one control * bit. But we lose one byte in the possible length of a tag. * @@ -230,7 +230,7 @@ static PGLZ_Strategy strategy_default_data = { PGLZ_Strategy *PGLZ_strategy_default = &strategy_default_data; -static PGLZ_Strategy strategy_allways_data = { +static PGLZ_Strategy strategy_always_data = { 0, /* Chunks of any size are compressed */ 0, /* */ 0, /* We want to save at least one single @@ -239,7 +239,7 @@ static PGLZ_Strategy strategy_allways_data = { * bytes is found */ 6 /* Look harder for a good match. */ }; -PGLZ_Strategy *PGLZ_strategy_allways = &strategy_allways_data; +PGLZ_Strategy *PGLZ_strategy_always = &strategy_always_data; static PGLZ_Strategy strategy_never_data = { @@ -247,7 +247,7 @@ static PGLZ_Strategy strategy_never_data = { 0, /* */ 0, /* */ 0, /* Zero indicates "store uncompressed - * allways" */ + * always" */ 0 /* */ }; PGLZ_Strategy *PGLZ_strategy_never = &strategy_never_data; @@ -716,7 +716,7 @@ pglz_decompress(PGLZ_Header *source, char *dest) /* * Now we copy the bytes specified by the tag from OUTPUT - * to OUTPUT. It is dangerous and platform dependant to + * to OUTPUT. It is dangerous and platform dependent to * use memcpy() here, because the copied areas could * overlap extremely! */ |
