PostgreSQL Source Code  git master
subselect.h File Reference
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
Include dependency graph for subselect.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void SS_process_ctes (PlannerInfo *root)
 
JoinExprconvert_ANY_sublink_to_join (PlannerInfo *root, SubLink *sublink, Relids available_rels)
 
JoinExprconvert_EXISTS_sublink_to_join (PlannerInfo *root, SubLink *sublink, bool under_not, Relids available_rels)
 
NodeSS_replace_correlation_vars (PlannerInfo *root, Node *expr)
 
NodeSS_process_sublinks (PlannerInfo *root, Node *expr, bool isQual)
 
void SS_identify_outer_params (PlannerInfo *root)
 
void SS_charge_for_initplans (PlannerInfo *root, RelOptInfo *final_rel)
 
void SS_attach_initplans (PlannerInfo *root, Plan *plan)
 
void SS_finalize_plan (PlannerInfo *root, Plan *plan)
 
ParamSS_make_initplan_output_param (PlannerInfo *root, Oid resulttype, int32 resulttypmod, Oid resultcollation)
 
void SS_make_initplan_from_plan (PlannerInfo *root, PlannerInfo *subroot, Plan *plan, Param *prm)
 

Function Documentation

◆ convert_ANY_sublink_to_join()

JoinExpr* convert_ANY_sublink_to_join ( PlannerInfo root,
SubLink sublink,
Relids  available_rels 
)

Definition at line 1268 of file subselect.c.

1270 {
1271  JoinExpr *result;
1272  Query *parse = root->parse;
1273  Query *subselect = (Query *) sublink->subselect;
1274  Relids upper_varnos;
1275  int rtindex;
1276  ParseNamespaceItem *nsitem;
1277  RangeTblEntry *rte;
1278  RangeTblRef *rtr;
1279  List *subquery_vars;
1280  Node *quals;
1281  ParseState *pstate;
1282 
1283  Assert(sublink->subLinkType == ANY_SUBLINK);
1284 
1285  /*
1286  * The sub-select must not refer to any Vars of the parent query. (Vars of
1287  * higher levels should be okay, though.)
1288  */
1289  if (contain_vars_of_level((Node *) subselect, 1))
1290  return NULL;
1291 
1292  /*
1293  * The test expression must contain some Vars of the parent query, else
1294  * it's not gonna be a join. (Note that it won't have Vars referring to
1295  * the subquery, rather Params.)
1296  */
1297  upper_varnos = pull_varnos(root, sublink->testexpr);
1298  if (bms_is_empty(upper_varnos))
1299  return NULL;
1300 
1301  /*
1302  * However, it can't refer to anything outside available_rels.
1303  */
1304  if (!bms_is_subset(upper_varnos, available_rels))
1305  return NULL;
1306 
1307  /*
1308  * The combining operators and left-hand expressions mustn't be volatile.
1309  */
1310  if (contain_volatile_functions(sublink->testexpr))
1311  return NULL;
1312 
1313  /* Create a dummy ParseState for addRangeTableEntryForSubquery */
1314  pstate = make_parsestate(NULL);
1315 
1316  /*
1317  * Okay, pull up the sub-select into upper range table.
1318  *
1319  * We rely here on the assumption that the outer query has no references
1320  * to the inner (necessarily true, other than the Vars that we build
1321  * below). Therefore this is a lot easier than what pull_up_subqueries has
1322  * to go through.
1323  */
1324  nsitem = addRangeTableEntryForSubquery(pstate,
1325  subselect,
1326  makeAlias("ANY_subquery", NIL),
1327  false,
1328  false);
1329  rte = nsitem->p_rte;
1330  parse->rtable = lappend(parse->rtable, rte);
1331  rtindex = list_length(parse->rtable);
1332 
1333  /*
1334  * Form a RangeTblRef for the pulled-up sub-select.
1335  */
1336  rtr = makeNode(RangeTblRef);
1337  rtr->rtindex = rtindex;
1338 
1339  /*
1340  * Build a list of Vars representing the subselect outputs.
1341  */
1342  subquery_vars = generate_subquery_vars(root,
1343  subselect->targetList,
1344  rtindex);
1345 
1346  /*
1347  * Build the new join's qual expression, replacing Params with these Vars.
1348  */
1349  quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
1350 
1351  /*
1352  * And finally, build the JoinExpr node.
1353  */
1354  result = makeNode(JoinExpr);
1355  result->jointype = JOIN_SEMI;
1356  result->isNatural = false;
1357  result->larg = NULL; /* caller must fill this in */
1358  result->rarg = (Node *) rtr;
1359  result->usingClause = NIL;
1360  result->join_using_alias = NULL;
1361  result->quals = quals;
1362  result->alias = NULL;
1363  result->rtindex = 0; /* we don't need an RTE for it */
1364 
1365  return result;
1366 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:316
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:704
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
#define makeNode(_type_)
Definition: nodes.h:176
@ JOIN_SEMI
Definition: nodes.h:318
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
ParseNamespaceItem * addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, bool lateral, bool inFromCl)
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
@ ANY_SUBLINK
Definition: primnodes.h:923
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
Node * quals
Definition: primnodes.h:1821
JoinType jointype
Definition: primnodes.h:1812
int rtindex
Definition: primnodes.h:1825
Node * larg
Definition: primnodes.h:1814
bool isNatural
Definition: primnodes.h:1813
Node * rarg
Definition: primnodes.h:1815
Definition: pg_list.h:54
Definition: nodes.h:129
Query * parse
Definition: pathnodes.h:202
static List * generate_subquery_vars(PlannerInfo *root, List *tlist, Index varno)
Definition: subselect.c:626
static Node * convert_testexpr(PlannerInfo *root, Node *testexpr, List *subst_nodes)
Definition: subselect.c:655
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:451
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108

