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_compute_initplan_cost (List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
 
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 1254 of file subselect.c.

1256 {
1257  JoinExpr *result;
1258  Query *parse = root->parse;
1259  Query *subselect = (Query *) sublink->subselect;
1260  Relids upper_varnos;
1261  int rtindex;
1262  ParseNamespaceItem *nsitem;
1263  RangeTblEntry *rte;
1264  RangeTblRef *rtr;
1265  List *subquery_vars;
1266  Node *quals;
1267  ParseState *pstate;
1268  Relids sub_ref_outer_relids;
1269  bool use_lateral;
1270 
1271  Assert(sublink->subLinkType == ANY_SUBLINK);
1272 
1273  /*
1274  * If the sub-select refers to any Vars of the parent query, we so let's
1275  * considering it as LATERAL. (Vars of higher levels don't matter here.)
1276  */
1277  sub_ref_outer_relids = pull_varnos_of_level(NULL, (Node *) subselect, 1);
1278  use_lateral = !bms_is_empty(sub_ref_outer_relids);
1279 
1280  /*
1281  * Check that sub-select refers nothing outside of available_rels of the
1282  * parent query.
1283  */
1284  if (!bms_is_subset(sub_ref_outer_relids, available_rels))
1285  return NULL;
1286 
1287  /*
1288  * The test expression must contain some Vars of the parent query, else
1289  * it's not gonna be a join. (Note that it won't have Vars referring to
1290  * the subquery, rather Params.)
1291  */
1292  upper_varnos = pull_varnos(root, sublink->testexpr);
1293  if (bms_is_empty(upper_varnos))
1294  return NULL;
1295 
1296  /*
1297  * However, it can't refer to anything outside available_rels.
1298  */
1299  if (!bms_is_subset(upper_varnos, available_rels))
1300  return NULL;
1301 
1302  /*
1303  * The combining operators and left-hand expressions mustn't be volatile.
1304  */
1305  if (contain_volatile_functions(sublink->testexpr))
1306  return NULL;
1307 
1308  /* Create a dummy ParseState for addRangeTableEntryForSubquery */
1309  pstate = make_parsestate(NULL);
1310 
1311  /*
1312  * Okay, pull up the sub-select into upper range table.
1313  *
1314  * We rely here on the assumption that the outer query has no references
1315  * to the inner (necessarily true, other than the Vars that we build
1316  * below). Therefore this is a lot easier than what pull_up_subqueries has
1317  * to go through.
1318  */
1319  nsitem = addRangeTableEntryForSubquery(pstate,
1320  subselect,
1321  makeAlias("ANY_subquery", NIL),
1322  use_lateral,
1323  false);
1324  rte = nsitem->p_rte;
1325  parse->rtable = lappend(parse->rtable, rte);
1326  rtindex = list_length(parse->rtable);
1327 
1328  /*
1329  * Form a RangeTblRef for the pulled-up sub-select.
1330  */
1331  rtr = makeNode(RangeTblRef);
1332  rtr->rtindex = rtindex;
1333 
1334  /*
1335  * Build a list of Vars representing the subselect outputs.
1336  */
1337  subquery_vars = generate_subquery_vars(root,
1338  subselect->targetList,
1339  rtindex);
1340 
1341  /*
1342  * Build the new join's qual expression, replacing Params with these Vars.
1343  */
1344  quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
1345 
1346  /*
1347  * And finally, build the JoinExpr node.
1348  */
1349  result = makeNode(JoinExpr);
1350  result->jointype = JOIN_SEMI;
1351  result->isNatural = false;
1352  result->larg = NULL; /* caller must fill this in */
1353  result->rarg = (Node *) rtr;
1354  result->usingClause = NIL;
1355  result->join_using_alias = NULL;
1356  result->quals = quals;
1357  result->alias = NULL;
1358  result->rtindex = 0; /* we don't need an RTE for it */
1359 
1360  return result;
1361 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
#define bms_is_empty(a)
Definition: bitmapset.h:118
#define Assert(condition)
Definition: c.h:858
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
List * lappend(List *list, void *datum)
Definition: list.c:339
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
#define makeNode(_type_)
Definition: nodes.h:155
@ JOIN_SEMI
Definition: nodes.h:307
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
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:969
tree ctl root
Definition: radixtree.h:1884
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715
Node * quals
Definition: primnodes.h:2261
JoinType jointype
Definition: primnodes.h:2252
int rtindex
Definition: primnodes.h:2265
Node * larg
Definition: primnodes.h:2254
bool isNatural
Definition: primnodes.h:2253
Node * rarg
Definition: primnodes.h:2255
Definition: pg_list.h:54
Definition: nodes.h:129
List * targetList
Definition: parsenodes.h:191
static List * generate_subquery_vars(PlannerInfo *root, List *tlist, Index varno)
Definition: subselect.c:613
static Node * convert_testexpr(PlannerInfo *root, Node *testexpr, List *subst_nodes)
Definition: subselect.c:642
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition: var.c:134
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108

References addRangeTableEntryForSubquery(), ANY_SUBLINK, Assert, bms_is_empty, bms_is_subset(), 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(), pull_varnos(), pull_varnos_of_level(), JoinExpr::quals, JoinExpr::rarg, root, 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 1371 of file subselect.c.

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

References Assert, bms_add_member(), bms_free(), bms_is_empty, bms_is_subset(), bms_next_member(), 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(), pull_varnos(), JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, replace_empty_jointree(), root, 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 2239 of file subselect.c.

2240 {
2241  plan->initPlan = root->init_plans;
2242 }
#define plan(x)
Definition: pg_regress.c:162

References plan, and root.

Referenced by create_plan().

◆ SS_charge_for_initplans()

void SS_charge_for_initplans ( PlannerInfo root,
RelOptInfo final_rel 
)

Definition at line 2134 of file subselect.c.

2135 {
2136  Cost initplan_cost;
2137  bool unsafe_initplans;
2138  ListCell *lc;
2139 
2140  /* Nothing to do if no initPlans */
2141  if (root->init_plans == NIL)
2142  return;
2143 
2144  /*
2145  * Compute the cost increment just once, since it will be the same for all
2146  * Paths. Also check for parallel-unsafe initPlans.
2147  */
2148  SS_compute_initplan_cost(root->init_plans,
2149  &initplan_cost, &unsafe_initplans);
2150 
2151  /*
2152  * Now adjust the costs and parallel_safe flags.
2153  */
2154  foreach(lc, final_rel->pathlist)
2155  {
2156  Path *path = (Path *) lfirst(lc);
2157 
2158  path->startup_cost += initplan_cost;
2159  path->total_cost += initplan_cost;
2160  if (unsafe_initplans)
2161  path->parallel_safe = false;
2162  }
2163 
2164  /*
2165  * Adjust partial paths' costs too, or forget them entirely if we must
2166  * consider the rel parallel-unsafe.
2167  */
2168  if (unsafe_initplans)
2169  {
2170  final_rel->partial_pathlist = NIL;
2171  final_rel->consider_parallel = false;
2172  }
2173  else
2174  {
2175  foreach(lc, final_rel->partial_pathlist)
2176  {
2177  Path *path = (Path *) lfirst(lc);
2178 
2179  path->startup_cost += initplan_cost;
2180  path->total_cost += initplan_cost;
2181  }
2182  }
2183 
2184  /* We needn't do set_cheapest() here, caller will do it */
2185 }
double Cost
Definition: nodes.h:251
#define lfirst(lc)
Definition: pg_list.h:172
Cost startup_cost
Definition: pathnodes.h:1650
Cost total_cost
Definition: pathnodes.h:1651
bool parallel_safe
Definition: pathnodes.h:1644
bool consider_parallel
Definition: pathnodes.h:877
List * pathlist
Definition: pathnodes.h:888
List * partial_pathlist
Definition: pathnodes.h:890
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition: subselect.c:2198

References RelOptInfo::consider_parallel, lfirst, NIL, Path::parallel_safe, RelOptInfo::partial_pathlist, RelOptInfo::pathlist, root, SS_compute_initplan_cost(), Path::startup_cost, and Path::total_cost.

Referenced by build_minmax_path(), and subquery_planner().

◆ SS_compute_initplan_cost()

void SS_compute_initplan_cost ( List init_plans,
Cost initplan_cost_p,
bool unsafe_initplans_p 
)

Definition at line 2198 of file subselect.c.

2201 {
2202  Cost initplan_cost;
2203  bool unsafe_initplans;
2204  ListCell *lc;
2205 
2206  /*
2207  * We assume each initPlan gets run once during top plan startup. This is
2208  * a conservative overestimate, since in fact an initPlan might be
2209  * executed later than plan startup, or even not at all.
2210  */
2211  initplan_cost = 0;
2212  unsafe_initplans = false;
2213  foreach(lc, init_plans)
2214  {
2215  SubPlan *initsubplan = lfirst_node(SubPlan, lc);
2216 
2217  initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
2218  if (!initsubplan->parallel_safe)
2219  unsafe_initplans = true;
2220  }
2221  *initplan_cost_p = initplan_cost;
2222  *unsafe_initplans_p = unsafe_initplans;
2223 }
#define lfirst_node(type, lc)
Definition: pg_list.h:176
bool parallel_safe
Definition: primnodes.h:1054
Cost startup_cost
Definition: primnodes.h:1063
Cost per_call_cost
Definition: primnodes.h:1064

References lfirst_node, SubPlan::parallel_safe, SubPlan::per_call_cost, and SubPlan::startup_cost.

Referenced by clean_up_removed_plan_level(), materialize_finished_plan(), SS_charge_for_initplans(), and standard_planner().

◆ SS_finalize_plan()

void SS_finalize_plan ( PlannerInfo root,
Plan plan 
)

Definition at line 2254 of file subselect.c.

2255 {
2256  /* No setup needed, just recurse through plan tree. */
2257  (void) finalize_plan(root, plan, -1, root->outer_params, NULL);
2258 }
static Bitmapset * finalize_plan(PlannerInfo *root, Plan *plan, int gather_param, Bitmapset *valid_params, Bitmapset *scan_params)
Definition: subselect.c:2292

References finalize_plan(), plan, and root.

Referenced by standard_planner().

◆ SS_identify_outer_params()

void SS_identify_outer_params ( PlannerInfo root)

Definition at line 2072 of file subselect.c.

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

References bms_add_member(), PlannerInfo::init_plans, lfirst, lfirst_int, NIL, PlannerParamItem::paramId, PlannerInfo::plan_params, root, 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 3017 of file subselect.c.

3020 {
3021  SubPlan *node;
3022 
3023  /*
3024  * Add the subplan and its PlannerInfo, as well as a dummy path entry, to
3025  * the global lists. Ideally we'd save a real path, but right now our
3026  * sole caller doesn't build a path that exactly matches the plan. Since
3027  * we're not currently going to need the path for an initplan, it's not
3028  * worth requiring construction of such a path.
3029  */
3030  root->glob->subplans = lappend(root->glob->subplans, plan);
3031  root->glob->subpaths = lappend(root->glob->subpaths, NULL);
3032  root->glob->subroots = lappend(root->glob->subroots, subroot);
3033 
3034  /*
3035  * Create a SubPlan node and add it to the outer list of InitPlans. Note
3036  * it has to appear after any other InitPlans it might depend on (see
3037  * comments in ExecReScan).
3038  */
3039  node = makeNode(SubPlan);
3040  node->subLinkType = EXPR_SUBLINK;
3041  node->plan_id = list_length(root->glob->subplans);
3042  node->plan_name = psprintf("InitPlan %d", node->plan_id);
3044  &node->firstColCollation);
3045  node->parallel_safe = plan->parallel_safe;
3046  node->setParam = list_make1_int(prm->paramid);
3047 
3048  root->init_plans = lappend(root->init_plans, node);
3049 
3050  /*
3051  * The node can't have any inputs (since it's an initplan), so the
3052  * parParam and args lists remain empty.
3053  */
3054 
3055  /* Set costs of SubPlan using info from the plan tree */
3056  cost_subplan(subroot, node, plan);
3057 }
void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
Definition: costsize.c:4435
#define list_make1_int(x1)
Definition: pg_list.h:227
@ EXPR_SUBLINK
Definition: primnodes.h:971
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
int paramid
Definition: primnodes.h:377
int plan_id
Definition: primnodes.h:1040
char * plan_name
Definition: primnodes.h:1042
int32 firstColTypmod
Definition: primnodes.h:1045
Oid firstColCollation
Definition: primnodes.h:1046
SubLinkType subLinkType
Definition: primnodes.h:1035
Oid firstColType
Definition: primnodes.h:1044
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(), lappend(), list_length(), list_make1_int, makeNode, SubPlan::parallel_safe, Param::paramid, plan, SubPlan::plan_id, SubPlan::plan_name, psprintf(), root, SubPlan::setParam, and SubPlan::subLinkType.

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 3001 of file subselect.c.

3004 {
3005  return generate_new_exec_param(root, resulttype,
3006  resulttypmod, resultcollation);
3007 }
Param * generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation)
Definition: paramassign.c:637

