PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
prepjointree.c File Reference
Include dependency graph for prepjointree.c:

Go to the source code of this file.

Data Structures

struct  pullup_replace_vars_context
 
struct  reduce_outer_joins_state
 
struct  substitute_multiple_relids_context
 

Typedefs

typedef struct
pullup_replace_vars_context 
pullup_replace_vars_context
 
typedef struct
reduce_outer_joins_state 
reduce_outer_joins_state
 

Functions

static Nodepull_up_sublinks_jointree_recurse (PlannerInfo *root, Node *jtnode, Relids *relids)
 
static Nodepull_up_sublinks_qual_recurse (PlannerInfo *root, Node *node, Node **jtlink1, Relids available_rels1, Node **jtlink2, Relids available_rels2)
 
static Nodepull_up_subqueries_recurse (PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel, bool deletion_ok)
 
static Nodepull_up_simple_subquery (PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel, bool deletion_ok)
 
static Nodepull_up_simple_union_all (PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
 
static void pull_up_union_leaf_queries (Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
 
static void make_setop_translation_list (Query *query, Index newvarno, List **translated_vars)
 
static bool is_simple_subquery (Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join, bool deletion_ok)
 
static Nodepull_up_simple_values (PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
 
static bool is_simple_values (PlannerInfo *root, RangeTblEntry *rte, bool deletion_ok)
 
static bool is_simple_union_all (Query *subquery)
 
static bool is_simple_union_all_recurse (Node *setOp, Query *setOpQuery, List *colTypes)
 
static bool is_safe_append_member (Query *subquery)
 
static bool jointree_contains_lateral_outer_refs (Node *jtnode, bool restricted, Relids safe_upper_varnos)
 
static void replace_vars_in_jointree (Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
 
static Nodepullup_replace_vars (Node *expr, pullup_replace_vars_context *context)
 
static Nodepullup_replace_vars_callback (Var *var, replace_rte_variables_context *context)
 
static Querypullup_replace_vars_subquery (Query *query, pullup_replace_vars_context *context)
 
static Nodepull_up_subqueries_cleanup (Node *jtnode)
 
static reduce_outer_joins_statereduce_outer_joins_pass1 (Node *jtnode)
 
static void reduce_outer_joins_pass2 (Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *nonnullable_vars, List *forced_null_vars)
 
static void substitute_multiple_relids (Node *node, int varno, Relids subrelids)
 
static void fix_append_rel_relids (List *append_rel_list, int varno, Relids subrelids)
 
static Nodefind_jointree_node_for_rel (Node *jtnode, int relid)
 
void pull_up_sublinks (PlannerInfo *root)
 
void inline_set_returning_functions (PlannerInfo *root)
 
void pull_up_subqueries (PlannerInfo *root)
 
void flatten_simple_union_all (PlannerInfo *root)
 
void reduce_outer_joins (PlannerInfo *root)
 
static bool substitute_multiple_relids_walker (Node *node, substitute_multiple_relids_context *context)
 
Relids get_relids_in_jointree (Node *jtnode, bool include_joins)
 
Relids get_relids_for_join (PlannerInfo *root, int joinrelid)
 

Typedef Documentation

Function Documentation

static Node * find_jointree_node_for_rel ( Node jtnode,
int  relid 
)
static

Definition at line 3004 of file prepjointree.c.

References elog, ERROR, FromExpr::fromlist, IsA, JoinExpr::larg, lfirst, nodeTag, JoinExpr::rarg, and JoinExpr::rtindex.

Referenced by get_relids_for_join().

3005 {
3006  if (jtnode == NULL)
3007  return NULL;
3008  if (IsA(jtnode, RangeTblRef))
3009  {
3010  int varno = ((RangeTblRef *) jtnode)->rtindex;
3011 
3012  if (relid == varno)
3013  return jtnode;
3014  }
3015  else if (IsA(jtnode, FromExpr))
3016  {
3017  FromExpr *f = (FromExpr *) jtnode;
3018  ListCell *l;
3019 
3020  foreach(l, f->fromlist)
3021  {
3022  jtnode = find_jointree_node_for_rel(lfirst(l), relid);
3023  if (jtnode)
3024  return jtnode;
3025  }
3026  }
3027  else if (IsA(jtnode, JoinExpr))
3028  {
3029  JoinExpr *j = (JoinExpr *) jtnode;
3030 
3031  if (relid == j->rtindex)
3032  return jtnode;
3033  jtnode = find_jointree_node_for_rel(j->larg, relid);
3034  if (jtnode)
3035  return jtnode;
3036  jtnode = find_jointree_node_for_rel(j->rarg, relid);
3037  if (jtnode)
3038  return jtnode;
3039  }
3040  else
3041  elog(ERROR, "unrecognized node type: %d",
3042  (int) nodeTag(jtnode));
3043  return NULL;
3044 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
List * fromlist
Definition: primnodes.h:1471
Node * larg
Definition: primnodes.h:1451
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:43
Node * rarg
Definition: primnodes.h:1452
#define lfirst(lc)
Definition: pg_list.h:106
#define nodeTag(nodeptr)
Definition: nodes.h:515
#define elog
Definition: elog.h:219
int rtindex
Definition: primnodes.h:1456
static void fix_append_rel_relids ( List append_rel_list,
int  varno,
Relids  subrelids 
)
static

Definition at line 2905 of file prepjointree.c.

References Assert, bms_singleton_member(), AppendRelInfo::child_relid, lfirst, AppendRelInfo::parent_relid, substitute_multiple_relids(), and AppendRelInfo::translated_vars.

Referenced by pull_up_simple_subquery().

2906 {
2907  ListCell *l;
2908  int subvarno = -1;
2909 
2910  /*
2911  * We only want to extract the member relid once, but we mustn't fail
2912  * immediately if there are multiple members; it could be that none of the
2913  * AppendRelInfo nodes refer to it. So compute it on first use. Note that
2914  * bms_singleton_member will complain if set is not singleton.
2915  */
2916  foreach(l, append_rel_list)
2917  {
2918  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
2919 
2920  /* The parent_relid shouldn't ever be a pullup target */
2921  Assert(appinfo->parent_relid != varno);
2922 
2923  if (appinfo->child_relid == varno)
2924  {
2925  if (subvarno < 0)
2926  subvarno = bms_singleton_member(subrelids);
2927  appinfo->child_relid = subvarno;
2928  }
2929 
2930  /* Also finish fixups for its translated vars */
2932  varno, subrelids);
2933  }
2934 }
Definition: nodes.h:510
List * translated_vars
Definition: relation.h:2093
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:526
static void substitute_multiple_relids(Node *node, int varno, Relids subrelids)
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
Index child_relid
Definition: relation.h:2066
Index parent_relid
Definition: relation.h:2065
void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2321 of file prepjointree.c.

References Assert, castNode, SetOperationStmt::colTypes, copyObject, FromExpr::fromlist, PlannerInfo::hasRecursion, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, Query::jointree, lappend(), SetOperationStmt::larg, list_length(), list_make1, makeNode, NIL, parse(), PlannerInfo::parse, pull_up_union_leaf_queries(), rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.

Referenced by subquery_planner().

2322 {
2323  Query *parse = root->parse;
2324  SetOperationStmt *topop;
2325  Node *leftmostjtnode;
2326  int leftmostRTI;
2327  RangeTblEntry *leftmostRTE;
2328  int childRTI;
2329  RangeTblEntry *childRTE;
2330  RangeTblRef *rtr;
2331 
2332  /* Shouldn't be called unless query has setops */
2333  topop = castNode(SetOperationStmt, parse->setOperations);
2334  Assert(topop);
2335 
2336  /* Can't optimize away a recursive UNION */
2337  if (root->hasRecursion)
2338  return;
2339 
2340  /*
2341  * Recursively check the tree of set operations. If not all UNION ALL
2342  * with identical column types, punt.
2343  */
2344  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2345  return;
2346 
2347  /*
2348  * Locate the leftmost leaf query in the setops tree. The upper query's
2349  * Vars all refer to this RTE (see transformSetOperationStmt).
2350  */
2351  leftmostjtnode = topop->larg;
2352  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2353  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2354  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2355  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2356  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2357  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2358 
2359  /*
2360  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2361  * will represent the leftmost leaf query in its capacity as a member of
2362  * the appendrel. The original will represent the appendrel as a whole.
2363  * (We must do things this way because the upper query's Vars have to be
2364  * seen as referring to the whole appendrel.)
2365  */
2366  childRTE = copyObject(leftmostRTE);
2367  parse->rtable = lappend(parse->rtable, childRTE);
2368  childRTI = list_length(parse->rtable);
2369 
2370  /* Modify the setops tree to reference the child copy */
2371  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2372 
2373  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2374  leftmostRTE->inh = true;
2375 
2376  /*
2377  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2378  * Query of a setops tree should have had an empty FromClause initially.
2379  */
2380  rtr = makeNode(RangeTblRef);
2381  rtr->rtindex = leftmostRTI;
2382  Assert(parse->jointree->fromlist == NIL);
2383  parse->jointree->fromlist = list_make1(rtr);
2384 
2385  /*
2386  * Now pretend the query has no setops. We must do this before trying to
2387  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2388  */
2389  parse->setOperations = NULL;
2390 
2391  /*
2392  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2393  * leaf queries of the UNION ALL. (We must do that now because they
2394  * weren't previously referenced by the jointree, and so were missed by
2395  * the main invocation of pull_up_subqueries.)
2396  */
2397  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2398 }
#define NIL
Definition: pg_list.h:69
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Query * parse
Definition: relation.h:155
FromExpr * jointree
Definition: parsenodes.h:136
#define castNode(_type_, nodeptr)
Definition: nodes.h:579
Definition: nodes.h:510
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * fromlist
Definition: primnodes.h:1471
bool hasRecursion
Definition: relation.h:308
#define list_make1(x1)
Definition: pg_list.h:139
List * rtable
Definition: parsenodes.h:135
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:128
#define makeNode(_type_)
Definition: nodes.h:558
#define Assert(condition)
Definition: c.h:681
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:945
Node * setOperations
Definition: parsenodes.h:163
#define copyObject(obj)
Definition: nodes.h:623
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649
Relids get_relids_for_join ( PlannerInfo root,
int  joinrelid 
)

Definition at line 2987 of file prepjointree.c.

References elog, ERROR, find_jointree_node_for_rel(), get_relids_in_jointree(), Query::jointree, and PlannerInfo::parse.

Referenced by alias_relid_set().

2988 {
2989  Node *jtnode;
2990 
2991  jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,
2992  joinrelid);
2993  if (!jtnode)
2994  elog(ERROR, "could not find join node %d", joinrelid);
2995  return get_relids_in_jointree(jtnode, false);
2996 }
Query * parse
Definition: relation.h:155
FromExpr * jointree
Definition: parsenodes.h:136
Definition: nodes.h:510
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:43
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define elog
Definition: elog.h:219
Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 2943 of file prepjointree.c.

References bms_add_member(), bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, get_relids_in_jointree(), IsA, JoinExpr::larg, lfirst, nodeTag, JoinExpr::rarg, and JoinExpr::rtindex.

Referenced by distribute_qual_to_rels(), get_relids_for_join(), get_relids_in_jointree(), is_simple_subquery(), preprocess_rowmarks(), and pull_up_simple_subquery().

2944 {
2945  Relids result = NULL;
2946 
2947  if (jtnode == NULL)
2948  return result;
2949  if (IsA(jtnode, RangeTblRef))
2950  {
2951  int varno = ((RangeTblRef *) jtnode)->rtindex;
2952 
2953  result = bms_make_singleton(varno);
2954  }
2955  else if (IsA(jtnode, FromExpr))
2956  {
2957  FromExpr *f = (FromExpr *) jtnode;
2958  ListCell *l;
2959 
2960  foreach(l, f->fromlist)
2961  {
2962  result = bms_join(result,
2964  include_joins));
2965  }
2966  }
2967  else if (IsA(jtnode, JoinExpr))
2968  {
2969  JoinExpr *j = (JoinExpr *) jtnode;
2970 
2971  result = get_relids_in_jointree(j->larg, include_joins);
2972  result = bms_join(result,
2973  get_relids_in_jointree(j->rarg, include_joins));
2974  if (include_joins && j->rtindex)
2975  result = bms_add_member(result, j->rtindex);
2976  }
2977  else
2978  elog(ERROR, "unrecognized node type: %d",
2979  (int) nodeTag(jtnode));
2980  return result;
2981 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
List * fromlist
Definition: primnodes.h:1471
Node * larg
Definition: primnodes.h:1451
#define ERROR
Definition: elog.h:43
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:838
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:179
Node * rarg
Definition: primnodes.h:1452
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define nodeTag(nodeptr)
Definition: nodes.h:515
#define elog
Definition: elog.h:219
int rtindex
Definition: primnodes.h:1456
void inline_set_returning_functions ( PlannerInfo root)

Definition at line 573 of file prepjointree.c.

References RangeTblEntry::functions, inline_set_returning_function(), lfirst, NIL, PlannerInfo::parse, Query::rtable, RTE_FUNCTION, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by pull_up_simple_subquery(), and subquery_planner().

574 {
575  ListCell *rt;
576 
577  foreach(rt, root->parse->rtable)
578  {
579  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
580 
581  if (rte->rtekind == RTE_FUNCTION)
582  {
583  Query *funcquery;
584 
585  /* Check safety of expansion, and expand if possible */
586  funcquery = inline_set_returning_function(root, rte);
587  if (funcquery)
588  {
589  /* Successful expansion, replace the rtable entry */
590  rte->rtekind = RTE_SUBQUERY;
591  rte->subquery = funcquery;
592  rte->functions = NIL;
593  }
594  }
595  }
596 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:155
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4806
List * rtable
Definition: parsenodes.h:135
#define lfirst(lc)
Definition: pg_list.h:106
List * functions
Definition: parsenodes.h:999
RTEKind rtekind
Definition: parsenodes.h:945
Query * subquery
Definition: parsenodes.h:968
static bool is_safe_append_member ( Query subquery)
static

Definition at line 1811 of file prepjointree.c.

References FromExpr::fromlist, IsA, Query::jointree, linitial, list_length(), and FromExpr::quals.

Referenced by pull_up_simple_subquery(), and pull_up_subqueries_recurse().

1812 {
1813  FromExpr *jtnode;
1814 
1815  /*
1816  * It's only safe to pull up the child if its jointree contains exactly
1817  * one RTE, else the AppendRelInfo data structure breaks. The one base RTE
1818  * could be buried in several levels of FromExpr, however.
1819  *
1820  * Also, the child can't have any WHERE quals because there's no place to
1821  * put them in an appendrel. (This is a bit annoying...) If we didn't
1822  * need to check this, we'd just test whether get_relids_in_jointree()
1823  * yields a singleton set, to be more consistent with the coding of
1824  * fix_append_rel_relids().
1825  */
1826  jtnode = subquery->jointree;
1827  while (IsA(jtnode, FromExpr))
1828  {
1829  if (jtnode->quals != NULL)
1830  return false;
1831  if (list_length(jtnode->fromlist) != 1)
1832  return false;
1833  jtnode = linitial(jtnode->fromlist);
1834  }
1835  if (!IsA(jtnode, RangeTblRef))
1836  return false;
1837 
1838  return true;
1839 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
FromExpr * jointree
Definition: parsenodes.h:136
List * fromlist
Definition: primnodes.h:1471
Node * quals
Definition: primnodes.h:1472
#define linitial(l)
Definition: pg_list.h:111
static int list_length(const List *l)
Definition: pg_list.h:89
static bool is_simple_subquery ( Query subquery,
RangeTblEntry rte,
JoinExpr lowest_outer_join,
bool  deletion_ok 
)
static

Definition at line 1407 of file prepjointree.c.

References bms_is_subset(), CMD_SELECT, Query::commandType, contain_volatile_functions(), Query::cteList, Query::distinctClause, elog, ERROR, FromExpr::fromlist, get_relids_in_jointree(), Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasForUpdate, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, jointree_contains_lateral_outer_refs(), RangeTblEntry::lateral, Query::limitCount, Query::limitOffset, NIL, pull_varnos_of_level(), FromExpr::quals, RangeTblEntry::security_barrier, Query::setOperations, Query::sortClause, and Query::targetList.

Referenced by pull_up_simple_subquery(), and pull_up_subqueries_recurse().

1410 {
1411  /*
1412  * Let's just make sure it's a valid subselect ...
1413  */
1414  if (!IsA(subquery, Query) ||
1415  subquery->commandType != CMD_SELECT)
1416  elog(ERROR, "subquery is bogus");
1417 
1418  /*
1419  * Can't currently pull up a query with setops (unless it's simple UNION
1420  * ALL, which is handled by a different code path). Maybe after querytree
1421  * redesign...
1422  */
1423  if (subquery->setOperations)
1424  return false;
1425 
1426  /*
1427  * Can't pull up a subquery involving grouping, aggregation, SRFs,
1428  * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later)
1429  *
1430  * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE
1431  * clauses, because pullup would cause the locking to occur semantically
1432  * higher than it should. Implicit FOR UPDATE/SHARE is okay because in
1433  * that case the locking was originally declared in the upper query
1434  * anyway.
1435  */
1436  if (subquery->hasAggs ||
1437  subquery->hasWindowFuncs ||
1438  subquery->hasTargetSRFs ||
1439  subquery->groupClause ||
1440  subquery->groupingSets ||
1441  subquery->havingQual ||
1442  subquery->sortClause ||
1443  subquery->distinctClause ||
1444  subquery->limitOffset ||
1445  subquery->limitCount ||
1446  subquery->hasForUpdate ||
1447  subquery->cteList)
1448  return false;
1449 
1450  /*
1451  * Don't pull up if the RTE represents a security-barrier view; we
1452  * couldn't prevent information leakage once the RTE's Vars are scattered
1453  * about in the upper query.
1454  */
1455  if (rte->security_barrier)
1456  return false;
1457 
1458  /*
1459  * Don't pull up a subquery with an empty jointree, unless it has no quals
1460  * and deletion_ok is TRUE and we're not underneath an outer join.
1461  *
1462  * query_planner() will correctly generate a Result plan for a jointree
1463  * that's totally empty, but we can't cope with an empty FromExpr
1464  * appearing lower down in a jointree: we identify join rels via baserelid
1465  * sets, so we couldn't distinguish a join containing such a FromExpr from
1466  * one without it. We can only handle such cases if the place where the
1467  * subquery is linked is a FromExpr or inner JOIN that would still be
1468  * nonempty after removal of the subquery, so that it's still identifiable
1469  * via its contained baserelids. Safe contexts are signaled by
1470  * deletion_ok.
1471  *
1472  * But even in a safe context, we must keep the subquery if it has any
1473  * quals, because it's unclear where to put them in the upper query.
1474  *
1475  * Also, we must forbid pullup if such a subquery is underneath an outer
1476  * join, because then we might need to wrap its output columns with
1477  * PlaceHolderVars, and the PHVs would then have empty relid sets meaning
1478  * we couldn't tell where to evaluate them. (This test is separate from
1479  * the deletion_ok flag for possible future expansion: deletion_ok tells
1480  * whether the immediate parent site in the jointree could cope, not
1481  * whether we'd have PHV issues. It's possible this restriction could be
1482  * fixed by letting the PHVs use the relids of the parent jointree item,
1483  * but that complication is for another day.)
1484  *
1485  * Note that deletion of a subquery is also dependent on the check below
1486  * that its targetlist contains no set-returning functions. Deletion from
1487  * a FROM list or inner JOIN is okay only if the subquery must return
1488  * exactly one row.
1489  */
1490  if (subquery->jointree->fromlist == NIL &&
1491  (subquery->jointree->quals != NULL ||
1492  !deletion_ok ||
1493  lowest_outer_join != NULL))
1494  return false;
1495 
1496  /*
1497  * If the subquery is LATERAL, check for pullup restrictions from that.
1498  */
1499  if (rte->lateral)
1500  {
1501  bool restricted;
1502  Relids safe_upper_varnos;
1503 
1504  /*
1505  * The subquery's WHERE and JOIN/ON quals mustn't contain any lateral
1506  * references to rels outside a higher outer join (including the case
1507  * where the outer join is within the subquery itself). In such a
1508  * case, pulling up would result in a situation where we need to
1509  * postpone quals from below an outer join to above it, which is
1510  * probably completely wrong and in any case is a complication that
1511  * doesn't seem worth addressing at the moment.
1512  */
1513  if (lowest_outer_join != NULL)
1514  {
1515  restricted = true;
1516  safe_upper_varnos = get_relids_in_jointree((Node *) lowest_outer_join,
1517  true);
1518  }
1519  else
1520  {
1521  restricted = false;
1522  safe_upper_varnos = NULL; /* doesn't matter */
1523  }
1524 
1526  restricted, safe_upper_varnos))
1527  return false;
1528 
1529  /*
1530  * If there's an outer join above the LATERAL subquery, also disallow
1531  * pullup if the subquery's targetlist has any references to rels
1532  * outside the outer join, since these might get pulled into quals
1533  * above the subquery (but in or below the outer join) and then lead
1534  * to qual-postponement issues similar to the case checked for above.
1535  * (We wouldn't need to prevent pullup if no such references appear in
1536  * outer-query quals, but we don't have enough info here to check
1537  * that. Also, maybe this restriction could be removed if we forced
1538  * such refs to be wrapped in PlaceHolderVars, even when they're below
1539  * the nearest outer join? But it's a pretty hokey usage, so not
1540  * clear this is worth sweating over.)
1541  */
1542  if (lowest_outer_join != NULL)
1543  {
1544  Relids lvarnos = pull_varnos_of_level((Node *) subquery->targetList, 1);
1545 
1546  if (!bms_is_subset(lvarnos, safe_upper_varnos))
1547  return false;
1548  }
1549  }
1550 
1551  /*
1552  * Don't pull up a subquery that has any volatile functions in its
1553  * targetlist. Otherwise we might introduce multiple evaluations of these
1554  * functions, if they get copied to multiple places in the upper query,
1555  * leading to surprising results. (Note: the PlaceHolderVar mechanism
1556  * doesn't quite guarantee single evaluation; else we could pull up anyway
1557  * and just wrap such items in PlaceHolderVars ...)
1558  */
1559  if (contain_volatile_functions((Node *) subquery->targetList))
1560  return false;
1561 
1562  return true;
1563 }
Node * limitOffset
Definition: parsenodes.h:158
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
List * sortClause
Definition: parsenodes.h:156
FromExpr * jointree
Definition: parsenodes.h:136
bool hasAggs
Definition: parsenodes.h:123
List * groupingSets
Definition: parsenodes.h:148
Definition: nodes.h:510
List * fromlist
Definition: primnodes.h:1471
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:957
Node * quals
Definition: primnodes.h:1472
List * targetList
Definition: parsenodes.h:138
List * distinctClause
Definition: parsenodes.h:154
#define ERROR
Definition: elog.h:43
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
Node * limitCount
Definition: parsenodes.h:159
static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, Relids safe_upper_varnos)
bool security_barrier
Definition: parsenodes.h:969
CmdType commandType
Definition: parsenodes.h:110
bool hasTargetSRFs
Definition: parsenodes.h:125
bool hasWindowFuncs
Definition: parsenodes.h:124
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
List * groupClause
Definition: parsenodes.h:146
bool hasForUpdate
Definition: parsenodes.h:130
#define elog
Definition: elog.h:219
Node * havingQual
Definition: parsenodes.h:150
Relids pull_varnos_of_level(Node *node, int levelsup)
Definition: var.c:120
static bool is_simple_union_all ( Query subquery)
static

Definition at line 1743 of file prepjointree.c.

References castNode, CMD_SELECT, SetOperationStmt::colTypes, Query::commandType, Query::cteList, elog, ERROR, is_simple_union_all_recurse(), IsA, Query::limitCount, Query::limitOffset, Query::rowMarks, Query::setOperations, and Query::sortClause.

Referenced by pull_up_subqueries_recurse().

1744 {
1745  SetOperationStmt *topop;
1746 
1747  /* Let's just make sure it's a valid subselect ... */
1748  if (!IsA(subquery, Query) ||
1749  subquery->commandType != CMD_SELECT)
1750  elog(ERROR, "subquery is bogus");
1751 
1752  /* Is it a set-operation query at all? */
1753  topop = castNode(SetOperationStmt, subquery->setOperations);
1754  if (!topop)
1755  return false;
1756 
1757  /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
1758  if (subquery->sortClause ||
1759  subquery->limitOffset ||
1760  subquery->limitCount ||
1761  subquery->rowMarks ||
1762  subquery->cteList)
1763  return false;
1764 
1765  /* Recursively check the tree of set operations */
1766  return is_simple_union_all_recurse((Node *) topop, subquery,
1767  topop->colTypes);
1768 }
Node * limitOffset
Definition: parsenodes.h:158
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
List * sortClause
Definition: parsenodes.h:156
#define castNode(_type_, nodeptr)
Definition: nodes.h:579
Definition: nodes.h:510
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * rowMarks
Definition: parsenodes.h:161
#define ERROR
Definition: elog.h:43
Node * limitCount
Definition: parsenodes.h:159
CmdType commandType
Definition: parsenodes.h:110
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
#define elog
Definition: elog.h:219
static bool is_simple_union_all_recurse ( Node setOp,
Query setOpQuery,
List colTypes 
)
static

Definition at line 1771 of file prepjointree.c.

References SetOperationStmt::all, Assert, elog, ERROR, IsA, SetOperationStmt::larg, nodeTag, SetOperationStmt::op, SetOperationStmt::rarg, rt_fetch, Query::rtable, RangeTblRef::rtindex, SETOP_UNION, RangeTblEntry::subquery, Query::targetList, and tlist_same_datatypes().

Referenced by flatten_simple_union_all(), and is_simple_union_all().

1772 {
1773  if (IsA(setOp, RangeTblRef))
1774  {
1775  RangeTblRef *rtr = (RangeTblRef *) setOp;
1776  RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
1777  Query *subquery = rte->subquery;
1778 
1779  Assert(subquery != NULL);
1780 
1781  /* Leaf nodes are OK if they match the toplevel column types */
1782  /* We don't have to compare typmods or collations here */
1783  return tlist_same_datatypes(subquery->targetList, colTypes, true);
1784  }
1785  else if (IsA(setOp, SetOperationStmt))
1786  {
1787  SetOperationStmt *op = (SetOperationStmt *) setOp;
1788 
1789  /* Must be UNION ALL */
1790  if (op->op != SETOP_UNION || !op->all)
1791  return false;
1792 
1793  /* Recurse to check inputs */
1794  return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
1795  is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
1796  }
1797  else
1798  {
1799  elog(ERROR, "unrecognized node type: %d",
1800  (int) nodeTag(setOp));
1801  return false; /* keep compiler quiet */
1802  }
1803 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition: tlist.c:251
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * targetList
Definition: parsenodes.h:138
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define Assert(condition)
Definition: c.h:681
SetOperation op
Definition: parsenodes.h:1574
#define nodeTag(nodeptr)
Definition: nodes.h:515
Query * subquery
Definition: parsenodes.h:968
#define elog
Definition: elog.h:219
static bool is_simple_values ( PlannerInfo root,
RangeTblEntry rte,
bool  deletion_ok 
)
static

Definition at line 1687 of file prepjointree.c.

References Assert, contain_volatile_functions(), expression_returns_set(), linitial, list_length(), PlannerInfo::parse, Query::rtable, RTE_VALUES, RangeTblEntry::rtekind, and RangeTblEntry::values_lists.

Referenced by pull_up_subqueries_recurse().

1688 {
1689  Assert(rte->rtekind == RTE_VALUES);
1690 
1691  /*
1692  * We can only pull up a VALUES RTE if deletion_ok is TRUE. It's
1693  * basically the same case as a sub-select with empty FROM list; see
1694  * comments in is_simple_subquery().
1695  */
1696  if (!deletion_ok)
1697  return false;
1698 
1699  /*
1700  * Also, there must be exactly one VALUES list, else it's not semantically
1701  * correct to delete the VALUES RTE.
1702  */
1703  if (list_length(rte->values_lists) != 1)
1704  return false;
1705 
1706  /*
1707  * Because VALUES can't appear under an outer join (or at least, we won't
1708  * try to pull it up if it does), we need not worry about LATERAL, nor
1709  * about validity of PHVs for the VALUES' outputs.
1710  */
1711 
1712  /*
1713  * Don't pull up a VALUES that contains any set-returning or volatile
1714  * functions. Again, the considerations here are basically identical to
1715  * restrictions on a subquery's targetlist.
1716  */
1717  if (expression_returns_set((Node *) rte->values_lists) ||
1719  return false;
1720 
1721  /*
1722  * Do not pull up a VALUES that's not the only RTE in its parent query.
1723  * This is actually the only case that the parser will generate at the
1724  * moment, and assuming this is true greatly simplifies
1725  * pull_up_simple_values().
1726  */
1727  if (list_length(root->parse->rtable) != 1 ||
1728  rte != (RangeTblEntry *) linitial(root->parse->rtable))
1729  return false;
1730 
1731  return true;
1732 }
Query * parse
Definition: relation.h:155
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:670
Definition: nodes.h:510
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:957
List * values_lists
Definition: parsenodes.h:1010
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
#define Assert(condition)
Definition: c.h:681
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:945
static bool jointree_contains_lateral_outer_refs ( Node jtnode,
bool  restricted,
Relids  safe_upper_varnos 
)
static

Definition at line 1852 of file prepjointree.c.

References bms_is_subset(), elog, ERROR, FromExpr::fromlist, IsA, JOIN_INNER, JoinExpr::jointype, JoinExpr::larg, lfirst, nodeTag, pull_varnos_of_level(), JoinExpr::quals, FromExpr::quals, and JoinExpr::rarg.

Referenced by is_simple_subquery().

1854 {
1855  if (jtnode == NULL)
1856  return false;
1857  if (IsA(jtnode, RangeTblRef))
1858  return false;
1859  else if (IsA(jtnode, FromExpr))
1860  {
1861  FromExpr *f = (FromExpr *) jtnode;
1862  ListCell *l;
1863 
1864  /* First, recurse to check child joins */
1865  foreach(l, f->fromlist)
1866  {
1868  restricted,
1869  safe_upper_varnos))
1870  return true;
1871  }
1872 
1873  /* Then check the top-level quals */
1874  if (restricted &&
1876  safe_upper_varnos))
1877  return true;
1878  }
1879  else if (IsA(jtnode, JoinExpr))
1880  {
1881  JoinExpr *j = (JoinExpr *) jtnode;
1882 
1883  /*
1884  * If this is an outer join, we mustn't allow any upper lateral
1885  * references in or below it.
1886  */
1887  if (j->jointype != JOIN_INNER)
1888  {
1889  restricted = true;
1890  safe_upper_varnos = NULL;
1891  }
1892 
1893  /* Check the child joins */
1895  restricted,
1896  safe_upper_varnos))
1897  return true;
1899  restricted,
1900  safe_upper_varnos))
1901  return true;
1902 
1903  /* Check the JOIN's qual clauses */
1904  if (restricted &&
1906  safe_upper_varnos))
1907  return true;
1908  }
1909  else
1910  elog(ERROR, "unrecognized node type: %d",
1911  (int) nodeTag(jtnode));
1912  return false;
1913 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
List * fromlist
Definition: primnodes.h:1471
Node * quals
Definition: primnodes.h:1472
Node * larg
Definition: primnodes.h:1451
#define ERROR
Definition: elog.h:43
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
Node * quals
Definition: primnodes.h:1454
static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, Relids safe_upper_varnos)
Node * rarg
Definition: primnodes.h:1452
JoinType jointype
Definition: primnodes.h:1449
#define lfirst(lc)
Definition: pg_list.h:106
#define nodeTag(nodeptr)
Definition: nodes.h:515
#define elog
Definition: elog.h:219
Relids pull_varnos_of_level(Node *node, int levelsup)
Definition: var.c:120
static void make_setop_translation_list ( Query query,
Index  newvarno,
List **  translated_vars 
)
static

