diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-12 20:47:02 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-12 20:47:02 -0500 |
commit | d487afbb813b7ca8803e20974b9e45530a1f4ef1 (patch) | |
tree | 81c79a1546e772ad11114d705fcc3cbc3b05822a /src/backend/executor/nodeModifyTable.c | |
parent | 7a32ff97321408afa0ddfcae1a4a060062956d24 (diff) | |
download | postgresql-d487afbb813b7ca8803e20974b9e45530a1f4ef1.tar.gz postgresql-d487afbb813b7ca8803e20974b9e45530a1f4ef1.zip |
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.
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 42 |
1 files changed, 22 insertions, 20 deletions
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 |