88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.212 2007/01/20 20:45:39 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.213 2007/02/19 07:03:29 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
4242#include "utils/syscache.h"
4343
4444
45- ParamListInfo PlannerBoundParamList = NULL ;/* current boundParams */
46-
47-
4845/* Expression kind codes for preprocess_expression */
4946#define EXPRKIND_QUAL 0
5047#define EXPRKIND_TARGET 1
@@ -86,35 +83,21 @@ Plan *
8683planner (Query * parse ,bool isCursor ,int cursorOptions ,
8784ParamListInfo boundParams )
8885{
86+ PlannerGlobal * glob ;
8987double tuple_fraction ;
9088Plan * result_plan ;
91- Index save_PlannerQueryLevel ;
92- List * save_PlannerParamList ;
93- ParamListInfo save_PlannerBoundParamList ;
9489
9590/*
96- * The planner can be called recursively (an example is when
97- * eval_const_expressions tries to pre-evaluate an SQL function). So,
98- * these global state variables must be saved and restored.
99- *
100- * Query level and the param list cannot be moved into the per-query
101- * PlannerInfo structure since their whole purpose is communication across
102- * multiple sub-queries. Also, boundParams is explicitly info from outside
103- * the query, and so is likewise better handled as a global variable.
104- *
105- * Note we do NOT save and restore PlannerPlanId: it exists to assign
106- * unique IDs to SubPlan nodes, and we want those IDs to be unique for the
107- * life of a backend. Also, PlannerInitPlan is saved/restored in
108- * subquery_planner, not here.
91+ * Set up global state for this planner invocation. This data is needed
92+ * across all levels of sub-Query that might exist in the given command,
93+ * so we keep it in a separate struct that's linked to by each per-Query
94+ * PlannerInfo.
10995 */
110- save_PlannerQueryLevel = PlannerQueryLevel ;
111- save_PlannerParamList = PlannerParamList ;
112- save_PlannerBoundParamList = PlannerBoundParamList ;
96+ glob = makeNode (PlannerGlobal );
11397
114- /* Initialize state for handling outer-level references and params */
115- PlannerQueryLevel = 0 ;/* will be 1 in top-level subquery_planner */
116- PlannerParamList = NIL ;
117- PlannerBoundParamList = boundParams ;
98+ glob -> boundParams = boundParams ;
99+ glob -> paramlist = NIL ;
100+ glob -> next_plan_id = 0 ;
118101
119102/* Determine what fraction of the plan is likely to be scanned */
120103if (isCursor )
@@ -134,10 +117,7 @@ planner(Query *parse, bool isCursor, int cursorOptions,
134117}
135118
136119/* primary planning entry point (may recurse for subqueries) */
137- result_plan = subquery_planner (parse ,tuple_fraction ,NULL );
138-
139- /* check we popped out the right number of levels */
140- Assert (PlannerQueryLevel == 0 );
120+ result_plan = subquery_planner (glob ,parse ,1 ,tuple_fraction ,NULL );
141121
142122/*
143123 * If creating a plan for a scrollable cursor, make sure it can run
@@ -153,12 +133,7 @@ planner(Query *parse, bool isCursor, int cursorOptions,
153133result_plan = set_plan_references (result_plan ,parse -> rtable );
154134
155135/* executor wants to know total number of Params used overall */
156- result_plan -> nParamExec = list_length (PlannerParamList );
157-
158- /* restore state for outer planner, if any */
159- PlannerQueryLevel = save_PlannerQueryLevel ;
160- PlannerParamList = save_PlannerParamList ;
161- PlannerBoundParamList = save_PlannerBoundParamList ;
136+ result_plan -> nParamExec = list_length (glob -> paramlist );
162137
163138return result_plan ;
164139}
@@ -169,7 +144,9 @@ planner(Query *parse, bool isCursor, int cursorOptions,
169144 * Invokes the planner on a subquery. We recurse to here for each
170145 * sub-SELECT found in the query tree.
171146 *
147+ * glob is the global state for the current planner run.
172148 * parse is the querytree produced by the parser & rewriter.
149+ * level is the current recursion depth (1 at the top-level Query).
173150 * tuple_fraction is the fraction of tuples we expect will be retrieved.
174151 * tuple_fraction is interpreted as explained for grouping_planner, below.
175152 *
@@ -189,24 +166,23 @@ planner(Query *parse, bool isCursor, int cursorOptions,
189166 *--------------------
190167 */
191168Plan *
192- subquery_planner (Query * parse ,double tuple_fraction ,
169+ subquery_planner (PlannerGlobal * glob ,Query * parse ,
170+ Index level ,double tuple_fraction ,
193171List * * subquery_pathkeys )
194172{
195- List * saved_initplan = PlannerInitPlan ;
196- int saved_planid = PlannerPlanId ;
173+ int saved_plan_id = glob -> next_plan_id ;
197174PlannerInfo * root ;
198175Plan * plan ;
199176List * newHaving ;
200177ListCell * l ;
201178
202- /* Set up for a new level of subquery */
203- PlannerQueryLevel ++ ;
204- PlannerInitPlan = NIL ;
205-
206179/* Create a PlannerInfo data structure for this subquery */
207180root = makeNode (PlannerInfo );
208181root -> parse = parse ;
182+ root -> glob = glob ;
183+ root -> query_level = level ;
209184root -> planner_cxt = CurrentMemoryContext ;
185+ root -> init_plans = NIL ;
210186root -> eq_classes = NIL ;
211187root -> in_info_list = NIL ;
212188root -> append_rel_list = NIL ;
@@ -396,18 +372,13 @@ subquery_planner(Query *parse, double tuple_fraction,
396372 * initPlan list and extParam/allParam sets for plan nodes, and attach the
397373 * initPlans to the top plan node.
398374 */
399- if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1 )
400- SS_finalize_plan (plan , parse -> rtable );
375+ if (root -> glob -> next_plan_id != saved_plan_id || root -> query_level > 1 )
376+ SS_finalize_plan (root , plan );
401377
402378/* Return sort ordering info if caller wants it */
403379if (subquery_pathkeys )
404380* subquery_pathkeys = root -> query_pathkeys ;
405381
406- /* Return to outer subquery context */
407- PlannerQueryLevel -- ;
408- PlannerInitPlan = saved_initplan ;
409- /* we do NOT restore PlannerPlanId; that's not an oversight! */
410-
411382return plan ;
412383}
413384
@@ -460,7 +431,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
460431if (kind != EXPRKIND_VALUES &&
461432(root -> parse -> jointree -> fromlist != NIL ||
462433kind == EXPRKIND_QUAL ||
463- PlannerQueryLevel > 1 ))
434+ root -> query_level > 1 ))
464435expr = eval_const_expressions (expr );
465436
466437/*
@@ -478,16 +449,16 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
478449
479450/* Expand SubLinks to SubPlans */
480451if (root -> parse -> hasSubLinks )
481- expr = SS_process_sublinks (expr , (kind == EXPRKIND_QUAL ));
452+ expr = SS_process_sublinks (root , expr , (kind == EXPRKIND_QUAL ));
482453
483454/*
484455 * XXX do not insert anything here unless you have grokked the comments in
485456 * SS_replace_correlation_vars ...
486457 */
487458
488459/* Replace uplevel vars with Param nodes (this IS possible in VALUES) */
489- if (PlannerQueryLevel > 1 )
490- expr = SS_replace_correlation_vars (expr );
460+ if (root -> query_level > 1 )
461+ expr = SS_replace_correlation_vars (root , expr );
491462
492463/*
493464 * If it's a qual or havingQual, convert it to implicit-AND format. (We
@@ -590,6 +561,7 @@ inheritance_planner(PlannerInfo *root)
590561subroot .in_info_list = (List * )
591562adjust_appendrel_attrs ((Node * )root -> in_info_list ,
592563appinfo );
564+ subroot .init_plans = NIL ;
593565/* There shouldn't be any OJ info to translate, as yet */
594566Assert (subroot .oj_info_list == NIL );
595567
@@ -612,6 +584,9 @@ inheritance_planner(PlannerInfo *root)
612584
613585subplans = lappend (subplans ,subplan );
614586
587+ /* Make sure any initplans from this rel get into the outer list */
588+ root -> init_plans = list_concat (root -> init_plans ,subroot .init_plans );
589+
615590/* Build target-relations list for the executor */
616591resultRelations = lappend_int (resultRelations ,appinfo -> child_relid );
617592
@@ -1201,7 +1176,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
12011176 */
12021177if (parse -> limitCount )
12031178{
1204- est = estimate_expression_value (parse -> limitCount );
1179+ est = estimate_expression_value (root , parse -> limitCount );
12051180if (est && IsA (est ,Const ))
12061181{
12071182if (((Const * )est )-> constisnull )
@@ -1224,7 +1199,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
12241199
12251200if (parse -> limitOffset )
12261201{
1227- est = estimate_expression_value (parse -> limitOffset );
1202+ est = estimate_expression_value (root , parse -> limitOffset );
12281203if (est && IsA (est ,Const ))
12291204{
12301205if (((Const * )est )-> constisnull )