Definition at line 1376 of file prepjointree.c.

References lappend(), lfirst, makeVarFromTargetEntry(), NIL, TargetEntry::resjunk, and Query::targetList.

Referenced by pull_up_union_leaf_queries().

1378 {
1379  List *vars = NIL;
1380  ListCell *l;
1381 
1382  foreach(l, query->targetList)
1383  {
1384  TargetEntry *tle = (TargetEntry *) lfirst(l);
1385 
1386  if (tle->resjunk)
1387  continue;
1388 
1389  vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1390  }
1391 
1392  *translated_vars = vars;
1393 }
#define NIL
Definition: pg_list.h:69
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:104
List * targetList
Definition: parsenodes.h:138
bool resjunk
Definition: primnodes.h:1375
List * lappend(List *list, void *datum)
Definition: list.c:128
#define lfirst(lc)
Definition: pg_list.h:106
Definition: regcomp.c:224
Definition: pg_list.h:45
static Node * pull_up_simple_subquery ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte,
JoinExpr lowest_outer_join,
JoinExpr lowest_nulling_outer_join,
AppendRelInfo containing_appendrel,
bool  deletion_ok 
)
static

Definition at line 868 of file prepjointree.c.

References PlannerInfo::append_rel_list, Assert, copyObject, PlannerInfo::cte_plan_ids, Query::cteList, CurrentMemoryContext, PlannerInfo::eq_classes, fix_append_rel_relids(), flatten_join_alias_vars(), FromExpr::fromlist, get_relids_in_jointree(), PlannerInfo::glob, PlannerInfo::grouping_map, PlannerInfo::hasDeletedRTEs, PlannerInfo::hasInheritedTarget, PlannerInfo::hasRecursion, Query::hasRowSecurity, Query::hasSubLinks, Query::havingQual, IncrementVarSublevelsUp(), PlannerInfo::init_plans, inline_set_returning_functions(), is_safe_append_member(), is_simple_subquery(), PlannerInfo::join_info_list, RangeTblEntry::joinaliasvars, Query::jointree, PlannerGlobal::lastPHId, RangeTblEntry::lateral, lfirst, list_concat(), list_length(), makeNode, PlannerInfo::minmax_aggs, PlannerInfo::multiexpr_params, pullup_replace_vars_context::need_phvs, NIL, PlannerInfo::non_recursive_path, OffsetVarNodes(), Query::onConflict, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, pullup_replace_vars_context::outer_hasSubLinks, PlannerInfo::outer_params, palloc0(), PlannerInfo::parent_root, parse(), PlannerInfo::parse, PlannerInfo::placeholder_list, PlannerInfo::plan_params, PlannerInfo::planner_cxt, PlannerInfo::processed_tlist, pull_up_sublinks(), pull_up_subqueries(), pullup_replace_vars(), PlannerInfo::qual_security_level, FromExpr::quals, PlannerInfo::query_level, pullup_replace_vars_context::relids, replace_vars_in_jointree(), Query::returningList, pullup_replace_vars_context::root, Query::rowMarks, PlannerInfo::rowMarks, Query::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, pullup_replace_vars_context::rv_cache, Query::setOperations, RangeTblEntry::subquery, substitute_multiple_relids(), RangeTblEntry::tablesample, pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, Query::targetList, AppendRelInfo::translated_vars, PlannerInfo::upper_rels, PlannerInfo::upper_targets, pullup_replace_vars_context::varno, pullup_replace_vars_context::wrap_non_vars, and PlannerInfo::wt_param_id.

