PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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)
 
ScalarArrayOpExprconvert_VALUES_to_ANY (PlannerInfo *root, Node *testexpr, Query *values)
 
JoinExprconvert_ANY_sublink_to_join (PlannerInfo *root, SubLink *sublink, bool under_not, 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,
bool  under_not,
Relids  available_rels 
)
extern

Definition at line 1339 of file subselect.c.

1341{
1342 JoinExpr *result;
1343 Query *parse = root->parse;
1344 Query *subselect = (Query *) sublink->subselect;
1346 int rtindex;
1351 Node *quals;
1352 ParseState *pstate;
1354 bool use_lateral;
1355
1356 Assert(sublink->subLinkType == ANY_SUBLINK);
1357
1358 /*
1359 * Per SQL spec, NOT IN is not ordinarily equivalent to an anti-join, so
1360 * that by default we have to fail when under_not. However, if we can
1361 * prove that neither the outer query's expressions nor the sub-select's
1362 * output columns can be NULL, and further that the operator itself cannot
1363 * return NULL for non-null inputs, then the logic is identical and it's
1364 * safe to convert NOT IN to an anti-join.
1365 */
1366 if (under_not &&
1368 !query_outputs_are_not_nullable(subselect)))
1369 return NULL;
1370
1371 /*
1372 * If the sub-select contains any Vars of the parent query, we treat it as
1373 * LATERAL. (Vars from higher levels don't matter here.)
1374 */
1377
1378 /*
1379 * Can't convert if the sub-select contains parent-level Vars of relations
1380 * not in available_rels.
1381 */
1383 return NULL;
1384
1385 /*
1386 * The test expression must contain some Vars of the parent query, else
1387 * it's not gonna be a join. (Note that it won't have Vars referring to
1388 * the subquery, rather Params.)
1389 */
1390 upper_varnos = pull_varnos(root, sublink->testexpr);
1392 return NULL;
1393
1394 /*
1395 * However, it can't refer to anything outside available_rels.
1396 */
1398 return NULL;
1399
1400 /*
1401 * The combining operators and left-hand expressions mustn't be volatile.
1402 */
1403 if (contain_volatile_functions(sublink->testexpr))
1404 return NULL;
1405
1406 /* Create a dummy ParseState for addRangeTableEntryForSubquery */
1407 pstate = make_parsestate(NULL);
1408
1409 /*
1410 * Okay, pull up the sub-select into upper range table.
1411 *
1412 * We rely here on the assumption that the outer query has no references
1413 * to the inner (necessarily true, other than the Vars that we build
1414 * below). Therefore this is a lot easier than what pull_up_subqueries has
1415 * to go through.
1416 */
1418 subselect,
1419 NULL,
1421 false);
1422 rte = nsitem->p_rte;
1423 parse->rtable = lappend(parse->rtable, rte);
1424 rtindex = list_length(parse->rtable);
1425
1426 /*
1427 * Form a RangeTblRef for the pulled-up sub-select.
1428 */
1430 rtr->rtindex = rtindex;
1431
1432 /*
1433 * Build a list of Vars representing the subselect outputs.
1434 */
1436 subselect->targetList,
1437 rtindex);
1438
1439 /*
1440 * Build the new join's qual expression, replacing Params with these Vars.
1441 */
1442 quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
1443
1444 /*
1445 * And finally, build the JoinExpr node.
1446 */
1447 result = makeNode(JoinExpr);
1448 result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
1449 result->isNatural = false;
1450 result->larg = NULL; /* caller must fill this in */
1451 result->rarg = (Node *) rtr;
1452 result->usingClause = NIL;
1453 result->join_using_alias = NULL;
1454 result->quals = quals;
1455 result->alias = NULL;
1456 result->rtindex = 0; /* we don't need an RTE for it */
1457
1458 return result;
1459}
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:945
bool query_outputs_are_not_nullable(Query *query)
Definition clauses.c:2049
bool contain_volatile_functions(Node *clause)
Definition clauses.c:549
void parse(int)
Definition parse.c:49
List * lappend(List *list, void *datum)
Definition list.c:339
#define makeNode(_type_)
Definition nodes.h:161
@ JOIN_SEMI
Definition nodes.h:317
@ JOIN_ANTI
Definition nodes.h:318
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
static int fb(int x)
@ ANY_SUBLINK
Definition primnodes.h:1032
tree ctl root
Definition radixtree.h:1857
Definition pg_list.h:54
Definition nodes.h:135
static bool sublink_testexpr_is_not_nullable(PlannerInfo *root, SubLink *sublink)
Definition subselect.c:1483
static List * generate_subquery_vars(PlannerInfo *root, List *tlist, Index varno)
Definition subselect.c:619
static Node * convert_testexpr(PlannerInfo *root, Node *testexpr, List *subst_nodes)
Definition subselect.c:648
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition var.c:140
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition var.c:114

