← Back to Overview

src/backend/optimizer/prep/prepjointree.c

Coverage: 0/0 lines (0.0%)
Total Lines
0
modified
Covered
0
0.0%
Uncovered
0
100.0%
키보드 네비게이션
pull_up_simple_subquery() lines 1331-1673
Modified Lines Coverage: 0/0 lines (0.0%)
LineHitsSourceCommit
1331 - pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, -
1332 - JoinExpr *lowest_outer_join, -
1333 - AppendRelInfo *containing_appendrel) -
1334 - { -
1335 - Query *parse = root->parse; -
1336 - int varno = ((RangeTblRef *) jtnode)->rtindex; -
1337 - Query *subquery; -
1338 - PlannerInfo *subroot; -
1339 - int rtoffset; -
1340 - pullup_replace_vars_context rvcontext; -
1341 - ListCell *lc; -
1342 - -
1343 - /* -
1344 - * Make a modifiable copy of the subquery to hack on, so that the RTE will -
1345 - * be left unchanged in case we decide below that we can't pull it up -
1346 - * after all. -
1347 - */ -
1348 - subquery = copyObject(rte->subquery); -
1349 - -
1350 - /* -
1351 - * Create a PlannerInfo data structure for this subquery. -
1352 - * -
1353 - * NOTE: the next few steps should match the first processing in -
1354 - * subquery_planner(). Can we refactor to avoid code duplication, or -
1355 - * would that just make things uglier? -
1356 - */ -
1357 - subroot = makeNode(PlannerInfo); -
1358 - subroot->parse = subquery; -
1359 - subroot->glob = root->glob; -
1360 - subroot->query_level = root->query_level; -
1361 - subroot->plan_name = root->plan_name; -
1362 - subroot->parent_root = root->parent_root; -
1363 - subroot->plan_params = NIL; -
1364 - subroot->outer_params = NULL; -
1365 - subroot->planner_cxt = CurrentMemoryContext; -
1366 - subroot->init_plans = NIL; -
1367 - subroot->cte_plan_ids = NIL; -
1368 - subroot->multiexpr_params = NIL; -
1369 - subroot->join_domains = NIL; -
1370 - subroot->eq_classes = NIL; -
1371 - subroot->ec_merging_done = false; -
1372 - subroot->last_rinfo_serial = 0; -
1373 - subroot->all_result_relids = NULL; -
1374 - subroot->leaf_result_relids = NULL; -
1375 - subroot->append_rel_list = NIL; -
1376 - subroot->row_identity_vars = NIL; -
1377 - subroot->rowMarks = NIL; -
1378 - memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels)); -
1379 - memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets)); -
1380 - subroot->processed_groupClause = NIL; -
1381 - subroot->processed_distinctClause = NIL; -
1382 - subroot->processed_tlist = NIL; -
1383 - subroot->update_colnos = NIL; -
1384 - subroot->grouping_map = NULL; -
1385 - subroot->minmax_aggs = NIL; -
1386 - subroot->qual_security_level = 0; -
1387 - subroot->placeholdersFrozen = false; -
1388 - subroot->hasRecursion = false; -
1389 - subroot->assumeReplanning = false; -
1390 - subroot->wt_param_id = -1; -
1391 - subroot->non_recursive_path = NULL; -
1392 - /* We don't currently need a top JoinDomain for the subroot */ -
1393 - -
1394 - /* No CTEs to worry about */ -
1395 - Assert(subquery->cteList == NIL); -
1396 - -
1397 - /* -
1398 - * Scan the rangetable for relation RTEs and retrieve the necessary -
1399 - * catalog information for each relation. Using this information, clear -
1400 - * the inh flag for any relation that has no children, collect not-null -
1401 - * attribute numbers for any relation that has column not-null -
1402 - * constraints, and expand virtual generated columns for any relation that -
1403 - * contains them. -
1404 - */ -
1405 - subquery = subroot->parse = preprocess_relation_rtes(subroot); -
1406 - -
1407 - /* -
1408 - * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so -
1409 - * that we don't need so many special cases to deal with that situation. -
1410 - */ -
1411 - replace_empty_jointree(subquery); -
1412 - -
1413 - /* -
1414 - * Pull up any SubLinks within the subquery's quals, so that we don't -
1415 - * leave unoptimized SubLinks behind. -
1416 - */ -
1417 - if (subquery->hasSubLinks) -
1418 - pull_up_sublinks(subroot); -
1419 - -
1420 - /* -
1421 - * Similarly, preprocess its function RTEs to inline any set-returning -
1422 - * functions in its rangetable. -
1423 - */ -
1424 - preprocess_function_rtes(subroot); -
1425 - -
1426 - /* -
1427 - * Recursively pull up the subquery's subqueries, so that -
1428 - * pull_up_subqueries' processing is complete for its jointree and -
1429 - * rangetable. -
1430 - * -
1431 - * Note: it's okay that the subquery's recursion starts with NULL for -
1432 - * containing-join info, even if we are within an outer join in the upper -
1433 - * query; the lower query starts with a clean slate for outer-join -
1434 - * semantics. Likewise, we needn't pass down appendrel state. -
1435 - */ -
1436 - pull_up_subqueries(subroot); -
1437 - -
1438 - /* -
1439 - * Now we must recheck whether the subquery is still simple enough to pull -
1440 - * up. If not, abandon processing it. -
1441 - * -
1442 - * We don't really need to recheck all the conditions involved, but it's -
1443 - * easier just to keep this "if" looking the same as the one in -
1444 - * pull_up_subqueries_recurse. -
1445 - */ -
1446 - if (is_simple_subquery(root, subquery, rte, lowest_outer_join) && -
1447 - (containing_appendrel == NULL || is_safe_append_member(subquery))) -
1448 - { -
1449 - /* good to go */ -
1450 - } -
1451 - else -
1452 - { -
1453 - /* -
1454 - * Give up, return unmodified RangeTblRef. -
1455 - * -
1456 - * Note: The work we just did will be redone when the subquery gets -
1457 - * planned on its own. Perhaps we could avoid that by storing the -
1458 - * modified subquery back into the rangetable, but I'm not gonna risk -
1459 - * it now. -
1460 - */ -
1461 - return jtnode; -
1462 - } -
1463 - -
1464 - /* -
1465 - * We must flatten any join alias Vars in the subquery's targetlist, -
1466 - * because pulling up the subquery's subqueries might have changed their -
1467 - * expansions into arbitrary expressions, which could affect -
1468 - * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers -
1469 - * are needed for tlist entries. (Likely it'd be better to do -
1470 - * flatten_join_alias_vars on the whole query tree at some earlier stage, -
1471 - * maybe even in the rewriter; but for now let's just fix this case here.) -
1472 - */ -
1473 - subquery->targetList = (List *) -
1474 - flatten_join_alias_vars(subroot, subroot->parse, -
1475 - (Node *) subquery->targetList); -
1476 - -
1477 - /* -
1478 - * Adjust level-0 varnos in subquery so that we can append its rangetable -
1479 - * to upper query's. We have to fix the subquery's append_rel_list as -
1480 - * well. -
1481 - */ -
1482 - rtoffset = list_length(parse->rtable); -
1483 - OffsetVarNodes((Node *) subquery, rtoffset, 0); -
1484 - OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0); -
1485 - -
1486 - /* -
1487 - * Upper-level vars in subquery are now one level closer to their parent -
1488 - * than before. -
1489 - */ -
1490 - IncrementVarSublevelsUp((Node *) subquery, -1, 1); -
1491 - IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1); -
1492 - -
1493 - /* -
1494 - * The subquery's targetlist items are now in the appropriate form to -
1495 - * insert into the top query, except that we may need to wrap them in -
1496 - * PlaceHolderVars. Set up required context data for pullup_replace_vars. -
1497 - * (Note that we should include the subquery's inner joins in relids, -
1498 - * since it may include join alias vars referencing them.) -
1499 - */ -
1500 - rvcontext.root = root; -
1501 - rvcontext.targetlist = subquery->targetList; -
1502 - rvcontext.target_rte = rte; -
1503 - rvcontext.result_relation = 0; -
1504 - if (rte->lateral) -
1505 - { -
1506 - rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree, -
1507 - true, true); -
1508 - rvcontext.nullinfo = get_nullingrels(parse); -
1509 - } -
1510 - else /* won't need these values */ -
1511 - { -
1512 - rvcontext.relids = NULL; -
1513 - rvcontext.nullinfo = NULL; -
1514 - } -
1515 - rvcontext.outer_hasSubLinks = &parse->hasSubLinks; -
1516 - rvcontext.varno = varno; -
1517 - /* this flag will be set below, if needed */ -
1518 - rvcontext.wrap_option = REPLACE_WRAP_NONE; -
1519 - /* initialize cache array with indexes 0 .. length(tlist) */ -
1520 - rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) * -
1521 - sizeof(Node *)); -
1522 - -
1523 - /* -
1524 - * If the parent query uses grouping sets, we need a PlaceHolderVar for -
1525 - * each expression of the subquery's targetlist items. This ensures that -
1526 - * expressions retain their separate identity so that they will match -
1527 - * grouping set columns when appropriate. (It'd be sufficient to wrap -
1528 - * values used in grouping set columns, and do so only in non-aggregated -
1529 - * portions of the tlist and havingQual, but that would require a lot of -
1530 - * infrastructure that pullup_replace_vars hasn't currently got.) -
1531 - */ -
1532 - if (parse->groupingSets) -
1533 - rvcontext.wrap_option = REPLACE_WRAP_ALL; -
1534 - -
1535 - /* -
1536 - * Replace all of the top query's references to the subquery's outputs -
1537 - * with copies of the adjusted subtlist items, being careful not to -
1538 - * replace any of the jointree structure. -
1539 - */ -
1540 - perform_pullup_replace_vars(root, &rvcontext, -
1541 - containing_appendrel); -
1542 - -
1543 - /* -
1544 - * If the subquery had a LATERAL marker, propagate that to any of its -
1545 - * child RTEs that could possibly now contain lateral cross-references. -
1546 - * The children might or might not contain any actual lateral -
1547 - * cross-references, but we have to mark the pulled-up child RTEs so that -
1548 - * later planner stages will check for such. -
1549 - */ -
1550 - if (rte->lateral) -
1551 - { -
1552 - foreach(lc, subquery->rtable) -
1553 - { -
1554 - RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc); -
1555 - -
1556 - switch (child_rte->rtekind) -
1557 - { -
1558 - case RTE_RELATION: -
1559 - if (child_rte->tablesample) -
1560 - child_rte->lateral = true; -
1561 - break; -
1562 - case RTE_SUBQUERY: -
1563 - case RTE_FUNCTION: -
1564 - case RTE_VALUES: -
1565 - case RTE_TABLEFUNC: -
1566 - child_rte->lateral = true; -
1567 - break; -
1568 - case RTE_JOIN: -
1569 - case RTE_CTE: -
1570 - case RTE_NAMEDTUPLESTORE: -
1571 - case RTE_RESULT: -
1572 - case RTE_GROUP: -
1573 - /* these can't contain any lateral references */ -
1574 - break; -
1575 - case RTE_GRAPH_TABLE: 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
1576 - /* shouldn't happen here */ 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
1577 - Assert(false); 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
1578 - break; 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
1579 - } -
1580 - } -
1581 - } -
1582 - -
1583 - /* -
1584 - * Now append the adjusted rtable entries and their perminfos to upper -
1585 - * query. (We hold off until after fixing the upper rtable entries; no -
1586 - * point in running that code on the subquery ones too.) -
1587 - */ -
1588 - CombineRangeTables(&parse->rtable, &parse->rteperminfos, -
1589 - subquery->rtable, subquery->rteperminfos); -
1590 - -
1591 - /* -
1592 - * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already -
1593 - * adjusted the marker rtindexes, so just concat the lists.) -
1594 - */ -
1595 - parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks); -
1596 - -
1597 - /* -
1598 - * We also have to fix the relid sets of any PlaceHolderVar nodes in the -
1599 - * parent query. (This could perhaps be done by pullup_replace_vars(), -
1600 - * but it seems cleaner to use two passes.) Note in particular that any -
1601 - * PlaceHolderVar nodes just created by pullup_replace_vars() will be -
1602 - * adjusted, so having created them with the subquery's varno is correct. -
1603 - * -
1604 - * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We -
1605 - * already checked that this won't require introducing multiple subrelids -
1606 - * into the single-slot AppendRelInfo structs. -
1607 - */ -
1608 - if (root->glob->lastPHId != 0 || root->append_rel_list) -
1609 - { -
1610 - Relids subrelids; -
1611 - -
1612 - subrelids = get_relids_in_jointree((Node *) subquery->jointree, -
1613 - true, false); -
1614 - if (root->glob->lastPHId != 0) -
1615 - substitute_phv_relids((Node *) parse, varno, subrelids); -
1616 - fix_append_rel_relids(root, varno, subrelids); -
1617 - } -
1618 - -
1619 - /* -
1620 - * And now add subquery's AppendRelInfos to our list. -
1621 - */ -
1622 - root->append_rel_list = list_concat(root->append_rel_list, -
1623 - subroot->append_rel_list); -
1624 - -
1625 - /* -
1626 - * We don't have to do the equivalent bookkeeping for outer-join info, -
1627 - * because that hasn't been set up yet. placeholder_list likewise. -
1628 - */ -
1629 - Assert(root->join_info_list == NIL); -
1630 - Assert(subroot->join_info_list == NIL); -
1631 - Assert(root->placeholder_list == NIL); -
1632 - Assert(subroot->placeholder_list == NIL); -
1633 - -
1634 - /* -
1635 - * We no longer need the RTE's copy of the subquery's query tree. Getting -
1636 - * rid of it saves nothing in particular so far as this level of query is -
1637 - * concerned; but if this query level is in turn pulled up into a parent, -
1638 - * we'd waste cycles copying the now-unused query tree. -
1639 - */ -
1640 - rte->subquery = NULL; -
1641 - -
1642 - /* -
1643 - * Miscellaneous housekeeping. -
1644 - * -
1645 - * Although replace_rte_variables() faithfully updated parse->hasSubLinks -
1646 - * if it copied any SubLinks out of the subquery's targetlist, we still -
1647 - * could have SubLinks added to the query in the expressions of FUNCTION -
1648 - * and VALUES RTEs copied up from the subquery. So it's necessary to copy -
1649 - * subquery->hasSubLinks anyway. Perhaps this can be improved someday. -
1650 - */ -
1651 - parse->hasSubLinks |= subquery->hasSubLinks; -
1652 - -
1653 - /* If subquery had any RLS conditions, now main query does too */ -
1654 - parse->hasRowSecurity |= subquery->hasRowSecurity; -
1655 - -
1656 - /* -
1657 - * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or -
1658 - * hasTargetSRFs, so no work needed on those flags -
1659 - */ -
1660 - -
1661 - /* -
1662 - * Return the adjusted subquery jointree to replace the RangeTblRef entry -
1663 - * in parent's jointree; or, if the FromExpr is degenerate, just return -
1664 - * its single member. -
1665 - */ -
1666 - Assert(IsA(subquery->jointree, FromExpr)); -
1667 - Assert(subquery->jointree->fromlist != NIL); -
1668 - if (subquery->jointree->quals == NULL && -
1669 - list_length(subquery->jointree->fromlist) == 1) -
1670 - return (Node *) linitial(subquery->jointree->fromlist); -
1671 - -
1672 - return (Node *) subquery->jointree; -
1673 - } -
replace_vars_in_jointree() lines 2584-2686
Modified Lines Coverage: 0/0 lines (0.0%)
LineHitsSourceCommit
2584 - replace_vars_in_jointree(Node *jtnode, -
2585 - pullup_replace_vars_context *context) -
2586 - { -
2587 - if (jtnode == NULL) -
2588 - return; -
2589 - if (IsA(jtnode, RangeTblRef)) -
2590 - { -
2591 - /* -
2592 - * If the RangeTblRef refers to a LATERAL subquery (that isn't the -
2593 - * same subquery we're pulling up), it might contain references to the -
2594 - * target subquery, which we must replace. We drive this from the -
2595 - * jointree scan, rather than a scan of the rtable, so that we can -
2596 - * avoid processing no-longer-referenced RTEs. -
2597 - */ -
2598 - int varno = ((RangeTblRef *) jtnode)->rtindex; -
2599 - -
2600 - if (varno != context->varno) /* ignore target subquery itself */ -
2601 - { -
2602 - RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable); -
2603 - -
2604 - Assert(rte != context->target_rte); -
2605 - if (rte->lateral) -
2606 - { -
2607 - switch (rte->rtekind) -
2608 - { -
2609 - case RTE_RELATION: -
2610 - /* shouldn't be marked LATERAL unless tablesample */ -
2611 - Assert(rte->tablesample); -
2612 - rte->tablesample = (TableSampleClause *) -
2613 - pullup_replace_vars((Node *) rte->tablesample, -
2614 - context); -
2615 - break; -
2616 - case RTE_SUBQUERY: -
2617 - rte->subquery = -
2618 - pullup_replace_vars_subquery(rte->subquery, -
2619 - context); -
2620 - break; -
2621 - case RTE_FUNCTION: -
2622 - rte->functions = (List *) -
2623 - pullup_replace_vars((Node *) rte->functions, -
2624 - context); -
2625 - break; -
2626 - case RTE_TABLEFUNC: -
2627 - rte->tablefunc = (TableFunc *) -
2628 - pullup_replace_vars((Node *) rte->tablefunc, -
2629 - context); -
2630 - break; -
2631 - case RTE_VALUES: -
2632 - rte->values_lists = (List *) -
2633 - pullup_replace_vars((Node *) rte->values_lists, -
2634 - context); -
2635 - break; -
2636 - case RTE_JOIN: -
2637 - case RTE_CTE: -
2638 - case RTE_NAMEDTUPLESTORE: -
2639 - case RTE_RESULT: -
2640 - case RTE_GROUP: -
2641 - /* these shouldn't be marked LATERAL */ -
2642 - Assert(false); -
2643 - break; -
2644 - case RTE_GRAPH_TABLE: 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2645 - /* shouldn't happen here */ 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2646 - Assert(false); 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2647 - break; 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2648 - } -
2649 - } -
2650 - } -
2651 - } -
2652 - else if (IsA(jtnode, FromExpr)) -
2653 - { -
2654 - FromExpr *f = (FromExpr *) jtnode; -
2655 - ListCell *l; -
2656 - -
2657 - foreach(l, f->fromlist) -
2658 - replace_vars_in_jointree(lfirst(l), context); -
2659 - f->quals = pullup_replace_vars(f->quals, context); -
2660 - } -
2661 - else if (IsA(jtnode, JoinExpr)) -
2662 - { -
2663 - JoinExpr *j = (JoinExpr *) jtnode; -
2664 - ReplaceWrapOption save_wrap_option = context->wrap_option; -
2665 - -
2666 - replace_vars_in_jointree(j->larg, context); -
2667 - replace_vars_in_jointree(j->rarg, context); -
2668 - -
2669 - /* -
2670 - * Use PHVs within the join quals of a full join for variable-free -
2671 - * expressions. Otherwise, we cannot identify which side of the join -
2672 - * a pulled-up variable-free expression came from, which can lead to -
2673 - * failure to make a plan at all because none of the quals appear to -
2674 - * be mergeable or hashable conditions. -
2675 - */ -
2676 - if (j->jointype == JOIN_FULL) -
2677 - context->wrap_option = REPLACE_WRAP_VARFREE; -
2678 - -
2679 - j->quals = pullup_replace_vars(j->quals, context); -
2680 - -
2681 - context->wrap_option = save_wrap_option; -
2682 - } -
2683 - else -
2684 - elog(ERROR, "unrecognized node type: %d", -
2685 - (int) nodeTag(jtnode)); -
2686 - } -