mirror of
https://github.com/postgres/postgres.git
synced 2025-06-27 23:21:58 +03:00
Fix PlanRowMark/ExecRowMark structures to handle inheritance correctly.
In an inherited UPDATE/DELETE, each target table has its own subplan, because it might have a column set different from other targets. This means that the resjunk columns we add to support EvalPlanQual might be at different physical column numbers in each subplan. The EvalPlanQual rewrite I did for 9.0 failed to account for this, resulting in possible misbehavior or even crashes during concurrent updates to the same row, as seen in a recent report from Gordon Shannon. Revise the data structure so that we track resjunk column numbers separately for each subplan. I also chose to move responsibility for identifying the physical column numbers back to executor startup, instead of assuming that numbers derived during preprocess_targetlist would stay valid throughout subsequent massaging of the plan. That's a bit slower, so we might want to consider undoing it someday; but it would complicate the patch considerably and didn't seem justifiable in a bug fix that has to be back-patched to 9.0.
This commit is contained in:
@ -824,7 +824,8 @@ ExecModifyTable(ModifyTableState *node)
|
||||
estate->es_result_relation_info++;
|
||||
subplanstate = node->mt_plans[node->mt_whichplan];
|
||||
junkfilter = estate->es_result_relation_info->ri_junkFilter;
|
||||
EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan);
|
||||
EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
|
||||
node->mt_arowmarks[node->mt_whichplan]);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@ -953,10 +954,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
mtstate->ps.targetlist = NIL; /* not actually used */
|
||||
|
||||
mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
|
||||
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
|
||||
mtstate->mt_nplans = nplans;
|
||||
mtstate->operation = operation;
|
||||
/* set up epqstate with dummy subplan pointer for the moment */
|
||||
EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, node->epqParam);
|
||||
/* set up epqstate with dummy subplan data for the moment */
|
||||
EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
|
||||
mtstate->fireBSTriggers = true;
|
||||
|
||||
/* For the moment, assume our targets are exactly the global result rels */
|
||||
@ -978,11 +980,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
}
|
||||
estate->es_result_relation_info = NULL;
|
||||
|
||||
/* select first subplan */
|
||||
mtstate->mt_whichplan = 0;
|
||||
subplan = (Plan *) linitial(node->plans);
|
||||
EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan);
|
||||
|
||||
/*
|
||||
* Initialize RETURNING projections if needed.
|
||||
*/
|
||||
@ -1046,8 +1043,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
foreach(l, node->rowMarks)
|
||||
{
|
||||
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
|
||||
ExecRowMark *erm = NULL;
|
||||
ListCell *lce;
|
||||
ExecRowMark *erm;
|
||||
|
||||
Assert(IsA(rc, PlanRowMark));
|
||||
|
||||
@ -1055,20 +1051,26 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
if (rc->isParent)
|
||||
continue;
|
||||
|
||||
foreach(lce, estate->es_rowMarks)
|
||||
{
|
||||
erm = (ExecRowMark *) lfirst(lce);
|
||||
if (erm->rti == rc->rti)
|
||||
break;
|
||||
erm = NULL;
|
||||
}
|
||||
if (erm == NULL)
|
||||
elog(ERROR, "failed to find ExecRowMark for PlanRowMark %u",
|
||||
rc->rti);
|
||||
/* find ExecRowMark (same for all subplans) */
|
||||
erm = ExecFindRowMark(estate, rc->rti);
|
||||
|
||||
EvalPlanQualAddRowMark(&mtstate->mt_epqstate, erm);
|
||||
/* build ExecAuxRowMark for each subplan */
|
||||
for (i = 0; i < nplans; i++)
|
||||
{
|
||||
ExecAuxRowMark *aerm;
|
||||
|
||||
subplan = mtstate->mt_plans[i]->plan;
|
||||
aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
|
||||
mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
|
||||
}
|
||||
}
|
||||
|
||||
/* select first subplan */
|
||||
mtstate->mt_whichplan = 0;
|
||||
subplan = (Plan *) linitial(node->plans);
|
||||
EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
|
||||
mtstate->mt_arowmarks[0]);
|
||||
|
||||
/*
|
||||
* Initialize the junk filter(s) if needed. INSERT queries need a filter
|
||||
* if there are any junk attrs in the tlist. UPDATE and DELETE always
|
||||
|
Reference in New Issue
Block a user