Referenced by pull_up_subqueries_recurse().

873 {
874  Query *parse = root->parse;
875  int varno = ((RangeTblRef *) jtnode)->rtindex;
876  Query *subquery;
877  PlannerInfo *subroot;
878  int rtoffset;
879  pullup_replace_vars_context rvcontext;
880  ListCell *lc;
881 
882  /*
883  * Need a modifiable copy of the subquery to hack on. Even if we didn't
884  * sometimes choose not to pull up below, we must do this to avoid
885  * problems if the same subquery is referenced from multiple jointree
886  * items (which can't happen normally, but might after rule rewriting).
887  */
888  subquery = copyObject(rte->subquery);
889 
890  /*
891  * Create a PlannerInfo data structure for this subquery.
892  *
893  * NOTE: the next few steps should match the first processing in
894  * subquery_planner(). Can we refactor to avoid code duplication, or
895  * would that just make things uglier?
896  */
897  subroot = makeNode(PlannerInfo);
898  subroot->parse = subquery;
899  subroot->glob = root->glob;
900  subroot->query_level = root->query_level;
901  subroot->parent_root = root->parent_root;
902  subroot->plan_params = NIL;
903  subroot->outer_params = NULL;
905  subroot->init_plans = NIL;
906  subroot->cte_plan_ids = NIL;
907  subroot->multiexpr_params = NIL;
908  subroot->eq_classes = NIL;
909  subroot->append_rel_list = NIL;
910  subroot->rowMarks = NIL;
911  memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels));
912  memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets));
913  subroot->processed_tlist = NIL;
914  subroot->grouping_map = NULL;
915  subroot->minmax_aggs = NIL;
916  subroot->qual_security_level = 0;
917  subroot->hasInheritedTarget = false;
918  subroot->hasRecursion = false;
919  subroot->wt_param_id = -1;
920  subroot->non_recursive_path = NULL;
921 
922  /* No CTEs to worry about */
923  Assert(subquery->cteList == NIL);
924 
925  /*
926  * Pull up any SubLinks within the subquery's quals, so that we don't
927  * leave unoptimized SubLinks behind.
928  */
929  if (subquery->hasSubLinks)
930  pull_up_sublinks(subroot);
931 
932  /*
933  * Similarly, inline any set-returning functions in its rangetable.
934  */
936 
937  /*
938  * Recursively pull up the subquery's subqueries, so that
939  * pull_up_subqueries' processing is complete for its jointree and
940  * rangetable.
941  *
942  * Note: it's okay that the subquery's recursion starts with NULL for
943  * containing-join info, even if we are within an outer join in the upper
944  * query; the lower query starts with a clean slate for outer-join
945  * semantics. Likewise, we needn't pass down appendrel state.
946  */
947  pull_up_subqueries(subroot);
948 
949  /*
950  * Now we must recheck whether the subquery is still simple enough to pull
951  * up. If not, abandon processing it.
952  *
953  * We don't really need to recheck all the conditions involved, but it's
954  * easier just to keep this "if" looking the same as the one in
955  * pull_up_subqueries_recurse.
956  */
957  if (is_simple_subquery(subquery, rte,
958  lowest_outer_join, deletion_ok) &&
959  (containing_appendrel == NULL || is_safe_append_member(subquery)))
960  {
961  /* good to go */
962  }
963  else
964  {
965  /*
966  * Give up, return unmodified RangeTblRef.
967  *
968  * Note: The work we just did will be redone when the subquery gets
969  * planned on its own. Perhaps we could avoid that by storing the
970  * modified subquery back into the rangetable, but I'm not gonna risk
971  * it now.
972  */
973  return jtnode;
974  }
975 
976  /*
977  * We must flatten any join alias Vars in the subquery's targetlist,
978  * because pulling up the subquery's subqueries might have changed their
979  * expansions into arbitrary expressions, which could affect
980  * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
981  * are needed for tlist entries. (Likely it'd be better to do
982  * flatten_join_alias_vars on the whole query tree at some earlier stage,
983  * maybe even in the rewriter; but for now let's just fix this case here.)
984  */
985  subquery->targetList = (List *)
986  flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
987 
988  /*
989  * Adjust level-0 varnos in subquery so that we can append its rangetable
990  * to upper query's. We have to fix the subquery's append_rel_list as
991  * well.
992  */
993  rtoffset = list_length(parse->rtable);
994  OffsetVarNodes((Node *) subquery, rtoffset, 0);
995  OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);
996 
997  /*
998  * Upper-level vars in subquery are now one level closer to their parent
999  * than before.
1000  */
1001  IncrementVarSublevelsUp((Node *) subquery, -1, 1);
1002  IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
1003 
1004  /*
1005  * The subquery's targetlist items are now in the appropriate form to
1006  * insert into the top query, but if we are under an outer join then
1007  * non-nullable items and lateral references may have to be turned into
1008  * PlaceHolderVars. If we are dealing with an appendrel member then
1009  * anything that's not a simple Var has to be turned into a
1010  * PlaceHolderVar. Set up required context data for pullup_replace_vars.
1011  */
1012  rvcontext.root = root;
1013  rvcontext.targetlist = subquery->targetList;
1014  rvcontext.target_rte = rte;
1015  if (rte->lateral)
1016  rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree,
1017  true);
1018  else /* won't need relids */
1019  rvcontext.relids = NULL;
1020  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1021  rvcontext.varno = varno;
1022  rvcontext.need_phvs = (lowest_nulling_outer_join != NULL ||
1023  containing_appendrel != NULL);
1024  rvcontext.wrap_non_vars = (containing_appendrel != NULL);
1025  /* initialize cache array with indexes 0 .. length(tlist) */
1026  rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
1027  sizeof(Node *));
1028 
1029  /*
1030  * Replace all of the top query's references to the subquery's outputs
1031  * with copies of the adjusted subtlist items, being careful not to
1032  * replace any of the jointree structure. (This'd be a lot cleaner if we
1033  * could use query_tree_mutator.) We have to use PHVs in the targetList,
1034  * returningList, and havingQual, since those are certainly above any
1035  * outer join. replace_vars_in_jointree tracks its location in the
1036  * jointree and uses PHVs or not appropriately.
1037  */
1038  parse->targetList = (List *)
1039  pullup_replace_vars((Node *) parse->targetList, &rvcontext);
1040  parse->returningList = (List *)
1041  pullup_replace_vars((Node *) parse->returningList, &rvcontext);
1042  if (parse->onConflict)
1043  {
1044  parse->onConflict->onConflictSet = (List *)
1046  &rvcontext);
1047  parse->onConflict->onConflictWhere =
1049  &rvcontext);
1050 
1051  /*
1052  * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
1053  * can't contain any references to a subquery
1054  */
1055  }
1056  replace_vars_in_jointree((Node *) parse->jointree, &rvcontext,
1057  lowest_nulling_outer_join);
1058  Assert(parse->setOperations == NULL);
1059  parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
1060 
1061  /*
1062  * Replace references in the translated_vars lists of appendrels. When
1063  * pulling up an appendrel member, we do not need PHVs in the list of the
1064  * parent appendrel --- there isn't any outer join between. Elsewhere, use
1065  * PHVs for safety. (This analysis could be made tighter but it seems
1066  * unlikely to be worth much trouble.)
1067  */
1068  foreach(lc, root->append_rel_list)
1069  {
1070  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
1071  bool save_need_phvs = rvcontext.need_phvs;
1072 
1073  if (appinfo == containing_appendrel)
1074  rvcontext.need_phvs = false;
1075  appinfo->translated_vars = (List *)
1076  pullup_replace_vars((Node *) appinfo->translated_vars, &rvcontext);
1077  rvcontext.need_phvs = save_need_phvs;
1078  }
1079 
1080  /*
1081  * Replace references in the joinaliasvars lists of join RTEs.
1082  *
1083  * You might think that we could avoid using PHVs for alias vars of joins
1084  * below lowest_nulling_outer_join, but that doesn't work because the
1085  * alias vars could be referenced above that join; we need the PHVs to be
1086  * present in such references after the alias vars get flattened. (It
1087  * might be worth trying to be smarter here, someday.)
1088  */
1089  foreach(lc, parse->rtable)
1090  {
1091  RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
1092 
1093  if (otherrte->rtekind == RTE_JOIN)
1094  otherrte->joinaliasvars = (List *)
1095  pullup_replace_vars((Node *) otherrte->joinaliasvars,
1096  &rvcontext);
1097  }
1098 
1099  /*
1100  * If the subquery had a LATERAL marker, propagate that to any of its
1101  * child RTEs that could possibly now contain lateral cross-references.
1102  * The children might or might not contain any actual lateral
1103  * cross-references, but we have to mark the pulled-up child RTEs so that
1104  * later planner stages will check for such.
1105  */
1106  if (rte->lateral)
1107  {
1108  foreach(lc, subquery->rtable)
1109  {
1110  RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc);
1111 
1112  switch (child_rte->rtekind)
1113  {
1114  case RTE_RELATION:
1115  if (child_rte->tablesample)
1116  child_rte->lateral = true;
1117  break;
1118  case RTE_SUBQUERY:
1119  case RTE_FUNCTION:
1120  case RTE_VALUES:
1121  case RTE_TABLEFUNC:
1122  child_rte->lateral = true;
1123  break;
1124  case RTE_JOIN:
1125  case RTE_CTE:
1126  case RTE_NAMEDTUPLESTORE:
1127  /* these can't contain any lateral references */
1128  break;
1129  }
1130  }
1131  }
1132 
1133  /*
1134  * Now append the adjusted rtable entries to upper query. (We hold off
1135  * until after fixing the upper rtable entries; no point in running that
1136  * code on the subquery ones too.)
1137  */
1138  parse->rtable = list_concat(parse->rtable, subquery->rtable);
1139 
1140  /*
1141  * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already
1142  * adjusted the marker rtindexes, so just concat the lists.)
1143  */
1144  parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
1145 
1146  /*
1147  * We also have to fix the relid sets of any PlaceHolderVar nodes in the
1148  * parent query. (This could perhaps be done by pullup_replace_vars(),
1149  * but it seems cleaner to use two passes.) Note in particular that any
1150  * PlaceHolderVar nodes just created by pullup_replace_vars() will be
1151  * adjusted, so having created them with the subquery's varno is correct.
1152  *
1153  * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We
1154  * already checked that this won't require introducing multiple subrelids
1155  * into the single-slot AppendRelInfo structs.
1156  */
1157  if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
1158  root->append_rel_list)
1159  {
1160  Relids subrelids;
1161 
1162  subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
1163  substitute_multiple_relids((Node *) parse, varno, subrelids);
1164  fix_append_rel_relids(root->append_rel_list, varno, subrelids);
1165  }
1166 
1167  /*
1168  * And now add subquery's AppendRelInfos to our list.
1169  */
1171  subroot->append_rel_list);
1172 
1173  /*
1174  * We don't have to do the equivalent bookkeeping for outer-join info,
1175  * because that hasn't been set up yet. placeholder_list likewise.
1176  */
1177  Assert(root->join_info_list == NIL);
1178  Assert(subroot->join_info_list == NIL);
1179  Assert(root->placeholder_list == NIL);
1180  Assert(subroot->placeholder_list == NIL);
1181 
1182  /*
1183  * Miscellaneous housekeeping.
1184  *
1185  * Although replace_rte_variables() faithfully updated parse->hasSubLinks
1186  * if it copied any SubLinks out of the subquery's targetlist, we still
1187  * could have SubLinks added to the query in the expressions of FUNCTION
1188  * and VALUES RTEs copied up from the subquery. So it's necessary to copy
1189  * subquery->hasSubLinks anyway. Perhaps this can be improved someday.
1190  */
1191  parse->hasSubLinks |= subquery->hasSubLinks;
1192 
1193  /* If subquery had any RLS conditions, now main query does too */
1194  parse->hasRowSecurity |= subquery->hasRowSecurity;
1195 
1196  /*
1197  * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
1198  * hasTargetSRFs, so no work needed on those flags
1199  */
1200 
1201  /*
1202  * Return the adjusted subquery jointree to replace the RangeTblRef entry
1203  * in parent's jointree; or, if we're flattening a subquery with empty
1204  * FROM list, return NULL to signal deletion of the subquery from the
1205  * parent jointree (and set hasDeletedRTEs to ensure cleanup later).
1206  */
1207  if (subquery->jointree->fromlist == NIL)
1208  {
1209  Assert(deletion_ok);
1210  Assert(subquery->jointree->quals == NULL);
1211  root->hasDeletedRTEs = true;
1212  return NULL;
1213  }
1214 
1215  return (Node *) subquery->jointree;
1216 }
#define NIL
Definition: pg_list.h:69
List * rowMarks
Definition: relation.h:256
Query * parse
Definition: relation.h:155
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:424
List * joinaliasvars
Definition: parsenodes.h:989
List * plan_params
Definition: relation.h:169
List * join_info_list
Definition: relation.h:250
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:773
FromExpr * jointree
Definition: parsenodes.h:136
OnConflictExpr * onConflict
Definition: parsenodes.h:142
Definition: nodes.h:510
List * list_concat(List *list1, List *list2)
Definition: list.c:321
List * minmax_aggs
Definition: relation.h:288
List * fromlist
Definition: primnodes.h:1471
List * rowMarks
Definition: parsenodes.h:161
AttrNumber * grouping_map
Definition: relation.h:287
bool hasRecursion
Definition: relation.h:308
void pull_up_subqueries(PlannerInfo *root)
Definition: prepjointree.c:607
List * translated_vars
Definition: relation.h:2093
Node * quals
Definition: primnodes.h:1472
List * targetList
Definition: parsenodes.h:138
List * multiexpr_params
Definition: relation.h:232
int wt_param_id
Definition: relation.h:311
List * rtable
Definition: parsenodes.h:135
RangeTblEntry * target_rte
Definition: prepjointree.c:44
bool hasDeletedRTEs
Definition: relation.h:304
void inline_set_returning_functions(PlannerInfo *root)
Definition: prepjointree.c:573
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
PlannerGlobal * glob
Definition: relation.h:157
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
List * returningList
Definition: parsenodes.h:144
struct PlannerInfo * parent_root
Definition: relation.h:161
void * palloc0(Size size)
Definition: mcxt.c:877
Node * flatten_join_alias_vars(PlannerInfo *root, Node *node)
Definition: var.c:670
List * append_rel_list
Definition: relation.h:252
Index lastPHId
Definition: relation.h:119
List * cte_plan_ids
Definition: relation.h:230
static void substitute_multiple_relids(Node *node, int varno, Relids subrelids)
List * init_plans
Definition: relation.h:228
static bool is_safe_append_member(Query *subquery)
#define makeNode(_type_)
Definition: nodes.h:558
static void fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join, bool deletion_ok)
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
List * eq_classes
Definition: relation.h:235
bool hasInheritedTarget
Definition: relation.h:300
Bitmapset * outer_params
Definition: relation.h:170
struct Path * non_recursive_path
Definition: relation.h:312
static int list_length(const List *l)
Definition: pg_list.h:89
Index qual_security_level
Definition: relation.h:297
Index query_level
Definition: relation.h:159
void pull_up_sublinks(PlannerInfo *root)
Definition: prepjointree.c:150
RTEKind rtekind
Definition: parsenodes.h:945
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
Query * subquery
Definition: parsenodes.h:968
bool hasSubLinks
Definition: parsenodes.h:126
List * placeholder_list
Definition: relation.h:258
List * onConflictSet
Definition: primnodes.h:1496
MemoryContext planner_cxt
Definition: relation.h:290
#define copyObject(obj)
Definition: nodes.h:623
Node * havingQual
Definition: parsenodes.h:150
List * processed_tlist
Definition: relation.h:284
Node * onConflictWhere
Definition: primnodes.h:1497
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
Definition: pg_list.h:45
struct TableSampleClause * tablesample
Definition: parsenodes.h:963
bool hasRowSecurity
Definition: parsenodes.h:131
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649
struct PathTarget * upper_targets[UPPERREL_FINAL+1]
Definition: relation.h:278
List * upper_rels[UPPERREL_FINAL+1]
Definition: relation.h:275
static Node * pull_up_simple_union_all ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte 
)
static

