diff options
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index a9fd8c4974f..3f1f9c093ee 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.1 2009/10/10 01:43:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.2 2009/10/26 02:26:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -273,7 +273,7 @@ ExecInsert(TupleTableSlot *slot, static TupleTableSlot * ExecDelete(ItemPointer tupleid, TupleTableSlot *planSlot, - PlanState *subplanstate, + EPQState *epqstate, EState *estate) { ResultRelInfo *resultRelInfo; @@ -294,7 +294,7 @@ ExecDelete(ItemPointer tupleid, { bool dodelete; - dodelete = ExecBRDeleteTriggers(estate, subplanstate, resultRelInfo, + dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo, tupleid); if (!dodelete) /* "do nothing" */ @@ -329,13 +329,14 @@ ldelete:; ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); - else if (!ItemPointerEquals(tupleid, &update_ctid)) + if (!ItemPointerEquals(tupleid, &update_ctid)) { TupleTableSlot *epqslot; epqslot = EvalPlanQual(estate, + epqstate, + resultRelationDesc, resultRelInfo->ri_RangeTableIndex, - subplanstate, &update_ctid, update_xmax); if (!TupIsNull(epqslot)) @@ -416,7 +417,7 @@ static TupleTableSlot * ExecUpdate(ItemPointer tupleid, TupleTableSlot *slot, TupleTableSlot *planSlot, - PlanState *subplanstate, + EPQState *epqstate, EState *estate) { HeapTuple tuple; @@ -451,7 +452,7 @@ ExecUpdate(ItemPointer tupleid, { HeapTuple newtuple; - newtuple = ExecBRUpdateTriggers(estate, subplanstate, resultRelInfo, + newtuple = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo, tupleid, tuple); if (newtuple == NULL) /* "do nothing" */ @@ -515,13 +516,14 @@ lreplace:; ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); - else if (!ItemPointerEquals(tupleid, &update_ctid)) + if (!ItemPointerEquals(tupleid, &update_ctid)) { TupleTableSlot *epqslot; epqslot = EvalPlanQual(estate, + epqstate, + resultRelationDesc, resultRelInfo->ri_RangeTableIndex, - subplanstate, &update_ctid, update_xmax); if (!TupIsNull(epqslot)) @@ -685,12 +687,14 @@ 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); continue; } else break; } + EvalPlanQualSetSlot(&node->mt_epqstate, planSlot); slot = planSlot; if (junkfilter != NULL) @@ -728,11 +732,11 @@ ExecModifyTable(ModifyTableState *node) break; case CMD_UPDATE: slot = ExecUpdate(tupleid, slot, planSlot, - subplanstate, estate); + &node->mt_epqstate, estate); break; case CMD_DELETE: slot = ExecDelete(tupleid, planSlot, - subplanstate, estate); + &node->mt_epqstate, estate); break; default: elog(ERROR, "unknown operation"); @@ -785,7 +789,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * a subplan tree to EvalPlanQual, instead. Use a runtime test not just * Assert because this condition is easy to miss in testing ... */ - if (estate->es_evTuple != NULL) + if (estate->es_epqTuple != NULL) elog(ERROR, "ModifyTable should not be called during EvalPlanQual"); /* @@ -799,6 +803,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * 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); mtstate->fireBSTriggers = true; /* For the moment, assume our targets are exactly the global result rels */ @@ -823,6 +829,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* select first subplan */ mtstate->mt_whichplan = 0; subplan = (Plan *) linitial(node->plans); + EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan); /* * Initialize RETURNING projections if needed. @@ -879,6 +886,38 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) } /* + * If we have any secondary relations in an UPDATE or DELETE, they need + * to be treated like non-locked relations in SELECT FOR UPDATE, ie, + * the EvalPlanQual mechanism needs to be told about them. Locate + * the relevant ExecRowMarks. + */ + foreach(l, node->rowMarks) + { + PlanRowMark *rc = (PlanRowMark *) lfirst(l); + ExecRowMark *erm = NULL; + ListCell *lce; + + Assert(IsA(rc, PlanRowMark)); + + /* ignore "parent" rowmarks; they are irrelevant at runtime */ + 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); + + EvalPlanQualAddRowMark(&mtstate->mt_epqstate, erm); + } + + /* * 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 need a filter, since there's always a junk 'ctid' attribute @@ -988,6 +1027,11 @@ ExecEndModifyTable(ModifyTableState *node) ExecClearTuple(node->ps.ps_ResultTupleSlot); /* + * Terminate EPQ execution if active + */ + EvalPlanQualEnd(&node->mt_epqstate); + + /* * shut down subplans */ for (i=0; i<node->mt_nplans; i++) |