diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index a173cf59dff671e75bde996a1b6778d61a1ed8f9..0600f63b5567616427dab633f0f4c3d5793d5623 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.298 2007/02/19 02:23:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.299 2007/02/19 07:03:27 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -1225,6 +1225,16 @@ _outHashPath(StringInfo str, HashPath *node) WRITE_NODE_FIELD(path_hashclauses); } +static void +_outPlannerGlobal(StringInfo str, PlannerGlobal *node) +{ + WRITE_NODE_TYPE("PLANNERGLOBAL"); + + /* NB: this isn't a complete set of fields */ + WRITE_NODE_FIELD(paramlist); + WRITE_INT_FIELD(next_plan_id); +} + static void _outPlannerInfo(StringInfo str, PlannerInfo *node) { @@ -1232,7 +1242,10 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node) /* NB: this isn't a complete set of fields */ WRITE_NODE_FIELD(parse); + WRITE_NODE_FIELD(glob); + WRITE_UINT_FIELD(query_level); WRITE_NODE_FIELD(join_rel_list); + WRITE_NODE_FIELD(init_plans); WRITE_NODE_FIELD(eq_classes); WRITE_NODE_FIELD(canon_pathkeys); WRITE_NODE_FIELD(left_join_clauses); @@ -1416,6 +1429,15 @@ _outAppendRelInfo(StringInfo str, AppendRelInfo *node) WRITE_OID_FIELD(parent_reloid); } +static void +_outPlannerParamItem(StringInfo str, PlannerParamItem *node) +{ + WRITE_NODE_TYPE("PLANNERPARAMITEM"); + + WRITE_NODE_FIELD(item); + WRITE_UINT_FIELD(abslevel); +} + /***************************************************************************** * * Stuff from parsenodes.h. @@ -2195,6 +2217,9 @@ _outNode(StringInfo str, void *obj) case T_HashPath: _outHashPath(str, obj); break; + case T_PlannerGlobal: + _outPlannerGlobal(str, obj); + break; case T_PlannerInfo: _outPlannerInfo(str, obj); break; @@ -2228,6 +2253,9 @@ _outNode(StringInfo str, void *obj) case T_AppendRelInfo: _outAppendRelInfo(str, obj); break; + case T_PlannerParamItem: + _outPlannerParamItem(str, obj); + break; case T_CreateStmt: _outCreateStmt(str, obj); diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README index 60505814fd49c1f1cb8a11b5c54d2aec2f59d0ec..6f9d008cbfffa5abe99a45c49fe13dcb638575b6 100644 --- a/src/backend/optimizer/README +++ b/src/backend/optimizer/README @@ -317,7 +317,10 @@ planner() Optimizer Data Structures ------------------------- -PlannerInfo - global information for planning a particular Query +PlannerGlobal - global information for a single planner invocation + +PlannerInfo - information for planning a particular Query (we make + a separate PlannerInfo node for each sub-Query) RelOptInfo - a relation or joined relations diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 43891a184594b0bde3f57bad62fd838d6744e6dc..1cb1d86be1b58374dc2c0f94a328e29e94f58dc9 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.158 2007/01/28 18:50:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.159 2007/02/19 07:03:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -517,7 +517,9 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, tuple_fraction = root->tuple_fraction; /* Generate the plan for the subquery */ - rel->subplan = subquery_planner(subquery, tuple_fraction, + rel->subplan = subquery_planner(root->glob, subquery, + root->query_level + 1, + tuple_fraction, &subquery_pathkeys); /* Copy number of output rows from subplan */ diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index f80e18a202093721e0efdcfc247f68bab1ad28c6..405ab6fcc3a6275dc1a132e547693b6ce6bbde07 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.83 2007/01/05 22:19:31 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.84 2007/02/19 07:03:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -537,7 +537,7 @@ clause_selectivity(PlannerInfo *root, else if (IsA(clause, Param)) { /* see if we can replace the Param */ - Node *subst = estimate_expression_value(clause); + Node *subst = estimate_expression_value(root, clause); if (IsA(subst, Const)) { diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 77ad0176db256f448ba06ee4d74fdcedf63d60a1..be26d17a28a2bca78bffb6a63e3a483e2e5677fe 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.26 2007/02/06 06:50:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.27 2007/02/19 07:03:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -450,6 +450,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info) */ memcpy(&subroot, root, sizeof(PlannerInfo)); subroot.parse = subparse = (Query *) copyObject(root->parse); + subroot.init_plans = NIL; subparse->commandType = CMD_SELECT; subparse->resultRelation = 0; subparse->resultRelations = NIL; @@ -524,6 +525,9 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info) info->param = SS_make_initplan_from_plan(&subroot, plan, exprType((Node *) tle->expr), -1); + + /* Make sure the InitPlan gets into the outer list */ + root->init_plans = list_concat(root->init_plans, subroot.init_plans); } /* diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index ae9c10fc6b6f9fb4d50c5b9b0764c210e6535733..f4a940175ea5c89c08ed9c8bd2e703072fcd585a 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.212 2007/01/20 20:45:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.213 2007/02/19 07:03:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,9 +42,6 @@ #include "utils/syscache.h" -ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */ - - /* Expression kind codes for preprocess_expression */ #define EXPRKIND_QUAL 0 #define EXPRKIND_TARGET 1 @@ -86,35 +83,21 @@ Plan * planner(Query *parse, bool isCursor, int cursorOptions, ParamListInfo boundParams) { + PlannerGlobal *glob; double tuple_fraction; Plan *result_plan; - Index save_PlannerQueryLevel; - List *save_PlannerParamList; - ParamListInfo save_PlannerBoundParamList; /* - * The planner can be called recursively (an example is when - * eval_const_expressions tries to pre-evaluate an SQL function). So, - * these global state variables must be saved and restored. - * - * Query level and the param list cannot be moved into the per-query - * PlannerInfo structure since their whole purpose is communication across - * multiple sub-queries. Also, boundParams is explicitly info from outside - * the query, and so is likewise better handled as a global variable. - * - * Note we do NOT save and restore PlannerPlanId: it exists to assign - * unique IDs to SubPlan nodes, and we want those IDs to be unique for the - * life of a backend. Also, PlannerInitPlan is saved/restored in - * subquery_planner, not here. + * Set up global state for this planner invocation. This data is needed + * across all levels of sub-Query that might exist in the given command, + * so we keep it in a separate struct that's linked to by each per-Query + * PlannerInfo. */ - save_PlannerQueryLevel = PlannerQueryLevel; - save_PlannerParamList = PlannerParamList; - save_PlannerBoundParamList = PlannerBoundParamList; + glob = makeNode(PlannerGlobal); - /* Initialize state for handling outer-level references and params */ - PlannerQueryLevel = 0; /* will be 1 in top-level subquery_planner */ - PlannerParamList = NIL; - PlannerBoundParamList = boundParams; + glob->boundParams = boundParams; + glob->paramlist = NIL; + glob->next_plan_id = 0; /* Determine what fraction of the plan is likely to be scanned */ if (isCursor) @@ -134,10 +117,7 @@ planner(Query *parse, bool isCursor, int cursorOptions, } /* primary planning entry point (may recurse for subqueries) */ - result_plan = subquery_planner(parse, tuple_fraction, NULL); - - /* check we popped out the right number of levels */ - Assert(PlannerQueryLevel == 0); + result_plan = subquery_planner(glob, parse, 1, tuple_fraction, NULL); /* * If creating a plan for a scrollable cursor, make sure it can run @@ -153,12 +133,7 @@ planner(Query *parse, bool isCursor, int cursorOptions, result_plan = set_plan_references(result_plan, parse->rtable); /* executor wants to know total number of Params used overall */ - result_plan->nParamExec = list_length(PlannerParamList); - - /* restore state for outer planner, if any */ - PlannerQueryLevel = save_PlannerQueryLevel; - PlannerParamList = save_PlannerParamList; - PlannerBoundParamList = save_PlannerBoundParamList; + result_plan->nParamExec = list_length(glob->paramlist); return result_plan; } @@ -169,7 +144,9 @@ planner(Query *parse, bool isCursor, int cursorOptions, * Invokes the planner on a subquery. We recurse to here for each * sub-SELECT found in the query tree. * + * glob is the global state for the current planner run. * parse is the querytree produced by the parser & rewriter. + * level is the current recursion depth (1 at the top-level Query). * tuple_fraction is the fraction of tuples we expect will be retrieved. * tuple_fraction is interpreted as explained for grouping_planner, below. * @@ -189,24 +166,23 @@ planner(Query *parse, bool isCursor, int cursorOptions, *-------------------- */ Plan * -subquery_planner(Query *parse, double tuple_fraction, +subquery_planner(PlannerGlobal *glob, Query *parse, + Index level, double tuple_fraction, List **subquery_pathkeys) { - List *saved_initplan = PlannerInitPlan; - int saved_planid = PlannerPlanId; + int saved_plan_id = glob->next_plan_id; PlannerInfo *root; Plan *plan; List *newHaving; ListCell *l; - /* Set up for a new level of subquery */ - PlannerQueryLevel++; - PlannerInitPlan = NIL; - /* Create a PlannerInfo data structure for this subquery */ root = makeNode(PlannerInfo); root->parse = parse; + root->glob = glob; + root->query_level = level; root->planner_cxt = CurrentMemoryContext; + root->init_plans = NIL; root->eq_classes = NIL; root->in_info_list = NIL; root->append_rel_list = NIL; @@ -396,18 +372,13 @@ subquery_planner(Query *parse, double tuple_fraction, * initPlan list and extParam/allParam sets for plan nodes, and attach the * initPlans to the top plan node. */ - if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1) - SS_finalize_plan(plan, parse->rtable); + if (root->glob->next_plan_id != saved_plan_id || root->query_level > 1) + SS_finalize_plan(root, plan); /* Return sort ordering info if caller wants it */ if (subquery_pathkeys) *subquery_pathkeys = root->query_pathkeys; - /* Return to outer subquery context */ - PlannerQueryLevel--; - PlannerInitPlan = saved_initplan; - /* we do NOT restore PlannerPlanId; that's not an oversight! */ - return plan; } @@ -460,7 +431,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind) if (kind != EXPRKIND_VALUES && (root->parse->jointree->fromlist != NIL || kind == EXPRKIND_QUAL || - PlannerQueryLevel > 1)) + root->query_level > 1)) expr = eval_const_expressions(expr); /* @@ -478,7 +449,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind) /* Expand SubLinks to SubPlans */ if (root->parse->hasSubLinks) - expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL)); + expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL)); /* * XXX do not insert anything here unless you have grokked the comments in @@ -486,8 +457,8 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind) */ /* Replace uplevel vars with Param nodes (this IS possible in VALUES) */ - if (PlannerQueryLevel > 1) - expr = SS_replace_correlation_vars(expr); + if (root->query_level > 1) + expr = SS_replace_correlation_vars(root, expr); /* * If it's a qual or havingQual, convert it to implicit-AND format. (We @@ -590,6 +561,7 @@ inheritance_planner(PlannerInfo *root) subroot.in_info_list = (List *) adjust_appendrel_attrs((Node *) root->in_info_list, appinfo); + subroot.init_plans = NIL; /* There shouldn't be any OJ info to translate, as yet */ Assert(subroot.oj_info_list == NIL); @@ -612,6 +584,9 @@ inheritance_planner(PlannerInfo *root) subplans = lappend(subplans, subplan); + /* Make sure any initplans from this rel get into the outer list */ + root->init_plans = list_concat(root->init_plans, subroot.init_plans); + /* Build target-relations list for the executor */ resultRelations = lappend_int(resultRelations, appinfo->child_relid); @@ -1201,7 +1176,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction, */ if (parse->limitCount) { - est = estimate_expression_value(parse->limitCount); + est = estimate_expression_value(root, parse->limitCount); if (est && IsA(est, Const)) { if (((Const *) est)->constisnull) @@ -1224,7 +1199,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction, if (parse->limitOffset) { - est = estimate_expression_value(parse->limitOffset); + est = estimate_expression_value(root, parse->limitOffset); if (est && IsA(est, Const)) { if (((Const *) est)->constisnull) diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index af035d9b104cbbff3e3fd395f85fa7c3d019f122..b62aeb853d85e0e4e460c1e8cb696ff3afe6a1cc 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.119 2007/02/19 02:23:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.120 2007/02/19 07:03:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,52 +31,19 @@ #include "utils/syscache.h" -Index PlannerQueryLevel; /* level of current query */ -List *PlannerInitPlan; /* init subplans for current query */ -List *PlannerParamList; /* to keep track of cross-level Params */ - -int PlannerPlanId = 0; /* to assign unique ID to subquery plans */ - -/* - * PlannerParamList keeps track of the PARAM_EXEC slots that we have decided - * we need for the query. At runtime these slots are used to pass values - * either down into subqueries (for outer references in subqueries) or up out - * of subqueries (for the results of a subplan). The n'th entry in the list - * (n counts from 0) corresponds to Param->paramid = n. - * - * Each ParamList item shows the absolute query level it is associated with, - * where the outermost query is level 1 and nested subqueries have higher - * numbers. The item the parameter slot represents can be one of three kinds: - * - * A Var: the slot represents a variable of that level that must be passed - * down because subqueries have outer references to it. The varlevelsup - * value in the Var will always be zero. - * - * An Aggref (with an expression tree representing its argument): the slot - * represents an aggregate expression that is an outer reference for some - * subquery. The Aggref itself has agglevelsup = 0, and its argument tree - * is adjusted to match in level. - * - * A Param: the slot holds the result of a subplan (it is a setParam item - * for that subplan). The absolute level shown for such items corresponds - * to the parent query of the subplan. - * - * Note: we detect duplicate Var parameters and coalesce them into one slot, - * but we do not do this for Aggref or Param slots. - */ -typedef struct PlannerParamItem -{ - Node *item; /* the Var, Aggref, or Param */ - Index abslevel; /* its absolute query level */ -} PlannerParamItem; - - typedef struct convert_testexpr_context { + PlannerInfo *root; int rtindex; /* RT index for Vars, or 0 for Params */ List *righthandIds; /* accumulated list of Vars or Param IDs */ } convert_testexpr_context; +typedef struct process_sublinks_context +{ + PlannerInfo *root; + bool isTopQual; +} process_sublinks_context; + typedef struct finalize_primnode_context { Bitmapset *paramids; /* Set of PARAM_EXEC paramids found */ @@ -84,15 +51,17 @@ typedef struct finalize_primnode_context } finalize_primnode_context; -static Node *convert_testexpr(Node *testexpr, - int rtindex, - List **righthandIds); +static Node *convert_testexpr(PlannerInfo *root, + Node *testexpr, + int rtindex, + List **righthandIds); static Node *convert_testexpr_mutator(Node *node, convert_testexpr_context *context); static bool subplan_is_hashable(SubLink *slink, SubPlan *node); static bool hash_ok_operator(OpExpr *expr); -static Node *replace_correlation_vars_mutator(Node *node, void *context); -static Node *process_sublinks_mutator(Node *node, bool *isTopQual); +static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root); +static Node *process_sublinks_mutator(Node *node, + process_sublinks_context *context); static Bitmapset *finalize_plan(Plan *plan, List *rtable, Bitmapset *outer_params, Bitmapset *valid_params); @@ -104,7 +73,7 @@ static bool finalize_primnode(Node *node, finalize_primnode_context *context); * which is expected to have varlevelsup > 0 (ie, it is not local). */ static Param * -replace_outer_var(Var *var) +replace_outer_var(PlannerInfo *root, Var *var) { Param *retval; ListCell *ppl; @@ -112,11 +81,11 @@ replace_outer_var(Var *var) Index abslevel; int i; - Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel); - abslevel = PlannerQueryLevel - var->varlevelsup; + Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level); + abslevel = root->query_level - var->varlevelsup; /* - * If there's already a PlannerParamList entry for this same Var, just use + * If there's already a paramlist entry for this same Var, just use * it. NOTE: in sufficiently complex querytrees, it is possible for the * same varno/abslevel to refer to different RTEs in different parts of * the parsetree, so that different fields might end up sharing the same @@ -130,7 +99,7 @@ replace_outer_var(Var *var) * a subplan's args list. */ i = 0; - foreach(ppl, PlannerParamList) + foreach(ppl, root->glob->paramlist) { pitem = (PlannerParamItem *) lfirst(ppl); if (pitem->abslevel == abslevel && IsA(pitem->item, Var)) @@ -152,11 +121,11 @@ replace_outer_var(Var *var) var = (Var *) copyObject(var); var->varlevelsup = 0; - pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem)); + pitem = makeNode(PlannerParamItem); pitem->item = (Node *) var; pitem->abslevel = abslevel; - PlannerParamList = lappend(PlannerParamList, pitem); + root->glob->paramlist = lappend(root->glob->paramlist, pitem); /* i is already the correct index for the new item */ } @@ -174,15 +143,15 @@ replace_outer_var(Var *var) * which is expected to have agglevelsup > 0 (ie, it is not local). */ static Param * -replace_outer_agg(Aggref *agg) +replace_outer_agg(PlannerInfo *root, Aggref *agg) { Param *retval; PlannerParamItem *pitem; Index abslevel; int i; - Assert(agg->agglevelsup > 0 && agg->agglevelsup < PlannerQueryLevel); - abslevel = PlannerQueryLevel - agg->agglevelsup; + Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level); + abslevel = root->query_level - agg->agglevelsup; /* * It does not seem worthwhile to try to match duplicate outer aggs. Just @@ -192,12 +161,12 @@ replace_outer_agg(Aggref *agg) IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0); Assert(agg->agglevelsup == 0); - pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem)); + pitem = makeNode(PlannerParamItem); pitem->item = (Node *) agg; pitem->abslevel = abslevel; - PlannerParamList = lappend(PlannerParamList, pitem); - i = list_length(PlannerParamList) - 1; + root->glob->paramlist = lappend(root->glob->paramlist, pitem); + i = list_length(root->glob->paramlist) - 1; retval = makeNode(Param); retval->paramkind = PARAM_EXEC; @@ -214,22 +183,22 @@ replace_outer_agg(Aggref *agg) * This is used to allocate PARAM_EXEC slots for subplan outputs. */ static Param * -generate_new_param(Oid paramtype, int32 paramtypmod) +generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod) { Param *retval; PlannerParamItem *pitem; retval = makeNode(Param); retval->paramkind = PARAM_EXEC; - retval->paramid = list_length(PlannerParamList); + retval->paramid = list_length(root->glob->paramlist); retval->paramtype = paramtype; retval->paramtypmod = paramtypmod; - pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem)); + pitem = makeNode(PlannerParamItem); pitem->item = (Node *) retval; - pitem->abslevel = PlannerQueryLevel; + pitem->abslevel = root->query_level; - PlannerParamList = lappend(PlannerParamList, pitem); + root->glob->paramlist = lappend(root->glob->paramlist, pitem); return retval; } @@ -248,7 +217,7 @@ generate_new_param(Oid paramtype, int32 paramtypmod) * tree containing InitPlan Param nodes. */ static Node * -make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) +make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual) { SubPlan *node = makeNode(SubPlan); Query *subquery = (Query *) (slink->subselect); @@ -297,9 +266,13 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) /* * Generate the plan for the subquery. */ - node->plan = plan = subquery_planner(subquery, tuple_fraction, NULL); + node->plan = plan = subquery_planner(root->glob, subquery, + root->query_level + 1, + tuple_fraction, + NULL); - node->plan_id = PlannerPlanId++; /* Assign unique ID to this SubPlan */ + /* Assign quasi-unique ID to this SubPlan */ + node->plan_id = root->glob->next_plan_id++; node->rtable = subquery->rtable; @@ -323,9 +296,9 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) tmpset = bms_copy(plan->extParam); while ((paramid = bms_first_member(tmpset)) >= 0) { - PlannerParamItem *pitem = list_nth(PlannerParamList, paramid); + PlannerParamItem *pitem = list_nth(root->glob->paramlist, paramid); - if (pitem->abslevel == PlannerQueryLevel) + if (pitem->abslevel == root->query_level) node->parParam = lappend_int(node->parParam, paramid); } bms_free(tmpset); @@ -342,9 +315,9 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) { Param *prm; - prm = generate_new_param(BOOLOID, -1); + prm = generate_new_param(root, BOOLOID, -1); node->setParam = list_make1_int(prm->paramid); - PlannerInitPlan = lappend(PlannerInitPlan, node); + root->init_plans = lappend(root->init_plans, node); result = (Node *) prm; } else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK) @@ -353,10 +326,11 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) Param *prm; Assert(!te->resjunk); - prm = generate_new_param(exprType((Node *) te->expr), + prm = generate_new_param(root, + exprType((Node *) te->expr), exprTypmod((Node *) te->expr)); node->setParam = list_make1_int(prm->paramid); - PlannerInitPlan = lappend(PlannerInitPlan, node); + root->init_plans = lappend(root->init_plans, node); result = (Node *) prm; } else if (node->parParam == NIL && slink->subLinkType == ARRAY_SUBLINK) @@ -370,19 +344,22 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) if (!OidIsValid(arraytype)) elog(ERROR, "could not find array type for datatype %s", format_type_be(exprType((Node *) te->expr))); - prm = generate_new_param(arraytype, exprTypmod((Node *) te->expr)); + prm = generate_new_param(root, + arraytype, + exprTypmod((Node *) te->expr)); node->setParam = list_make1_int(prm->paramid); - PlannerInitPlan = lappend(PlannerInitPlan, node); + root->init_plans = lappend(root->init_plans, node); result = (Node *) prm; } else if (node->parParam == NIL && slink->subLinkType == ROWCOMPARE_SUBLINK) { /* Adjust the Params */ - result = convert_testexpr(testexpr, + result = convert_testexpr(root, + testexpr, 0, &node->paramIds); node->setParam = list_copy(node->paramIds); - PlannerInitPlan = lappend(PlannerInitPlan, node); + root->init_plans = lappend(root->init_plans, node); /* * The executable expression is returned to become part of the outer @@ -395,7 +372,8 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) ListCell *l; /* Adjust the Params */ - node->testexpr = convert_testexpr(testexpr, + node->testexpr = convert_testexpr(root, + testexpr, 0, &node->paramIds); @@ -442,7 +420,8 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) args = NIL; foreach(l, node->parParam) { - PlannerParamItem *pitem = list_nth(PlannerParamList, lfirst_int(l)); + PlannerParamItem *pitem = list_nth(root->glob->paramlist, + lfirst_int(l)); /* * The Var or Aggref has already been adjusted to have the correct @@ -477,13 +456,15 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) * any we find are for our own level of SubLink. */ static Node * -convert_testexpr(Node *testexpr, +convert_testexpr(PlannerInfo *root, + Node *testexpr, int rtindex, List **righthandIds) { Node *result; convert_testexpr_context context; + context.root = root; context.rtindex = rtindex; context.righthandIds = NIL; result = convert_testexpr_mutator(testexpr, &context); @@ -536,7 +517,8 @@ convert_testexpr_mutator(Node *node, /* Make the Param node representing the subplan's result */ Param *newparam; - newparam = generate_new_param(param->paramtype, + newparam = generate_new_param(context->root, + param->paramtype, param->paramtypmod); /* Record its ID */ context->righthandIds = lappend_int(context->righthandIds, @@ -765,7 +747,8 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink) * ininfo->sub_targetlist is filled with a list of Vars representing the * subselect outputs. */ - result = convert_testexpr(sublink->testexpr, + result = convert_testexpr(root, + sublink->testexpr, rtindex, &ininfo->sub_targetlist); @@ -795,30 +778,30 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink) * argument expressions, either in the parent or the child level. */ Node * -SS_replace_correlation_vars(Node *expr) +SS_replace_correlation_vars(PlannerInfo *root, Node *expr) { /* No setup needed for tree walk, so away we go */ - return replace_correlation_vars_mutator(expr, NULL); + return replace_correlation_vars_mutator(expr, root); } static Node * -replace_correlation_vars_mutator(Node *node, void *context) +replace_correlation_vars_mutator(Node *node, PlannerInfo *root) { if (node == NULL) return NULL; if (IsA(node, Var)) { if (((Var *) node)->varlevelsup > 0) - return (Node *) replace_outer_var((Var *) node); + return (Node *) replace_outer_var(root, (Var *) node); } if (IsA(node, Aggref)) { if (((Aggref *) node)->agglevelsup > 0) - return (Node *) replace_outer_agg((Aggref *) node); + return (Node *) replace_outer_agg(root, (Aggref *) node); } return expression_tree_mutator(node, replace_correlation_vars_mutator, - context); + (void *) root); } /* @@ -829,16 +812,21 @@ replace_correlation_vars_mutator(Node *node, void *context) * not distinguish FALSE from UNKNOWN return values. */ Node * -SS_process_sublinks(Node *expr, bool isQual) +SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual) { - /* The only context needed is the initial are-we-in-a-qual flag */ - return process_sublinks_mutator(expr, &isQual); + process_sublinks_context context; + + context.root = root; + context.isTopQual = isQual; + return process_sublinks_mutator(expr, &context); } static Node * -process_sublinks_mutator(Node *node, bool *isTopQual) +process_sublinks_mutator(Node *node, process_sublinks_context *context) { - bool locTopQual; + process_sublinks_context locContext; + + locContext.root = context->root; if (node == NULL) return NULL; @@ -849,14 +837,18 @@ process_sublinks_mutator(Node *node, bool *isTopQual) /* * First, recursively process the lefthand-side expressions, if any. + * They're not top-level anymore. */ - locTopQual = false; - testexpr = process_sublinks_mutator(sublink->testexpr, &locTopQual); + locContext.isTopQual = false; + testexpr = process_sublinks_mutator(sublink->testexpr, &locContext); /* * Now build the SubPlan node and make the expr to return. */ - return make_subplan(sublink, testexpr, *isTopQual); + return make_subplan(context->root, + sublink, + testexpr, + context->isTopQual); } /* @@ -883,14 +875,13 @@ process_sublinks_mutator(Node *node, bool *isTopQual) ListCell *l; /* Still at qual top-level */ - locTopQual = *isTopQual; + locContext.isTopQual = context->isTopQual; foreach(l, ((BoolExpr *) node)->args) { Node *newarg; - newarg = process_sublinks_mutator(lfirst(l), - (void *) &locTopQual); + newarg = process_sublinks_mutator(lfirst(l), &locContext); if (and_clause(newarg)) newargs = list_concat(newargs, ((BoolExpr *) newarg)->args); else @@ -900,7 +891,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual) } /* otherwise not at qual top-level */ - locTopQual = false; + locContext.isTopQual = false; if (or_clause(node)) { @@ -911,8 +902,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual) { Node *newarg; - newarg = process_sublinks_mutator(lfirst(l), - (void *) &locTopQual); + newarg = process_sublinks_mutator(lfirst(l), &locContext); if (or_clause(newarg)) newargs = list_concat(newargs, ((BoolExpr *) newarg)->args); else @@ -923,7 +913,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual) return expression_tree_mutator(node, process_sublinks_mutator, - (void *) &locTopQual); + (void *) &locContext); } /* @@ -934,7 +924,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual) * to the top plan node. */ void -SS_finalize_plan(Plan *plan, List *rtable) +SS_finalize_plan(PlannerInfo *root, Plan *plan) { Bitmapset *outer_params, *valid_params, @@ -951,17 +941,17 @@ SS_finalize_plan(Plan *plan, List *rtable) */ outer_params = valid_params = NULL; paramid = 0; - foreach(l, PlannerParamList) + foreach(l, root->glob->paramlist) { PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l); - if (pitem->abslevel < PlannerQueryLevel) + if (pitem->abslevel < root->query_level) { /* valid outer-level parameter */ outer_params = bms_add_member(outer_params, paramid); valid_params = bms_add_member(valid_params, paramid); } - else if (pitem->abslevel == PlannerQueryLevel && + else if (pitem->abslevel == root->query_level && IsA(pitem->item, Param)) { /* valid local parameter (i.e., a setParam of my child) */ @@ -974,7 +964,7 @@ SS_finalize_plan(Plan *plan, List *rtable) /* * Now recurse through plan tree. */ - (void) finalize_plan(plan, rtable, outer_params, valid_params); + (void) finalize_plan(plan, root->parse->rtable, outer_params, valid_params); bms_free(outer_params); bms_free(valid_params); @@ -991,8 +981,8 @@ SS_finalize_plan(Plan *plan, List *rtable) * top node. This is a conservative overestimate, since in fact each * initPlan might be executed later than plan startup, or even not at all. */ - plan->initPlan = PlannerInitPlan; - PlannerInitPlan = NIL; /* make sure they're not attached twice */ + plan->initPlan = root->init_plans; + root->init_plans = NIL; /* make sure they're not attached twice */ initExtParam = initSetParam = NULL; initplan_cost = 0; @@ -1287,25 +1277,27 @@ Param * SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, Oid resulttype, int32 resulttypmod) { - List *saved_initplan = PlannerInitPlan; + List *saved_init_plans; SubPlan *node; Param *prm; /* * Set up for a new level of subquery. This is just to keep - * SS_finalize_plan from becoming confused. + * SS_finalize_plan from becoming confused; we don't bother with making + * a whole new PlannerInfo struct. */ - PlannerQueryLevel++; - PlannerInitPlan = NIL; + root->query_level++; + saved_init_plans = root->init_plans; + root->init_plans = NIL; /* * Build extParam/allParam sets for plan nodes. */ - SS_finalize_plan(plan, root->parse->rtable); + SS_finalize_plan(root, plan); /* Return to outer subquery context */ - PlannerQueryLevel--; - PlannerInitPlan = saved_initplan; + root->query_level--; + root->init_plans = saved_init_plans; /* * Create a SubPlan node and add it to the outer list of InitPlans. @@ -1313,11 +1305,12 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, node = makeNode(SubPlan); node->subLinkType = EXPR_SUBLINK; node->plan = plan; - node->plan_id = PlannerPlanId++; /* Assign unique ID to this SubPlan */ + /* Assign quasi-unique ID to this SubPlan */ + node->plan_id = root->glob->next_plan_id++; node->rtable = root->parse->rtable; - PlannerInitPlan = lappend(PlannerInitPlan, node); + root->init_plans = lappend(root->init_plans, node); /* * The node can't have any inputs (since it's an initplan), so the @@ -1327,7 +1320,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, /* * Make a Param that will be the subplan's output. */ - prm = generate_new_param(resulttype, resulttypmod); + prm = generate_new_param(root, resulttype, resulttypmod); node->setParam = list_make1_int(prm->paramid); return prm; diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index ce6f9cc38e4b470b0fc88a59076db765eaf6fdda..1519c01e60e725c8c5ad72ddd0a6f96fda58edc5 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.46 2007/01/20 20:45:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.47 2007/02/19 07:03:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -292,7 +292,10 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, */ subroot = makeNode(PlannerInfo); subroot->parse = subquery; + subroot->glob = root->glob; + subroot->query_level = root->query_level; subroot->planner_cxt = CurrentMemoryContext; + subroot->init_plans = NIL; subroot->in_info_list = NIL; subroot->append_rel_list = NIL; diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index b8d98cc9e3cd7ead395795c6d02324cef13ace42..310b57392cd9460e14039d3920929e9f6256d45d 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -16,7 +16,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.85 2007/01/05 22:19:32 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.86 2007/02/19 07:03:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -124,7 +124,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) /* * Currently the executor only supports FOR UPDATE/SHARE at top level */ - if (PlannerQueryLevel > 1) + if (root->query_level > 1) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SELECT FOR UPDATE/SHARE is not allowed in subqueries"))); diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 5ee03b75cffd7e87e9d1322eda94390cb5f8f710..2f06e1bf5322dfe3a03c14d310c9dbc03d964590 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.137 2007/01/22 20:00:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.138 2007/02/19 07:03:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -177,7 +177,10 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, /* * Generate plan for primitive subquery */ - subplan = subquery_planner(subquery, tuple_fraction, NULL); + subplan = subquery_planner(root->glob, subquery, + root->query_level + 1, + tuple_fraction, + NULL); /* * Add a SubqueryScan with the caller-requested targetlist diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 528f02ed111389beef7c228d18678d0002db662d..f90d55001979b65c15f8fdb222473cc349e83a1e 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.234 2007/02/16 23:32:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.235 2007/02/19 07:03:30 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -49,6 +49,7 @@ typedef struct { + ParamListInfo boundParams; List *active_fns; Node *case_val; bool estimate; @@ -1578,6 +1579,7 @@ eval_const_expressions(Node *node) { eval_const_expressions_context context; + context.boundParams = NULL; /* don't use any bound params */ context.active_fns = NIL; /* nothing being recursively simplified */ context.case_val = NULL; /* no CASE being examined */ context.estimate = false; /* safe transformations only */ @@ -1601,10 +1603,11 @@ eval_const_expressions(Node *node) *-------------------- */ Node * -estimate_expression_value(Node *node) +estimate_expression_value(PlannerInfo *root, Node *node) { eval_const_expressions_context context; + context.boundParams = root->glob->boundParams; /* bound Params */ context.active_fns = NIL; /* nothing being recursively simplified */ context.case_val = NULL; /* no CASE being examined */ context.estimate = true; /* unsafe transformations OK */ @@ -1623,11 +1626,11 @@ eval_const_expressions_mutator(Node *node, /* Look to see if we've been given a value for this Param */ if (param->paramkind == PARAM_EXTERN && - PlannerBoundParamList != NULL && + context->boundParams != NULL && param->paramid > 0 && - param->paramid <= PlannerBoundParamList->numParams) + param->paramid <= context->boundParams->numParams) { - ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1]; + ParamExternData *prm = &context->boundParams->params[param->paramid - 1]; if (OidIsValid(prm->ptype)) { diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 7908ab15167a74ddf34a705fd33458d45b027f67..c6b8e8481c498d822de7700ca293713910021716 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.225 2007/01/31 16:54:51 teodor Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.226 2007/02/19 07:03:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3411,7 +3411,7 @@ get_restriction_variable(PlannerInfo *root, List *args, int varRelid, if (vardata->rel && rdata.rel == NULL) { *varonleft = true; - *other = estimate_expression_value(rdata.var); + *other = estimate_expression_value(root, rdata.var); /* Assume we need no ReleaseVariableStats(rdata) here */ return true; } @@ -3419,7 +3419,7 @@ get_restriction_variable(PlannerInfo *root, List *args, int varRelid, if (vardata->rel == NULL && rdata.rel) { *varonleft = false; - *other = estimate_expression_value(vardata->var); + *other = estimate_expression_value(root, vardata->var); /* Assume we need no ReleaseVariableStats(*vardata) here */ *vardata = rdata; return true; diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 2452f792940788985bb36782abc2ab9d9bfbb7e4..44175591e7502c38910a2286bfecff1bd57a8940 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.194 2007/02/03 14:06:55 petere Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.195 2007/02/19 07:03:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -175,6 +175,7 @@ typedef enum NodeTag * TAGS FOR PLANNER NODES (relation.h) */ T_PlannerInfo = 500, + T_PlannerGlobal, T_RelOptInfo, T_IndexOptInfo, T_Path, @@ -198,6 +199,7 @@ typedef enum NodeTag T_OuterJoinInfo, T_InClauseInfo, T_AppendRelInfo, + T_PlannerParamItem, /* * TAGS FOR MEMORY NODES (memnodes.h) diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 298ac0d95d6f7920b3312bdd7e3e8151227f3bd1..caa689e262379074e18b09fd35dcd769fe068b29 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.124 2007/02/03 14:06:56 petere Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.125 2007/02/19 07:03:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -442,10 +442,9 @@ typedef struct SubPlan List *paramIds; /* IDs of Params embedded in the above */ /* The subselect, transformed to a Plan: */ struct Plan *plan; /* subselect plan itself */ - int plan_id; /* dummy thing because of we haven't equal - * funcs for plan nodes... actually, we could - * put *plan itself somewhere else (TopPlan - * node ?)... */ + int plan_id; /* kluge because we haven't equal-funcs for + * plan nodes... we compare this instead of + * subselect plan */ List *rtable; /* range table for subselect */ /* Information about execution strategy: */ bool useHashTable; /* TRUE to store subselect output in a hash diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index dac7d959bbd23bd8dcbd5a6ad779f8eec693ad5e..6de06ebc918f769327cf32ca075b3ab26ff9262a 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.135 2007/02/16 20:57:19 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.136 2007/02/19 07:03:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "access/sdir.h" #include "nodes/bitmapset.h" +#include "nodes/params.h" #include "nodes/parsenodes.h" #include "storage/block.h" @@ -46,6 +47,27 @@ typedef struct QualCost } QualCost; +/*---------- + * PlannerGlobal + * Global information for planning/optimization + * + * PlannerGlobal holds state for an entire planner invocation; this state + * is shared across all levels of sub-Queries that exist in the command being + * planned. + *---------- + */ +typedef struct PlannerGlobal +{ + NodeTag type; + + ParamListInfo boundParams; /* Param values provided to planner() */ + + List *paramlist; /* to keep track of cross-level Params */ + + int next_plan_id; /* hack for distinguishing SubPlans */ +} PlannerGlobal; + + /*---------- * PlannerInfo * Per-query information for planning/optimization @@ -62,6 +84,10 @@ typedef struct PlannerInfo Query *parse; /* the Query being planned */ + PlannerGlobal *glob; /* global info for current planner run */ + + Index query_level; /* 1 at the outermost Query */ + /* * simple_rel_array holds pointers to "base rels" and "other rels" (see * comments for RelOptInfo for more info). It is indexed by rangetable @@ -84,6 +110,8 @@ typedef struct PlannerInfo List *join_rel_list; /* list of join-relation RelOptInfos */ struct HTAB *join_rel_hash; /* optional hashtable for join relations */ + List *init_plans; /* init subplans for query */ + List *eq_classes; /* list of active EquivalenceClasses */ List *canon_pathkeys; /* list of "canonical" PathKeys */ @@ -1109,4 +1137,39 @@ typedef struct AppendRelInfo Oid parent_reloid; /* OID of parent relation */ } AppendRelInfo; +/* + * glob->paramlist keeps track of the PARAM_EXEC slots that we have decided + * we need for the query. At runtime these slots are used to pass values + * either down into subqueries (for outer references in subqueries) or up out + * of subqueries (for the results of a subplan). The n'th entry in the list + * (n counts from 0) corresponds to Param->paramid = n. + * + * Each paramlist item shows the absolute query level it is associated with, + * where the outermost query is level 1 and nested subqueries have higher + * numbers. The item the parameter slot represents can be one of three kinds: + * + * A Var: the slot represents a variable of that level that must be passed + * down because subqueries have outer references to it. The varlevelsup + * value in the Var will always be zero. + * + * An Aggref (with an expression tree representing its argument): the slot + * represents an aggregate expression that is an outer reference for some + * subquery. The Aggref itself has agglevelsup = 0, and its argument tree + * is adjusted to match in level. + * + * A Param: the slot holds the result of a subplan (it is a setParam item + * for that subplan). The absolute level shown for such items corresponds + * to the parent query of the subplan. + * + * Note: we detect duplicate Var parameters and coalesce them into one slot, + * but we do not do this for Aggref or Param slots. + */ +typedef struct PlannerParamItem +{ + NodeTag type; + + Node *item; /* the Var, Aggref, or Param */ + Index abslevel; /* its absolute query level */ +} PlannerParamItem; + #endif /* RELATION_H */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 500112591429a58a92915e014ab855dd098c24d9..bd4a7964355f3473db5324a3ac7851ee49c664b2 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.86 2007/01/22 01:35:22 tgl Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.87 2007/02/19 07:03:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -77,7 +77,7 @@ extern void set_coercionform_dontcare(Node *node); extern Node *eval_const_expressions(Node *node); -extern Node *estimate_expression_value(Node *node); +extern Node *estimate_expression_value(PlannerInfo *root, Node *node); extern bool expression_tree_walker(Node *node, bool (*walker) (), void *context); diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index 6567e5b8b77920e566079a77aaedbb0a3d2c3f80..44d03602694120f59dd557b3328ea1f2005f6420 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -7,23 +7,21 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.36 2007/01/05 22:19:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.37 2007/02/19 07:03:34 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef PLANNER_H #define PLANNER_H -#include "nodes/params.h" -#include "nodes/parsenodes.h" #include "nodes/plannodes.h" +#include "nodes/relation.h" -extern ParamListInfo PlannerBoundParamList; /* current boundParams */ - extern Plan *planner(Query *parse, bool isCursor, int cursorOptions, ParamListInfo boundParams); -extern Plan *subquery_planner(Query *parse, double tuple_fraction, - List **subquery_pathkeys); +extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse, + Index level, double tuple_fraction, + List **subquery_pathkeys); #endif /* PLANNER_H */ diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index 8a4328bd1f2d487017b7af1e5d39dc32885986f2..17c94bf6099ee8cfe4b68486b77f20277d1e93e0 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -5,7 +5,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.28 2007/01/05 22:19:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.29 2007/02/19 07:03:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -15,16 +15,10 @@ #include "nodes/plannodes.h" #include "nodes/relation.h" - -extern Index PlannerQueryLevel; /* level of current query */ -extern List *PlannerInitPlan; /* init subplans for current query */ -extern List *PlannerParamList; /* to keep track of cross-level Params */ -extern int PlannerPlanId; /* to assign unique ID to subquery plans */ - extern Node *convert_IN_to_join(PlannerInfo *root, SubLink *sublink); -extern Node *SS_replace_correlation_vars(Node *expr); -extern Node *SS_process_sublinks(Node *expr, bool isQual); -extern void SS_finalize_plan(Plan *plan, List *rtable); +extern Node *SS_replace_correlation_vars(PlannerInfo *root, Node *expr); +extern Node *SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual); +extern void SS_finalize_plan(PlannerInfo *root, Plan *plan); extern Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, Oid resulttype, int32 resulttypmod);