Definition at line 1228 of file prepjointree.c.

References Assert, copyObject, IncrementVarSublevelsUp_rtable(), RangeTblEntry::inh, RangeTblEntry::lateral, lfirst, list_concat(), list_length(), PlannerInfo::parse, pull_up_union_leaf_queries(), Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, Query::setOperations, and RangeTblEntry::subquery.

Referenced by pull_up_subqueries_recurse().

1229 {
1230  int varno = ((RangeTblRef *) jtnode)->rtindex;
1231  Query *subquery = rte->subquery;
1232  int rtoffset = list_length(root->parse->rtable);
1233  List *rtable;
1234 
1235  /*
1236  * Make a modifiable copy of the subquery's rtable, so we can adjust
1237  * upper-level Vars in it. There are no such Vars in the setOperations
1238  * tree proper, so fixing the rtable should be sufficient.
1239  */
1240  rtable = copyObject(subquery->rtable);
1241 
1242  /*
1243  * Upper-level vars in subquery are now one level closer to their parent
1244  * than before. We don't have to worry about offsetting varnos, though,
1245  * because the UNION leaf queries can't cross-reference each other.
1246  */
1247  IncrementVarSublevelsUp_rtable(rtable, -1, 1);
1248 
1249  /*
1250  * If the UNION ALL subquery had a LATERAL marker, propagate that to all
1251  * its children. The individual children might or might not contain any
1252  * actual lateral cross-references, but we have to mark the pulled-up
1253  * child RTEs so that later planner stages will check for such.
1254  */
1255  if (rte->lateral)
1256  {
1257  ListCell *rt;
1258 
1259  foreach(rt, rtable)
1260  {
1261  RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
1262 
1263  Assert(child_rte->rtekind == RTE_SUBQUERY);
1264  child_rte->lateral = true;
1265  }
1266  }
1267 
1268  /*
1269  * Append child RTEs to parent rtable.
1270  */
1271  root->parse->rtable = list_concat(root->parse->rtable, rtable);
1272 
1273  /*
1274  * Recursively scan the subquery's setOperations tree and add
1275  * AppendRelInfo nodes for leaf subqueries to the parent's
1276  * append_rel_list. Also apply pull_up_subqueries to the leaf subqueries.
1277  */
1278  Assert(subquery->setOperations);
1279  pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery,
1280  rtoffset);
1281 
1282  /*
1283  * Mark the parent as an append relation.
1284  */
1285  rte->inh = true;
1286 
1287  return jtnode;
1288 }
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
Query * parse
Definition: relation.h:155
List * list_concat(List *list1, List *list2)
Definition: list.c:321
void IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:796
List * rtable
Definition: parsenodes.h:135
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:945
Node * setOperations
Definition: parsenodes.h:163
Query * subquery
Definition: parsenodes.h:968
#define copyObject(obj)
Definition: nodes.h:623
Definition: pg_list.h:45
static Node * pull_up_simple_values ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte 
)
static

Definition at line 1579 of file prepjointree.c.

References PlannerInfo::append_rel_list, Assert, contain_vars_of_level(), copyObject, PlannerInfo::hasDeletedRTEs, Query::hasSubLinks, Query::havingQual, PlannerInfo::join_info_list, Query::jointree, lappend(), lfirst, linitial, list_length(), makeTargetEntry(), pullup_replace_vars_context::need_phvs, NIL, Query::onConflict, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, pullup_replace_vars_context::outer_hasSubLinks, palloc0(), parse(), PlannerInfo::parse, PlannerInfo::placeholder_list, pullup_replace_vars(), pullup_replace_vars_context::relids, replace_vars_in_jointree(), Query::returningList, pullup_replace_vars_context::root, Query::rtable, RTE_VALUES, RangeTblEntry::rtekind, pullup_replace_vars_context::rv_cache, Query::setOperations, pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, Query::targetList, RangeTblEntry::values_lists, pullup_replace_vars_context::varno, and pullup_replace_vars_context::wrap_non_vars.

Referenced by pull_up_subqueries_recurse().

1580 {
1581  Query *parse = root->parse;
1582  int varno = ((RangeTblRef *) jtnode)->rtindex;
1583  List *values_list;
1584  List *tlist;
1585  AttrNumber attrno;
1586  pullup_replace_vars_context rvcontext;
1587  ListCell *lc;
1588 
1589  Assert(rte->rtekind == RTE_VALUES);
1590  Assert(list_length(rte->values_lists) == 1);
1591 
1592  /*
1593  * Need a modifiable copy of the VALUES list to hack on, just in case it's
1594  * multiply referenced.
1595  */
1596  values_list = copyObject(linitial(rte->values_lists));
1597 
1598  /*
1599  * The VALUES RTE can't contain any Vars of level zero, let alone any that
1600  * are join aliases, so no need to flatten join alias Vars.
1601  */
1602  Assert(!contain_vars_of_level((Node *) values_list, 0));
1603 
1604  /*
1605  * Set up required context data for pullup_replace_vars. In particular,
1606  * we have to make the VALUES list look like a subquery targetlist.
1607  */
1608  tlist = NIL;
1609  attrno = 1;
1610  foreach(lc, values_list)
1611  {
1612  tlist = lappend(tlist,
1613  makeTargetEntry((Expr *) lfirst(lc),
1614  attrno,
1615  NULL,
1616  false));
1617  attrno++;
1618  }
1619  rvcontext.root = root;
1620  rvcontext.targetlist = tlist;
1621  rvcontext.target_rte = rte;
1622  rvcontext.relids = NULL;
1623  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1624  rvcontext.varno = varno;
1625  rvcontext.need_phvs = false;
1626  rvcontext.wrap_non_vars = false;
1627  /* initialize cache array with indexes 0 .. length(tlist) */
1628  rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1629  sizeof(Node *));
1630 
1631  /*
1632  * Replace all of the top query's references to the RTE's outputs with
1633  * copies of the adjusted VALUES expressions, being careful not to replace
1634  * any of the jointree structure. (This'd be a lot cleaner if we could use
1635  * query_tree_mutator.) Much of this should be no-ops in the dummy Query
1636  * that surrounds a VALUES RTE, but it's not enough code to be worth
1637  * removing.
1638  */
1639  parse->targetList = (List *)
1640  pullup_replace_vars((Node *) parse->targetList, &rvcontext);
1641  parse->returningList = (List *)
1642  pullup_replace_vars((Node *) parse->returningList, &rvcontext);
1643  if (parse->onConflict)
1644  {
1645  parse->onConflict->onConflictSet = (List *)
1647  &rvcontext);
1648  parse->onConflict->onConflictWhere =
1650  &rvcontext);
1651 
1652  /*
1653  * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
1654  * can't contain any references to a subquery
1655  */
1656  }
1657  replace_vars_in_jointree((Node *) parse->jointree, &rvcontext, NULL);
1658  Assert(parse->setOperations == NULL);
1659  parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
1660 
1661  /*
1662  * There should be no appendrels to fix, nor any join alias Vars, nor any
1663  * outer joins and hence no PlaceHolderVars.
1664  */
1665  Assert(root->append_rel_list == NIL);
1666  Assert(list_length(parse->rtable) == 1);
1667  Assert(root->join_info_list == NIL);
1668  Assert(root->placeholder_list == NIL);
1669 
1670  /*
1671  * Return NULL to signal deletion of the VALUES RTE from the parent
1672  * jointree (and set hasDeletedRTEs to ensure cleanup later).
1673  */
1674  root->hasDeletedRTEs = true;
1675  return NULL;
1676 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:155
List * join_info_list
Definition: relation.h:250
FromExpr * jointree
Definition: parsenodes.h:136
OnConflictExpr * onConflict
Definition: parsenodes.h:142
Definition: nodes.h:510
List * values_lists
Definition: parsenodes.h:1010
List * targetList
Definition: parsenodes.h:138
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
RangeTblEntry * target_rte
Definition: prepjointree.c:44
bool hasDeletedRTEs
Definition: relation.h:304
List * returningList
Definition: parsenodes.h:144
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:235
List * lappend(List *list, void *datum)
Definition: list.c:128
void * palloc0(Size size)
Definition: mcxt.c:877
List * append_rel_list
Definition: relation.h:252
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:369
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:945
Node * setOperations
Definition: parsenodes.h:163
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
bool hasSubLinks
Definition: parsenodes.h:126
List * placeholder_list
Definition: relation.h:258
List * onConflictSet
Definition: primnodes.h:1496
#define copyObject(obj)
Definition: nodes.h:623
Node * havingQual
Definition: parsenodes.h:150
Node * onConflictWhere
Definition: primnodes.h:1497
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649
void pull_up_sublinks ( PlannerInfo root)

Definition at line 150 of file prepjointree.c.

References IsA, Query::jointree, list_make1, makeFromExpr(), PlannerInfo::parse, and pull_up_sublinks_jointree_recurse().

Referenced by pull_up_simple_subquery(), and subquery_planner().

