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.
This commit is contained in:
Vadim B. Mikheev 1999-01-29 11:56:01 +00:00
parent 1d41e88568
commit aaef7beb79
3 changed files with 51 additions and 43 deletions

View File

@ -42,7 +42,7 @@ void FreeTriggerDesc(Relation relation);
static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger); static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
bool before); TupleTableSlot **newSlot);
extern GlobalMemory CacheCxt; extern GlobalMemory CacheCxt;
@ -664,9 +664,10 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
HeapTuple trigtuple; HeapTuple trigtuple;
HeapTuple newtuple = NULL; HeapTuple newtuple = NULL;
TupleTableSlot *newSlot;
int i; int i;
trigtuple = GetTupleForTrigger(estate, tupleid, true); trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
if (trigtuple == NULL) if (trigtuple == NULL)
return false; return false;
@ -701,7 +702,7 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
HeapTuple trigtuple; HeapTuple trigtuple;
int i; int i;
trigtuple = GetTupleForTrigger(estate, tupleid, false); trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
Assert(trigtuple != NULL); Assert(trigtuple != NULL);
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
@ -732,12 +733,20 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
HeapTuple trigtuple; HeapTuple trigtuple;
HeapTuple oldtuple; HeapTuple oldtuple;
HeapTuple intuple = newtuple; HeapTuple intuple = newtuple;
TupleTableSlot *newSlot;
int i; int i;
trigtuple = GetTupleForTrigger(estate, tupleid, true); trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
if (trigtuple == NULL) if (trigtuple == NULL)
return 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 = (TriggerData *) palloc(sizeof(TriggerData));
SaveTriggerData->tg_event = SaveTriggerData->tg_event =
TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
@ -770,7 +779,7 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
HeapTuple trigtuple; HeapTuple trigtuple;
int i; int i;
trigtuple = GetTupleForTrigger(estate, tupleid, false); trigtuple = GetTupleForTrigger(estate, tupleid, NULL);
Assert(trigtuple != NULL); Assert(trigtuple != NULL);
SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); 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); extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
static HeapTuple 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; Relation relation = estate->es_result_relation_info->ri_RelationDesc;
HeapTupleData tuple; HeapTupleData tuple;
HeapTuple result; HeapTuple result;
Buffer buffer; Buffer buffer;
if (before) if (newSlot != NULL)
{ {
int test; int test;
/* /*
* mark tuple for update * mark tuple for update
*/ */
*newSlot = NULL;
tuple.t_self = *tid; tuple.t_self = *tid;
ltrmark:; ltrmark:;
test = heap_mark4update(relation, &tuple, &buffer); test = heap_mark4update(relation, &tuple, &buffer);
@ -826,13 +836,14 @@ ltrmark:;
elog(ERROR, "Can't serialize access due to concurrent update"); elog(ERROR, "Can't serialize access due to concurrent update");
else if (!(ItemPointerEquals(&(tuple.t_self), tid))) else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
{ {
TupleTableSlot *slot = EvalPlanQual(estate, TupleTableSlot *epqslot = EvalPlanQual(estate,
estate->es_result_relation_info->ri_RangeTableIndex, estate->es_result_relation_info->ri_RangeTableIndex,
&(tuple.t_self)); &(tuple.t_self));
if (!(TupIsNull(slot))) if (!(TupIsNull(epqslot)))
{ {
*tid = tuple.t_self; *tid = tuple.t_self;
*newSlot = epqslot;
goto ltrmark; goto ltrmark;
} }
} }

View File

@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * 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, static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
CmdType operation, int numberTuples, ScanDirection direction, CmdType operation, int numberTuples, ScanDirection direction,
DestReceiver *destfunc); DestReceiver *destfunc);
static void ExecRetrieve(TupleTableSlot *slot, static void ExecRetrieve(TupleTableSlot *slot,
DestReceiver *destfunc, DestReceiver *destfunc,
EState *estate); EState *estate);
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid, static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
@ -170,11 +170,11 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
TupleTableSlot * TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
{ {
CmdType operation; CmdType operation;
Plan *plan; Plan *plan;
TupleTableSlot *result; TupleTableSlot *result;
CommandDest dest; CommandDest dest;
void (*destination) (); DestReceiver *destfunc;
/****************** /******************
* sanity checks * sanity checks
@ -190,10 +190,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation = queryDesc->operation; operation = queryDesc->operation;
plan = queryDesc->plantree; plan = queryDesc->plantree;
dest = queryDesc->dest; dest = queryDesc->dest;
destination = (void (*) ()) DestToFunction(dest); destfunc = DestToFunction(dest);
estate->es_processed = 0; estate->es_processed = 0;
estate->es_lastoid = InvalidOid; 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) switch (feature)
{ {
@ -203,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
ALL_TUPLES, ALL_TUPLES,
ForwardScanDirection, ForwardScanDirection,
destination); destfunc);
break; break;
case EXEC_FOR: case EXEC_FOR:
result = ExecutePlan(estate, result = ExecutePlan(estate,
@ -211,7 +220,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
count, count,
ForwardScanDirection, ForwardScanDirection,
destination); destfunc);
break; break;
/****************** /******************
@ -224,7 +233,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
count, count,
BackwardScanDirection, BackwardScanDirection,
destination); destfunc);
break; break;
/****************** /******************
@ -238,7 +247,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
ONE_TUPLE, ONE_TUPLE,
ForwardScanDirection, ForwardScanDirection,
destination); destfunc);
break; break;
default: default:
result = NULL; result = NULL;
@ -246,6 +255,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
break; break;
} }
(*destfunc->cleanup) (destfunc);
return result; return result;
} }
@ -756,7 +767,7 @@ ExecutePlan(EState *estate,
CmdType operation, CmdType operation,
int numberTuples, int numberTuples,
ScanDirection direction, ScanDirection direction,
DestReceiver *destfunc) DestReceiver* destfunc)
{ {
JunkFilter *junkfilter; JunkFilter *junkfilter;
@ -941,7 +952,7 @@ lmark:;
{ {
case CMD_SELECT: case CMD_SELECT:
ExecRetrieve(slot, /* slot containing tuple */ ExecRetrieve(slot, /* slot containing tuple */
destfunc, /* print function */ destfunc, /* destination's tuple-receiver obj */
estate); /* */ estate); /* */
result = slot; result = slot;
break; break;
@ -1024,7 +1035,7 @@ ExecRetrieve(TupleTableSlot *slot,
* send the tuple to the front end (or the screen) * send the tuple to the front end (or the screen)
****************** ******************
*/ */
(*printfunc) (tuple, attrtype); (*destfunc->receiveTuple) (tuple, attrtype, destfunc);
IncrRetrieved(); IncrRetrieved();
(estate->es_processed)++; (estate->es_processed)++;
} }

