1
0
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:
Tom Lane
2011-01-12 20:47:02 -05:00
parent 7a32ff9732
commit d487afbb81
12 changed files with 193 additions and 123 deletions

View File

@ -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