#include "utils/syscache.h"
-ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
-
-
/* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1
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)
}
/* 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
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;
}
* 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.
*
*--------------------
*/
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;
* 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;
}
if (kind != EXPRKIND_VALUES &&
(root->parse->jointree->fromlist != NIL ||
kind == EXPRKIND_QUAL ||
- PlannerQueryLevel > 1))
+ root->query_level > 1))
expr = eval_const_expressions(expr);
/*
/* 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
*/
/* 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
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);
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);
*/
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)
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)
#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 */
} 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);
* 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;
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
* 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))
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 */
}
* 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
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;
* 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;
}
* 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);
/*
* 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;
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);
{
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)
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)
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
ListCell *l;
/* Adjust the Params */
- node->testexpr = convert_testexpr(testexpr,
+ node->testexpr = convert_testexpr(root,
+ testexpr,
0,
&node->paramIds);
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
* 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);
/* 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,
* 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);
* 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);
}
/*
* 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;
/*
* 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);
}
/*
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
}
/* otherwise not at qual top-level */
- locTopQual = false;
+ locContext.isTopQual = false;
if (or_clause(node))
{
{
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
return expression_tree_mutator(node,
process_sublinks_mutator,
- (void *) &locTopQual);
+ (void *) &locContext);
}
/*
* 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,
*/
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) */
/*
* 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);
* 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;
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.
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
/*
* 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;