References addRangeTableEntryForSubquery(), ANY_SUBLINK, Assert(), bms_is_empty(), bms_is_subset(), contain_vars_of_level(), contain_volatile_functions(), convert_testexpr(), generate_subquery_vars(), JoinExpr::isNatural, JOIN_SEMI, JoinExpr::jointype, lappend(), JoinExpr::larg, list_length(), make_parsestate(), makeAlias(), makeNode, NIL, parse(), PlannerInfo::parse, pull_varnos(), JoinExpr::quals, JoinExpr::rarg, JoinExpr::rtindex, SubLink::subLinkType, SubLink::subselect, Query::targetList, and SubLink::testexpr.

Referenced by pull_up_sublinks_qual_recurse().

◆ convert_EXISTS_sublink_to_join()

JoinExpr* convert_EXISTS_sublink_to_join ( PlannerInfo root,
SubLink sublink,
bool  under_not,
Relids  available_rels 
)

Definition at line 1376 of file subselect.c.

1378 {
1379  JoinExpr *result;
1380  Query *parse = root->parse;
1381  Query *subselect = (Query *) sublink->subselect;
1382  Node *whereClause;
1383  int rtoffset;
1384  int varno;
1385  Relids clause_varnos;
1386  Relids upper_varnos;
1387 
1388  Assert(sublink->subLinkType == EXISTS_SUBLINK);
1389 
1390  /*
1391  * Can't flatten if it contains WITH. (We could arrange to pull up the
1392  * WITH into the parent query's cteList, but that risks changing the
1393  * semantics, since a WITH ought to be executed once per associated query
1394  * call.) Note that convert_ANY_sublink_to_join doesn't have to reject
1395  * this case, since it just produces a subquery RTE that doesn't have to
1396  * get flattened into the parent query.
1397  */
1398  if (subselect->cteList)
1399  return NULL;
1400 
1401  /*
1402  * Copy the subquery so we can modify it safely (see comments in
1403  * make_subplan).
1404  */
1405  subselect = copyObject(subselect);
1406 
1407  /*
1408  * See if the subquery can be simplified based on the knowledge that it's
1409  * being used in EXISTS(). If we aren't able to get rid of its
1410  * targetlist, we have to fail, because the pullup operation leaves us
1411  * with noplace to evaluate the targetlist.
1412  */
1413  if (!simplify_EXISTS_query(root, subselect))
1414  return NULL;
1415 
1416  /*
1417  * Separate out the WHERE clause. (We could theoretically also remove
1418  * top-level plain JOIN/ON clauses, but it's probably not worth the
1419  * trouble.)
1420  */
1421  whereClause = subselect->jointree->quals;
1422  subselect->jointree->quals = NULL;
1423 
1424  /*
1425  * The rest of the sub-select must not refer to any Vars of the parent
1426  * query. (Vars of higher levels should be okay, though.)
1427  */
1428  if (contain_vars_of_level((Node *) subselect, 1))
1429  return NULL;
1430 
1431  /*
1432  * On the other hand, the WHERE clause must contain some Vars of the
1433  * parent query, else it's not gonna be a join.
1434  */
1435  if (!contain_vars_of_level(whereClause, 1))
1436  return NULL;
1437 
1438  /*
1439  * We don't risk optimizing if the WHERE clause is volatile, either.
1440  */
1441  if (contain_volatile_functions(whereClause))
1442  return NULL;
1443 
1444  /*
1445  * The subquery must have a nonempty jointree, but we can make it so.
1446  */
1447  replace_empty_jointree(subselect);
1448 
1449  /*
1450  * Prepare to pull up the sub-select into top range table.
1451  *
1452  * We rely here on the assumption that the outer query has no references
1453  * to the inner (necessarily true). Therefore this is a lot easier than
1454  * what pull_up_subqueries has to go through.
1455  *
1456  * In fact, it's even easier than what convert_ANY_sublink_to_join has to
1457  * do. The machinations of simplify_EXISTS_query ensured that there is
1458  * nothing interesting in the subquery except an rtable and jointree, and
1459  * even the jointree FromExpr no longer has quals. So we can just append
1460  * the rtable to our own and use the FromExpr in our jointree. But first,
1461  * adjust all level-zero varnos in the subquery to account for the rtable
1462  * merger.
1463  */
1464  rtoffset = list_length(parse->rtable);
1465  OffsetVarNodes((Node *) subselect, rtoffset, 0);
1466  OffsetVarNodes(whereClause, rtoffset, 0);
1467 
1468  /*
1469  * Upper-level vars in subquery will now be one level closer to their
1470  * parent than before; in particular, anything that had been level 1
1471  * becomes level zero.
1472  */
1473  IncrementVarSublevelsUp((Node *) subselect, -1, 1);
1474  IncrementVarSublevelsUp(whereClause, -1, 1);
1475 
1476  /*
1477  * Now that the WHERE clause is adjusted to match the parent query
1478  * environment, we can easily identify all the level-zero rels it uses.
1479  * The ones <= rtoffset belong to the upper query; the ones > rtoffset do
1480  * not.
1481  */
1482  clause_varnos = pull_varnos(root, whereClause);
1483  upper_varnos = NULL;
1484  while ((varno = bms_first_member(clause_varnos)) >= 0)
1485  {
1486  if (varno <= rtoffset)
1487  upper_varnos = bms_add_member(upper_varnos, varno);
1488  }
1489  bms_free(clause_varnos);
1490  Assert(!bms_is_empty(upper_varnos));
1491 
1492  /*
1493  * Now that we've got the set of upper-level varnos, we can make the last
1494  * check: only available_rels can be referenced.
1495  */
1496  if (!bms_is_subset(upper_varnos, available_rels))
1497  return NULL;
1498 
1499  /*
1500  * Now we can attach the modified subquery rtable to the parent. This also
1501  * adds subquery's RTEPermissionInfos into the upper query.
1502  */
1503  CombineRangeTables(&parse->rtable, &parse->rteperminfos,
1504  subselect->rtable, subselect->rteperminfos);
1505 
1506  /*
1507  * And finally, build the JoinExpr node.
1508  */
1509  result = makeNode(JoinExpr);
1510  result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
1511  result->isNatural = false;
1512  result->larg = NULL; /* caller must fill this in */
1513  /* flatten out the FromExpr node if it's useless */
1514  if (list_length(subselect->jointree->fromlist) == 1)
1515  result->rarg = (Node *) linitial(subselect->jointree->fromlist);
1516  else
1517  result->rarg = (Node *) subselect->jointree;
1518  result->usingClause = NIL;
1519  result->join_using_alias = NULL;
1520  result->quals = whereClause;
1521  result->alias = NULL;
1522  result->rtindex = 0; /* we don't need an RTE for it */
1523 
1524  return result;
1525 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:1000
#define copyObject(obj)
Definition: nodes.h:244
@ JOIN_ANTI
Definition: nodes.h:319
#define linitial(l)
Definition: pg_list.h:178
void replace_empty_jointree(Query *parse)
Definition: prepjointree.c:235
@ EXISTS_SUBLINK
Definition: primnodes.h:921
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:480
void CombineRangeTables(List **dst_rtable, List **dst_perminfos, List *src_rtable, List *src_perminfos)
Definition: rewriteManip.c:350
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:836
Node * quals
Definition: primnodes.h:1841
FromExpr * jointree
Definition: parsenodes.h:182
List * cteList
Definition: parsenodes.h:173
static bool simplify_EXISTS_query(PlannerInfo *root, Query *query)
Definition: subselect.c:1544

References Assert(), bms_add_member(), bms_first_member(), bms_free(), bms_is_empty(), bms_is_subset(), CombineRangeTables(), contain_vars_of_level(), contain_volatile_functions(), copyObject, Query::cteList, EXISTS_SUBLINK, FromExpr::fromlist, IncrementVarSublevelsUp(), JoinExpr::isNatural, JOIN_ANTI, JOIN_SEMI, Query::jointree, JoinExpr::jointype, JoinExpr::larg, linitial, list_length(), makeNode, NIL, OffsetVarNodes(), parse(), PlannerInfo::parse, pull_varnos(), JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, replace_empty_jointree(), Query::rtable, JoinExpr::rtindex, simplify_EXISTS_query(), SubLink::subLinkType, and SubLink::subselect.

Referenced by pull_up_sublinks_qual_recurse().

◆ SS_attach_initplans()

void SS_attach_initplans ( PlannerInfo root,
Plan plan 
)

Definition at line 2188 of file subselect.c.

2189 {
2190  plan->initPlan = root->init_plans;
2191 }
List * initPlan
Definition: plannodes.h:160
List * init_plans
Definition: pathnodes.h:299

References PlannerInfo::init_plans, and Plan::initPlan.

Referenced by create_plan().

◆ SS_charge_for_initplans()

void SS_charge_for_initplans ( PlannerInfo root,
RelOptInfo final_rel 
)

Definition at line 2131 of file subselect.c.

2132 {
2133  Cost initplan_cost;
2134  ListCell *lc;
2135 
2136  /* Nothing to do if no initPlans */
2137  if (root->init_plans == NIL)
2138  return;
2139 
2140  /*
2141  * Compute the cost increment just once, since it will be the same for all
2142  * Paths. We assume each initPlan gets run once during top plan startup.
2143  * This is a conservative overestimate, since in fact an initPlan might be
2144  * executed later than plan startup, or even not at all.
2145  */
2146  initplan_cost = 0;
2147  foreach(lc, root->init_plans)
2148  {
2149  SubPlan *initsubplan = (SubPlan *) lfirst(lc);
2150 
2151  initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
2152  }
2153 
2154  /*
2155  * Now adjust the costs and parallel_safe flags.
2156  */
2157  foreach(lc, final_rel->pathlist)
2158  {
2159  Path *path = (Path *) lfirst(lc);
2160 
2161  path->startup_cost += initplan_cost;
2162  path->total_cost += initplan_cost;
2163  path->parallel_safe = false;
2164  }
2165 
2166  /*
2167  * Forget about any partial paths and clear consider_parallel, too;
2168  * they're not usable if we attached an initPlan.
2169  */
2170  final_rel->partial_pathlist = NIL;
2171  final_rel->consider_parallel = false;
2172 
2173  /* We needn't do set_cheapest() here, caller will do it */
2174 }
double Cost
Definition: nodes.h:262
#define lfirst(lc)
Definition: pg_list.h:172
Cost startup_cost
Definition: pathnodes.h:1639
Cost total_cost
Definition: pathnodes.h:1640
bool parallel_safe
Definition: pathnodes.h:1633
bool consider_parallel
Definition: pathnodes.h:882
List * pathlist
Definition: pathnodes.h:893
List * partial_pathlist
Definition: pathnodes.h:895
Cost startup_cost
Definition: primnodes.h:1015
Cost per_call_cost
Definition: primnodes.h:1016

References RelOptInfo::consider_parallel, PlannerInfo::init_plans, lfirst, NIL, Path::parallel_safe, RelOptInfo::partial_pathlist, RelOptInfo::pathlist, SubPlan::per_call_cost, Path::startup_cost, SubPlan::startup_cost, and Path::total_cost.

Referenced by build_minmax_path(), and subquery_planner().

◆ SS_finalize_plan()

void SS_finalize_plan ( PlannerInfo root,
Plan plan 
)

Definition at line 2203 of file subselect.c.

2204 {
2205  /* No setup needed, just recurse through plan tree. */
2206  (void) finalize_plan(root, plan, -1, root->outer_params, NULL);
2207 }
Bitmapset * outer_params
Definition: pathnodes.h:221
static Bitmapset * finalize_plan(PlannerInfo *root, Plan *plan, int gather_param, Bitmapset *valid_params, Bitmapset *scan_params)
Definition: subselect.c:2241

References finalize_plan(), and PlannerInfo::outer_params.

Referenced by standard_planner().

◆ SS_identify_outer_params()

void SS_identify_outer_params ( PlannerInfo root)

Definition at line 2069 of file subselect.c.

2070 {
2071  Bitmapset *outer_params;
2072  PlannerInfo *proot;
2073  ListCell *l;
2074 
2075  /*
2076  * If no parameters have been assigned anywhere in the tree, we certainly
2077  * don't need to do anything here.
2078  */
2079  if (root->glob->paramExecTypes == NIL)
2080  return;
2081 
2082  /*
2083  * Scan all query levels above this one to see which parameters are due to
2084  * be available from them, either because lower query levels have
2085  * requested them (via plan_params) or because they will be available from
2086  * initPlans of those levels.
2087  */
2088  outer_params = NULL;
2089  for (proot = root->parent_root; proot != NULL; proot = proot->parent_root)
2090  {
2091  /* Include ordinary Var/PHV/Aggref/GroupingFunc params */
2092  foreach(l, proot->plan_params)
2093  {
2094  PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l);
2095 
2096  outer_params = bms_add_member(outer_params, pitem->paramId);
2097  }
2098  /* Include any outputs of outer-level initPlans */
2099  foreach(l, proot->init_plans)
2100  {
2101  SubPlan *initsubplan = (SubPlan *) lfirst(l);
2102  ListCell *l2;
2103 
2104  foreach(l2, initsubplan->setParam)
2105  {
2106  outer_params = bms_add_member(outer_params, lfirst_int(l2));
2107  }
2108  }
2109  /* Include worktable ID, if a recursive query is being planned */
2110  if (proot->wt_param_id >= 0)
2111  outer_params = bms_add_member(outer_params, proot->wt_param_id);
2112  }
2113  root->outer_params = outer_params;
2114 }
#define lfirst_int(lc)
Definition: pg_list.h:173
List * paramExecTypes
Definition: pathnodes.h:138
PlannerGlobal * glob
Definition: pathnodes.h:205
int wt_param_id
Definition: pathnodes.h:524
List * plan_params
Definition: pathnodes.h:220
List * setParam
Definition: primnodes.h:1010

