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

1343{
1345 Query *parse = root->parse;
1346 Query *subselect = (Query *) sublink->subselect;
1348 int rtindex;
1353 Node *quals;
1354 ParseState *pstate;
1356 bool use_lateral;
1357
1358 Assert(sublink->subLinkType == ANY_SUBLINK);
1359
1360 /*
1361 * Per SQL spec, NOT IN is not ordinarily equivalent to an anti-join, so
1362 * that by default we have to fail when under_not. However, if we can
1363 * prove that neither the outer query's expressions nor the sub-select's
1364 * output columns can be NULL, and further that the operator itself cannot
1365 * return NULL for non-null inputs, then the logic is identical and it's
1366 * safe to convert NOT IN to an anti-join.
1367 */
1368 if (under_not &&
1370 !query_outputs_are_not_nullable(subselect)))
1371 return NULL;
1372
1373 /*
1374 * If the sub-select contains any Vars of the parent query, we treat it as
1375 * LATERAL. (Vars from higher levels don't matter here.)
1376 */
1379
1380 /*
1381 * Can't convert if the sub-select contains parent-level Vars of relations
1382 * not in available_rels.
1383 */
1385 return NULL;
1386
1387 /*
1388 * The test expression must contain some Vars of the parent query, else
1389 * it's not gonna be a join. (Note that it won't have Vars referring to
1390 * the subquery, rather Params.)
1391 */
1392 upper_varnos = pull_varnos(root, sublink->testexpr);
1394 return NULL;
1395
1396 /*
1397 * However, it can't refer to anything outside available_rels.
1398 */
1400 return NULL;
1401
1402 /*
1403 * The combining operators and left-hand expressions mustn't be volatile.
1404 */
1405 if (contain_volatile_functions(sublink->testexpr))
1406 return NULL;
1407
1408 /* Create a dummy ParseState for addRangeTableEntryForSubquery */
1409 pstate = make_parsestate(NULL);
1410
1411 /*
1412 * Okay, pull up the sub-select into upper range table.
1413 *
1414 * We rely here on the assumption that the outer query has no references
1415 * to the inner (necessarily true, other than the Vars that we build
1416 * below). Therefore this is a lot easier than what pull_up_subqueries has
1417 * to go through.
1418 */
1420 subselect,
1421 NULL,
1423 false);
1424 rte = nsitem->p_rte;
1425 parse->rtable = lappend(parse->rtable, rte);
1426 rtindex = list_length(parse->rtable);
1427
1428 /*
1429 * Form a RangeTblRef for the pulled-up sub-select.
1430 */
1432 rtr->rtindex = rtindex;
1433
1434 /*
1435 * Build a list of Vars representing the subselect outputs.
1436 */
1438 subselect->targetList,
1439 rtindex);
1440
1441 /*
1442 * Build the new join's qual expression, replacing Params with these Vars.
1443 */
1444 quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
1445
1446 /*
1447 * And finally, build the JoinExpr node.
1448 */
1450 result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
1451 result->isNatural = false;
1452 result->larg = NULL; /* caller must fill this in */
1453 result->rarg = (Node *) rtr;
1454 result->usingClause = NIL;
1455 result->join_using_alias = NULL;
1456 result->quals = quals;
1457 result->alias = NULL;
1458 result->rtindex = 0; /* we don't need an RTE for it */
1459
1460 return result;
1461}
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:943
uint32 result
bool query_outputs_are_not_nullable(Query *query)
Definition clauses.c:2051
bool contain_volatile_functions(Node *clause)
Definition clauses.c:551
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:1485
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(), JOIN_ANTI, JOIN_SEMI, lappend(), list_length(), make_parsestate(), makeNode, NIL, parse(), pull_varnos(), pull_varnos_of_level(), query_outputs_are_not_nullable(), result, root, 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 1593 of file subselect.c.

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

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

2537{
2538 plan->initPlan = root->init_plans;
2539}
#define plan(x)
Definition pg_regress.c:164

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

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

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

2498{
2500 bool unsafe_initplans;
2501 ListCell *lc;
2502
2503 /*
2504 * We assume each initPlan gets run once during top plan startup. This is
2505 * a conservative overestimate, since in fact an initPlan might be
2506 * executed later than plan startup, or even not at all.
2507 */
2508 initplan_cost = 0;
2509 unsafe_initplans = false;
2510 foreach(lc, init_plans)
2511 {
2513
2514 initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
2515 if (!initsubplan->parallel_safe)
2516 unsafe_initplans = true;
2517 }
2520}
#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 2551 of file subselect.c.

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

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

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

3315{
3316 SubPlan *node;
3317
3318 /*
3319 * Add the subplan and its PlannerInfo, as well as a dummy path entry, to
3320 * the global lists. Ideally we'd save a real path, but right now our
3321 * sole caller doesn't build a path that exactly matches the plan. Since
3322 * we're not currently going to need the path for an initplan, it's not
3323 * worth requiring construction of such a path.
3324 */
3325 root->glob->subplans = lappend(root->glob->subplans, plan);
3326 root->glob->subpaths = lappend(root->glob->subpaths, NULL);
3327 root->glob->subroots = lappend(root->glob->subroots, subroot);
3328
3329 /*
3330 * Create a SubPlan node and add it to the outer list of InitPlans. Note
3331 * it has to appear after any other InitPlans it might depend on (see
3332 * comments in ExecReScan).
3333 */
3334 node = makeNode(SubPlan);
3335 node->subLinkType = EXPR_SUBLINK;
3336 node->plan_id = list_length(root->glob->subplans);
3337 node->plan_name = subroot->plan_name;
3338 node->isInitPlan = true;
3340 &node->firstColCollation);
3341 node->parallel_safe = plan->parallel_safe;
3342 node->setParam = list_make1_int(prm->paramid);
3343
3344 root->init_plans = lappend(root->init_plans, node);
3345
3346 /*
3347 * The node can't have any inputs (since it's an initplan), so the
3348 * parParam and args lists remain empty.
3349 */
3350
3351 /* Set costs of SubPlan using info from the plan tree */
3352 cost_subplan(subroot, node, plan);
3353}
void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
Definition costsize.c:4677
#define list_make1_int(x1)
Definition pg_list.h:259
@ 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 3296 of file subselect.c.

3299{
3300 return generate_new_exec_param(root, resulttype,
3302}
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 886 of file subselect.c.

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

References 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(), get_first_col_type(), inline_cte(), lappend(), lappend_int(), lfirst, list_length(), list_make1_int, makeNode, NIL, plan, PlannerInfo::plan_name, root, subquery_planner(), and UPPERREL_FINAL.

Referenced by subquery_planner().

◆ SS_process_sublinks()

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

Definition at line 2209 of file subselect.c.

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

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

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

References replace_correlation_vars_mutator(), and root.

Referenced by preprocess_expression().