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)
 
ScalarArrayOpExprconvert_VALUES_to_ANY (PlannerInfo *root, Node *testexpr, Query *values)
 
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 1335 of file subselect.c.

1337{
1338 JoinExpr *result;
1339 Query *parse = root->parse;
1340 Query *subselect = (Query *) sublink->subselect;
1341 Relids upper_varnos;
1342 int rtindex;
1343 ParseNamespaceItem *nsitem;
1344 RangeTblEntry *rte;
1345 RangeTblRef *rtr;
1346 List *subquery_vars;
1347 Node *quals;
1348 ParseState *pstate;
1349 Relids sub_ref_outer_relids;
1350 bool use_lateral;
1351
1352 Assert(sublink->subLinkType == ANY_SUBLINK);
1353
1354 /*
1355 * If the sub-select contains any Vars of the parent query, we treat it as
1356 * LATERAL. (Vars from higher levels don't matter here.)
1357 */
1358 sub_ref_outer_relids = pull_varnos_of_level(NULL, (Node *) subselect, 1);
1359 use_lateral = !bms_is_empty(sub_ref_outer_relids);
1360
1361 /*
1362 * Can't convert if the sub-select contains parent-level Vars of relations
1363 * not in available_rels.
1364 */
1365 if (!bms_is_subset(sub_ref_outer_relids, available_rels))
1366 return NULL;
1367
1368 /*
1369 * The test expression must contain some Vars of the parent query, else
1370 * it's not gonna be a join. (Note that it won't have Vars referring to
1371 * the subquery, rather Params.)
1372 */
1373 upper_varnos = pull_varnos(root, sublink->testexpr);
1374 if (bms_is_empty(upper_varnos))
1375 return NULL;
1376
1377 /*
1378 * However, it can't refer to anything outside available_rels.
1379 */
1380 if (!bms_is_subset(upper_varnos, available_rels))
1381 return NULL;
1382
1383 /*
1384 * The combining operators and left-hand expressions mustn't be volatile.
1385 */
1387 return NULL;
1388
1389 /* Create a dummy ParseState for addRangeTableEntryForSubquery */
1390 pstate = make_parsestate(NULL);
1391
1392 /*
1393 * Okay, pull up the sub-select into upper range table.
1394 *
1395 * We rely here on the assumption that the outer query has no references
1396 * to the inner (necessarily true, other than the Vars that we build
1397 * below). Therefore this is a lot easier than what pull_up_subqueries has
1398 * to go through.
1399 */
1400 nsitem = addRangeTableEntryForSubquery(pstate,
1401 subselect,
1402 NULL,
1403 use_lateral,
1404 false);
1405 rte = nsitem->p_rte;
1406 parse->rtable = lappend(parse->rtable, rte);
1407 rtindex = list_length(parse->rtable);
1408
1409 /*
1410 * Form a RangeTblRef for the pulled-up sub-select.
1411 */
1412 rtr = makeNode(RangeTblRef);
1413 rtr->rtindex = rtindex;
1414
1415 /*
1416 * Build a list of Vars representing the subselect outputs.
1417 */
1418 subquery_vars = generate_subquery_vars(root,
1419 subselect->targetList,
1420 rtindex);
1421
1422 /*
1423 * Build the new join's qual expression, replacing Params with these Vars.
1424 */
1425 quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
1426
1427 /*
1428 * And finally, build the JoinExpr node.
1429 */
1430 result = makeNode(JoinExpr);
1431 result->jointype = JOIN_SEMI;
1432 result->isNatural = false;
1433 result->larg = NULL; /* caller must fill this in */
1434 result->rarg = (Node *) rtr;
1435 result->usingClause = NIL;
1436 result->join_using_alias = NULL;
1437 result->quals = quals;
1438 result->alias = NULL;
1439 result->rtindex = 0; /* we don't need an RTE for it */
1440
1441 return result;
1442}
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
#define bms_is_empty(a)
Definition: bitmapset.h:118
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:550
Assert(PointerIsAligned(start, uint64))
List * lappend(List *list, void *datum)
Definition: list.c:339
#define makeNode(_type_)
Definition: nodes.h:161
@ JOIN_SEMI
Definition: nodes.h:317
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:1031
tree ctl root
Definition: radixtree.h:1857
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
Node * quals
Definition: primnodes.h:2338
JoinType jointype
Definition: primnodes.h:2329
int rtindex
Definition: primnodes.h:2342
Node * larg
Definition: primnodes.h:2331
bool isNatural
Definition: primnodes.h:2330
Node * rarg
Definition: primnodes.h:2332
Definition: pg_list.h:54
Definition: nodes.h:135
List * targetList
Definition: parsenodes.h:198
static List * generate_subquery_vars(PlannerInfo *root, List *tlist, Index varno)
Definition: subselect.c:618
static Node * convert_testexpr(PlannerInfo *root, Node *testexpr, List *subst_nodes)
Definition: subselect.c:647
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(), generate_subquery_vars(), JoinExpr::isNatural, JOIN_SEMI, JoinExpr::jointype, lappend(), JoinExpr::larg, list_length(), make_parsestate(), 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 1452 of file subselect.c.

