aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeModifyTable.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-01-12 20:47:02 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2011-01-12 20:47:02 -0500
commitd487afbb813b7ca8803e20974b9e45530a1f4ef1 (patch)
tree81c79a1546e772ad11114d705fcc3cbc3b05822a /src/backend/executor/nodeModifyTable.c
parent7a32ff97321408afa0ddfcae1a4a060062956d24 (diff)
downloadpostgresql-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.c42
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