151 {
152  Node *jtnode;
153  Relids relids;
154 
155  /* Begin recursion through the jointree */
156  jtnode = pull_up_sublinks_jointree_recurse(root,
157  (Node *) root->parse->jointree,
158  &relids);
159 
160  /*
161  * root->parse->jointree must always be a FromExpr, so insert a dummy one
162  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
163  */
164  if (IsA(jtnode, FromExpr))
165  root->parse->jointree = (FromExpr *) jtnode;
166  else
167  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
168 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:282
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Query * parse
Definition: relation.h:155
FromExpr * jointree
Definition: parsenodes.h:136
Definition: nodes.h:510
#define list_make1(x1)
Definition: pg_list.h:139
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:177
static Node * pull_up_sublinks_jointree_recurse ( PlannerInfo root,
Node jtnode,
Relids relids 
)
static

Definition at line 177 of file prepjointree.c.

References bms_add_member(), bms_join(), bms_make_singleton(), bms_union(), elog, ERROR, FromExpr::fromlist, IsA, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JoinExpr::jointype, lappend(), JoinExpr::larg, lfirst, makeFromExpr(), NIL, nodeTag, palloc(), pull_up_sublinks_qual_recurse(), JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, and JoinExpr::rtindex.

Referenced by pull_up_sublinks(), and pull_up_sublinks_qual_recurse().

179 {
180  if (jtnode == NULL)
181  {
182  *relids = NULL;
183  }
184  else if (IsA(jtnode, RangeTblRef))
185  {
186  int varno = ((RangeTblRef *) jtnode)->rtindex;
187 
188  *relids = bms_make_singleton(varno);
189  /* jtnode is returned unmodified */
190  }
191  else if (IsA(jtnode, FromExpr))
192  {
193  FromExpr *f = (FromExpr *) jtnode;
194  List *newfromlist = NIL;
195  Relids frelids = NULL;
196  FromExpr *newf;
197  Node *jtlink;
198  ListCell *l;
199 
200  /* First, recurse to process children and collect their relids */
201  foreach(l, f->fromlist)
202  {
203  Node *newchild;
204  Relids childrelids;
205 
206  newchild = pull_up_sublinks_jointree_recurse(root,
207  lfirst(l),
208  &childrelids);
209  newfromlist = lappend(newfromlist, newchild);
210  frelids = bms_join(frelids, childrelids);
211  }
212  /* Build the replacement FromExpr; no quals yet */
213  newf = makeFromExpr(newfromlist, NULL);
214  /* Set up a link representing the rebuilt jointree */
215  jtlink = (Node *) newf;
216  /* Now process qual --- all children are available for use */
217  newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
218  &jtlink, frelids,
219  NULL, NULL);
220 
221  /*
222  * Note that the result will be either newf, or a stack of JoinExprs
223  * with newf at the base. We rely on subsequent optimization steps to
224  * flatten this and rearrange the joins as needed.
225  *
226  * Although we could include the pulled-up subqueries in the returned
227  * relids, there's no need since upper quals couldn't refer to their
228  * outputs anyway.
229  */
230  *relids = frelids;
231  jtnode = jtlink;
232  }
233  else if (IsA(jtnode, JoinExpr))
234  {
235  JoinExpr *j;
236  Relids leftrelids;
237  Relids rightrelids;
238  Node *jtlink;
239 
240  /*
241  * Make a modifiable copy of join node, but don't bother copying its
242  * subnodes (yet).
243  */
244  j = (JoinExpr *) palloc(sizeof(JoinExpr));
245  memcpy(j, jtnode, sizeof(JoinExpr));
246  jtlink = (Node *) j;
247 
248  /* Recurse to process children and collect their relids */
250  &leftrelids);
252  &rightrelids);
253 
254  /*
255  * Now process qual, showing appropriate child relids as available,
256  * and attach any pulled-up jointree items at the right place. In the
257  * inner-join case we put new JoinExprs above the existing one (much
258  * as for a FromExpr-style join). In outer-join cases the new
259  * JoinExprs must go into the nullable side of the outer join. The
260  * point of the available_rels machinations is to ensure that we only
261  * pull up quals for which that's okay.
262  *
263  * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI
264  * nodes here.
265  */
266  switch (j->jointype)
267  {
268  case JOIN_INNER:
270  &jtlink,
271  bms_union(leftrelids,
272  rightrelids),
273  NULL, NULL);
274  break;
275  case JOIN_LEFT:
277  &j->rarg,
278  rightrelids,
279  NULL, NULL);
280  break;
281  case JOIN_FULL:
282  /* can't do anything with full-join quals */
283  break;
284  case JOIN_RIGHT:
286  &j->larg,
287  leftrelids,
288  NULL, NULL);
289  break;
290  default:
291  elog(ERROR, "unrecognized join type: %d",
292  (int) j->jointype);
293  break;
294  }
295 
296  /*
297  * Although we could include the pulled-up subqueries in the returned
298  * relids, there's no need since upper quals couldn't refer to their
299  * outputs anyway. But we *do* need to include the join's own rtindex
300  * because we haven't yet collapsed join alias variables, so upper
301  * levels would mistakenly think they couldn't use references to this
302  * join.
303  */
304  *relids = bms_join(leftrelids, rightrelids);
305  if (j->rtindex)
306  *relids = bms_add_member(*relids, j->rtindex);
307  jtnode = jtlink;
308  }
309  else
310  elog(ERROR, "unrecognized node type: %d",
311  (int) nodeTag(jtnode));
312  return jtnode;
313 }
#define NIL
Definition: pg_list.h:69
static Node * pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, Node **jtlink1, Relids available_rels1, Node **jtlink2, Relids available_rels2)
Definition: prepjointree.c:331
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:282
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Definition: nodes.h:510
List * fromlist
Definition: primnodes.h:1471
Node * quals
Definition: primnodes.h:1472
Node * larg
Definition: primnodes.h:1451
#define ERROR
Definition: elog.h:43
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:838
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:179
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:177
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * quals
Definition: primnodes.h:1454
Node * rarg
Definition: primnodes.h:1452
JoinType jointype
Definition: primnodes.h:1449
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:218
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define nodeTag(nodeptr)
Definition: nodes.h:515
void * palloc(Size size)
Definition: mcxt.c:848
#define elog
Definition: elog.h:219
int rtindex
Definition: primnodes.h:1456
Definition: pg_list.h:45
static Node * pull_up_sublinks_qual_recurse ( PlannerInfo root,
Node node,
Node **  jtlink1,
Relids  available_rels1,
Node **  jtlink2,
Relids  available_rels2 
)
static

Definition at line 331 of file prepjointree.c.

References and_clause(), ANY_SUBLINK, generate_unaccent_rules::args, convert_ANY_sublink_to_join(), convert_EXISTS_sublink_to_join(), EXISTS_SUBLINK, get_notclausearg(), IsA, lappend(), JoinExpr::larg, lfirst, linitial, list_length(), make_andclause(), NIL, not_clause(), pull_up_sublinks_jointree_recurse(), JoinExpr::quals, JoinExpr::rarg, and SubLink::subLinkType.

Referenced by pull_up_sublinks_jointree_recurse().

334 {
335  if (node == NULL)
336  return NULL;
337  if (IsA(node, SubLink))
338  {
339  SubLink *sublink = (SubLink *) node;
340  JoinExpr *j;
341  Relids child_rels;
342 
343  /* Is it a convertible ANY or EXISTS clause? */
344  if (sublink->subLinkType == ANY_SUBLINK)
345  {
346  if ((j = convert_ANY_sublink_to_join(root, sublink,
347  available_rels1)) != NULL)
348  {
349  /* Yes; insert the new join node into the join tree */
350  j->larg = *jtlink1;
351  *jtlink1 = (Node *) j;
352  /* Recursively process pulled-up jointree nodes */
354  j->rarg,
355  &child_rels);
356 
357  /*
358  * Now recursively process the pulled-up quals. Any inserted
359  * joins can get stacked onto either j->larg or j->rarg,
360  * depending on which rels they reference.
361  */
363  j->quals,
364  &j->larg,
365  available_rels1,
366  &j->rarg,
367  child_rels);
368  /* Return NULL representing constant TRUE */
369  return NULL;
370  }
371  if (available_rels2 != NULL &&
372  (j = convert_ANY_sublink_to_join(root, sublink,
373  available_rels2)) != NULL)
374  {
375  /* Yes; insert the new join node into the join tree */
376  j->larg = *jtlink2;
377  *jtlink2 = (Node *) j;
378  /* Recursively process pulled-up jointree nodes */
380  j->rarg,
381  &child_rels);
382 
383  /*
384  * Now recursively process the pulled-up quals. Any inserted
385  * joins can get stacked onto either j->larg or j->rarg,
386  * depending on which rels they reference.
387  */
389  j->quals,
390  &j->larg,
391  available_rels2,
392  &j->rarg,
393  child_rels);
394  /* Return NULL representing constant TRUE */
395  return NULL;
396  }
397  }
398  else if (sublink->subLinkType == EXISTS_SUBLINK)
399  {
400  if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
401  available_rels1)) != NULL)
402  {
403  /* Yes; insert the new join node into the join tree */
404  j->larg = *jtlink1;
405  *jtlink1 = (Node *) j;
406  /* Recursively process pulled-up jointree nodes */
408  j->rarg,
409  &child_rels);
410 
411  /*
412  * Now recursively process the pulled-up quals. Any inserted
413  * joins can get stacked onto either j->larg or j->rarg,
414  * depending on which rels they reference.
415  */
417  j->quals,
418  &j->larg,
419  available_rels1,
420  &j->rarg,
421  child_rels);
422  /* Return NULL representing constant TRUE */
423  return NULL;
424  }
425  if (available_rels2 != NULL &&
426  (j = convert_EXISTS_sublink_to_join(root, sublink, false,
427  available_rels2)) != NULL)
428  {
429  /* Yes; insert the new join node into the join tree */
430  j->larg = *jtlink2;
431  *jtlink2 = (Node *) j;
432  /* Recursively process pulled-up jointree nodes */
434  j->rarg,
435  &child_rels);
436 
437  /*
438  * Now recursively process the pulled-up quals. Any inserted
439  * joins can get stacked onto either j->larg or j->rarg,
440  * depending on which rels they reference.
441  */
443  j->quals,
444  &j->larg,
445  available_rels2,
446  &j->rarg,
447  child_rels);
448  /* Return NULL representing constant TRUE */
449  return NULL;
450  }
451  }
452  /* Else return it unmodified */
453  return node;
454  }
455  if (not_clause(node))
456  {
457  /* If the immediate argument of NOT is EXISTS, try to convert */
458  SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
459  JoinExpr *j;
460  Relids child_rels;
461 
462  if (sublink && IsA(sublink, SubLink))
463  {
464  if (sublink->subLinkType == EXISTS_SUBLINK)
465  {
466  if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
467  available_rels1)) != NULL)
468  {
469  /* Yes; insert the new join node into the join tree */
470  j->larg = *jtlink1;
471  *jtlink1 = (Node *) j;
472  /* Recursively process pulled-up jointree nodes */
474  j->rarg,
475  &child_rels);
476 
477  /*
478  * Now recursively process the pulled-up quals. Because
479  * we are underneath a NOT, we can't pull up sublinks that
480  * reference the left-hand stuff, but it's still okay to
481  * pull up sublinks referencing j->rarg.
482  */
484  j->quals,
485  &j->rarg,
486  child_rels,
487  NULL, NULL);
488  /* Return NULL representing constant TRUE */
489  return NULL;
490  }
491  if (available_rels2 != NULL &&
492  (j = convert_EXISTS_sublink_to_join(root, sublink, true,
493  available_rels2)) != NULL)
494  {
495  /* Yes; insert the new join node into the join tree */
496  j->larg = *jtlink2;
497  *jtlink2 = (Node *) j;
498  /* Recursively process pulled-up jointree nodes */
500  j->rarg,
501  &child_rels);
502 
503  /*
504  * Now recursively process the pulled-up quals. Because
505  * we are underneath a NOT, we can't pull up sublinks that
506  * reference the left-hand stuff, but it's still okay to
507  * pull up sublinks referencing j->rarg.
508  */
510  j->quals,
511  &j->rarg,
512  child_rels,
513  NULL, NULL);
514  /* Return NULL representing constant TRUE */
515  return NULL;
516  }
517  }
518  }
519  /* Else return it unmodified */
520  return node;
521  }
522  if (and_clause(node))
523  {
524  /* Recurse into AND clause */
525  List *newclauses = NIL;
526  ListCell *l;
527 
528  foreach(l, ((BoolExpr *) node)->args)
529  {
530  Node *oldclause = (Node *) lfirst(l);
531  Node *newclause;
532 
533  newclause = pull_up_sublinks_qual_recurse(root,
534  oldclause,
535  jtlink1,
536  available_rels1,
537  jtlink2,
538  available_rels2);
539  if (newclause)
540  newclauses = lappend(newclauses, newclause);
541  }
542  /* We might have got back fewer clauses than we started with */
543  if (newclauses == NIL)
544  return NULL;
545  else if (list_length(newclauses) == 1)
546  return (Node *) linitial(newclauses);
547  else
548  return (Node *) make_andclause(newclauses);
549  }
550  /* Stop if not an AND */
551  return node;
552 }
Expr * get_notclausearg(Expr *notclause)
Definition: clauses.c:265
#define NIL
Definition: pg_list.h:69
static Node * pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, Node **jtlink1, Relids available_rels1, Node **jtlink2, Relids available_rels2)
Definition: prepjointree.c:331
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Definition: nodes.h:510
JoinExpr * convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink, Relids available_rels)
Definition: subselect.c:1300
JoinExpr * convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, bool under_not, Relids available_rels)
Definition: subselect.c:1405
Node * larg
Definition: primnodes.h:1451
#define linitial(l)
Definition: pg_list.h:111
bool and_clause(Node *clause)
Definition: clauses.c:314
bool not_clause(Node *clause)
Definition: clauses.c:236
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:177
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * quals
Definition: primnodes.h:1454
Node * rarg
Definition: primnodes.h:1452
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
Expr * make_andclause(List *andclauses)
Definition: clauses.c:327
Definition: pg_list.h:45
void pull_up_subqueries ( PlannerInfo root)

Definition at line 607 of file prepjointree.c.

References Assert, PlannerInfo::hasDeletedRTEs, IsA, Query::jointree, PlannerInfo::parse, pull_up_subqueries_cleanup(), and pull_up_subqueries_recurse().

Referenced by pull_up_simple_subquery(), and subquery_planner().

608 {
609  /* Top level of jointree must always be a FromExpr */
610  Assert(IsA(root->parse->jointree, FromExpr));
611  /* Reset flag saying we need a deletion cleanup pass */
612  root->hasDeletedRTEs = false;
613  /* Recursion starts with no containing join nor appendrel */
614  root->parse->jointree = (FromExpr *)
616  NULL, NULL, NULL, false);
617  /* Apply cleanup phase if necessary */
618  if (root->hasDeletedRTEs)
619  root->parse->jointree = (FromExpr *)
621  Assert(IsA(root->parse->jointree, FromExpr));
622 }
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel, bool deletion_ok)
Definition: prepjointree.c:673
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Query * parse
Definition: relation.h:155
FromExpr * jointree
Definition: parsenodes.h:136
Definition: nodes.h:510
bool hasDeletedRTEs
Definition: relation.h:304
static Node * pull_up_subqueries_cleanup(Node *jtnode)
#define Assert(condition)
Definition: c.h:681
static Node * pull_up_subqueries_cleanup ( Node jtnode)
static

Definition at line 2255 of file prepjointree.c.

References Assert, elog, ERROR, FromExpr::fromlist, IsA, JOIN_INNER, JoinExpr::jointype, lappend(), JoinExpr::larg, lfirst, list_make1, makeFromExpr(), NIL, nodeTag, JoinExpr::quals, and JoinExpr::rarg.

Referenced by pull_up_subqueries().

2256 {
2257  Assert(jtnode != NULL);
2258  if (IsA(jtnode, RangeTblRef))
2259  {
2260  /* Nothing to do at leaf nodes. */
2261  }
2262  else if (IsA(jtnode, FromExpr))
2263  {
2264  FromExpr *f = (FromExpr *) jtnode;
2265  List *newfrom = NIL;
2266  ListCell *l;
2267 
2268  foreach(l, f->fromlist)
2269  {
2270  Node *child = (Node *) lfirst(l);
2271 
2272  if (child == NULL)
2273  continue;
2274  child = pull_up_subqueries_cleanup(child);
2275  newfrom = lappend(newfrom, child);
2276  }
2277  f->fromlist = newfrom;
2278  }
2279  else if (IsA(jtnode, JoinExpr))
2280  {
2281  JoinExpr *j = (JoinExpr *) jtnode;
2282 
2283  if (j->larg)
2285  if (j->rarg)
2287  if (j->larg == NULL)
2288  {
2289  Assert(j->jointype == JOIN_INNER);
2290  Assert(j->rarg != NULL);
2291  return (Node *) makeFromExpr(list_make1(j->rarg), j->quals);
2292  }
2293  else if (j->rarg == NULL)
2294  {
2295  Assert(j->jointype == JOIN_INNER);
2296  return (Node *) makeFromExpr(list_make1(j->larg), j->quals);
2297  }
2298  }
2299  else
2300  elog(ERROR, "unrecognized node type: %d",
2301  (int) nodeTag(jtnode));
2302  return jtnode;
2303 }
#define NIL
Definition: pg_list.h:69
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:282
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Definition: nodes.h:510
List * fromlist
Definition: primnodes.h:1471
Node * larg
Definition: primnodes.h:1451
#define list_make1(x1)
Definition: pg_list.h:139
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * quals
Definition: primnodes.h:1454
static Node * pull_up_subqueries_cleanup(Node *jtnode)
Node * rarg
Definition: primnodes.h:1452
JoinType jointype
Definition: primnodes.h:1449
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
#define nodeTag(nodeptr)
Definition: nodes.h:515
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
static Node * pull_up_subqueries_recurse ( PlannerInfo root,
Node jtnode,
JoinExpr lowest_outer_join,
JoinExpr lowest_nulling_outer_join,
AppendRelInfo containing_appendrel,
bool  deletion_ok 
)
static