1454{
1455 JoinExpr *result;
1456 Query *parse = root->parse;
1457 Query *subselect = (Query *) sublink->subselect;
1458 Node *whereClause;
1459 PlannerInfo subroot;
1460 int rtoffset;
1461 int varno;
1462 Relids clause_varnos;
1463 Relids upper_varnos;
1464
1465 Assert(sublink->subLinkType == EXISTS_SUBLINK);
1466
1467 /*
1468 * Can't flatten if it contains WITH. (We could arrange to pull up the
1469 * WITH into the parent query's cteList, but that risks changing the
1470 * semantics, since a WITH ought to be executed once per associated query
1471 * call.) Note that convert_ANY_sublink_to_join doesn't have to reject
1472 * this case, since it just produces a subquery RTE that doesn't have to
1473 * get flattened into the parent query.
1474 */
1475 if (subselect->cteList)
1476 return NULL;
1477
1478 /*
1479 * Copy the subquery so we can modify it safely (see comments in
1480 * make_subplan).
1481 */
1482 subselect = copyObject(subselect);
1483
1484 /*
1485 * See if the subquery can be simplified based on the knowledge that it's
1486 * being used in EXISTS(). If we aren't able to get rid of its
1487 * targetlist, we have to fail, because the pullup operation leaves us
1488 * with noplace to evaluate the targetlist.
1489 */
1490 if (!simplify_EXISTS_query(root, subselect))
1491 return NULL;
1492
1493 /*
1494 * Separate out the WHERE clause. (We could theoretically also remove
1495 * top-level plain JOIN/ON clauses, but it's probably not worth the
1496 * trouble.)
1497 */
1498 whereClause = subselect->jointree->quals;
1499 subselect->jointree->quals = NULL;
1500
1501 /*
1502 * The rest of the sub-select must not refer to any Vars of the parent
1503 * query. (Vars of higher levels should be okay, though.)
1504 */
1505 if (contain_vars_of_level((Node *) subselect, 1))
1506 return NULL;
1507
1508 /*
1509 * On the other hand, the WHERE clause must contain some Vars of the
1510 * parent query, else it's not gonna be a join.
1511 */
1512 if (!contain_vars_of_level(whereClause, 1))
1513 return NULL;
1514
1515 /*
1516 * We don't risk optimizing if the WHERE clause is volatile, either.
1517 */
1518 if (contain_volatile_functions(whereClause))
1519 return NULL;
1520
1521 /*
1522 * Scan the rangetable for relation RTEs and retrieve the necessary
1523 * catalog information for each relation. Using this information, clear
1524 * the inh flag for any relation that has no children, collect not-null
1525 * attribute numbers for any relation that has column not-null
1526 * constraints, and expand virtual generated columns for any relation that
1527 * contains them.
1528 *
1529 * Note: we construct up an entirely dummy PlannerInfo for use here. This
1530 * is fine because only the "glob" and "parse" links will be used in this
1531 * case.
1532 *
1533 * Note: we temporarily assign back the WHERE clause so that any virtual
1534 * generated column references within it can be expanded. It should be
1535 * separated out again afterward.
1536 */
1537 MemSet(&subroot, 0, sizeof(subroot));
1538 subroot.type = T_PlannerInfo;
1539 subroot.glob = root->glob;
1540 subroot.parse = subselect;
1541 subselect->jointree->quals = whereClause;
1542 subselect = preprocess_relation_rtes(&subroot);
1543
1544 /*
1545 * Now separate out the WHERE clause again.
1546 */
1547 whereClause = subselect->jointree->quals;
1548 subselect->jointree->quals = NULL;
1549
1550 /*
1551 * The subquery must have a nonempty jointree, but we can make it so.
1552 */
1553 replace_empty_jointree(subselect);
1554
1555 /*
1556 * Prepare to pull up the sub-select into top range table.
1557 *
1558 * We rely here on the assumption that the outer query has no references
1559 * to the inner (necessarily true). Therefore this is a lot easier than
1560 * what pull_up_subqueries has to go through.
1561 *
1562 * In fact, it's even easier than what convert_ANY_sublink_to_join has to
1563 * do. The machinations of simplify_EXISTS_query ensured that there is
1564 * nothing interesting in the subquery except an rtable and jointree, and
1565 * even the jointree FromExpr no longer has quals. So we can just append
1566 * the rtable to our own and use the FromExpr in our jointree. But first,
1567 * adjust all level-zero varnos in the subquery to account for the rtable
1568 * merger.
1569 */
1570 rtoffset = list_length(parse->rtable);
1571 OffsetVarNodes((Node *) subselect, rtoffset, 0);
1572 OffsetVarNodes(whereClause, rtoffset, 0);
1573
1574 /*
1575 * Upper-level vars in subquery will now be one level closer to their
1576 * parent than before; in particular, anything that had been level 1
1577 * becomes level zero.
1578 */
1579 IncrementVarSublevelsUp((Node *) subselect, -1, 1);
1580 IncrementVarSublevelsUp(whereClause, -1, 1);
1581
1582 /*
1583 * Now that the WHERE clause is adjusted to match the parent query
1584 * environment, we can easily identify all the level-zero rels it uses.
1585 * The ones <= rtoffset belong to the upper query; the ones > rtoffset do
1586 * not.
1587 */
1588 clause_varnos = pull_varnos(root, whereClause);
1589 upper_varnos = NULL;
1590 varno = -1;
1591 while ((varno = bms_next_member(clause_varnos, varno)) >= 0)
1592 {
1593 if (varno <= rtoffset)
1594 upper_varnos = bms_add_member(upper_varnos, varno);
1595 }
1596 bms_free(clause_varnos);
1597 Assert(!bms_is_empty(upper_varnos));
1598
1599 /*
1600 * Now that we've got the set of upper-level varnos, we can make the last
1601 * check: only available_rels can be referenced.
1602 */
1603 if (!bms_is_subset(upper_varnos, available_rels))
1604 return NULL;
1605
1606 /*
1607 * Now we can attach the modified subquery rtable to the parent. This also
1608 * adds subquery's RTEPermissionInfos into the upper query.
1609 */
1610 CombineRangeTables(&parse->rtable, &parse->rteperminfos,
1611 subselect->rtable, subselect->rteperminfos);
1612
1613 /*
1614 * And finally, build the JoinExpr node.
1615 */
1616 result = makeNode(JoinExpr);
1617 result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
1618 result->isNatural = false;
1619 result->larg = NULL; /* caller must fill this in */
1620 /* flatten out the FromExpr node if it's useless */
1621 if (list_length(subselect->jointree->fromlist) == 1)
1622 result->rarg = (Node *) linitial(subselect->jointree->fromlist);
1623 else
1624 result->rarg = (Node *) subselect->jointree;
1625 result->usingClause = NIL;
1626 result->join_using_alias = NULL;
1627 result->quals = whereClause;
1628 result->alias = NULL;
1629 result->rtindex = 0; /* we don't need an RTE for it */
1630
1631 return result;
1632}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1305
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:814
#define MemSet(start, val, len)
Definition: c.h:1022
#define copyObject(obj)
Definition: nodes.h:232
@ JOIN_ANTI
Definition: nodes.h:318
#define linitial(l)
Definition: pg_list.h:178
void replace_empty_jointree(Query *parse)
Definition: prepjointree.c:589
Query * preprocess_relation_rtes(PlannerInfo *root)
Definition: prepjointree.c:417
@ EXISTS_SUBLINK
Definition: primnodes.h:1029
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:476
void CombineRangeTables(List **dst_rtable, List **dst_perminfos, List *src_rtable, List *src_perminfos)
Definition: rewriteManip.c:347
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:881
Node * quals
Definition: primnodes.h:2358
FromExpr * jointree
Definition: parsenodes.h:182
List * cteList
Definition: parsenodes.h:173
static bool simplify_EXISTS_query(PlannerInfo *root, Query *query)
Definition: subselect.c:1651
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, FromExpr::fromlist, IncrementVarSublevelsUp(), JoinExpr::isNatural, JOIN_ANTI, JOIN_SEMI, Query::jointree, JoinExpr::jointype, JoinExpr::larg, linitial, list_length(), makeNode, MemSet, NIL, OffsetVarNodes(), parse(), preprocess_relation_rtes(), 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().