References addRangeTableEntryForSubquery(), ANY_SUBLINK, Assert, bms_is_empty, bms_is_subset(), contain_volatile_functions(), convert_testexpr(), fb(), generate_subquery_vars(), JoinExpr::isNatural, JOIN_ANTI, JOIN_SEMI, JoinExpr::jointype, lappend(), JoinExpr::larg, list_length(), make_parsestate(), makeNode, NIL, parse(), pull_varnos(), pull_varnos_of_level(), JoinExpr::quals, query_outputs_are_not_nullable(), JoinExpr::rarg, root, JoinExpr::rtindex, sublink_testexpr_is_not_nullable(), and Query::targetList.

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 
)
extern

Definition at line 1591 of file subselect.c.

1593{
1594 JoinExpr *result;
1595 Query *parse = root->parse;
1596 Query *subselect = (Query *) sublink->subselect;
1597 Node *whereClause;
1598 PlannerInfo subroot;
1599 int rtoffset;
1600 int varno;
1603
1604 Assert(sublink->subLinkType == EXISTS_SUBLINK);
1605
1606 /*
1607 * Can't flatten if it contains WITH. (We could arrange to pull up the
1608 * WITH into the parent query's cteList, but that risks changing the
1609 * semantics, since a WITH ought to be executed once per associated query
1610 * call.) Note that convert_ANY_sublink_to_join doesn't have to reject
1611 * this case, since it just produces a subquery RTE that doesn't have to
1612 * get flattened into the parent query.
1613 */
1614 if (subselect->cteList)
1615 return NULL;
1616
1617 /*
1618 * Copy the subquery so we can modify it safely (see comments in
1619 * make_subplan).
1620 */
1621 subselect = copyObject(subselect);
1622
1623 /*
1624 * See if the subquery can be simplified based on the knowledge that it's
1625 * being used in EXISTS(). If we aren't able to get rid of its
1626 * targetlist, we have to fail, because the pullup operation leaves us
1627 * with noplace to evaluate the targetlist.
1628 */
1629 if (!simplify_EXISTS_query(root, subselect))
1630 return NULL;
1631
1632 /*
1633 * Separate out the WHERE clause. (We could theoretically also remove
1634 * top-level plain JOIN/ON clauses, but it's probably not worth the
1635 * trouble.)
1636 */
1637 whereClause = subselect->jointree->quals;
1638 subselect->jointree->quals = NULL;
1639
1640 /*
1641 * The rest of the sub-select must not refer to any Vars of the parent
1642 * query. (Vars of higher levels should be okay, though.)
1643 */
1644 if (contain_vars_of_level((Node *) subselect, 1))
1645 return NULL;
1646
1647 /*
1648 * On the other hand, the WHERE clause must contain some Vars of the
1649 * parent query, else it's not gonna be a join.
1650 */
1651 if (!contain_vars_of_level(whereClause, 1))
1652 return NULL;
1653
1654 /*
1655 * We don't risk optimizing if the WHERE clause is volatile, either.
1656 */
1657 if (contain_volatile_functions(whereClause))
1658 return NULL;
1659
1660 /*
1661 * Scan the rangetable for relation RTEs and retrieve the necessary
1662 * catalog information for each relation. Using this information, clear
1663 * the inh flag for any relation that has no children, collect not-null
1664 * attribute numbers for any relation that has column not-null
1665 * constraints, and expand virtual generated columns for any relation that
1666 * contains them.
1667 *
1668 * Note: we construct up an entirely dummy PlannerInfo for use here. This
1669 * is fine because only the "glob" and "parse" links will be used in this
1670 * case.
1671 *
1672 * Note: we temporarily assign back the WHERE clause so that any virtual
1673 * generated column references within it can be expanded. It should be
1674 * separated out again afterward.
1675 */
1676 MemSet(&subroot, 0, sizeof(subroot));
1677 subroot.type = T_PlannerInfo;
1678 subroot.glob = root->glob;
1679 subroot.parse = subselect;
1680 subselect->jointree->quals = whereClause;
1681 subselect = preprocess_relation_rtes(&subroot);
1682
1683 /*
1684 * Now separate out the WHERE clause again.
1685 */
1686 whereClause = subselect->jointree->quals;
1687 subselect->jointree->quals = NULL;
1688
1689 /*
1690 * The subquery must have a nonempty jointree, but we can make it so.
1691 */
1692 replace_empty_jointree(subselect);
1693
1694 /*
1695 * Prepare to pull up the sub-select into top range table.
1696 *
1697 * We rely here on the assumption that the outer query has no references
1698 * to the inner (necessarily true). Therefore this is a lot easier than
1699 * what pull_up_subqueries has to go through.
1700 *
1701 * In fact, it's even easier than what convert_ANY_sublink_to_join has to
1702 * do. The machinations of simplify_EXISTS_query ensured that there is
1703 * nothing interesting in the subquery except an rtable and jointree, and
1704 * even the jointree FromExpr no longer has quals. So we can just append
1705 * the rtable to our own and use the FromExpr in our jointree. But first,
1706 * adjust all level-zero varnos in the subquery to account for the rtable
1707 * merger.
1708 */
1709 rtoffset = list_length(parse->rtable);
1710 OffsetVarNodes((Node *) subselect, rtoffset, 0);
1711 OffsetVarNodes(whereClause, rtoffset, 0);
1712
1713 /*
1714 * Upper-level vars in subquery will now be one level closer to their
1715 * parent than before; in particular, anything that had been level 1
1716 * becomes level zero.
1717 */
1718 IncrementVarSublevelsUp((Node *) subselect, -1, 1);
1719 IncrementVarSublevelsUp(whereClause, -1, 1);
1720
1721 /*
1722 * Now that the WHERE clause is adjusted to match the parent query
1723 * environment, we can easily identify all the level-zero rels it uses.
1724 * The ones <= rtoffset belong to the upper query; the ones > rtoffset do
1725 * not.
1726 */
1727 clause_varnos = pull_varnos(root, whereClause);
1729 varno = -1;
1730 while ((varno = bms_next_member(clause_varnos, varno)) >= 0)
1731 {
1732 if (varno <= rtoffset)
1734 }
1737
1738 /*
1739 * Now that we've got the set of upper-level varnos, we can make the last
1740 * check: only available_rels can be referenced.
1741 */
1743 return NULL;
1744
1745 /*
1746 * Now we can attach the modified subquery rtable to the parent. This also
1747 * adds subquery's RTEPermissionInfos into the upper query.
1748 */
1749 CombineRangeTables(&parse->rtable, &parse->rteperminfos,
1750 subselect->rtable, subselect->rteperminfos);
1751
1752 /*
1753 * And finally, build the JoinExpr node.
1754 */
1755 result = makeNode(JoinExpr);
1756 result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
1757 result->isNatural = false;
1758 result->larg = NULL; /* caller must fill this in */
1759 /* flatten out the FromExpr node if it's useless */
1760 if (list_length(subselect->jointree->fromlist) == 1)
1761 result->rarg = (Node *) linitial(subselect->jointree->fromlist);
1762 else
1763 result->rarg = (Node *) subselect->jointree;
1764 result->usingClause = NIL;
1765 result->join_using_alias = NULL;
1766 result->quals = whereClause;
1767 result->alias = NULL;
1768 result->rtindex = 0; /* we don't need an RTE for it */
1769
1770 return result;
1771}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
void bms_free(Bitmapset *a)
Definition bitmapset.c:239
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
#define MemSet(start, val, len)
Definition c.h:1109
#define copyObject(obj)
Definition nodes.h:232
#define linitial(l)
Definition pg_list.h:178
void replace_empty_jointree(Query *parse)
Query * preprocess_relation_rtes(PlannerInfo *root)
@ EXISTS_SUBLINK
Definition primnodes.h:1030
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
void CombineRangeTables(List **dst_rtable, List **dst_perminfos, List *src_rtable, List *src_perminfos)
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
PlannerGlobal * glob
Definition pathnodes.h:312
Query * parse
Definition pathnodes.h:309
static bool simplify_EXISTS_query(PlannerInfo *root, Query *query)
Definition subselect.c:1796
bool contain_vars_of_level(Node *node, int levelsup)
Definition var.c:444

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, fb(), FromExpr::fromlist, PlannerInfo::glob, IncrementVarSublevelsUp(), JoinExpr::isNatural, JOIN_ANTI, JOIN_SEMI, Query::jointree, JoinExpr::jointype, JoinExpr::larg, linitial, list_length(), makeNode, MemSet, NIL, OffsetVarNodes(), PlannerInfo::parse, parse(), preprocess_relation_rtes(), pull_varnos(), JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, replace_empty_jointree(), root, Query::rtable, JoinExpr::rtindex, and simplify_EXISTS_query().