References bms_add_member(), PlannerInfo::glob, PlannerInfo::init_plans, lfirst, lfirst_int, NIL, PlannerInfo::outer_params, PlannerGlobal::paramExecTypes, PlannerParamItem::paramId, PlannerInfo::plan_params, SubPlan::setParam, and PlannerInfo::wt_param_id.

Referenced by build_minmax_path(), and subquery_planner().

◆ SS_make_initplan_from_plan()

void SS_make_initplan_from_plan ( PlannerInfo root,
PlannerInfo subroot,
Plan plan,
Param prm 
)

Definition at line 2952 of file subselect.c.

2955 {
2956  SubPlan *node;
2957 
2958  /*
2959  * Add the subplan and its PlannerInfo to the global lists.
2960  */
2961  root->glob->subplans = lappend(root->glob->subplans, plan);
2962  root->glob->subroots = lappend(root->glob->subroots, subroot);
2963 
2964  /*
2965  * Create a SubPlan node and add it to the outer list of InitPlans. Note
2966  * it has to appear after any other InitPlans it might depend on (see
2967  * comments in ExecReScan).
2968  */
2969  node = makeNode(SubPlan);
2970  node->subLinkType = EXPR_SUBLINK;
2971  node->plan_id = list_length(root->glob->subplans);
2972  node->plan_name = psprintf("InitPlan %d (returns $%d)",
2973  node->plan_id, prm->paramid);
2974  get_first_col_type(plan, &node->firstColType, &node->firstColTypmod,
2975  &node->firstColCollation);
2976  node->setParam = list_make1_int(prm->paramid);
2977 
2978  root->init_plans = lappend(root->init_plans, node);
2979 
2980  /*
2981  * The node can't have any inputs (since it's an initplan), so the
2982  * parParam and args lists remain empty.
2983  */
2984 
2985  /* Set costs of SubPlan using info from the plan tree */
2986  cost_subplan(subroot, node, plan);
2987 }
void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
Definition: costsize.c:4162
#define list_make1_int(x1)
Definition: pg_list.h:227
@ EXPR_SUBLINK
Definition: primnodes.h:925
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
int paramid
Definition: primnodes.h:352
List * subplans
Definition: pathnodes.h:105
int plan_id
Definition: primnodes.h:992
char * plan_name
Definition: primnodes.h:994
int32 firstColTypmod
Definition: primnodes.h:997
Oid firstColCollation
Definition: primnodes.h:998
SubLinkType subLinkType
Definition: primnodes.h:987
Oid firstColType
Definition: primnodes.h:996
static void get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod, Oid *colcollation)
Definition: subselect.c:118