◆ convert_VALUES_to_ANY()

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

Definition at line 1229 of file subselect.c.

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

References generate_unaccent_rules::args, contain_volatile_functions(), convert_testexpr(), eval_const_expressions(), exprType(), IsA, lappend(), lfirst, linitial, linitial_node, linitial_oid, list_length(), list_make1, lsecond, make_SAOP_expr(), NIL, root, RTE_VALUES, RangeTblEntry::rtekind, value, values, and RangeTblEntry::values_lists.

Referenced by pull_up_sublinks_qual_recurse().

◆ SS_attach_initplans()

void SS_attach_initplans ( PlannerInfo root,
Plan plan 
)

Definition at line 2389 of file subselect.c.

2390{
2391 plan->initPlan = root->init_plans;
2392}
#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 
)

Definition at line 2284 of file subselect.c.

2285{
2286 Cost initplan_cost;
2287 bool unsafe_initplans;
2288 ListCell *lc;
2289
2290 /* Nothing to do if no initPlans */
2291 if (root->init_plans == NIL)
2292 return;
2293
2294 /*
2295 * Compute the cost increment just once, since it will be the same for all
2296 * Paths. Also check for parallel-unsafe initPlans.
2297 */
2298 SS_compute_initplan_cost(root->init_plans,
2299 &initplan_cost, &unsafe_initplans);
2300
2301 /*
2302 * Now adjust the costs and parallel_safe flags.
2303 */
2304 foreach(lc, final_rel->pathlist)
2305 {
2306 Path *path = (Path *) lfirst(lc);
2307
2308 path->startup_cost += initplan_cost;
2309 path->total_cost += initplan_cost;
2310 if (unsafe_initplans)
2311 path->parallel_safe = false;
2312 }
2313
2314 /*
2315 * Adjust partial paths' costs too, or forget them entirely if we must
2316 * consider the rel parallel-unsafe.
2317 */
2318 if (unsafe_initplans)
2319 {
2320 final_rel->partial_pathlist = NIL;
2321 final_rel->consider_parallel = false;
2322 }
2323 else
2324 {
2325 foreach(lc, final_rel->partial_pathlist)
2326 {
2327 Path *path = (Path *) lfirst(lc);
2328
2329 path->startup_cost += initplan_cost;
2330 path->total_cost += initplan_cost;
2331 }
2332 }
2333
2334 /* We needn't do set_cheapest() here, caller will do it */
2335}
double Cost
Definition: nodes.h:261
Cost startup_cost
Definition: pathnodes.h:1909
Cost total_cost
Definition: pathnodes.h:1910
bool parallel_safe
Definition: pathnodes.h:1902
bool consider_parallel
Definition: pathnodes.h:943
List * pathlist
Definition: pathnodes.h:954
List * partial_pathlist
Definition: pathnodes.h:956
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition: subselect.c:2348

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