Referenced by pull_up_sublinks_qual_recurse().

◆ convert_VALUES_to_ANY()

ScalarArrayOpExpr * convert_VALUES_to_ANY ( PlannerInfo root,
Node testexpr,
Query values 
)
extern

Definition at line 1230 of file subselect.c.

1231{
1233 Node *leftop;
1234 Node *rightop;
1235 Oid opno;
1236 ListCell *lc;
1237 Oid inputcollid;
1238 List *exprs = NIL;
1239
1240 /*
1241 * Check we have a binary operator over a single-column subquery with no
1242 * joins and no LIMIT/OFFSET/ORDER BY clauses.
1243 */
1244 if (!IsA(testexpr, OpExpr) ||
1245 list_length(((OpExpr *) testexpr)->args) != 2 ||
1246 list_length(values->targetList) > 1 ||
1247 values->limitCount != NULL ||
1248 values->limitOffset != NULL ||
1249 values->sortClause != NIL ||
1250 list_length(values->rtable) != 1)
1251 return NULL;
1252
1254 leftop = linitial(((OpExpr *) testexpr)->args);
1255 rightop = lsecond(((OpExpr *) testexpr)->args);
1256 opno = ((OpExpr *) testexpr)->opno;
1257 inputcollid = ((OpExpr *) testexpr)->inputcollid;
1258
1259 /*
1260 * Also, check that only RTE corresponds to VALUES; the list of values has
1261 * at least two items and no volatile functions.
1262 */
1263 if (rte->rtekind != RTE_VALUES ||
1264 list_length(rte->values_lists) < 2 ||
1265 contain_volatile_functions((Node *) rte->values_lists))
1266 return NULL;
1267
1268 foreach(lc, rte->values_lists)
1269 {
1270 List *elem = lfirst(lc);
1271 Node *value = linitial(elem);
1272
1273 /*
1274 * Prepare an evaluation of the right side of the operator with
1275 * substitution of the given value.
1276 */
1278
1279 /*
1280 * Try to evaluate constant expressions. We could get Const as a
1281 * result.
1282 */
1284
1285 /*
1286 * As we only support constant output arrays, all the items must also
1287 * be constant.
1288 */
1289 if (!IsA(value, Const))
1290 return NULL;
1291
1292 exprs = lappend(exprs, value);
1293 }
1294
1295 /* Finally, build ScalarArrayOpExpr at the top of the 'exprs' list. */
1296 return make_SAOP_expr(opno, leftop, exprType(rightop),
1297 linitial_oid(rte->colcollations), inputcollid,
1298 exprs, false);
1299}
static Datum values[MAXATTR]
Definition bootstrap.c:188
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition clauses.c:2498
ScalarArrayOpExpr * make_SAOP_expr(Oid oper, Node *leftexpr, Oid coltype, Oid arraycollid, Oid inputcollid, List *exprs, bool haveNonConst)
Definition clauses.c:6236
static struct @174 value
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define IsA(nodeptr, _type_)
Definition nodes.h:164
@ RTE_VALUES
#define lfirst(lc)
Definition pg_list.h:172
#define linitial_node(type, l)
Definition pg_list.h:181
#define list_make1(x1)
Definition pg_list.h:212
#define lsecond(l)
Definition pg_list.h:183
#define linitial_oid(l)
Definition pg_list.h:180
unsigned int Oid

