From aaef7beb79dd397a6c7ab004909a1beebe5843b8 Mon Sep 17 00:00:00 2001 From: "Vadim B. Mikheev" Date: Fri, 29 Jan 1999 11:56:01 +0000 Subject: [PATCH] Hope that execMain.c good merged. Fix for BEFORE ROW UPDATE triggers: result tuple may be different (due to concurrent update) from one initially produced by top level plan. --- src/backend/commands/trigger.c | 29 ++++++++++++++++-------- src/backend/executor/execMain.c | 39 +++++++++++++++++++++------------ src/pl/plpgsql/src/gram.c | 26 +++++----------------- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index a5e27227cf..aac9f2599f 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -42,7 +42,7 @@ void FreeTriggerDesc(Relation relation); static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger); static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, - bool before); + TupleTableSlot **newSlot); extern GlobalMemory CacheCxt; @@ -664,9 +664,10 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid) Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; HeapTuple trigtuple; HeapTuple newtuple = NULL; + TupleTableSlot *newSlot; int i; - trigtuple = GetTupleForTrigger(estate, tupleid, true); + trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot); if (trigtuple == NULL) return false; @@ -701,7 +702,7 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid) HeapTuple trigtuple; int i; - trigtuple = GetTupleForTrigger(estate, tupleid, false); + trigtuple = GetTupleForTrigger(estate, tupleid, NULL); Assert(trigtuple != NULL); SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); @@ -732,12 +733,20 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) HeapTuple trigtuple; HeapTuple oldtuple; HeapTuple intuple = newtuple; + TupleTableSlot *newSlot; int i; - trigtuple = GetTupleForTrigger(estate, tupleid, true); + trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot); if (trigtuple == NULL) return NULL; + /* + * In READ COMMITTED isolevel it's possible that newtuple + * was changed due to concurrent update. + */ + if (newSlot != NULL) + intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot); + SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); SaveTriggerData->tg_event = TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; @@ -770,7 +779,7 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) HeapTuple trigtuple; int i; - trigtuple = GetTupleForTrigger(estate, tupleid, false); + trigtuple = GetTupleForTrigger(estate, tupleid, NULL); Assert(trigtuple != NULL); SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); @@ -794,20 +803,21 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid); static HeapTuple -GetTupleForTrigger(EState *estate, ItemPointer tid, bool before) +GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot) { Relation relation = estate->es_result_relation_info->ri_RelationDesc; HeapTupleData tuple; HeapTuple result; Buffer buffer; - if (before) + if (newSlot != NULL) { int test; /* * mark tuple for update */ + *newSlot = NULL; tuple.t_self = *tid; ltrmark:; test = heap_mark4update(relation, &tuple, &buffer); @@ -826,13 +836,14 @@ ltrmark:; elog(ERROR, "Can't serialize access due to concurrent update"); else if (!(ItemPointerEquals(&(tuple.t_self), tid))) { - TupleTableSlot *slot = EvalPlanQual(estate, + TupleTableSlot *epqslot = EvalPlanQual(estate, estate->es_result_relation_info->ri_RangeTableIndex, &(tuple.t_self)); - if (!(TupIsNull(slot))) + if (!(TupIsNull(epqslot))) { *tid = tuple.t_self; + *newSlot = epqslot; goto ltrmark; } } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ba4d09eaa3..f074ce951f 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.67 1999/01/29 10:15:09 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.68 1999/01/29 11:56:00 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -66,7 +66,7 @@ static void EndPlan(Plan *plan, EState *estate); static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan, CmdType operation, int numberTuples, ScanDirection direction, DestReceiver *destfunc); -static void ExecRetrieve(TupleTableSlot *slot, +static void ExecRetrieve(TupleTableSlot *slot, DestReceiver *destfunc, EState *estate); static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid, @@ -170,11 +170,11 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate) TupleTableSlot * ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) { - CmdType operation; - Plan *plan; + CmdType operation; + Plan *plan; TupleTableSlot *result; - CommandDest dest; - void (*destination) (); + CommandDest dest; + DestReceiver *destfunc; /****************** * sanity checks @@ -190,10 +190,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation = queryDesc->operation; plan = queryDesc->plantree; dest = queryDesc->dest; - destination = (void (*) ()) DestToFunction(dest); + destfunc = DestToFunction(dest); estate->es_processed = 0; estate->es_lastoid = InvalidOid; + /****************** + * FIXME: the dest setup function ought to be handed the tuple desc + * for the tuples to be output, but I'm not quite sure how to get that + * info at this point. For now, passing NULL is OK because no existing + * dest setup function actually uses the pointer. + ****************** + */ + (*destfunc->setup) (destfunc, (TupleDesc) NULL); + switch (feature) { @@ -203,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, ALL_TUPLES, ForwardScanDirection, - destination); + destfunc); break; case EXEC_FOR: result = ExecutePlan(estate, @@ -211,7 +220,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, count, ForwardScanDirection, - destination); + destfunc); break; /****************** @@ -224,7 +233,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, count, BackwardScanDirection, - destination); + destfunc); break; /****************** @@ -238,7 +247,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, ONE_TUPLE, ForwardScanDirection, - destination); + destfunc); break; default: result = NULL; @@ -246,6 +255,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) break; } + (*destfunc->cleanup) (destfunc); + return result; } @@ -756,7 +767,7 @@ ExecutePlan(EState *estate, CmdType operation, int numberTuples, ScanDirection direction, - DestReceiver *destfunc) + DestReceiver* destfunc) { JunkFilter *junkfilter; @@ -941,7 +952,7 @@ lmark:; { case CMD_SELECT: ExecRetrieve(slot, /* slot containing tuple */ - destfunc, /* print function */ + destfunc, /* destination's tuple-receiver obj */ estate); /* */ result = slot; break; @@ -1024,7 +1035,7 @@ ExecRetrieve(TupleTableSlot *slot, * send the tuple to the front end (or the screen) ****************** */ - (*printfunc) (tuple, attrtype); + (*destfunc->receiveTuple) (tuple, attrtype, destfunc); IncrRetrieved(); (estate->es_processed)++; } diff --git a/src/pl/plpgsql/src/gram.c b/src/pl/plpgsql/src/gram.c index 2d4ef46a1b..2ca9936c32 100644 --- a/src/pl/plpgsql/src/gram.c +++ b/src/pl/plpgsql/src/gram.c @@ -65,7 +65,7 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/gram.c,v 1.3 1999/01/28 11:50:41 wieck Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/gram.c,v 1.4 1999/01/29 11:56:01 vadim Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -414,7 +414,7 @@ static const short yycheck[] = { 21, 152, 62 }; /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/share/bison.simple" +#line 3 "/usr/share/misc/bison.simple" /* Skeleton output parser for bison, Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. @@ -467,16 +467,6 @@ void *alloca (); #endif /* not GNU C. */ #endif /* alloca not defined. */ -#ifdef __cplusplus -extern "C" { - void yyerror(char *); - int yylex(); -}; -#else - extern void yyerror(char *); - extern int yylex(); -#endif - /* This is the parser code that is written into each bison parser when the %semantic_parser declaration is not specified in the grammar. It was written by Richard Stallman by simplifying the hairy parser @@ -573,13 +563,9 @@ int yydebug; /* nonzero means print parse trace */ #define YYMAXDEPTH 10000 #endif -#ifndef YYPARSE_RETURN_TYPE -#define YYPARSE_RETURN_TYPE int -#endif - /* Prevent warning if -Wstrict-prototypes. */ #ifdef __GNUC__ -YYPARSE_RETURN_TYPE yyparse (void); +int yyparse (void); #endif #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ @@ -621,7 +607,7 @@ __yy_memcpy (char *to, char *from, int count) #endif #endif -#line 196 "/usr/share/bison.simple" +#line 196 "/usr/share/misc/bison.simple" /* The user can define YYPARSE_PARAM as the name of an argument to be passed into yyparse. The argument should have type void *. @@ -642,7 +628,7 @@ __yy_memcpy (char *to, char *from, int count) #define YYPARSE_PARAM_DECL #endif /* not YYPARSE_PARAM */ -YYPARSE_RETURN_TYPE +int yyparse(YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL { @@ -1905,7 +1891,7 @@ case 105: break;} } /* the action file gets copied in in place of this dollarsign */ -#line 498 "/usr/share/bison.simple" +#line 498 "/usr/share/misc/bison.simple" yyvsp -= yylen; yyssp -= yylen;