aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeModifyTable.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-01-28 17:43:57 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-01-28 17:43:57 -0500
commit7c1719bc68ec1c347e7c80c3735bf3373e765f35 (patch)
tree347f18c3e52ef0cc406195b0c9f8720c347d30d1 /src/backend/executor/nodeModifyTable.c
parent672614cf2137b2a3778c69de8d73770d84790e44 (diff)
downloadpostgresql-7c1719bc68ec1c347e7c80c3735bf3373e765f35.tar.gz
postgresql-7c1719bc68ec1c347e7c80c3735bf3373e765f35.zip
Fix handling of data-modifying CTE subplans in EvalPlanQual.
We can't just skip initializing such subplans, because the referencing CTE node will expect to find the subplan available when it initializes. That in turn means that ExecInitModifyTable must allow the case (which actually it needed to do anyway, since there's no guarantee that ModifyTable is exactly at the top of the CTE plan tree). So move the complaint about not being allowed in EvalPlanQual mode to execution instead of initialization. Testing turned up yet another problem, which is that we'd try to re-initialize the result relation's index list, leading to leaks and dangling pointers. Per report from Phil Sorber. Back-patch to 9.1 where data-modifying CTEs were introduced.
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r--src/backend/executor/nodeModifyTable.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 37b70b88d53..dfdcb20b1d1 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -716,6 +716,18 @@ ExecModifyTable(ModifyTableState *node)
HeapTupleHeader oldtuple = NULL;
/*
+ * This should NOT get called during EvalPlanQual; we should have passed a
+ * subplan tree to EvalPlanQual, instead. Use a runtime test not just
+ * Assert because this condition is easy to miss in testing. (Note:
+ * although ModifyTable should not get executed within an EvalPlanQual
+ * operation, we do have to allow it to be initialized and shut down in
+ * case it is within a CTE subplan. Hence this test must be here, not in
+ * ExecInitModifyTable.)
+ */
+ if (estate->es_epqTuple != NULL)
+ elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
+
+ /*
* If we've already completed processing, don't try to do more. We need
* this test because ExecPostprocessPlan might call us an extra time, and
* our subplan's nodes aren't necessarily robust against being called
@@ -893,14 +905,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
- * This should NOT get called during EvalPlanQual; we should have passed 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_epqTuple != NULL)
- elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
-
- /*
* create state structure
*/
mtstate = makeNode(ModifyTableState);
@@ -947,9 +951,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* descriptors in the result relation info, so that we can add new
* index entries for the tuples we add/update. We need not do this
* for a DELETE, however, since deletion doesn't affect indexes.
+ * Also, inside an EvalPlanQual operation, the indexes might be open
+ * already, since we share the resultrel state with the original
+ * query.
*/
if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
- operation != CMD_DELETE)
+ operation != CMD_DELETE &&
+ resultRelInfo->ri_IndexRelationDescs == NULL)
ExecOpenIndices(resultRelInfo);
/* Now init the plan for this result rel */