References contain_volatile_functions(), convert_testexpr(), eval_const_expressions(), exprType(), fb(), IsA, lappend(), lfirst, linitial, linitial_node, linitial_oid, list_length(), list_make1, lsecond, make_SAOP_expr(), NIL, root, RTE_VALUES, value, and values.

Referenced by pull_up_sublinks_qual_recurse().

◆ SS_attach_initplans()

void SS_attach_initplans ( PlannerInfo root,
Plan plan 
)
extern

Definition at line 2534 of file subselect.c.

2535{
2536 plan->initPlan = root->init_plans;
2537}
#define plan(x)
Definition pg_regress.c:161

References plan, and root.

Referenced by create_plan().

◆ SS_charge_for_initplans()

void SS_charge_for_initplans ( PlannerInfo root,
RelOptInfo final_rel 
)
extern

Definition at line 2429 of file subselect.c.

2430{
2432 bool unsafe_initplans;
2433 ListCell *lc;
2434
2435 /* Nothing to do if no initPlans */
2436 if (root->init_plans == NIL)
2437 return;
2438
2439 /*
2440 * Compute the cost increment just once, since it will be the same for all
2441 * Paths. Also check for parallel-unsafe initPlans.
2442 */
2443 SS_compute_initplan_cost(root->init_plans,
2445
2446 /*
2447 * Now adjust the costs and parallel_safe flags.
2448 */
2449 foreach(lc, final_rel->pathlist)
2450 {
2451 Path *path = (Path *) lfirst(lc);
2452
2453 path->startup_cost += initplan_cost;
2454 path->total_cost += initplan_cost;
2455 if (unsafe_initplans)
2456 path->parallel_safe = false;
2457 }
2458
2459 /*
2460 * Adjust partial paths' costs too, or forget them entirely if we must
2461 * consider the rel parallel-unsafe.
2462 */
2463 if (unsafe_initplans)
2464 {
2465 final_rel->partial_pathlist = NIL;
2466 final_rel->consider_parallel = false;
2467 }
2468 else
2469 {
2470 foreach(lc, final_rel->partial_pathlist)
2471 {
2472 Path *path = (Path *) lfirst(lc);
2473
2474 path->startup_cost += initplan_cost;
2475 path->total_cost += initplan_cost;
2476 }
2477 }
2478
2479 /* We needn't do set_cheapest() here, caller will do it */
2480}
double Cost
Definition nodes.h:261
Cost startup_cost
Definition pathnodes.h:1995
Cost total_cost
Definition pathnodes.h:1996
bool parallel_safe
Definition pathnodes.h:1988
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition subselect.c:2493

References fb(), lfirst, NIL, Path::parallel_safe, 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 
)
extern