2351{
2352 Cost initplan_cost;
2353 bool unsafe_initplans;
2354 ListCell *lc;
2355
2356 /*
2357 * We assume each initPlan gets run once during top plan startup. This is
2358 * a conservative overestimate, since in fact an initPlan might be
2359 * executed later than plan startup, or even not at all.
2360 */
2361 initplan_cost = 0;
2362 unsafe_initplans = false;
2363 foreach(lc, init_plans)
2364 {
2365 SubPlan *initsubplan = lfirst_node(SubPlan, lc);
2366
2367 initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
2368 if (!initsubplan->parallel_safe)
2369 unsafe_initplans = true;
2370 }
2371 *initplan_cost_p = initplan_cost;
2372 *unsafe_initplans_p = unsafe_initplans;
2373}
#define lfirst_node(type, lc)
Definition: pg_list.h:176
bool parallel_safe
Definition: primnodes.h:1117
Cost startup_cost
Definition: primnodes.h:1126
Cost per_call_cost
Definition: primnodes.h:1127

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

2405{
2406 /* No setup needed, just recurse through plan tree. */
2407 (void) finalize_plan(root, plan, -1, root->outer_params, NULL);
2408}
static Bitmapset * finalize_plan(PlannerInfo *root, Plan *plan, int gather_param, Bitmapset *valid_params, Bitmapset *scan_params)
Definition: subselect.c:2442