Definition at line 673 of file prepjointree.c.

References Assert, elog, ERROR, FromExpr::fromlist, PlannerInfo::hasDeletedRTEs, is_safe_append_member(), is_simple_subquery(), is_simple_union_all(), is_simple_values(), IsA, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, Query::jointree, JoinExpr::jointype, JoinExpr::larg, lfirst, lnext, nodeTag, PlannerInfo::parse, pull_up_simple_subquery(), pull_up_simple_union_all(), pull_up_simple_values(), FromExpr::quals, JoinExpr::rarg, rt_fetch, Query::rtable, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by pull_up_subqueries(), and pull_up_union_leaf_queries().

678 {
679  Assert(jtnode != NULL);
680  if (IsA(jtnode, RangeTblRef))
681  {
682  int varno = ((RangeTblRef *) jtnode)->rtindex;
683  RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
684 
685  /*
686  * Is this a subquery RTE, and if so, is the subquery simple enough to
687  * pull up?
688  *
689  * If we are looking at an append-relation member, we can't pull it up
690  * unless is_safe_append_member says so.
691  */
692  if (rte->rtekind == RTE_SUBQUERY &&
693  is_simple_subquery(rte->subquery, rte,
694  lowest_outer_join, deletion_ok) &&
695  (containing_appendrel == NULL ||
697  return pull_up_simple_subquery(root, jtnode, rte,
698  lowest_outer_join,
699  lowest_nulling_outer_join,
700  containing_appendrel,
701  deletion_ok);
702 
703  /*
704  * Alternatively, is it a simple UNION ALL subquery? If so, flatten
705  * into an "append relation".
706  *
707  * It's safe to do this regardless of whether this query is itself an
708  * appendrel member. (If you're thinking we should try to flatten the
709  * two levels of appendrel together, you're right; but we handle that
710  * in set_append_rel_pathlist, not here.)
711  */
712  if (rte->rtekind == RTE_SUBQUERY &&
714  return pull_up_simple_union_all(root, jtnode, rte);
715 
716  /*
717  * Or perhaps it's a simple VALUES RTE?
718  *
719  * We don't allow VALUES pullup below an outer join nor into an
720  * appendrel (such cases are impossible anyway at the moment).
721  */
722  if (rte->rtekind == RTE_VALUES &&
723  lowest_outer_join == NULL &&
724  containing_appendrel == NULL &&
725  is_simple_values(root, rte, deletion_ok))
726  return pull_up_simple_values(root, jtnode, rte);
727 
728  /* Otherwise, do nothing at this node. */
729  }
730  else if (IsA(jtnode, FromExpr))
731  {
732  FromExpr *f = (FromExpr *) jtnode;
733  bool have_undeleted_child = false;
734  ListCell *l;
735 
736  Assert(containing_appendrel == NULL);
737 
738  /*
739  * If the FromExpr has quals, it's not deletable even if its parent
740  * would allow deletion.
741  */
742  if (f->quals)
743  deletion_ok = false;
744 
745  foreach(l, f->fromlist)
746  {
747  /*
748  * In a non-deletable FromExpr, we can allow deletion of child
749  * nodes so long as at least one child remains; so it's okay
750  * either if any previous child survives, or if there's more to
751  * come. If all children are deletable in themselves, we'll force
752  * the last one to remain unflattened.
753  *
754  * As a separate matter, we can allow deletion of all children of
755  * the top-level FromExpr in a query, since that's a special case
756  * anyway.
757  */
758  bool sub_deletion_ok = (deletion_ok ||
759  have_undeleted_child ||
760  lnext(l) != NULL ||
761  f == root->parse->jointree);
762 
764  lowest_outer_join,
765  lowest_nulling_outer_join,
766  NULL,
767  sub_deletion_ok);
768  if (lfirst(l) != NULL)
769  have_undeleted_child = true;
770  }
771 
772  if (deletion_ok && !have_undeleted_child)
773  {
774  /* OK to delete this FromExpr entirely */
775  root->hasDeletedRTEs = true; /* probably is set already */
776  return NULL;
777  }
778  }
779  else if (IsA(jtnode, JoinExpr))
780  {
781  JoinExpr *j = (JoinExpr *) jtnode;
782 
783  Assert(containing_appendrel == NULL);
784  /* Recurse, being careful to tell myself when inside outer join */
785  switch (j->jointype)
786  {
787  case JOIN_INNER:
788 
789  /*
790  * INNER JOIN can allow deletion of either child node, but not
791  * both. So right child gets permission to delete only if
792  * left child didn't get removed.
793  */
794  j->larg = pull_up_subqueries_recurse(root, j->larg,
795  lowest_outer_join,
796  lowest_nulling_outer_join,
797  NULL,
798  true);
799  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
800  lowest_outer_join,
801  lowest_nulling_outer_join,
802  NULL,
803  j->larg != NULL);
804  break;
805  case JOIN_LEFT:
806  case JOIN_SEMI:
807  case JOIN_ANTI:
808  j->larg = pull_up_subqueries_recurse(root, j->larg,
809  j,
810  lowest_nulling_outer_join,
811  NULL,
812  false);
813  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
814  j,
815  j,
816  NULL,
817  false);
818  break;
819  case JOIN_FULL:
820  j->larg = pull_up_subqueries_recurse(root, j->larg,
821  j,
822  j,
823  NULL,
824  false);
825  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
826  j,
827  j,
828  NULL,
829  false);
830  break;
831  case JOIN_RIGHT:
832  j->larg = pull_up_subqueries_recurse(root, j->larg,
833  j,
834  j,
835  NULL,
836  false);
837  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
838  j,
839  lowest_nulling_outer_join,
840  NULL,
841  false);
842  break;
843  default:
844  elog(ERROR, "unrecognized join type: %d",
845  (int) j->jointype);
846  break;
847  }
848  }
849  else
850  elog(ERROR, "unrecognized node type: %d",
851  (int) nodeTag(jtnode));
852  return jtnode;
853 }
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel, bool deletion_ok)
Definition: prepjointree.c:673
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Query * parse
Definition: relation.h:155
FromExpr * jointree
Definition: parsenodes.h:136
List * fromlist
Definition: primnodes.h:1471
static bool is_simple_union_all(Query *subquery)
static bool is_simple_values(PlannerInfo *root, RangeTblEntry *rte, bool deletion_ok)
Node * quals
Definition: primnodes.h:1472
Node * larg
Definition: primnodes.h:1451
static Node * pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
bool hasDeletedRTEs
Definition: relation.h:304
#define lnext(lc)
Definition: pg_list.h:105
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static bool is_safe_append_member(Query *subquery)
Node * rarg
Definition: primnodes.h:1452
static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join, bool deletion_ok)
JoinType jointype
Definition: primnodes.h:1449
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
#define nodeTag(nodeptr)
Definition: nodes.h:515
static Node * pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel, bool deletion_ok)
Definition: prepjointree.c:868
RTEKind rtekind
Definition: parsenodes.h:945
Query * subquery
Definition: parsenodes.h:968
#define elog
Definition: elog.h:219
static Node * pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
static void pull_up_union_leaf_queries ( Node setOp,
PlannerInfo root,
int  parentRTindex,
Query setOpQuery,
int  childRToffset 
)
static

Definition at line 1309 of file prepjointree.c.

References PlannerInfo::append_rel_list, AppendRelInfo::child_relid, AppendRelInfo::child_reltype, elog, ERROR, InvalidOid, IsA, lappend(), SetOperationStmt::larg, make_setop_translation_list(), makeNode, nodeTag, AppendRelInfo::parent_relid, AppendRelInfo::parent_reloid, AppendRelInfo::parent_reltype, pull_up_subqueries_recurse(), SetOperationStmt::rarg, RangeTblRef::rtindex, and AppendRelInfo::translated_vars.

Referenced by flatten_simple_union_all(), and pull_up_simple_union_all().

1311 {
1312  if (IsA(setOp, RangeTblRef))
1313  {
1314  RangeTblRef *rtr = (RangeTblRef *) setOp;
1315  int childRTindex;
1316  AppendRelInfo *appinfo;
1317 
1318  /*
1319  * Calculate the index in the parent's range table
1320  */
1321  childRTindex = childRToffset + rtr->rtindex;
1322 
1323  /*
1324  * Build a suitable AppendRelInfo, and attach to parent's list.
1325  */
1326  appinfo = makeNode(AppendRelInfo);
1327  appinfo->parent_relid = parentRTindex;
1328  appinfo->child_relid = childRTindex;
1329  appinfo->parent_reltype = InvalidOid;
1330  appinfo->child_reltype = InvalidOid;
1331  make_setop_translation_list(setOpQuery, childRTindex,
1332  &appinfo->translated_vars);
1333  appinfo->parent_reloid = InvalidOid;
1334  root->append_rel_list = lappend(root->append_rel_list, appinfo);
1335 
1336  /*
1337  * Recursively apply pull_up_subqueries to the new child RTE. (We
1338  * must build the AppendRelInfo first, because this will modify it.)
1339  * Note that we can pass NULL for containing-join info even if we're
1340  * actually under an outer join, because the child's expressions
1341  * aren't going to propagate up to the join. Also, we ignore the
1342  * possibility that pull_up_subqueries_recurse() returns a different
1343  * jointree node than what we pass it; if it does, the important thing
1344  * is that it replaced the child relid in the AppendRelInfo node.
1345  */
1346  rtr = makeNode(RangeTblRef);
1347  rtr->rtindex = childRTindex;
1348  (void) pull_up_subqueries_recurse(root, (Node *) rtr,
1349  NULL, NULL, appinfo, false);
1350  }
1351  else if (IsA(setOp, SetOperationStmt))
1352  {
1353  SetOperationStmt *op = (SetOperationStmt *) setOp;
1354 
1355  /* Recurse to reach leaf queries */
1356  pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
1357  childRToffset);
1358  pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
1359  childRToffset);
1360  }
1361  else
1362  {
1363  elog(ERROR, "unrecognized node type: %d",
1364  (int) nodeTag(setOp));
1365  }
1366 }
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel, bool deletion_ok)
Definition: prepjointree.c:673
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Definition: nodes.h:510
List * translated_vars
Definition: relation.h:2093
Oid parent_reltype
Definition: relation.h:2074
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:128
List * append_rel_list
Definition: relation.h:252
#define InvalidOid
Definition: postgres_ext.h:36
#define makeNode(_type_)
Definition: nodes.h:558
#define nodeTag(nodeptr)
Definition: nodes.h:515
static void make_setop_translation_list(Query *query, Index newvarno, List **translated_vars)
Oid child_reltype
Definition: relation.h:2075
#define elog
Definition: elog.h:219
Index child_relid
Definition: relation.h:2066
Oid parent_reloid
Definition: relation.h:2100
Index parent_relid
Definition: relation.h:2065
static Node * pullup_replace_vars ( Node expr,
pullup_replace_vars_context context 
)
static

Definition at line 2032 of file prepjointree.c.

References pullup_replace_vars_context::outer_hasSubLinks, pullup_replace_vars_callback(), replace_rte_variables(), and pullup_replace_vars_context::varno.

Referenced by pull_up_simple_subquery(), pull_up_simple_values(), and replace_vars_in_jointree().

2033 {
2034  return replace_rte_variables(expr,
2035  context->varno, 0,
2037  (void *) context,
2038  context->outer_hasSubLinks);
2039 }
static Node * pullup_replace_vars_callback(Var *var, replace_rte_variables_context *context)
Node * replace_rte_variables(Node *node, int target_varno, int sublevels_up, replace_rte_variables_callback callback, void *callback_arg, bool *outer_hasSubLinks)
static Node * pullup_replace_vars_callback ( Var var,
replace_rte_variables_context context 
)
static

Definition at line 2042 of file prepjointree.c.

References RowExpr::args, bms_is_member(), bms_make_singleton(), bms_overlap(), replace_rte_variables_context::callback_arg, COERCE_IMPLICIT_CAST, RowExpr::colnames, contain_nonstrict_functions(), contain_vars_of_level(), copyObject, elog, ERROR, expandRTE(), TargetEntry::expr, get_tle_by_resno(), IncrementVarSublevelsUp(), InvalidAttrNumber, IsA, RangeTblEntry::lateral, list_length(), Var::location, RowExpr::location, make_placeholder_expr(), makeNode, pullup_replace_vars_context::need_phvs, pull_varnos(), RECORDOID, pullup_replace_vars_context::relids, replace_rte_variables_mutator(), pullup_replace_vars_context::root, RowExpr::row_format, RowExpr::row_typeid, pullup_replace_vars_context::rv_cache, replace_rte_variables_context::sublevels_up, pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, Var::varattno, Var::varlevelsup, pullup_replace_vars_context::varno, Var::varno, Var::vartype, and pullup_replace_vars_context::wrap_non_vars.

Referenced by pullup_replace_vars(), and pullup_replace_vars_subquery().