Definition at line 2493 of file subselect.c.

2496{
2498 bool unsafe_initplans;
2499 ListCell *lc;
2500
2501 /*
2502 * We assume each initPlan gets run once during top plan startup. This is
2503 * a conservative overestimate, since in fact an initPlan might be
2504 * executed later than plan startup, or even not at all.
2505 */
2506 initplan_cost = 0;
2507 unsafe_initplans = false;
2508 foreach(lc, init_plans)
2509 {
2511
2512 initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
2513 if (!initsubplan->parallel_safe)
2514 unsafe_initplans = true;
2515 }
2518}
#define lfirst_node(type, lc)
Definition pg_list.h:176

References fb(), and lfirst_node.

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 
)
extern

Definition at line 2549 of file subselect.c.

2550{
2551 /* No setup needed, just recurse through plan tree. */
2552 (void) finalize_plan(root, plan, -1, root->outer_params, NULL);
2553}
static Bitmapset * finalize_plan(PlannerInfo *root, Plan *plan, int gather_param, Bitmapset *valid_params, Bitmapset *scan_params)
Definition subselect.c:2587

References fb(), finalize_plan(), plan, and root.

Referenced by standard_planner().

◆ SS_identify_outer_params()

void SS_identify_outer_params ( PlannerInfo root)
extern

