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:
parent
1d41e88568
commit
aaef7beb79
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)++;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user