From d487afbb813b7ca8803e20974b9e45530a1f4ef1 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 12 Jan 2011 20:47:02 -0500 Subject: 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. --- src/backend/executor/nodeModifyTable.c | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src/backend/executor/nodeModifyTable.c') diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 36ef991f441..42662bdc461 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -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) + /* find ExecRowMark (same for all subplans) */ + erm = ExecFindRowMark(estate, rc->rti); + + /* build ExecAuxRowMark for each subplan */ + for (i = 0; i < nplans; i++) { - 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); + ExecAuxRowMark *aerm; - EvalPlanQualAddRowMark(&mtstate->mt_epqstate, erm); + 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 -- cgit v1.2.3