mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user