diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-12 20:47:09 -0500 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-12 20:47:09 -0500 |
| commit | fed8dcdb84d255088d22efa3156a193f3399e792 (patch) | |
| tree | 8262474db57695b73d2fcdb0975a5f89f5573307 /src/backend/executor/nodeModifyTable.c | |
| parent | a1ed4cf6ca6ee2115d9f618ed7930a97842042a8 (diff) | |
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 969938130ec..f4b2b16b69e 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -701,7 +701,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 @@ -815,10 +816,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 */ @@ -840,11 +842,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. */ @@ -908,8 +905,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)); @@ -917,20 +913,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 |