References cost_subplan(), EXPR_SUBLINK, SubPlan::firstColCollation, SubPlan::firstColType, SubPlan::firstColTypmod, get_first_col_type(), PlannerInfo::glob, PlannerInfo::init_plans, lappend(), list_length(), list_make1_int, makeNode, Param::paramid, SubPlan::plan_id, SubPlan::plan_name, psprintf(), SubPlan::setParam, SubPlan::subLinkType, and PlannerGlobal::subplans.

Referenced by create_minmaxagg_plan().

◆ SS_make_initplan_output_param()

Param* SS_make_initplan_output_param ( PlannerInfo root,
Oid  resulttype,
int32  resulttypmod,
Oid  resultcollation 
)

Definition at line 2936 of file subselect.c.

2939 {
2940  return generate_new_exec_param(root, resulttype,
2941  resulttypmod, resultcollation);
2942 }
Param * generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation)
Definition: paramassign.c:553

References generate_new_exec_param().

Referenced by preprocess_minmax_aggregates().

◆ SS_process_ctes()

void SS_process_ctes ( PlannerInfo root)

Definition at line 893 of file subselect.c.

894 {
895  ListCell *lc;
896 
897  Assert(root->cte_plan_ids == NIL);
898 
899  foreach(lc, root->parse->cteList)
900  {
901  CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
902  CmdType cmdType = ((Query *) cte->ctequery)->commandType;
903  Query *subquery;
904  PlannerInfo *subroot;
905  RelOptInfo *final_rel;
906  Path *best_path;
907  Plan *plan;
908  SubPlan *splan;
909  int paramid;
910 
911  /*
912  * Ignore SELECT CTEs that are not actually referenced anywhere.
913  */
914  if (cte->cterefcount == 0 && cmdType == CMD_SELECT)
915  {
916  /* Make a dummy entry in cte_plan_ids */
917  root->cte_plan_ids = lappend_int(root->cte_plan_ids, -1);
918  continue;
919  }
920 
921  /*
922  * Consider inlining the CTE (creating RTE_SUBQUERY RTE(s)) instead of
923  * implementing it as a separately-planned CTE.
924  *
925  * We cannot inline if any of these conditions hold:
926  *
927  * 1. The user said not to (the CTEMaterializeAlways option).
928  *
929  * 2. The CTE is recursive.
930  *
931  * 3. The CTE has side-effects; this includes either not being a plain
932  * SELECT, or containing volatile functions. Inlining might change
933  * the side-effects, which would be bad.
934  *
935  * 4. The CTE is multiply-referenced and contains a self-reference to
936  * a recursive CTE outside itself. Inlining would result in multiple
937  * recursive self-references, which we don't support.
938  *
939  * Otherwise, we have an option whether to inline or not. That should
940  * always be a win if there's just a single reference, but if the CTE
941  * is multiply-referenced then it's unclear: inlining adds duplicate
942  * computations, but the ability to absorb restrictions from the outer
943  * query level could outweigh that. We do not have nearly enough
944  * information at this point to tell whether that's true, so we let
945  * the user express a preference. Our default behavior is to inline
946  * only singly-referenced CTEs, but a CTE marked CTEMaterializeNever
947  * will be inlined even if multiply referenced.
948  *
949  * Note: we check for volatile functions last, because that's more
950  * expensive than the other tests needed.
951  */
952  if ((cte->ctematerialized == CTEMaterializeNever ||
954  cte->cterefcount == 1)) &&
955  !cte->cterecursive &&
956  cmdType == CMD_SELECT &&
957  !contain_dml(cte->ctequery) &&
958  (cte->cterefcount <= 1 ||
961  {
962  inline_cte(root, cte);
963  /* Make a dummy entry in cte_plan_ids */
964  root->cte_plan_ids = lappend_int(root->cte_plan_ids, -1);
965  continue;
966  }
967 
968  /*
969  * Copy the source Query node. Probably not necessary, but let's keep
970  * this similar to make_subplan.
971  */
972  subquery = (Query *) copyObject(cte->ctequery);
973 
974  /* plan_params should not be in use in current query level */
975  Assert(root->plan_params == NIL);
976 
977  /*
978  * Generate Paths for the CTE query. Always plan for full retrieval
979  * --- we don't have enough info to predict otherwise.
980  */
981  subroot = subquery_planner(root->glob, subquery,
982  root,
983  cte->cterecursive, 0.0);
984 
985  /*
986  * Since the current query level doesn't yet contain any RTEs, it
987  * should not be possible for the CTE to have requested parameters of
988  * this level.
989  */
990  if (root->plan_params)
991  elog(ERROR, "unexpected outer reference in CTE query");
992 
993  /*
994  * Select best Path and turn it into a Plan. At least for now, there
995  * seems no reason to postpone doing that.
996  */
997  final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
998  best_path = final_rel->cheapest_total_path;
999 
1000  plan = create_plan(subroot, best_path);
1001 
1002  /*
1003  * Make a SubPlan node for it. This is just enough unlike
1004  * build_subplan that we can't share code.
1005  *
1006  * Note plan_id, plan_name, and cost fields are set further down.
1007  */
1008  splan = makeNode(SubPlan);
1009  splan->subLinkType = CTE_SUBLINK;
1010  splan->testexpr = NULL;
1011  splan->paramIds = NIL;
1012  get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
1013  &splan->firstColCollation);
1014  splan->useHashTable = false;
1015  splan->unknownEqFalse = false;
1016 
1017  /*
1018  * CTE scans are not considered for parallelism (cf
1019  * set_rel_consider_parallel), and even if they were, initPlans aren't
1020  * parallel-safe.
1021  */
1022  splan->parallel_safe = false;
1023  splan->setParam = NIL;
1024  splan->parParam = NIL;
1025  splan->args = NIL;
1026 
1027  /*
1028  * The node can't have any inputs (since it's an initplan), so the
1029  * parParam and args lists remain empty. (It could contain references
1030  * to earlier CTEs' output param IDs, but CTE outputs are not
1031  * propagated via the args list.)
1032  */
1033 
1034  /*
1035  * Assign a param ID to represent the CTE's output. No ordinary
1036  * "evaluation" of this param slot ever happens, but we use the param
1037  * ID for setParam/chgParam signaling just as if the CTE plan were
1038  * returning a simple scalar output. (Also, the executor abuses the
1039  * ParamExecData slot for this param ID for communication among
1040  * multiple CteScan nodes that might be scanning this CTE.)
1041  */
1042  paramid = assign_special_exec_param(root);
1043  splan->setParam = list_make1_int(paramid);
1044 
1045  /*
1046  * Add the subplan and its PlannerInfo to the global lists.
1047  */
1048  root->glob->subplans = lappend(root->glob->subplans, plan);
1049  root->glob->subroots = lappend(root->glob->subroots, subroot);
1050  splan->plan_id = list_length(root->glob->subplans);
1051 
1052  root->init_plans = lappend(root->init_plans, splan);
1053 
1054  root->cte_plan_ids = lappend_int(root->cte_plan_ids, splan->plan_id);
1055 
1056  /* Label the subplan for EXPLAIN purposes */
1057  splan->plan_name = psprintf("CTE %s", cte->ctename);
1058 
1059  /* Lastly, fill in the cost estimates for use later */
1060  cost_subplan(root, splan, plan);
1061  }
1062 }
Plan * create_plan(PlannerInfo *root, Path *best_path)
Definition: createplan.c:335
#define ERROR
Definition: elog.h:39
List * lappend_int(List *list, int datum)
Definition: list.c:356
CmdType
Definition: nodes.h:274
@ CMD_SELECT
Definition: nodes.h:276
int assign_special_exec_param(PlannerInfo *root)
Definition: paramassign.c:580
@ CTEMaterializeNever
Definition: parsenodes.h:1593
@ CTEMaterializeDefault
Definition: parsenodes.h:1591
@ UPPERREL_FINAL
Definition: pathnodes.h:79
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction)
Definition: planner.c:604
@ CTE_SUBLINK
Definition: primnodes.h:928
static SPIPlanPtr splan
Definition: regress.c:270
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1395
CTEMaterialize ctematerialized
Definition: parsenodes.h:1632
List * cte_plan_ids
Definition: pathnodes.h:305
struct Path * cheapest_total_path
Definition: pathnodes.h:897
static bool contain_outer_selfref(Node *node)
Definition: subselect.c:1097
static bool contain_dml(Node *node)
Definition: subselect.c:1070
static void inline_cte(PlannerInfo *root, CommonTableExpr *cte)
Definition: subselect.c:1152