2044 {
2046  int varattno = var->varattno;
2047  Node *newnode;
2048 
2049  /*
2050  * If PlaceHolderVars are needed, we cache the modified expressions in
2051  * rcon->rv_cache[]. This is not in hopes of any material speed gain
2052  * within this function, but to avoid generating identical PHVs with
2053  * different IDs. That would result in duplicate evaluations at runtime,
2054  * and possibly prevent optimizations that rely on recognizing different
2055  * references to the same subquery output as being equal(). So it's worth
2056  * a bit of extra effort to avoid it.
2057  */
2058  if (rcon->need_phvs &&
2059  varattno >= InvalidAttrNumber &&
2060  varattno <= list_length(rcon->targetlist) &&
2061  rcon->rv_cache[varattno] != NULL)
2062  {
2063  /* Just copy the entry and fall through to adjust its varlevelsup */
2064  newnode = copyObject(rcon->rv_cache[varattno]);
2065  }
2066  else if (varattno == InvalidAttrNumber)
2067  {
2068  /* Must expand whole-tuple reference into RowExpr */
2069  RowExpr *rowexpr;
2070  List *colnames;
2071  List *fields;
2072  bool save_need_phvs = rcon->need_phvs;
2073  int save_sublevelsup = context->sublevels_up;
2074 
2075  /*
2076  * If generating an expansion for a var of a named rowtype (ie, this
2077  * is a plain relation RTE), then we must include dummy items for
2078  * dropped columns. If the var is RECORD (ie, this is a JOIN), then
2079  * omit dropped columns. Either way, attach column names to the
2080  * RowExpr for use of ruleutils.c.
2081  *
2082  * In order to be able to cache the results, we always generate the
2083  * expansion with varlevelsup = 0, and then adjust if needed.
2084  */
2085  expandRTE(rcon->target_rte,
2086  var->varno, 0 /* not varlevelsup */ , var->location,
2087  (var->vartype != RECORDOID),
2088  &colnames, &fields);
2089  /* Adjust the generated per-field Vars, but don't insert PHVs */
2090  rcon->need_phvs = false;
2091  context->sublevels_up = 0; /* to match the expandRTE output */
2092  fields = (List *) replace_rte_variables_mutator((Node *) fields,
2093  context);
2094  rcon->need_phvs = save_need_phvs;
2095  context->sublevels_up = save_sublevelsup;
2096 
2097  rowexpr = makeNode(RowExpr);
2098  rowexpr->args = fields;
2099  rowexpr->row_typeid = var->vartype;
2100  rowexpr->row_format = COERCE_IMPLICIT_CAST;
2101  rowexpr->colnames = colnames;
2102  rowexpr->location = var->location;
2103  newnode = (Node *) rowexpr;
2104 
2105  /*
2106  * Insert PlaceHolderVar if needed. Notice that we are wrapping one
2107  * PlaceHolderVar around the whole RowExpr, rather than putting one
2108  * around each element of the row. This is because we need the
2109  * expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
2110  * to null by an outer join.
2111  */
2112  if (rcon->need_phvs)
2113  {
2114  /* RowExpr is certainly not strict, so always need PHV */
2115  newnode = (Node *)
2117  (Expr *) newnode,
2118  bms_make_singleton(rcon->varno));
2119  /* cache it with the PHV, and with varlevelsup still zero */
2120  rcon->rv_cache[InvalidAttrNumber] = copyObject(newnode);
2121  }
2122  }
2123  else
2124  {
2125  /* Normal case referencing one targetlist element */
2126  TargetEntry *tle = get_tle_by_resno(rcon->targetlist, varattno);
2127 
2128  if (tle == NULL) /* shouldn't happen */
2129  elog(ERROR, "could not find attribute %d in subquery targetlist",
2130  varattno);
2131 
2132  /* Make a copy of the tlist item to return */
2133  newnode = (Node *) copyObject(tle->expr);
2134 
2135  /* Insert PlaceHolderVar if needed */
2136  if (rcon->need_phvs)
2137  {
2138  bool wrap;
2139 
2140  if (newnode && IsA(newnode, Var) &&
2141  ((Var *) newnode)->varlevelsup == 0)
2142  {
2143  /*
2144  * Simple Vars always escape being wrapped, unless they are
2145  * lateral references to something outside the subquery being
2146  * pulled up. (Even then, we could omit the PlaceHolderVar if
2147  * the referenced rel is under the same lowest outer join, but
2148  * it doesn't seem worth the trouble to check that.)
2149  */
2150  if (rcon->target_rte->lateral &&
2151  !bms_is_member(((Var *) newnode)->varno, rcon->relids))
2152  wrap = true;
2153  else
2154  wrap = false;
2155  }
2156  else if (newnode && IsA(newnode, PlaceHolderVar) &&
2157  ((PlaceHolderVar *) newnode)->phlevelsup == 0)
2158  {
2159  /* No need to wrap a PlaceHolderVar with another one, either */
2160  wrap = false;
2161  }
2162  else if (rcon->wrap_non_vars)
2163  {
2164  /* Wrap all non-Vars in a PlaceHolderVar */
2165  wrap = true;
2166  }
2167  else
2168  {
2169  /*
2170  * If it contains a Var of the subquery being pulled up, and
2171  * does not contain any non-strict constructs, then it's
2172  * certainly nullable so we don't need to insert a
2173  * PlaceHolderVar.
2174  *
2175  * This analysis could be tighter: in particular, a non-strict
2176  * construct hidden within a lower-level PlaceHolderVar is not
2177  * reason to add another PHV. But for now it doesn't seem
2178  * worth the code to be more exact.
2179  *
2180  * Note: in future maybe we should insert a PlaceHolderVar
2181  * anyway, if the tlist item is expensive to evaluate?
2182  *
2183  * For a LATERAL subquery, we have to check the actual var
2184  * membership of the node, but if it's non-lateral then any
2185  * level-zero var must belong to the subquery.
2186  */
2187  if ((rcon->target_rte->lateral ?
2188  bms_overlap(pull_varnos((Node *) newnode), rcon->relids) :
2189  contain_vars_of_level((Node *) newnode, 0)) &&
2190  !contain_nonstrict_functions((Node *) newnode))
2191  {
2192  /* No wrap needed */
2193  wrap = false;
2194  }
2195  else
2196  {
2197  /* Else wrap it in a PlaceHolderVar */
2198  wrap = true;
2199  }
2200  }
2201 
2202  if (wrap)
2203  newnode = (Node *)
2205  (Expr *) newnode,
2206  bms_make_singleton(rcon->varno));
2207 
2208  /*
2209  * Cache it if possible (ie, if the attno is in range, which it
2210  * probably always should be). We can cache the value even if we
2211  * decided we didn't need a PHV, since this result will be
2212  * suitable for any request that has need_phvs.
2213  */
2214  if (varattno > InvalidAttrNumber &&
2215  varattno <= list_length(rcon->targetlist))
2216  rcon->rv_cache[varattno] = copyObject(newnode);
2217  }
2218  }
2219 
2220  /* Must adjust varlevelsup if tlist item is from higher query */
2221  if (var->varlevelsup > 0)
2222  IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
2223 
2224  return newnode;
2225 }
List * args
Definition: primnodes.h:986
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Index varlevelsup
Definition: primnodes.h:173
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:773
Definition: nodes.h:510
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
Definition: placeholder.c:40
#define ERROR
Definition: elog.h:43
List * colnames
Definition: primnodes.h:999
RangeTblEntry * target_rte
Definition: prepjointree.c:44
Node * replace_rte_variables_mutator(Node *node, replace_rte_variables_context *context)
Oid vartype
Definition: primnodes.h:170
int location
Definition: primnodes.h:178
int location
Definition: primnodes.h:1000
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:179
#define RECORDOID
Definition: pg_type.h:680
Relids pull_varnos(Node *node)
Definition: var.c:95
Index varno
Definition: primnodes.h:166
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
#define makeNode(_type_)
Definition: nodes.h:558
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:369
Expr * expr
Definition: primnodes.h:1368
Oid row_typeid
Definition: primnodes.h:987
static int list_length(const List *l)
Definition: pg_list.h:89
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define elog
Definition: elog.h:219
bool contain_nonstrict_functions(Node *clause)
Definition: clauses.c:1288
#define copyObject(obj)
Definition: nodes.h:623
CoercionForm row_format
Definition: primnodes.h:998
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
static Query * pullup_replace_vars_subquery ( Query query,
pullup_replace_vars_context context 
)
static

Definition at line 2235 of file prepjointree.c.

References Assert, IsA, pullup_replace_vars_callback(), replace_rte_variables(), and pullup_replace_vars_context::varno.

Referenced by replace_vars_in_jointree().

2237 {
2238  Assert(IsA(query, Query));
2239  return (Query *) replace_rte_variables((Node *) query,
2240  context->varno, 1,
2242  (void *) context,
2243  NULL);
2244 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
static Node * pullup_replace_vars_callback(Var *var, replace_rte_variables_context *context)
Definition: nodes.h:510
#define Assert(condition)
Definition: c.h:681
Node * replace_rte_variables(Node *node, int target_varno, int sublevels_up, replace_rte_variables_callback callback, void *callback_arg, bool *outer_hasSubLinks)
void reduce_outer_joins ( PlannerInfo root)

Definition at line 2439 of file prepjointree.c.

References reduce_outer_joins_state::contains_outer, elog, ERROR, Query::jointree, NIL, PlannerInfo::parse, reduce_outer_joins_pass1(), and reduce_outer_joins_pass2().

Referenced by subquery_planner().

2440 {
2442 
2443  /*
2444  * To avoid doing strictness checks on more quals than necessary, we want
2445  * to stop descending the jointree as soon as there are no outer joins
2446  * below our current point. This consideration forces a two-pass process.
2447  * The first pass gathers information about which base rels appear below
2448  * each side of each join clause, and about whether there are outer
2449  * join(s) below each side of each join clause. The second pass examines
2450  * qual clauses and changes join types as it descends the tree.
2451  */
2452  state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2453 
2454  /* planner.c shouldn't have called me if no outer joins */
2455  if (state == NULL || !state->contains_outer)
2456  elog(ERROR, "so where are the outer joins?");
2457 
2459  state, root, NULL, NIL, NIL);
2460 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:155
FromExpr * jointree
Definition: parsenodes.h:136
Definition: nodes.h:510
#define ERROR
Definition: elog.h:43
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
Definition: regguts.h:298
#define elog
Definition: elog.h:219
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *nonnullable_vars, List *forced_null_vars)
static reduce_outer_joins_state * reduce_outer_joins_pass1 ( Node jtnode)
static

Definition at line 2468 of file prepjointree.c.

References bms_add_members(), bms_make_singleton(), reduce_outer_joins_state::contains_outer, elog, ERROR, FromExpr::fromlist, IS_OUTER_JOIN, IsA, JoinExpr::jointype, lappend(), JoinExpr::larg, lfirst, NIL, nodeTag, palloc(), JoinExpr::rarg, reduce_outer_joins_state::relids, and reduce_outer_joins_state::sub_states.

Referenced by reduce_outer_joins().

