aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/subselect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r--src/backend/optimizer/plan/subselect.c396
1 files changed, 26 insertions, 370 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index cb1ea86afb2..64272dd6500 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1,7 +1,10 @@
/*-------------------------------------------------------------------------
*
* subselect.c
- * Planning routines for subselects and parameters.
+ * Planning routines for subselects.
+ *
+ * This module deals with SubLinks and CTEs, but not subquery RTEs (i.e.,
+ * not sub-SELECT-in-FROM cases).
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -22,6 +25,7 @@
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
+#include "optimizer/paramassign.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
@@ -87,355 +91,6 @@ static bool finalize_agg_primnode(Node *node, finalize_primnode_context *context
/*
- * Select a PARAM_EXEC number to identify the given Var as a parameter for
- * the current subquery, or for a nestloop's inner scan.
- * If the Var already has a param in the current context, return that one.
- */
-static int
-assign_param_for_var(PlannerInfo *root, Var *var)
-{
- ListCell *ppl;
- PlannerParamItem *pitem;
- Index levelsup;
-
- /* Find the query level the Var belongs to */
- for (levelsup = var->varlevelsup; levelsup > 0; levelsup--)
- root = root->parent_root;
-
- /* If there's already a matching PlannerParamItem there, just use it */
- foreach(ppl, root->plan_params)
- {
- pitem = (PlannerParamItem *) lfirst(ppl);
- if (IsA(pitem->item, Var))
- {
- Var *pvar = (Var *) pitem->item;
-
- /*
- * This comparison must match _equalVar(), except for ignoring
- * varlevelsup. Note that _equalVar() ignores the location.
- */
- if (pvar->varno == var->varno &&
- pvar->varattno == var->varattno &&
- pvar->vartype == var->vartype &&
- pvar->vartypmod == var->vartypmod &&
- pvar->varcollid == var->varcollid &&
- pvar->varnoold == var->varnoold &&
- pvar->varoattno == var->varoattno)
- return pitem->paramId;
- }
- }
-
- /* Nope, so make a new one */
- var = copyObject(var);
- var->varlevelsup = 0;
-
- pitem = makeNode(PlannerParamItem);
- pitem->item = (Node *) var;
- pitem->paramId = list_length(root->glob->paramExecTypes);
- root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
- var->vartype);
-
- root->plan_params = lappend(root->plan_params, pitem);
-
- return pitem->paramId;
-}
-
-/*
- * Generate a Param node to replace the given Var,
- * which is expected to have varlevelsup > 0 (ie, it is not local).
- */
-static Param *
-replace_outer_var(PlannerInfo *root, Var *var)
-{
- Param *retval;
- int i;
-
- Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
-
- /* Find the Var in the appropriate plan_params, or add it if not present */
- i = assign_param_for_var(root, var);
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = i;
- retval->paramtype = var->vartype;
- retval->paramtypmod = var->vartypmod;
- retval->paramcollid = var->varcollid;
- retval->location = var->location;
-
- return retval;
-}
-
-/*
- * Generate a Param node to replace the given Var, which will be supplied
- * from an upper NestLoop join node.
- *
- * This is effectively the same as replace_outer_var, except that we expect
- * the Var to be local to the current query level.
- */
-Param *
-assign_nestloop_param_var(PlannerInfo *root, Var *var)
-{
- Param *retval;
- int i;
-
- Assert(var->varlevelsup == 0);
-
- i = assign_param_for_var(root, var);
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = i;
- retval->paramtype = var->vartype;
- retval->paramtypmod = var->vartypmod;
- retval->paramcollid = var->varcollid;
- retval->location = var->location;
-
- return retval;
-}
-
-/*
- * Select a PARAM_EXEC number to identify the given PlaceHolderVar as a
- * parameter for the current subquery, or for a nestloop's inner scan.
- * If the PHV already has a param in the current context, return that one.
- *
- * This is just like assign_param_for_var, except for PlaceHolderVars.
- */
-static int
-assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
-{
- ListCell *ppl;
- PlannerParamItem *pitem;
- Index levelsup;
-
- /* Find the query level the PHV belongs to */
- for (levelsup = phv->phlevelsup; levelsup > 0; levelsup--)
- root = root->parent_root;
-
- /* If there's already a matching PlannerParamItem there, just use it */
- foreach(ppl, root->plan_params)
- {
- pitem = (PlannerParamItem *) lfirst(ppl);
- if (IsA(pitem->item, PlaceHolderVar))
- {
- PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item;
-
- /* We assume comparing the PHIDs is sufficient */
- if (pphv->phid == phv->phid)
- return pitem->paramId;
- }
- }
-
- /* Nope, so make a new one */
- phv = copyObject(phv);
- if (phv->phlevelsup != 0)
- {
- IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0);
- Assert(phv->phlevelsup == 0);
- }
-
- pitem = makeNode(PlannerParamItem);
- pitem->item = (Node *) phv;
- pitem->paramId = list_length(root->glob->paramExecTypes);
- root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
- exprType((Node *) phv->phexpr));
-
- root->plan_params = lappend(root->plan_params, pitem);
-
- return pitem->paramId;
-}
-
-/*
- * Generate a Param node to replace the given PlaceHolderVar,
- * which is expected to have phlevelsup > 0 (ie, it is not local).
- *
- * This is just like replace_outer_var, except for PlaceHolderVars.
- */
-static Param *
-replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
-{
- Param *retval;
- int i;
-
- Assert(phv->phlevelsup > 0 && phv->phlevelsup < root->query_level);
-
- /* Find the PHV in the appropriate plan_params, or add it if not present */
- i = assign_param_for_placeholdervar(root, phv);
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = i;
- retval->paramtype = exprType((Node *) phv->phexpr);
- retval->paramtypmod = exprTypmod((Node *) phv->phexpr);
- retval->paramcollid = exprCollation((Node *) phv->phexpr);
- retval->location = -1;
-
- return retval;
-}
-
-/*
- * Generate a Param node to replace the given PlaceHolderVar, which will be
- * supplied from an upper NestLoop join node.
- *
- * This is just like assign_nestloop_param_var, except for PlaceHolderVars.
- */
-Param *
-assign_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
-{
- Param *retval;
- int i;
-
- Assert(phv->phlevelsup == 0);
-
- i = assign_param_for_placeholdervar(root, phv);
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = i;
- retval->paramtype = exprType((Node *) phv->phexpr);
- retval->paramtypmod = exprTypmod((Node *) phv->phexpr);
- retval->paramcollid = exprCollation((Node *) phv->phexpr);
- retval->location = -1;
-
- return retval;
-}
-
-/*
- * Generate a Param node to replace the given Aggref
- * which is expected to have agglevelsup > 0 (ie, it is not local).
- */
-static Param *
-replace_outer_agg(PlannerInfo *root, Aggref *agg)
-{
- Param *retval;
- PlannerParamItem *pitem;
- Index levelsup;
-
- Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level);
-
- /* Find the query level the Aggref belongs to */
- for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--)
- root = root->parent_root;
-
- /*
- * It does not seem worthwhile to try to match duplicate outer aggs. Just
- * make a new slot every time.
- */
- agg = copyObject(agg);
- IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
- Assert(agg->agglevelsup == 0);
-
- pitem = makeNode(PlannerParamItem);
- pitem->item = (Node *) agg;
- pitem->paramId = list_length(root->glob->paramExecTypes);
- root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
- agg->aggtype);
-
- root->plan_params = lappend(root->plan_params, pitem);
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = pitem->paramId;
- retval->paramtype = agg->aggtype;
- retval->paramtypmod = -1;
- retval->paramcollid = agg->aggcollid;
- retval->location = agg->location;
-
- return retval;
-}
-
-/*
- * Generate a Param node to replace the given GroupingFunc expression which is
- * expected to have agglevelsup > 0 (ie, it is not local).
- */
-static Param *
-replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp)
-{
- Param *retval;
- PlannerParamItem *pitem;
- Index levelsup;
- Oid ptype;
-
- Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level);
-
- /* Find the query level the GroupingFunc belongs to */
- for (levelsup = grp->agglevelsup; levelsup > 0; levelsup--)
- root = root->parent_root;
-
- /*
- * It does not seem worthwhile to try to match duplicate outer aggs. Just
- * make a new slot every time.
- */
- grp = copyObject(grp);
- IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0);
- Assert(grp->agglevelsup == 0);
- ptype = exprType((Node *) grp);
-
- pitem = makeNode(PlannerParamItem);
- pitem->item = (Node *) grp;
- pitem->paramId = list_length(root->glob->paramExecTypes);
- root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
- ptype);
-
- root->plan_params = lappend(root->plan_params, pitem);
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = pitem->paramId;
- retval->paramtype = ptype;
- retval->paramtypmod = -1;
- retval->paramcollid = InvalidOid;
- retval->location = grp->location;
-
- return retval;
-}
-
-/*
- * Generate a new Param node that will not conflict with any other.
- *
- * This is used to create Params representing subplan outputs.
- * We don't need to build a PlannerParamItem for such a Param, but we do
- * need to make sure we record the type in paramExecTypes (otherwise,
- * there won't be a slot allocated for it).
- */
-static Param *
-generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod,
- Oid paramcollation)
-{
- Param *retval;
-
- retval = makeNode(Param);
- retval->paramkind = PARAM_EXEC;
- retval->paramid = list_length(root->glob->paramExecTypes);
- root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
- paramtype);
- retval->paramtype = paramtype;
- retval->paramtypmod = paramtypmod;
- retval->paramcollid = paramcollation;
- retval->location = -1;
-
- return retval;
-}
-
-/*
- * Assign a (nonnegative) PARAM_EXEC ID for a special parameter (one that
- * is not actually used to carry a value at runtime). Such parameters are
- * used for special runtime signaling purposes, such as connecting a
- * recursive union node to its worktable scan node or forcing plan
- * re-evaluation within the EvalPlanQual mechanism. No actual Param node
- * exists with this ID, however.
- */
-int
-SS_assign_special_param(PlannerInfo *root)
-{
- int paramId = list_length(root->glob->paramExecTypes);
-
- root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
- InvalidOid);
- return paramId;
-}
-
-/*
* Get the datatype/typmod/collation of the first column of the plan's output.
*
* This information is stored for ARRAY_SUBLINK execution and for
@@ -716,7 +371,7 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
Param *prm;
Assert(testexpr == NULL);
- prm = generate_new_param(root, BOOLOID, -1, InvalidOid);
+ prm = generate_new_exec_param(root, BOOLOID, -1, InvalidOid);
splan->setParam = list_make1_int(prm->paramid);
isInitPlan = true;
result = (Node *) prm;
@@ -728,10 +383,10 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
Assert(!te->resjunk);
Assert(testexpr == NULL);
- prm = generate_new_param(root,
- exprType((Node *) te->expr),
- exprTypmod((Node *) te->expr),
- exprCollation((Node *) te->expr));
+ prm = generate_new_exec_param(root,
+ exprType((Node *) te->expr),
+ exprTypmod((Node *) te->expr),
+ exprCollation((Node *) te->expr));
splan->setParam = list_make1_int(prm->paramid);
isInitPlan = true;
result = (Node *) prm;
@@ -748,10 +403,10 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
if (!OidIsValid(arraytype))
elog(ERROR, "could not find array type for datatype %s",
format_type_be(exprType((Node *) te->expr)));
- prm = generate_new_param(root,
- arraytype,
- exprTypmod((Node *) te->expr),
- exprCollation((Node *) te->expr));
+ prm = generate_new_exec_param(root,
+ arraytype,
+ exprTypmod((Node *) te->expr),
+ exprCollation((Node *) te->expr));
splan->setParam = list_make1_int(prm->paramid);
isInitPlan = true;
result = (Node *) prm;
@@ -930,10 +585,10 @@ generate_subquery_params(PlannerInfo *root, List *tlist, List **paramIds)
if (tent->resjunk)
continue;
- param = generate_new_param(root,
- exprType((Node *) tent->expr),
- exprTypmod((Node *) tent->expr),
- exprCollation((Node *) tent->expr));
+ param = generate_new_exec_param(root,
+ exprType((Node *) tent->expr),
+ exprTypmod((Node *) tent->expr),
+ exprCollation((Node *) tent->expr));
result = lappend(result, param);
ids = lappend_int(ids, param->paramid);
}
@@ -1257,7 +912,7 @@ SS_process_ctes(PlannerInfo *root)
* ParamExecData slot for this param ID for communication among
* multiple CteScan nodes that might be scanning this CTE.)
*/
- paramid = SS_assign_special_param(root);
+ paramid = assign_special_exec_param(root);
splan->setParam = list_make1_int(paramid);
/*
@@ -1863,10 +1518,10 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
Param *param;
cc = lnext(cc);
- param = generate_new_param(root,
- exprType(rightarg),
- exprTypmod(rightarg),
- exprCollation(rightarg));
+ param = generate_new_exec_param(root,
+ exprType(rightarg),
+ exprTypmod(rightarg),
+ exprCollation(rightarg));
tlist = lappend(tlist,
makeTargetEntry((Expr *) rightarg,
resno++,
@@ -2917,7 +2572,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
* parameter change signaling since we always re-evaluate the subplan.
* Note that this wouldn't work too well if there might be uses of the
* same param IDs elsewhere in the plan, but that can't happen because
- * generate_new_param never tries to merge params.
+ * generate_new_exec_param never tries to merge params.
*/
foreach(lc, subplan->paramIds)
{
@@ -2983,7 +2638,8 @@ SS_make_initplan_output_param(PlannerInfo *root,
Oid resulttype, int32 resulttypmod,
Oid resultcollation)
{
- return generate_new_param(root, resulttype, resulttypmod, resultcollation);
+ return generate_new_exec_param(root, resulttype,
+ resulttypmod, resultcollation);
}
/*