@@ -68,6 +68,7 @@ ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL;
6868
6969/* decls for local routines only used within this module */
7070static void InitPlan (QueryDesc * queryDesc ,int eflags );
71+ static void ExecPostprocessPlan (EState * estate );
7172static void ExecEndPlan (PlanState * planstate ,EState * estate );
7273static void ExecutePlan (EState * estate ,PlanState * planstate ,
7374CmdType operation ,
@@ -161,9 +162,13 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
161162switch (queryDesc -> operation )
162163{
163164case CMD_SELECT :
164- /* SELECT INTO and SELECT FOR UPDATE/SHARE need to mark tuples */
165+ /*
166+ * SELECT INTO, SELECT FOR UPDATE/SHARE and modifying CTEs need to
167+ * mark tuples
168+ */
165169if (queryDesc -> plannedstmt -> intoClause != NULL ||
166- queryDesc -> plannedstmt -> rowMarks != NIL )
170+ queryDesc -> plannedstmt -> rowMarks != NIL ||
171+ queryDesc -> plannedstmt -> hasModifyingCTE )
167172estate -> es_output_cid = GetCurrentCommandId (true);
168173break ;
169174
@@ -307,13 +312,19 @@ standard_ExecutorRun(QueryDesc *queryDesc,
307312 *
308313 *We provide a function hook variable that lets loadable plugins
309314 *get control when ExecutorEnd is called. Such a plugin would
310- *normally call standard_ExecutorEnd().
315+ *normally call standard_ExecutorEnd(). Because such hooks expect
316+ *to execute after all plan execution is done, we run
317+ *ExecPostprocessPlan before invoking the hook.
311318 *
312319 * ----------------------------------------------------------------
313320 */
314321void
315322ExecutorEnd (QueryDesc * queryDesc )
316323{
324+ /* Let plan nodes do any final processing required */
325+ ExecPostprocessPlan (queryDesc -> estate );
326+
327+ /* Now close down */
317328if (ExecutorEnd_hook )
318329(* ExecutorEnd_hook ) (queryDesc );
319330else
@@ -681,7 +692,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
681692InitResultRelInfo (resultRelInfo ,
682693resultRelation ,
683694resultRelationIndex ,
684- operation ,
685695estate -> es_instrument );
686696resultRelInfo ++ ;
687697}
@@ -873,24 +883,18 @@ InitPlan(QueryDesc *queryDesc, int eflags)
873883}
874884
875885/*
876- * Initialize ResultRelInfo data for one result relation
886+ * Check that a proposed result relation is a legal target for the operation
887+ *
888+ * In most cases parser and/or planner should have noticed this already, but
889+ * let's make sure. In the view case we do need a test here, because if the
890+ * view wasn't rewritten by a rule, it had better have an INSTEAD trigger.
877891 */
878892void
879- InitResultRelInfo (ResultRelInfo * resultRelInfo ,
880- Relation resultRelationDesc ,
881- Index resultRelationIndex ,
882- CmdType operation ,
883- int instrument_options )
893+ CheckValidResultRel (Relation resultRel ,CmdType operation )
884894{
885- TriggerDesc * trigDesc = resultRelationDesc -> trigdesc ;
895+ TriggerDesc * trigDesc = resultRel -> trigdesc ;
886896
887- /*
888- * Check valid relkind ... in most cases parser and/or planner should have
889- * noticed this already, but let's make sure. In the view case we do need
890- * a test here, because if the view wasn't rewritten by a rule, it had
891- * better have an INSTEAD trigger.
892- */
893- switch (resultRelationDesc -> rd_rel -> relkind )
897+ switch (resultRel -> rd_rel -> relkind )
894898{
895899case RELKIND_RELATION :
896900/* OK */
@@ -899,13 +903,13 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
899903ereport (ERROR ,
900904(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
901905errmsg ("cannot change sequence \"%s\"" ,
902- RelationGetRelationName (resultRelationDesc ))));
906+ RelationGetRelationName (resultRel ))));
903907break ;
904908case RELKIND_TOASTVALUE :
905909ereport (ERROR ,
906910(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
907911errmsg ("cannot change TOAST relation \"%s\"" ,
908- RelationGetRelationName (resultRelationDesc ))));
912+ RelationGetRelationName (resultRel ))));
909913break ;
910914case RELKIND_VIEW :
911915switch (operation )
@@ -915,23 +919,23 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
915919ereport (ERROR ,
916920(errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
917921errmsg ("cannot insert into view \"%s\"" ,
918- RelationGetRelationName (resultRelationDesc )),
922+ RelationGetRelationName (resultRel )),
919923errhint ("You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger." )));
920924break ;
921925case CMD_UPDATE :
922926if (!trigDesc || !trigDesc -> trig_update_instead_row )
923927ereport (ERROR ,
924928(errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
925929errmsg ("cannot update view \"%s\"" ,
926- RelationGetRelationName (resultRelationDesc )),
930+ RelationGetRelationName (resultRel )),
927931errhint ("You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger." )));
928932break ;
929933case CMD_DELETE :
930934if (!trigDesc || !trigDesc -> trig_delete_instead_row )
931935ereport (ERROR ,
932936(errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
933937errmsg ("cannot delete from view \"%s\"" ,
934- RelationGetRelationName (resultRelationDesc )),
938+ RelationGetRelationName (resultRel )),
935939errhint ("You need an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger." )));
936940break ;
937941default :
@@ -943,17 +947,30 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
943947ereport (ERROR ,
944948(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
945949errmsg ("cannot change foreign table \"%s\"" ,
946- RelationGetRelationName (resultRelationDesc ))));
950+ RelationGetRelationName (resultRel ))));
947951break ;
948952default :
949953ereport (ERROR ,
950954(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
951955errmsg ("cannot change relation \"%s\"" ,
952- RelationGetRelationName (resultRelationDesc ))));
956+ RelationGetRelationName (resultRel ))));
953957break ;
954958}
959+ }
955960
956- /* OK, fill in the node */
961+ /*
962+ * Initialize ResultRelInfo data for one result relation
963+ *
964+ * Caution: before Postgres 9.1, this function included the relkind checking
965+ * that's now in CheckValidResultRel, and it also did ExecOpenIndices if
966+ * appropriate. Be sure callers cover those needs.
967+ */
968+ void
969+ InitResultRelInfo (ResultRelInfo * resultRelInfo ,
970+ Relation resultRelationDesc ,
971+ Index resultRelationIndex ,
972+ int instrument_options )
973+ {
957974MemSet (resultRelInfo ,0 ,sizeof (ResultRelInfo ));
958975resultRelInfo -> type = T_ResultRelInfo ;
959976resultRelInfo -> ri_RangeTableIndex = resultRelationIndex ;
@@ -962,7 +979,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
962979resultRelInfo -> ri_IndexRelationDescs = NULL ;
963980resultRelInfo -> ri_IndexRelationInfo = NULL ;
964981/* make a copy so as not to depend on relcache info not changing... */
965- resultRelInfo -> ri_TrigDesc = CopyTriggerDesc (trigDesc );
982+ resultRelInfo -> ri_TrigDesc = CopyTriggerDesc (resultRelationDesc -> trigdesc );
966983if (resultRelInfo -> ri_TrigDesc )
967984{
968985int n = resultRelInfo -> ri_TrigDesc -> numtriggers ;
@@ -983,16 +1000,6 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
9831000resultRelInfo -> ri_ConstraintExprs = NULL ;
9841001resultRelInfo -> ri_junkFilter = NULL ;
9851002resultRelInfo -> ri_projectReturning = NULL ;
986-
987- /*
988- * If there are indices on the result relation, open them and save
989- * descriptors in the result relation info, so that we can add new index
990- * entries for the tuples we add/update. We need not do this for a
991- * DELETE, however, since deletion doesn't affect indexes.
992- */
993- if (resultRelationDesc -> rd_rel -> relhasindex &&
994- operation != CMD_DELETE )
995- ExecOpenIndices (resultRelInfo );
9961003}
9971004
9981005/*
@@ -1042,26 +1049,29 @@ ExecGetTriggerResultRel(EState *estate, Oid relid)
10421049/*
10431050 * Open the target relation's relcache entry. We assume that an
10441051 * appropriate lock is still held by the backend from whenever the trigger
1045- * event got queued, so we need take no new lock here.
1052+ * event got queued, so we need take no new lock here. Also, we need
1053+ * not recheck the relkind, so no need for CheckValidResultRel.
10461054 */
10471055rel = heap_open (relid ,NoLock );
10481056
10491057/*
1050- * Make the new entry in the right context. Currently, we don't need any
1051- * index information in ResultRelInfos used only for triggers, so tell
1052- * InitResultRelInfo it's a DELETE.
1058+ * Make the new entry in the right context.
10531059 */
10541060oldcontext = MemoryContextSwitchTo (estate -> es_query_cxt );
10551061rInfo = makeNode (ResultRelInfo );
10561062InitResultRelInfo (rInfo ,
10571063rel ,
105810640 ,/* dummy rangetable index */
1059- CMD_DELETE ,
10601065estate -> es_instrument );
10611066estate -> es_trig_target_relations =
10621067lappend (estate -> es_trig_target_relations ,rInfo );
10631068MemoryContextSwitchTo (oldcontext );
10641069
1070+ /*
1071+ * Currently, we don't need any index information in ResultRelInfos used
1072+ * only for triggers, so no need to call ExecOpenIndices.
1073+ */
1074+
10651075return rInfo ;
10661076}
10671077
@@ -1122,6 +1132,54 @@ ExecContextForcesOids(PlanState *planstate, bool *hasoids)
11221132return false;
11231133}
11241134
1135+ /* ----------------------------------------------------------------
1136+ *ExecPostprocessPlan
1137+ *
1138+ *Give plan nodes a final chance to execute before shutdown
1139+ * ----------------------------------------------------------------
1140+ */
1141+ static void
1142+ ExecPostprocessPlan (EState * estate )
1143+ {
1144+ MemoryContext oldcontext ;
1145+ ListCell * lc ;
1146+
1147+ /*
1148+ * Switch into per-query memory context
1149+ */
1150+ oldcontext = MemoryContextSwitchTo (estate -> es_query_cxt );
1151+
1152+ /*
1153+ * Make sure nodes run forward.
1154+ */
1155+ estate -> es_direction = ForwardScanDirection ;
1156+
1157+ /*
1158+ * Run any secondary ModifyTable nodes to completion, in case the main
1159+ * query did not fetch all rows from them. (We do this to ensure that
1160+ * such nodes have predictable results.)
1161+ */
1162+ foreach (lc ,estate -> es_auxmodifytables )
1163+ {
1164+ PlanState * ps = (PlanState * )lfirst (lc );
1165+
1166+ for (;;)
1167+ {
1168+ TupleTableSlot * slot ;
1169+
1170+ /* Reset the per-output-tuple exprcontext each time */
1171+ ResetPerTupleExprContext (estate );
1172+
1173+ slot = ExecProcNode (ps );
1174+
1175+ if (TupIsNull (slot ))
1176+ break ;
1177+ }
1178+ }
1179+
1180+ MemoryContextSwitchTo (oldcontext );
1181+ }
1182+
11251183/* ----------------------------------------------------------------
11261184 *ExecEndPlan
11271185 *
@@ -2026,6 +2084,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
20262084estate -> es_instrument = parentestate -> es_instrument ;
20272085estate -> es_select_into = parentestate -> es_select_into ;
20282086estate -> es_into_oids = parentestate -> es_into_oids ;
2087+ estate -> es_auxmodifytables = NIL ;
20292088
20302089/*
20312090 * The external param list is simply shared from parent. The internal
@@ -2080,15 +2139,23 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
20802139 * ExecInitSubPlan expects to be able to find these entries. Some of the
20812140 * SubPlans might not be used in the part of the plan tree we intend to
20822141 * run, but since it's not easy to tell which, we just initialize them
2083- * all.
2142+ * all. (However, if the subplan is headed by a ModifyTable node, then
2143+ * it must be a data-modifying CTE, which we will certainly not need to
2144+ * re-run, so we can skip initializing it. This is just an efficiency
2145+ * hack; it won't skip data-modifying CTEs for which the ModifyTable node
2146+ * is not at the top.)
20842147 */
20852148Assert (estate -> es_subplanstates == NIL );
20862149foreach (l ,parentestate -> es_plannedstmt -> subplans )
20872150{
20882151Plan * subplan = (Plan * )lfirst (l );
20892152PlanState * subplanstate ;
20902153
2091- subplanstate = ExecInitNode (subplan ,estate ,0 );
2154+ /* Don't initialize ModifyTable subplans, per comment above */
2155+ if (IsA (subplan ,ModifyTable ))
2156+ subplanstate = NULL ;
2157+ else
2158+ subplanstate = ExecInitNode (subplan ,estate ,0 );
20922159
20932160estate -> es_subplanstates = lappend (estate -> es_subplanstates ,
20942161subplanstate );