References finalize_plan(), plan, and root.

Referenced by standard_planner().

◆ SS_identify_outer_params()

void SS_identify_outer_params ( PlannerInfo root)

Definition at line 2220 of file subselect.c.

2221{
2222 Bitmapset *outer_params;
2223 PlannerInfo *proot;
2224 ListCell *l;
2225
2226 /*
2227 * If no parameters have been assigned anywhere in the tree, we certainly
2228 * don't need to do anything here.
2229 */
2230 if (root->glob->paramExecTypes == NIL)
2231 return;
2232
2233 /*
2234 * Scan all query levels above this one to see which parameters are due to
2235 * be available from them, either because lower query levels have
2236 * requested them (via plan_params) or because they will be available from
2237 * initPlans of those levels.
2238 */
2239 outer_params = NULL;
2240 for (proot = root->parent_root; proot != NULL; proot = proot->parent_root)
2241 {
2242 /*
2243 * Include ordinary Var/PHV/Aggref/GroupingFunc/ReturningExpr params.
2244 */
2245 foreach(l, proot->plan_params)
2246 {
2248
2249 outer_params = bms_add_member(outer_params, pitem->paramId);
2250 }
2251 /* Include any outputs of outer-level initPlans */
2252 foreach(l, proot->init_plans)
2253 {
2254 SubPlan *initsubplan = (SubPlan *) lfirst(l);
2255 ListCell *l2;
2256
2257 foreach(l2, initsubplan->setParam)
2258 {
2259 outer_params = bms_add_member(outer_params, lfirst_int(l2));
2260 }
2261 }
2262 /* Include worktable ID, if a recursive query is being planned */
2263 if (proot->wt_param_id >= 0)
2264 outer_params = bms_add_member(outer_params, proot->wt_param_id);
2265 }
2266 root->outer_params = outer_params;
2267}
#define lfirst_int(lc)
Definition: pg_list.h:173
List * init_plans
Definition: pathnodes.h:327
int wt_param_id
Definition: pathnodes.h:575
List * plan_params
Definition: pathnodes.h:248
List * setParam
Definition: primnodes.h:1121

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