Definition at line 2365 of file subselect.c.

2366{
2367 Bitmapset *outer_params;
2369 ListCell *l;
2370
2371 /*
2372 * If no parameters have been assigned anywhere in the tree, we certainly
2373 * don't need to do anything here.
2374 */
2375 if (root->glob->paramExecTypes == NIL)
2376 return;
2377
2378 /*
2379 * Scan all query levels above this one to see which parameters are due to
2380 * be available from them, either because lower query levels have
2381 * requested them (via plan_params) or because they will be available from
2382 * initPlans of those levels.
2383 */
2384 outer_params = NULL;
2385 for (proot = root->parent_root; proot != NULL; proot = proot->parent_root)
2386 {
2387 /*
2388 * Include ordinary Var/PHV/Aggref/GroupingFunc/ReturningExpr params.
2389 */
2390 foreach(l, proot->plan_params)
2391 {
2393
2394 outer_params = bms_add_member(outer_params, pitem->paramId);
2395 }
2396 /* Include any outputs of outer-level initPlans */
2397 foreach(l, proot->init_plans)
2398 {
2400 ListCell *l2;
2401
2402 foreach(l2, initsubplan->setParam)
2403 {
2404 outer_params = bms_add_member(outer_params, lfirst_int(l2));
2405 }
2406 }
2407 /* Include worktable ID, if a recursive query is being planned */
2408 if (proot->wt_param_id >= 0)
2409 outer_params = bms_add_member(outer_params, proot->wt_param_id);
2410 }
2411 root->outer_params = outer_params;
2412}
#define lfirst_int(lc)
Definition pg_list.h:173

References bms_add_member(), fb(), lfirst, lfirst_int, NIL, and root.

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 
)
extern

Definition at line 3310 of file subselect.c.