View File

@ -65,7 +65,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -414,7 +414,7 @@ static const short yycheck[] = { 21,
152, 62 152, 62
}; };
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ /* -*-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, /* Skeleton output parser for bison,
Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
@ -467,16 +467,6 @@ void *alloca ();
#endif /* not GNU C. */ #endif /* not GNU C. */
#endif /* alloca not defined. */ #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 /* This is the parser code that is written into each bison parser
when the %semantic_parser declaration is not specified in the grammar. when the %semantic_parser declaration is not specified in the grammar.
It was written by Richard Stallman by simplifying the hairy parser 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 #define YYMAXDEPTH 10000
#endif #endif
#ifndef YYPARSE_RETURN_TYPE
#define YYPARSE_RETURN_TYPE int
#endif
/* Prevent warning if -Wstrict-prototypes. */ /* Prevent warning if -Wstrict-prototypes. */
#ifdef __GNUC__ #ifdef __GNUC__
YYPARSE_RETURN_TYPE yyparse (void); int yyparse (void);
#endif #endif
#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
@ -621,7 +607,7 @@ __yy_memcpy (char *to, char *from, int count)
#endif #endif
#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 /* The user can define YYPARSE_PARAM as the name of an argument to be passed
into yyparse. The argument should have type void *. into yyparse. The argument should have type void *.
@ -642,7 +628,7 @@ __yy_memcpy (char *to, char *from, int count)
#define YYPARSE_PARAM_DECL #define YYPARSE_PARAM_DECL
#endif /* not YYPARSE_PARAM */ #endif /* not YYPARSE_PARAM */
YYPARSE_RETURN_TYPE int
yyparse(YYPARSE_PARAM_ARG) yyparse(YYPARSE_PARAM_ARG)
YYPARSE_PARAM_DECL YYPARSE_PARAM_DECL
{ {
@ -1905,7 +1891,7 @@ case 105:
break;} break;}
} }
/* the action file gets copied in in place of this dollarsign */ /* 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; yyvsp -= yylen;
yyssp -= yylen; yyssp -= yylen;