3168{
3169 SubPlan *node;
3170
3171 /*
3172 * Add the subplan and its PlannerInfo, as well as a dummy path entry, to
3173 * the global lists. Ideally we'd save a real path, but right now our
3174 * sole caller doesn't build a path that exactly matches the plan. Since
3175 * we're not currently going to need the path for an initplan, it's not
3176 * worth requiring construction of such a path.
3177 */
3178 root->glob->subplans = lappend(root->glob->subplans, plan);
3179 root->glob->subpaths = lappend(root->glob->subpaths, NULL);
3180 root->glob->subroots = lappend(root->glob->subroots, subroot);
3181
3182 /*
3183 * Create a SubPlan node and add it to the outer list of InitPlans. Note
3184 * it has to appear after any other InitPlans it might depend on (see
3185 * comments in ExecReScan).
3186 */
3187 node = makeNode(SubPlan);
3188 node->subLinkType = EXPR_SUBLINK;
3189 node->plan_id = list_length(root->glob->subplans);
3190 node->plan_name = subroot->plan_name;
3191 node->isInitPlan = true;
3193 &node->firstColCollation);
3194 node->parallel_safe = plan->parallel_safe;
3195 node->setParam = list_make1_int(prm->paramid);
3196
3197 root->init_plans = lappend(root->init_plans, node);
3198
3199 /*
3200 * The node can't have any inputs (since it's an initplan), so the
3201 * parParam and args lists remain empty.
3202 */
3203
3204 /* Set costs of SubPlan using info from the plan tree */
3205 cost_subplan(subroot, node, plan);
3206}
void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
Definition: costsize.c:4559
#define list_make1_int(x1)
Definition: pg_list.h:227
@ EXPR_SUBLINK
Definition: primnodes.h:1033
int paramid
Definition: primnodes.h:396
char * plan_name
Definition: pathnodes.h:239
int plan_id
Definition: primnodes.h:1102
char * plan_name
Definition: primnodes.h:1104
bool isInitPlan
Definition: primnodes.h:1111
int32 firstColTypmod
Definition: primnodes.h:1107
Oid firstColCollation
Definition: primnodes.h:1108
SubLinkType subLinkType
Definition: primnodes.h:1097
Oid firstColType
Definition: primnodes.h:1106
static void get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod, Oid *colcollation)
Definition: subselect.c:120

References cost_subplan(), EXPR_SUBLINK, SubPlan::firstColCollation, SubPlan::firstColType, SubPlan::firstColTypmod, get_first_col_type(), SubPlan::isInitPlan, lappend(), list_length(), list_make1_int, makeNode, SubPlan::parallel_safe, Param::paramid, 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 
)

Definition at line 3149 of file subselect.c.

3152{
3153 return generate_new_exec_param(root, resulttype,
3154 resulttypmod, resultcollation);
3155}
Param * generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation)
Definition: paramassign.c:727

References generate_new_exec_param(), and root.

Referenced by preprocess_minmax_aggregates().

◆ SS_process_ctes()

void SS_process_ctes ( PlannerInfo root)

Definition at line 883 of file subselect.c.

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

References SubPlan::args, Assert(), assign_special_exec_param(), RelOptInfo::cheapest_total_path, 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, 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 
)

Definition at line 2062 of file subselect.c.

2063{
2065
2066 context.root = root;
2067 context.isTopQual = isQual;
2068 return process_sublinks_mutator(expr, &context);
2069}
static Node * process_sublinks_mutator(Node *node, process_sublinks_context *context)
Definition: subselect.c:2072

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

Definition at line 2007 of file subselect.c.

2008{
2009 /* No setup needed for tree walk, so away we go */
2011}
static Node * replace_correlation_vars_mutator(Node *node, PlannerInfo *root)
Definition: subselect.c:2014

References replace_correlation_vars_mutator(), and root.

Referenced by preprocess_expression().