2469 {
2470  reduce_outer_joins_state *result;
2471 
2472  result = (reduce_outer_joins_state *)
2474  result->relids = NULL;
2475  result->contains_outer = false;
2476  result->sub_states = NIL;
2477 
2478  if (jtnode == NULL)
2479  return result;
2480  if (IsA(jtnode, RangeTblRef))
2481  {
2482  int varno = ((RangeTblRef *) jtnode)->rtindex;
2483 
2484  result->relids = bms_make_singleton(varno);
2485  }
2486  else if (IsA(jtnode, FromExpr))
2487  {
2488  FromExpr *f = (FromExpr *) jtnode;
2489  ListCell *l;
2490 
2491  foreach(l, f->fromlist)
2492  {
2493  reduce_outer_joins_state *sub_state;
2494 
2495  sub_state = reduce_outer_joins_pass1(lfirst(l));
2496  result->relids = bms_add_members(result->relids,
2497  sub_state->relids);
2498  result->contains_outer |= sub_state->contains_outer;
2499  result->sub_states = lappend(result->sub_states, sub_state);
2500  }
2501  }
2502  else if (IsA(jtnode, JoinExpr))
2503  {
2504  JoinExpr *j = (JoinExpr *) jtnode;
2505  reduce_outer_joins_state *sub_state;
2506 
2507  /* join's own RT index is not wanted in result->relids */
2508  if (IS_OUTER_JOIN(j->jointype))
2509  result->contains_outer = true;
2510 
2511  sub_state = reduce_outer_joins_pass1(j->larg);
2512  result->relids = bms_add_members(result->relids,
2513  sub_state->relids);
2514  result->contains_outer |= sub_state->contains_outer;
2515  result->sub_states = lappend(result->sub_states, sub_state);
2516 
2517  sub_state = reduce_outer_joins_pass1(j->rarg);
2518  result->relids = bms_add_members(result->relids,
2519  sub_state->relids);
2520  result->contains_outer |= sub_state->contains_outer;
2521  result->sub_states = lappend(result->sub_states, sub_state);
2522  }
2523  else
2524  elog(ERROR, "unrecognized node type: %d",
2525  (int) nodeTag(jtnode));
2526  return result;
2527 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:723
List * fromlist
Definition: primnodes.h:1471
Node * larg
Definition: primnodes.h:1451
#define ERROR
Definition: elog.h:43
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:179
List * lappend(List *list, void *datum)
Definition: list.c:128
Node * rarg
Definition: primnodes.h:1452
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
JoinType jointype
Definition: primnodes.h:1449
#define lfirst(lc)
Definition: pg_list.h:106
#define nodeTag(nodeptr)
Definition: nodes.h:515
void * palloc(Size size)
Definition: mcxt.c:848
#define elog
Definition: elog.h:219
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:755
static void reduce_outer_joins_pass2 ( Node jtnode,
reduce_outer_joins_state state,
PlannerInfo root,
Relids  nonnullable_rels,
List nonnullable_vars,
List forced_null_vars 
)
static

Definition at line 2540 of file prepjointree.c.

References Assert, bms_add_members(), bms_free(), bms_overlap(), reduce_outer_joins_state::contains_outer, elog, ERROR, find_forced_null_vars(), find_nonnullable_rels(), find_nonnullable_vars(), forboth, FromExpr::fromlist, IsA, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, RangeTblEntry::jointype, JoinExpr::jointype, JoinExpr::larg, lfirst, linitial, list_concat(), list_intersection(), list_length(), lsecond, NIL, nodeTag, PlannerInfo::parse, pull_varnos(), JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, reduce_outer_joins_state::relids, rt_fetch, Query::rtable, RTE_JOIN, RangeTblEntry::rtekind, JoinExpr::rtindex, and reduce_outer_joins_state::sub_states.

Referenced by reduce_outer_joins().

2546 {
2547  /*
2548  * pass 2 should never descend as far as an empty subnode or base rel,
2549  * because it's only called on subtrees marked as contains_outer.
2550  */
2551  if (jtnode == NULL)
2552  elog(ERROR, "reached empty jointree");
2553  if (IsA(jtnode, RangeTblRef))
2554  elog(ERROR, "reached base rel");
2555  else if (IsA(jtnode, FromExpr))
2556  {
2557  FromExpr *f = (FromExpr *) jtnode;
2558  ListCell *l;
2559  ListCell *s;
2560  Relids pass_nonnullable_rels;
2561  List *pass_nonnullable_vars;
2562  List *pass_forced_null_vars;
2563 
2564  /* Scan quals to see if we can add any constraints */
2565  pass_nonnullable_rels = find_nonnullable_rels(f->quals);
2566  pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
2567  nonnullable_rels);
2568  /* NB: we rely on list_concat to not damage its second argument */
2569  pass_nonnullable_vars = find_nonnullable_vars(f->quals);
2570  pass_nonnullable_vars = list_concat(pass_nonnullable_vars,
2571  nonnullable_vars);
2572  pass_forced_null_vars = find_forced_null_vars(f->quals);
2573  pass_forced_null_vars = list_concat(pass_forced_null_vars,
2574  forced_null_vars);
2575  /* And recurse --- but only into interesting subtrees */
2577  forboth(l, f->fromlist, s, state->sub_states)
2578  {
2579  reduce_outer_joins_state *sub_state = lfirst(s);
2580 
2581  if (sub_state->contains_outer)
2582  reduce_outer_joins_pass2(lfirst(l), sub_state, root,
2583  pass_nonnullable_rels,
2584  pass_nonnullable_vars,
2585  pass_forced_null_vars);
2586  }
2587  bms_free(pass_nonnullable_rels);
2588  /* can't so easily clean up var lists, unfortunately */
2589  }
2590  else if (IsA(jtnode, JoinExpr))
2591  {
2592  JoinExpr *j = (JoinExpr *) jtnode;
2593  int rtindex = j->rtindex;
2594  JoinType jointype = j->jointype;
2595  reduce_outer_joins_state *left_state = linitial(state->sub_states);
2596  reduce_outer_joins_state *right_state = lsecond(state->sub_states);
2597  List *local_nonnullable_vars = NIL;
2598  bool computed_local_nonnullable_vars = false;
2599 
2600  /* Can we simplify this join? */
2601  switch (jointype)
2602  {
2603  case JOIN_INNER:
2604  break;
2605  case JOIN_LEFT:
2606  if (bms_overlap(nonnullable_rels, right_state->relids))
2607  jointype = JOIN_INNER;
2608  break;
2609  case JOIN_RIGHT:
2610  if (bms_overlap(nonnullable_rels, left_state->relids))
2611  jointype = JOIN_INNER;
2612  break;
2613  case JOIN_FULL:
2614  if (bms_overlap(nonnullable_rels, left_state->relids))
2615  {
2616  if (bms_overlap(nonnullable_rels, right_state->relids))
2617  jointype = JOIN_INNER;
2618  else
2619  jointype = JOIN_LEFT;
2620  }
2621  else
2622  {
2623  if (bms_overlap(nonnullable_rels, right_state->relids))
2624  jointype = JOIN_RIGHT;
2625  }
2626  break;
2627  case JOIN_SEMI:
2628  case JOIN_ANTI:
2629 
2630  /*
2631  * These could only have been introduced by pull_up_sublinks,
2632  * so there's no way that upper quals could refer to their
2633  * righthand sides, and no point in checking.
2634  */
2635  break;
2636  default:
2637  elog(ERROR, "unrecognized join type: %d",
2638  (int) jointype);
2639  break;
2640  }
2641 
2642  /*
2643  * Convert JOIN_RIGHT to JOIN_LEFT. Note that in the case where we
2644  * reduced JOIN_FULL to JOIN_RIGHT, this will mean the JoinExpr no
2645  * longer matches the internal ordering of any CoalesceExpr's built to
2646  * represent merged join variables. We don't care about that at
2647  * present, but be wary of it ...
2648  */
2649  if (jointype == JOIN_RIGHT)
2650  {
2651  Node *tmparg;
2652 
2653  tmparg = j->larg;
2654  j->larg = j->rarg;
2655  j->rarg = tmparg;
2656  jointype = JOIN_LEFT;
2657  right_state = linitial(state->sub_states);
2658  left_state = lsecond(state->sub_states);
2659  }
2660 
2661  /*
2662  * See if we can reduce JOIN_LEFT to JOIN_ANTI. This is the case if
2663  * the join's own quals are strict for any var that was forced null by
2664  * higher qual levels. NOTE: there are other ways that we could
2665  * detect an anti-join, in particular if we were to check whether Vars
2666  * coming from the RHS must be non-null because of table constraints.
2667  * That seems complicated and expensive though (in particular, one
2668  * would have to be wary of lower outer joins). For the moment this
2669  * seems sufficient.
2670  */
2671  if (jointype == JOIN_LEFT)
2672  {
2673  List *overlap;
2674 
2675  local_nonnullable_vars = find_nonnullable_vars(j->quals);
2676  computed_local_nonnullable_vars = true;
2677 
2678  /*
2679  * It's not sufficient to check whether local_nonnullable_vars and
2680  * forced_null_vars overlap: we need to know if the overlap
2681  * includes any RHS variables.
2682  */
2683  overlap = list_intersection(local_nonnullable_vars,
2684  forced_null_vars);
2685  if (overlap != NIL &&
2686  bms_overlap(pull_varnos((Node *) overlap),
2687  right_state->relids))
2688  jointype = JOIN_ANTI;
2689  }
2690 
2691  /* Apply the jointype change, if any, to both jointree node and RTE */
2692  if (rtindex && jointype != j->jointype)
2693  {
2694  RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
2695 
2696  Assert(rte->rtekind == RTE_JOIN);
2697  Assert(rte->jointype == j->jointype);
2698  rte->jointype = jointype;
2699  }
2700  j->jointype = jointype;
2701 
2702  /* Only recurse if there's more to do below here */
2703  if (left_state->contains_outer || right_state->contains_outer)
2704  {
2705  Relids local_nonnullable_rels;
2706  List *local_forced_null_vars;
2707  Relids pass_nonnullable_rels;
2708  List *pass_nonnullable_vars;
2709  List *pass_forced_null_vars;
2710 
2711  /*
2712  * If this join is (now) inner, we can add any constraints its
2713  * quals provide to those we got from above. But if it is outer,
2714  * we can pass down the local constraints only into the nullable
2715  * side, because an outer join never eliminates any rows from its
2716  * non-nullable side. Also, there is no point in passing upper
2717  * constraints into the nullable side, since if there were any
2718  * we'd have been able to reduce the join. (In the case of upper
2719  * forced-null constraints, we *must not* pass them into the
2720  * nullable side --- they either applied here, or not.) The upshot
2721  * is that we pass either the local or the upper constraints,
2722  * never both, to the children of an outer join.
2723  *
2724  * Note that a SEMI join works like an inner join here: it's okay
2725  * to pass down both local and upper constraints. (There can't be
2726  * any upper constraints affecting its inner side, but it's not
2727  * worth having a separate code path to avoid passing them.)
2728  *
2729  * At a FULL join we just punt and pass nothing down --- is it
2730  * possible to be smarter?
2731  */
2732  if (jointype != JOIN_FULL)
2733  {
2734  local_nonnullable_rels = find_nonnullable_rels(j->quals);
2735  if (!computed_local_nonnullable_vars)
2736  local_nonnullable_vars = find_nonnullable_vars(j->quals);
2737  local_forced_null_vars = find_forced_null_vars(j->quals);
2738  if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2739  {
2740  /* OK to merge upper and local constraints */
2741  local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
2742  nonnullable_rels);
2743  local_nonnullable_vars = list_concat(local_nonnullable_vars,
2744  nonnullable_vars);
2745  local_forced_null_vars = list_concat(local_forced_null_vars,
2746  forced_null_vars);
2747  }
2748  }
2749  else
2750  {
2751  /* no use in calculating these */
2752  local_nonnullable_rels = NULL;
2753  local_forced_null_vars = NIL;
2754  }
2755 
2756  if (left_state->contains_outer)
2757  {
2758  if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2759  {
2760  /* pass union of local and upper constraints */
2761  pass_nonnullable_rels = local_nonnullable_rels;
2762  pass_nonnullable_vars = local_nonnullable_vars;
2763  pass_forced_null_vars = local_forced_null_vars;
2764  }
2765  else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
2766  {
2767  /* can't pass local constraints to non-nullable side */
2768  pass_nonnullable_rels = nonnullable_rels;
2769  pass_nonnullable_vars = nonnullable_vars;
2770  pass_forced_null_vars = forced_null_vars;
2771  }
2772  else
2773  {
2774  /* no constraints pass through JOIN_FULL */
2775  pass_nonnullable_rels = NULL;
2776  pass_nonnullable_vars = NIL;
2777  pass_forced_null_vars = NIL;
2778  }
2779  reduce_outer_joins_pass2(j->larg, left_state, root,
2780  pass_nonnullable_rels,
2781  pass_nonnullable_vars,
2782  pass_forced_null_vars);
2783  }
2784 
2785  if (right_state->contains_outer)
2786  {
2787  if (jointype != JOIN_FULL) /* ie, INNER/LEFT/SEMI/ANTI */
2788  {
2789  /* pass appropriate constraints, per comment above */
2790  pass_nonnullable_rels = local_nonnullable_rels;
2791  pass_nonnullable_vars = local_nonnullable_vars;
2792  pass_forced_null_vars = local_forced_null_vars;
2793  }
2794  else
2795  {
2796  /* no constraints pass through JOIN_FULL */
2797  pass_nonnullable_rels = NULL;
2798  pass_nonnullable_vars = NIL;
2799  pass_forced_null_vars = NIL;
2800  }
2801  reduce_outer_joins_pass2(j->rarg, right_state, root,
2802  pass_nonnullable_rels,
2803  pass_nonnullable_vars,
2804  pass_forced_null_vars);
2805  }
2806  bms_free(local_nonnullable_rels);
2807  }
2808  }
2809  else
2810  elog(ERROR, "unrecognized node type: %d",
2811  (int) nodeTag(jtnode));
2812 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Query * parse
Definition: relation.h:155
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
Definition: nodes.h:510
List * list_concat(List *list1, List *list2)
Definition: list.c:321
List * fromlist
Definition: primnodes.h:1471
Node * quals
Definition: primnodes.h:1472
#define lsecond(l)
Definition: pg_list.h:116
JoinType
Definition: nodes.h:674
Node * larg
Definition: primnodes.h:1451
List * find_forced_null_vars(Node *node)
Definition: clauses.c:2035
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
Relids find_nonnullable_rels(Node *clause)
Definition: clauses.c:1634
JoinType jointype
Definition: parsenodes.h:988
List * list_intersection(const List *list1, const List *list2)
Definition: list.c:800
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Relids pull_varnos(Node *node)
Definition: var.c:95
Node * quals
Definition: primnodes.h:1454
List * find_nonnullable_vars(Node *clause)
Definition: clauses.c:1842
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
Node * rarg
Definition: primnodes.h:1452
JoinType jointype
Definition: primnodes.h:1449
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
#define nodeTag(nodeptr)
Definition: nodes.h:515
RTEKind rtekind
Definition: parsenodes.h:945
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
#define elog
Definition: elog.h:219
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *nonnullable_vars, List *forced_null_vars)
int rtindex
Definition: primnodes.h:1456
Definition: pg_list.h:45
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:755
static void replace_vars_in_jointree ( Node jtnode,
pullup_replace_vars_context context,
JoinExpr lowest_nulling_outer_join 
)
static

Definition at line 1924 of file prepjointree.c.

References Assert, elog, ERROR, FromExpr::fromlist, RangeTblEntry::functions, IsA, JoinExpr::larg, RangeTblEntry::lateral, lfirst, pullup_replace_vars_context::need_phvs, nodeTag, PlannerInfo::parse, pullup_replace_vars(), pullup_replace_vars_subquery(), JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, pullup_replace_vars_context::root, rt_fetch, Query::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, pullup_replace_vars_context::target_rte, RangeTblEntry::values_lists, and pullup_replace_vars_context::varno.

Referenced by pull_up_simple_subquery(), and pull_up_simple_values().

1927 {
1928  if (jtnode == NULL)
1929  return;
1930  if (IsA(jtnode, RangeTblRef))
1931  {
1932  /*
1933  * If the RangeTblRef refers to a LATERAL subquery (that isn't the
1934  * same subquery we're pulling up), it might contain references to the
1935  * target subquery, which we must replace. We drive this from the
1936  * jointree scan, rather than a scan of the rtable, for a couple of
1937  * reasons: we can avoid processing no-longer-referenced RTEs, and we
1938  * can use the appropriate setting of need_phvs depending on whether
1939  * the RTE is above possibly-nulling outer joins or not.
1940  */
1941  int varno = ((RangeTblRef *) jtnode)->rtindex;
1942 
1943  if (varno != context->varno) /* ignore target subquery itself */
1944  {
1945  RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable);
1946 
1947  Assert(rte != context->target_rte);
1948  if (rte->lateral)
1949  {
1950  switch (rte->rtekind)
1951  {
1952  case RTE_RELATION:
1953  /* shouldn't be marked LATERAL unless tablesample */
1954  Assert(rte->tablesample);
1955  rte->tablesample = (TableSampleClause *)
1957  context);
1958  break;
1959  case RTE_SUBQUERY:
1960  rte->subquery =
1962  context);
1963  break;
1964  case RTE_FUNCTION:
1965  rte->functions = (List *)
1967  context);
1968  break;
1969  case RTE_TABLEFUNC:
1970  rte->tablefunc = (TableFunc *)
1972  context);
1973  break;
1974  case RTE_VALUES:
1975  rte->values_lists = (List *)
1977  context);
1978  break;
1979  case RTE_JOIN:
1980  case RTE_CTE:
1981  case RTE_NAMEDTUPLESTORE:
1982  /* these shouldn't be marked LATERAL */
1983  Assert(false);
1984  break;
1985  }
1986  }
1987  }
1988  }
1989  else if (IsA(jtnode, FromExpr))
1990  {
1991  FromExpr *f = (FromExpr *) jtnode;
1992  ListCell *l;
1993 
1994  foreach(l, f->fromlist)
1995  replace_vars_in_jointree(lfirst(l), context,
1996  lowest_nulling_outer_join);
1997  f->quals = pullup_replace_vars(f->quals, context);
1998  }
1999  else if (IsA(jtnode, JoinExpr))
2000  {
2001  JoinExpr *j = (JoinExpr *) jtnode;
2002  bool save_need_phvs = context->need_phvs;
2003 
2004  if (j == lowest_nulling_outer_join)
2005  {
2006  /* no more PHVs in or below this join */
2007  context->need_phvs = false;
2008  lowest_nulling_outer_join = NULL;
2009  }
2010  replace_vars_in_jointree(j->larg, context, lowest_nulling_outer_join);
2011  replace_vars_in_jointree(j->rarg, context, lowest_nulling_outer_join);
2012  j->quals = pullup_replace_vars(j->quals, context);
2013 
2014  /*
2015  * We don't bother to update the colvars list, since it won't be used
2016  * again ...
2017  */
2018  context->need_phvs = save_need_phvs;
2019  }
2020  else
2021  elog(ERROR, "unrecognized node type: %d",
2022  (int) nodeTag(jtnode));
2023 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
Query * parse
Definition: relation.h:155
Definition: nodes.h:510
List * fromlist
Definition: primnodes.h:1471
List * values_lists
Definition: parsenodes.h:1010
Node * quals
Definition: primnodes.h:1472
Node * larg
Definition: primnodes.h:1451
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
RangeTblEntry * target_rte
Definition: prepjointree.c:44
TableFunc * tablefunc
Definition: parsenodes.h:1005
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * quals
Definition: primnodes.h:1454
Node * rarg
Definition: primnodes.h:1452
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
List * functions
Definition: parsenodes.h:999
#define nodeTag(nodeptr)
Definition: nodes.h:515
RTEKind rtekind
Definition: parsenodes.h:945
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
Query * subquery
Definition: parsenodes.h:968
static Query * pullup_replace_vars_subquery(Query *query, pullup_replace_vars_context *context)
#define elog
Definition: elog.h:219
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
Definition: pg_list.h:45
struct TableSampleClause * tablesample
Definition: parsenodes.h:963
static void substitute_multiple_relids ( Node node,
int  varno,
Relids  subrelids 
)
static

Definition at line 2877 of file prepjointree.c.

References query_or_expression_tree_walker(), substitute_multiple_relids_context::sublevels_up, substitute_multiple_relids_context::subrelids, substitute_multiple_relids_walker(), and substitute_multiple_relids_context::varno.

Referenced by fix_append_rel_relids(), and pull_up_simple_subquery().

2878 {
2880 
2881  context.varno = varno;
2882  context.sublevels_up = 0;
2883  context.subrelids = subrelids;
2884 
2885  /*
2886  * Must be prepared to start with a Query or a bare expression tree.
2887  */
2890  (void *) &context,
2891  0);
2892 }
static bool substitute_multiple_relids_walker(Node *node, substitute_multiple_relids_context *context)
bool query_or_expression_tree_walker(Node *node, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:3178
static bool substitute_multiple_relids_walker ( Node node,
substitute_multiple_relids_context context 
)
static

Definition at line 2835 of file prepjointree.c.

References Assert, bms_del_member(), bms_is_member(), bms_union(), expression_tree_walker(), IsA, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, query_tree_walker(), substitute_multiple_relids_context::sublevels_up, substitute_multiple_relids_context::subrelids, and substitute_multiple_relids_context::varno.

Referenced by substitute_multiple_relids().

2837 {
2838  if (node == NULL)
2839  return false;
2840  if (IsA(node, PlaceHolderVar))
2841  {
2842  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2843 
2844  if (phv->phlevelsup == context->sublevels_up &&
2845  bms_is_member(context->varno, phv->phrels))
2846  {
2847  phv->phrels = bms_union(phv->phrels,
2848  context->subrelids);
2849  phv->phrels = bms_del_member(phv->phrels,
2850  context->varno);
2851  }
2852  /* fall through to examine children */
2853  }
2854  if (IsA(node, Query))
2855  {
2856  /* Recurse into subselects */
2857  bool result;
2858 
2859  context->sublevels_up++;
2860  result = query_tree_walker((Query *) node,
2862  (void *) context, 0);
2863  context->sublevels_up--;
2864  return result;
2865  }
2866  /* Shouldn't need to handle planner auxiliary nodes here */
2867  Assert(!IsA(node, SpecialJoinInfo));
2868  Assert(!IsA(node, AppendRelInfo));
2869  Assert(!IsA(node, PlaceHolderInfo));
2870  Assert(!IsA(node, MinMaxAggInfo));
2871 
2873  (void *) context);
2874 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2245
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
static bool substitute_multiple_relids_walker(Node *node, substitute_multiple_relids_context *context)
Relids phrels
Definition: relation.h:1941
#define Assert(condition)
Definition: c.h:681
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:218
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1834
Index phlevelsup
Definition: relation.h:1943
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:735
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420