26
26
*
27
27
*
28
28
* 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 $
30
30
*
31
31
*-------------------------------------------------------------------------
32
32
*/
@@ -70,6 +70,7 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
70
70
List * rangeTable ,
71
71
CmdType operation ,
72
72
bool doInstrument );
73
+ static void ExecEndPlan (PlanState * planstate , EState * estate );
73
74
static TupleTableSlot * ExecutePlan (EState * estate , PlanState * planstate ,
74
75
CmdType operation ,
75
76
long numberTuples ,
@@ -466,6 +467,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
466
467
PlanState * planstate ;
467
468
TupleDesc tupType ;
468
469
ListCell * l ;
470
+ int i ;
469
471
470
472
/*
471
473
* Do permissions checks
@@ -551,15 +553,25 @@ InitPlan(QueryDesc *queryDesc, int eflags)
551
553
}
552
554
553
555
/*
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
555
557
* nodes, plus possibly output slots for the junkfilter(s). At this point
556
558
* we aren't sure if we need junkfilters, so just add slots for them
557
559
* 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.
559
561
*/
560
562
{
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 );
562
571
572
+ nSlots += ExecCountSlotsNode (subplan );
573
+ }
574
+ /* Add slots for junkfilter(s) */
563
575
if (plannedstmt -> resultRelations != NIL )
564
576
nSlots += list_length (plannedstmt -> resultRelations );
565
577
else
@@ -584,7 +596,38 @@ InitPlan(QueryDesc *queryDesc, int eflags)
584
596
estate -> es_useEvalPlan = false;
585
597
586
598
/*
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
588
631
* tree. This opens files, allocates storage and leaves us ready to start
589
632
* processing tuples.
590
633
*/
@@ -648,7 +691,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
648
691
PlanState * * appendplans ;
649
692
int as_nplans ;
650
693
ResultRelInfo * resultRelInfo ;
651
- int i ;
652
694
653
695
/* Top plan had better be an Append here. */
654
696
Assert (IsA (plan , Append ));
@@ -768,20 +810,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
768
810
resultRelInfo -> ri_RelationDesc -> rd_att );
769
811
resultRelInfo ++ ;
770
812
}
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
- }
785
813
}
786
814
787
815
queryDesc -> tupDesc = tupType ;
@@ -945,7 +973,7 @@ ExecContextForcesOids(PlanState *planstate, bool *hasoids)
945
973
* tuple tables must be cleared or dropped to ensure pins are released.
946
974
* ----------------------------------------------------------------
947
975
*/
948
- void
976
+ static void
949
977
ExecEndPlan (PlanState * planstate , EState * estate )
950
978
{
951
979
ResultRelInfo * resultRelInfo ;
@@ -963,6 +991,16 @@ ExecEndPlan(PlanState *planstate, EState *estate)
963
991
*/
964
992
ExecEndNode (planstate );
965
993
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
+
966
1004
/*
967
1005
* destroy the executor "tuple" table.
968
1006
*/
@@ -2205,13 +2243,10 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
2205
2243
EState * epqstate ;
2206
2244
int rtsize ;
2207
2245
MemoryContext oldcontext ;
2246
+ ListCell * l ;
2208
2247
2209
2248
rtsize = list_length (estate -> es_range_table );
2210
2249
2211
- /*
2212
- * It's tempting to think about using CreateSubExecutorState here, but
2213
- * at present we can't because of memory leakage concerns ...
2214
- */
2215
2250
epq -> estate = epqstate = CreateExecutorState ();
2216
2251
2217
2252
oldcontext = MemoryContextSwitchTo (epqstate -> es_query_cxt );
@@ -2256,9 +2291,34 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
2256
2291
/* later stack entries share the same storage */
2257
2292
epqstate -> es_evTuple = priorepq -> estate -> es_evTuple ;
2258
2293
2294
+ /*
2295
+ * Create sub-tuple-table; we needn't redo the CountSlots work though.
2296
+ */
2259
2297
epqstate -> es_tupleTable =
2260
2298
ExecCreateTupleTable (estate -> es_tupleTable -> size );
2261
2299
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
+ */
2262
2322
epq -> planstate = ExecInitNode (estate -> es_plannedstmt -> planTree , epqstate , 0 );
2263
2323
2264
2324
MemoryContextSwitchTo (oldcontext );
@@ -2276,11 +2336,19 @@ EvalPlanQualStop(evalPlanQual *epq)
2276
2336
{
2277
2337
EState * epqstate = epq -> estate ;
2278
2338
MemoryContext oldcontext ;
2339
+ ListCell * l ;
2279
2340
2280
2341
oldcontext = MemoryContextSwitchTo (epqstate -> es_query_cxt );
2281
2342
2282
2343
ExecEndNode (epq -> planstate );
2283
2344
2345
+ foreach (l , epqstate -> es_subplanstates )
2346
+ {
2347
+ PlanState * subplanstate = (PlanState * ) lfirst (l );
2348
+
2349
+ ExecEndNode (subplanstate );
2350
+ }
2351
+
2284
2352
ExecDropTupleTable (epqstate -> es_tupleTable , true);
2285
2353
epqstate -> es_tupleTable = NULL ;
2286
2354
0 commit comments