References Assert(), assign_special_exec_param(), RelOptInfo::cheapest_total_path, CMD_SELECT, contain_dml(), contain_outer_selfref(), contain_volatile_functions(), copyObject, cost_subplan(), create_plan(), PlannerInfo::cte_plan_ids, CTE_SUBLINK, Query::cteList, CommonTableExpr::ctematerialized, CTEMaterializeDefault, CTEMaterializeNever, CommonTableExpr::ctename, CommonTableExpr::ctequery, elog(), ERROR, fetch_upper_rel(), get_first_col_type(), PlannerInfo::glob, PlannerInfo::init_plans, inline_cte(), lappend(), lappend_int(), lfirst, list_length(), list_make1_int, makeNode, NIL, PlannerInfo::parse, PlannerInfo::plan_params, psprintf(), splan, PlannerGlobal::subplans, subquery_planner(), and UPPERREL_FINAL.

Referenced by subquery_planner().

◆ SS_process_sublinks()

Node* SS_process_sublinks ( PlannerInfo root,
Node expr,
bool  isQual 
)

Definition at line 1916 of file subselect.c.

1917 {
1918  process_sublinks_context context;
1919 
1920  context.root = root;
1921  context.isTopQual = isQual;
1922  return process_sublinks_mutator(expr, &context);
1923 }
static Node * process_sublinks_mutator(Node *node, process_sublinks_context *context)
Definition: subselect.c:1926

References process_sublinks_context::isTopQual, process_sublinks_mutator(), and process_sublinks_context::root.

Referenced by build_subplan(), and preprocess_expression().

◆ SS_replace_correlation_vars()

Node* SS_replace_correlation_vars ( PlannerInfo root,
Node expr 
)

Definition at line 1871 of file subselect.c.

1872 {
1873  /* No setup needed for tree walk, so away we go */
1874  return replace_correlation_vars_mutator(expr, root);
1875 }
static Node * replace_correlation_vars_mutator(Node *node, PlannerInfo *root)
Definition: subselect.c:1878

References replace_correlation_vars_mutator().

Referenced by preprocess_expression().