3313{
3314 SubPlan *node;
3315
3316 /*
3317 * Add the subplan and its PlannerInfo, as well as a dummy path entry, to
3318 * the global lists. Ideally we'd save a real path, but right now our
3319 * sole caller doesn't build a path that exactly matches the plan. Since
3320 * we're not currently going to need the path for an initplan, it's not
3321 * worth requiring construction of such a path.
3322 */
3323 root->glob->subplans = lappend(root->glob->subplans, plan);
3324 root->glob->subpaths = lappend(root->glob->subpaths, NULL);
3325 root->glob->subroots = lappend(root->glob->subroots, subroot);
3326
3327 /*
3328 * Create a SubPlan node and add it to the outer list of InitPlans. Note
3329 * it has to appear after any other InitPlans it might depend on (see
3330 * comments in ExecReScan).
3331 */
3332 node = makeNode(SubPlan);
3333 node->subLinkType = EXPR_SUBLINK;
3334 node->plan_id = list_length(root->glob->subplans);
3335 node->plan_name = subroot->plan_name;
3336 node->isInitPlan = true;
3338 &node->firstColCollation);
3339 node->parallel_safe = plan->parallel_safe;
3340 node->setParam = list_make1_int(prm->paramid);
3341
3342 root->init_plans = lappend(root->init_plans, node);
3343
3344 /*
3345 * The node can't have any inputs (since it's an initplan), so the
3346 * parParam and args lists remain empty.
3347 */
3348
3349 /* Set costs of SubPlan using info from the plan tree */
3350 cost_subplan(subroot, node, plan);
3351}
void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
Definition costsize.c:4677
#define list_make1_int(x1)
Definition pg_list.h:227
@ EXPR_SUBLINK
Definition primnodes.h:1034
char * plan_name
Definition pathnodes.h:321
int plan_id
Definition primnodes.h:1103
char * plan_name
Definition primnodes.h:1105
bool isInitPlan
Definition primnodes.h:1112
int32 firstColTypmod
Definition primnodes.h:1108
bool parallel_safe
Definition primnodes.h:1118
List * setParam
Definition primnodes.h:1122
Oid firstColCollation
Definition primnodes.h:1109
SubLinkType subLinkType
Definition primnodes.h:1098
Oid firstColType
Definition primnodes.h:1107
static void get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod, Oid *colcollation)
Definition subselect.c:121

References cost_subplan(), EXPR_SUBLINK, fb(), SubPlan::firstColCollation, SubPlan::firstColType, SubPlan::firstColTypmod, get_first_col_type(), SubPlan::isInitPlan, lappend(), list_length(), list_make1_int, makeNode, SubPlan::parallel_safe, plan, SubPlan::plan_id, PlannerInfo::plan_name, SubPlan::plan_name, 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 
)
extern

Definition at line 3294 of file subselect.c.

3297{
3298 return generate_new_exec_param(root, resulttype,
3300}
Param * generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation)

References fb(), generate_new_exec_param(), and root.

Referenced by preprocess_minmax_aggregates().

◆ SS_process_ctes()

void SS_process_ctes ( PlannerInfo root)
extern

Definition at line 884 of file subselect.c.

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

References SubPlan::args, Assert, assign_special_exec_param(), choose_plan_name(), 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, fb(), fetch_upper_rel(), SubPlan::firstColCollation, SubPlan::firstColType, SubPlan::firstColTypmod, get_first_col_type(), inline_cte(), lappend(), lappend_int(), lfirst, list_length(), list_make1_int, makeNode, NIL, SubPlan::parallel_safe, SubPlan::paramIds, SubPlan::parParam, plan, SubPlan::plan_id, PlannerInfo::plan_name, SubPlan::plan_name, root, SubPlan::setParam, SubPlan::subLinkType, subquery_planner(), SubPlan::testexpr, SubPlan::unknownEqFalse, UPPERREL_FINAL, and SubPlan::useHashTable.

Referenced by subquery_planner().

◆ SS_process_sublinks()

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

Definition at line 2207 of file subselect.c.

2208{
2210
2211 context.root = root;
2212 context.isTopQual = isQual;
2213 return process_sublinks_mutator(expr, &context);
2214}
static Node * process_sublinks_mutator(Node *node, process_sublinks_context *context)
Definition subselect.c:2217

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

Referenced by build_subplan(), and preprocess_expression().

◆ SS_replace_correlation_vars()

Node * SS_replace_correlation_vars ( PlannerInfo root,
Node expr 
)
extern

Definition at line 2152 of file subselect.c.

2153{
2154 /* No setup needed for tree walk, so away we go */
2156}
static Node * replace_correlation_vars_mutator(Node *node, PlannerInfo *root)
Definition subselect.c:2159

References replace_correlation_vars_mutator(), and root.

Referenced by preprocess_expression().