2626 *
2727 *
2828 * IDENTIFICATION
29- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.288 2007/02/22 22:00:22 tgl Exp $
29+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.289 2007/02/27 01:11:25 tgl Exp $
3030 *
3131 *-------------------------------------------------------------------------
3232 */
@@ -70,6 +70,7 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
7070 List * rangeTable ,
7171 CmdType operation ,
7272 bool doInstrument );
73+ static void ExecEndPlan (PlanState * planstate , EState * estate );
7374static TupleTableSlot * ExecutePlan (EState * estate , PlanState * planstate ,
7475 CmdType operation ,
7576 long numberTuples ,
@@ -466,6 +467,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
466467 PlanState * planstate ;
467468 TupleDesc tupType ;
468469 ListCell * l ;
470+ int i ;
469471
470472 /*
471473 * Do permissions checks
@@ -551,15 +553,25 @@ InitPlan(QueryDesc *queryDesc, int eflags)
551553 }
552554
553555 /*
554- * initialize the executor "tuple" table. We need slots for all the plan
556+ * Initialize the executor "tuple" table. We need slots for all the plan
555557 * nodes, plus possibly output slots for the junkfilter(s). At this point
556558 * we aren't sure if we need junkfilters, so just add slots for them
557559 * unconditionally. Also, if it's not a SELECT, set up a slot for use for
558- * trigger output tuples.
560+ * trigger output tuples. Also, one for RETURNING-list evaluation.
559561 */
560562 {
561- int nSlots = ExecCountSlotsNode (plan );
563+ int nSlots ;
564+
565+ /* Slots for the main plan tree */
566+ nSlots = ExecCountSlotsNode (plan );
567+ /* Add slots for subplans and initplans */
568+ foreach (l , plannedstmt -> subplans )
569+ {
570+ Plan * subplan = (Plan * ) lfirst (l );
562571
572+ nSlots += ExecCountSlotsNode (subplan );
573+ }
574+ /* Add slots for junkfilter(s) */
563575 if (plannedstmt -> resultRelations != NIL )
564576 nSlots += list_length (plannedstmt -> resultRelations );
565577 else
@@ -584,7 +596,38 @@ InitPlan(QueryDesc *queryDesc, int eflags)
584596 estate -> es_useEvalPlan = false;
585597
586598 /*
587- * initialize the private state information for all the nodes in the query
599+ * Initialize private state information for each SubPlan. We must do
600+ * this before running ExecInitNode on the main query tree, since
601+ * ExecInitSubPlan expects to be able to find these entries.
602+ */
603+ Assert (estate -> es_subplanstates == NIL );
604+ i = 1 ; /* subplan indices count from 1 */
605+ foreach (l , plannedstmt -> subplans )
606+ {
607+ Plan * subplan = (Plan * ) lfirst (l );
608+ PlanState * subplanstate ;
609+ int sp_eflags ;
610+
611+ /*
612+ * A subplan will never need to do BACKWARD scan nor MARK/RESTORE.
613+ * If it is a parameterless subplan (not initplan), we suggest that it
614+ * be prepared to handle REWIND efficiently; otherwise there is no
615+ * need.
616+ */
617+ sp_eflags = eflags & EXEC_FLAG_EXPLAIN_ONLY ;
618+ if (bms_is_member (i , plannedstmt -> rewindPlanIDs ))
619+ sp_eflags |= EXEC_FLAG_REWIND ;
620+
621+ subplanstate = ExecInitNode (subplan , estate , sp_eflags );
622+
623+ estate -> es_subplanstates = lappend (estate -> es_subplanstates ,
624+ subplanstate );
625+
626+ i ++ ;
627+ }
628+
629+ /*
630+ * Initialize the private state information for all the nodes in the query
588631 * tree. This opens files, allocates storage and leaves us ready to start
589632 * processing tuples.
590633 */
@@ -648,7 +691,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
648691 PlanState * * appendplans ;
649692 int as_nplans ;
650693 ResultRelInfo * resultRelInfo ;
651- int i ;
652694
653695 /* Top plan had better be an Append here. */
654696 Assert (IsA (plan , Append ));
@@ -768,20 +810,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
768810 resultRelInfo -> ri_RelationDesc -> rd_att );
769811 resultRelInfo ++ ;
770812 }
771-
772- /*
773- * Because we already ran ExecInitNode() for the top plan node, any
774- * subplans we just attached to it won't have been initialized; so we
775- * have to do it here. (Ugly, but the alternatives seem worse.)
776- */
777- foreach (l , planstate -> subPlan )
778- {
779- SubPlanState * sstate = (SubPlanState * ) lfirst (l );
780-
781- Assert (IsA (sstate , SubPlanState ));
782- if (sstate -> planstate == NULL ) /* already inited? */
783- ExecInitSubPlan (sstate , estate , eflags );
784- }
785813 }
786814
787815 queryDesc -> tupDesc = tupType ;
@@ -945,7 +973,7 @@ ExecContextForcesOids(PlanState *planstate, bool *hasoids)
945973 * tuple tables must be cleared or dropped to ensure pins are released.
946974 * ----------------------------------------------------------------
947975 */
948- void
976+ static void
949977ExecEndPlan (PlanState * planstate , EState * estate )
950978{
951979 ResultRelInfo * resultRelInfo ;
@@ -963,6 +991,16 @@ ExecEndPlan(PlanState *planstate, EState *estate)
963991 */
964992 ExecEndNode (planstate );
965993
994+ /*
995+ * for subplans too
996+ */
997+ foreach (l , estate -> es_subplanstates )
998+ {
999+ PlanState * subplanstate = (PlanState * ) lfirst (l );
1000+
1001+ ExecEndNode (subplanstate );
1002+ }
1003+
9661004 /*
9671005 * destroy the executor "tuple" table.
9681006 */
@@ -2205,13 +2243,10 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
22052243 EState * epqstate ;
22062244 int rtsize ;
22072245 MemoryContext oldcontext ;
2246+ ListCell * l ;
22082247
22092248 rtsize = list_length (estate -> es_range_table );
22102249
2211- /*
2212- * It's tempting to think about using CreateSubExecutorState here, but
2213- * at present we can't because of memory leakage concerns ...
2214- */
22152250 epq -> estate = epqstate = CreateExecutorState ();
22162251
22172252 oldcontext = MemoryContextSwitchTo (epqstate -> es_query_cxt );
@@ -2256,9 +2291,34 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
22562291 /* later stack entries share the same storage */
22572292 epqstate -> es_evTuple = priorepq -> estate -> es_evTuple ;
22582293
2294+ /*
2295+ * Create sub-tuple-table; we needn't redo the CountSlots work though.
2296+ */
22592297 epqstate -> es_tupleTable =
22602298 ExecCreateTupleTable (estate -> es_tupleTable -> size );
22612299
2300+ /*
2301+ * Initialize private state information for each SubPlan. We must do
2302+ * this before running ExecInitNode on the main query tree, since
2303+ * ExecInitSubPlan expects to be able to find these entries.
2304+ */
2305+ Assert (epqstate -> es_subplanstates == NIL );
2306+ foreach (l , estate -> es_plannedstmt -> subplans )
2307+ {
2308+ Plan * subplan = (Plan * ) lfirst (l );
2309+ PlanState * subplanstate ;
2310+
2311+ subplanstate = ExecInitNode (subplan , epqstate , 0 );
2312+
2313+ epqstate -> es_subplanstates = lappend (epqstate -> es_subplanstates ,
2314+ subplanstate );
2315+ }
2316+
2317+ /*
2318+ * Initialize the private state information for all the nodes in the query
2319+ * tree. This opens files, allocates storage and leaves us ready to start
2320+ * processing tuples.
2321+ */
22622322 epq -> planstate = ExecInitNode (estate -> es_plannedstmt -> planTree , epqstate , 0 );
22632323
22642324 MemoryContextSwitchTo (oldcontext );
@@ -2276,11 +2336,19 @@ EvalPlanQualStop(evalPlanQual *epq)
22762336{
22772337 EState * epqstate = epq -> estate ;
22782338 MemoryContext oldcontext ;
2339+ ListCell * l ;
22792340
22802341 oldcontext = MemoryContextSwitchTo (epqstate -> es_query_cxt );
22812342
22822343 ExecEndNode (epq -> planstate );
22832344
2345+ foreach (l , epqstate -> es_subplanstates )
2346+ {
2347+ PlanState * subplanstate = (PlanState * ) lfirst (l );
2348+
2349+ ExecEndNode (subplanstate );
2350+ }
2351+
22842352 ExecDropTupleTable (epqstate -> es_tupleTable , true);
22852353 epqstate -> es_tupleTable = NULL ;
22862354
0 commit comments