References generate_new_exec_param(), and root.

Referenced by preprocess_minmax_aggregates().

◆ SS_process_ctes()

void SS_process_ctes ( PlannerInfo root)

Definition at line 880 of file subselect.c.

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

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(), CTE_SUBLINK, CommonTableExpr::ctematerialized, CTEMaterializeDefault, CTEMaterializeNever, CommonTableExpr::ctename, CommonTableExpr::ctequery, elog, ERROR, fetch_upper_rel(), get_first_col_type(), inline_cte(), lappend(), lappend_int(), lfirst, list_length(), list_make1_int, makeNode, NIL, plan, psprintf(), root, splan, 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 1919 of file subselect.c.

1920 {
1922 
1923  context.root = root;
1924  context.isTopQual = isQual;
1925  return process_sublinks_mutator(expr, &context);
1926 }
tree context
Definition: radixtree.h:1833
static Node * process_sublinks_mutator(Node *node, process_sublinks_context *context)
Definition: subselect.c:1929

References context, process_sublinks_mutator(), and root.

Referenced by build_subplan(), and preprocess_expression().

◆ SS_replace_correlation_vars()

Node* SS_replace_correlation_vars ( PlannerInfo root,
Node expr 
)

Definition at line 1868 of file subselect.c.

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

References replace_correlation_vars_mutator(), and root.

Referenced by preprocess_expression().