PostgreSQL Source Code  git master
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  find_dependent_phvs_context
 
struct  substitute_phv_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)
 
static Nodepull_up_simple_subquery (PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
 
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, int newvarno, AppendRelInfo *appinfo)
 
static bool is_simple_subquery (PlannerInfo *root, Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join)
 
static Nodepull_up_simple_values (PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
 
static bool is_simple_values (PlannerInfo *root, RangeTblEntry *rte)
 
static Nodepull_up_constant_function (PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
 
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 (PlannerInfo *root, Node *jtnode, bool restricted, Relids safe_upper_varnos)
 
static void perform_pullup_replace_vars (PlannerInfo *root, pullup_replace_vars_context *rvcontext, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
 
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 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 *forced_null_vars)
 
static Noderemove_useless_results_recurse (PlannerInfo *root, Node *jtnode)
 
static int get_result_relid (PlannerInfo *root, Node *jtnode)
 
static void remove_result_refs (PlannerInfo *root, int varno, Node *newjtloc)
 
static bool find_dependent_phvs (PlannerInfo *root, int varno)
 
static bool find_dependent_phvs_in_jointree (PlannerInfo *root, Node *node, int varno)
 
static void substitute_phv_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 transform_MERGE_to_join (Query *parse)
 
void replace_empty_jointree (Query *parse)
 
void pull_up_sublinks (PlannerInfo *root)
 
void preprocess_function_rtes (PlannerInfo *root)
 
void pull_up_subqueries (PlannerInfo *root)
 
void flatten_simple_union_all (PlannerInfo *root)
 
void reduce_outer_joins (PlannerInfo *root)
 
void remove_useless_result_rtes (PlannerInfo *root)
 
static bool find_dependent_phvs_walker (Node *node, find_dependent_phvs_context *context)
 
static bool substitute_phv_relids_walker (Node *node, substitute_phv_relids_context *context)
 
Relids get_relids_in_jointree (Node *jtnode, bool include_joins)
 
Relids get_relids_for_join (Query *query, int joinrelid)
 

Typedef Documentation

◆ pullup_replace_vars_context

◆ reduce_outer_joins_state

Function Documentation

◆ find_dependent_phvs()

static bool find_dependent_phvs ( PlannerInfo root,
int  varno 
)
static

Definition at line 3405 of file prepjointree.c.

3406 {
3408 
3409  /* If there are no PHVs anywhere, we needn't work hard */
3410  if (root->glob->lastPHId == 0)
3411  return false;
3412 
3413  context.relids = bms_make_singleton(varno);
3414  context.sublevels_up = 0;
3415 
3416  return query_tree_walker(root->parse,
3418  (void *) &context,
3419  0);
3420 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
static bool find_dependent_phvs_walker(Node *node, find_dependent_phvs_context *context)
Index lastPHId
Definition: pathnodes.h:141
PlannerGlobal * glob
Definition: pathnodes.h:205
Query * parse
Definition: pathnodes.h:202

References bms_make_singleton(), find_dependent_phvs_walker(), PlannerInfo::glob, PlannerGlobal::lastPHId, PlannerInfo::parse, query_tree_walker, find_dependent_phvs_context::relids, and find_dependent_phvs_context::sublevels_up.

Referenced by remove_useless_results_recurse().

◆ find_dependent_phvs_in_jointree()

static bool find_dependent_phvs_in_jointree ( PlannerInfo root,
Node node,
int  varno 
)
static

Definition at line 3423 of file prepjointree.c.

3424 {
3426  Relids subrelids;
3427  int relid;
3428 
3429  /* If there are no PHVs anywhere, we needn't work hard */
3430  if (root->glob->lastPHId == 0)
3431  return false;
3432 
3433  context.relids = bms_make_singleton(varno);
3434  context.sublevels_up = 0;
3435 
3436  /*
3437  * See if the jointree fragment itself contains references (in join quals)
3438  */
3439  if (find_dependent_phvs_walker(node, &context))
3440  return true;
3441 
3442  /*
3443  * Otherwise, identify the set of referenced RTEs (we can ignore joins,
3444  * since they should be flattened already, so their join alias lists no
3445  * longer matter), and tediously check each RTE. We can ignore RTEs that
3446  * are not marked LATERAL, though, since they couldn't possibly contain
3447  * any cross-references to other RTEs.
3448  */
3449  subrelids = get_relids_in_jointree(node, false);
3450  relid = -1;
3451  while ((relid = bms_next_member(subrelids, relid)) >= 0)
3452  {
3453  RangeTblEntry *rte = rt_fetch(relid, root->parse->rtable);
3454 
3455  if (rte->lateral &&
3458  (void *) &context,
3459  0))
3460  return true;
3461  }
3462 
3463  return false;
3464 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1047
#define range_table_entry_walker(r, w, c, f)
Definition: nodeFuncs.h:166
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
List * rtable
Definition: parsenodes.h:155

References bms_make_singleton(), bms_next_member(), find_dependent_phvs_walker(), get_relids_in_jointree(), PlannerInfo::glob, PlannerGlobal::lastPHId, RangeTblEntry::lateral, PlannerInfo::parse, range_table_entry_walker, find_dependent_phvs_context::relids, rt_fetch, Query::rtable, and find_dependent_phvs_context::sublevels_up.

Referenced by remove_useless_results_recurse().

◆ find_dependent_phvs_walker()

static bool find_dependent_phvs_walker ( Node node,
find_dependent_phvs_context context 
)
static

Definition at line 3368 of file prepjointree.c.

3370 {
3371  if (node == NULL)
3372  return false;
3373  if (IsA(node, PlaceHolderVar))
3374  {
3375  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3376 
3377  if (phv->phlevelsup == context->sublevels_up &&
3378  bms_equal(context->relids, phv->phrels))
3379  return true;
3380  /* fall through to examine children */
3381  }
3382  if (IsA(node, Query))
3383  {
3384  /* Recurse into subselects */
3385  bool result;
3386 
3387  context->sublevels_up++;
3388  result = query_tree_walker((Query *) node,
3390  (void *) context, 0);
3391  context->sublevels_up--;
3392  return result;
3393  }
3394  /* Shouldn't need to handle planner auxiliary nodes here */
3395  Assert(!IsA(node, SpecialJoinInfo));
3396  Assert(!IsA(node, AppendRelInfo));
3397  Assert(!IsA(node, PlaceHolderInfo));
3398  Assert(!IsA(node, MinMaxAggInfo));
3399 
3401  (void *) context);
3402 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:94
Assert(fmt[strlen(fmt) - 1] !='\n')
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define IsA(nodeptr, _type_)
Definition: nodes.h:168
Index phlevelsup
Definition: pathnodes.h:2633

References Assert(), bms_equal(), expression_tree_walker, IsA, PlaceHolderVar::phlevelsup, query_tree_walker, find_dependent_phvs_context::relids, and find_dependent_phvs_context::sublevels_up.

Referenced by find_dependent_phvs(), and find_dependent_phvs_in_jointree().

◆ find_jointree_node_for_rel()

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

Definition at line 3658 of file prepjointree.c.

3659 {
3660  if (jtnode == NULL)
3661  return NULL;
3662  if (IsA(jtnode, RangeTblRef))
3663  {
3664  int varno = ((RangeTblRef *) jtnode)->rtindex;
3665 
3666  if (relid == varno)
3667  return jtnode;
3668  }
3669  else if (IsA(jtnode, FromExpr))
3670  {
3671  FromExpr *f = (FromExpr *) jtnode;
3672  ListCell *l;
3673 
3674  foreach(l, f->fromlist)
3675  {
3676  jtnode = find_jointree_node_for_rel(lfirst(l), relid);
3677  if (jtnode)
3678  return jtnode;
3679  }
3680  }
3681  else if (IsA(jtnode, JoinExpr))
3682  {
3683  JoinExpr *j = (JoinExpr *) jtnode;
3684 
3685  if (relid == j->rtindex)
3686  return jtnode;
3687  jtnode = find_jointree_node_for_rel(j->larg, relid);
3688  if (jtnode)
3689  return jtnode;
3690  jtnode = find_jointree_node_for_rel(j->rarg, relid);
3691  if (jtnode)
3692  return jtnode;
3693  }
3694  else
3695  elog(ERROR, "unrecognized node type: %d",
3696  (int) nodeTag(jtnode));
3697  return NULL;
3698 }
#define ERROR
Definition: elog.h:35
int j
Definition: isn.c:74
#define nodeTag(nodeptr)
Definition: nodes.h:122
#define lfirst(lc)
Definition: pg_list.h:170
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
List * fromlist
Definition: primnodes.h:1664

References elog(), ERROR, FromExpr::fromlist, IsA, j, lfirst, and nodeTag.

Referenced by get_relids_for_join().

◆ fix_append_rel_relids()

static void fix_append_rel_relids ( List append_rel_list,
int  varno,
Relids  subrelids 
)
static

Definition at line 3559 of file prepjointree.c.

3560 {
3561  ListCell *l;
3562  int subvarno = -1;
3563 
3564  /*
3565  * We only want to extract the member relid once, but we mustn't fail
3566  * immediately if there are multiple members; it could be that none of the
3567  * AppendRelInfo nodes refer to it. So compute it on first use. Note that
3568  * bms_singleton_member will complain if set is not singleton.
3569  */
3570  foreach(l, append_rel_list)
3571  {
3572  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
3573 
3574  /* The parent_relid shouldn't ever be a pullup target */
3575  Assert(appinfo->parent_relid != varno);
3576 
3577  if (appinfo->child_relid == varno)
3578  {
3579  if (subvarno < 0)
3580  subvarno = bms_singleton_member(subrelids);
3581  appinfo->child_relid = subvarno;
3582  }
3583 
3584  /* Also fix up any PHVs in its translated vars */
3586  varno, subrelids);
3587  }
3588 }
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:580
static void substitute_phv_relids(Node *node, int varno, Relids subrelids)
Index child_relid
Definition: pathnodes.h:2758
List * translated_vars
Definition: pathnodes.h:2785
Index parent_relid
Definition: pathnodes.h:2757
Definition: nodes.h:118

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

Referenced by pull_up_simple_subquery(), and remove_result_refs().

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2553 of file prepjointree.c.

2554 {
2555  Query *parse = root->parse;
2556  SetOperationStmt *topop;
2557  Node *leftmostjtnode;
2558  int leftmostRTI;
2559  RangeTblEntry *leftmostRTE;
2560  int childRTI;
2561  RangeTblEntry *childRTE;
2562  RangeTblRef *rtr;
2563 
2564  /* Shouldn't be called unless query has setops */
2565  topop = castNode(SetOperationStmt, parse->setOperations);
2566  Assert(topop);
2567 
2568  /* Can't optimize away a recursive UNION */
2569  if (root->hasRecursion)
2570  return;
2571 
2572  /*
2573  * Recursively check the tree of set operations. If not all UNION ALL
2574  * with identical column types, punt.
2575  */
2576  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2577  return;
2578 
2579  /*
2580  * Locate the leftmost leaf query in the setops tree. The upper query's
2581  * Vars all refer to this RTE (see transformSetOperationStmt).
2582  */
2583  leftmostjtnode = topop->larg;
2584  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2585  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2586  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2587  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2588  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2589  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2590 
2591  /*
2592  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2593  * will represent the leftmost leaf query in its capacity as a member of
2594  * the appendrel. The original will represent the appendrel as a whole.
2595  * (We must do things this way because the upper query's Vars have to be
2596  * seen as referring to the whole appendrel.)
2597  */
2598  childRTE = copyObject(leftmostRTE);
2599  parse->rtable = lappend(parse->rtable, childRTE);
2600  childRTI = list_length(parse->rtable);
2601 
2602  /* Modify the setops tree to reference the child copy */
2603  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2604 
2605  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2606  leftmostRTE->inh = true;
2607 
2608  /*
2609  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2610  * Query of a setops tree should have had an empty FromClause initially.
2611  */
2612  rtr = makeNode(RangeTblRef);
2613  rtr->rtindex = leftmostRTI;
2614  Assert(parse->jointree->fromlist == NIL);
2615  parse->jointree->fromlist = list_make1(rtr);
2616 
2617  /*
2618  * Now pretend the query has no setops. We must do this before trying to
2619  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2620  */
2621  parse->setOperations = NULL;
2622 
2623  /*
2624  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2625  * leaf queries of the UNION ALL. (We must do that now because they
2626  * weren't previously referenced by the jointree, and so were missed by
2627  * the main invocation of pull_up_subqueries.)
2628  */
2629  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2630 }
List * lappend(List *list, void *datum)
Definition: list.c:338
#define copyObject(obj)
Definition: nodes.h:233
#define makeNode(_type_)
Definition: nodes.h:165
#define castNode(_type_, nodeptr)
Definition: nodes.h:186
@ RTE_SUBQUERY
Definition: parsenodes.h:983
static int list_length(const List *l)
Definition: pg_list.h:150
#define NIL
Definition: pg_list.h:66
#define list_make1(x1)
Definition: pg_list.h:210
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
bool hasRecursion
Definition: pathnodes.h:466
RTEKind rtekind
Definition: parsenodes.h:1001

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

Referenced by subquery_planner().

◆ get_relids_for_join()

Relids get_relids_for_join ( Query query,
int  joinrelid 
)

Definition at line 3641 of file prepjointree.c.

3642 {
3643  Node *jtnode;
3644 
3645  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3646  joinrelid);
3647  if (!jtnode)
3648  elog(ERROR, "could not find join node %d", joinrelid);
3649  return get_relids_in_jointree(jtnode, false);
3650 }
FromExpr * jointree
Definition: parsenodes.h:158

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

Referenced by alias_relid_set().

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 3597 of file prepjointree.c.

3598 {
3599  Relids result = NULL;
3600 
3601  if (jtnode == NULL)
3602  return result;
3603  if (IsA(jtnode, RangeTblRef))
3604  {
3605  int varno = ((RangeTblRef *) jtnode)->rtindex;
3606 
3607  result = bms_make_singleton(varno);
3608  }
3609  else if (IsA(jtnode, FromExpr))
3610  {
3611  FromExpr *f = (FromExpr *) jtnode;
3612  ListCell *l;
3613 
3614  foreach(l, f->fromlist)
3615  {
3616  result = bms_join(result,
3618  include_joins));
3619  }
3620  }
3621  else if (IsA(jtnode, JoinExpr))
3622  {
3623  JoinExpr *j = (JoinExpr *) jtnode;
3624 
3625  result = get_relids_in_jointree(j->larg, include_joins);
3626  result = bms_join(result,
3627  get_relids_in_jointree(j->rarg, include_joins));
3628  if (include_joins && j->rtindex)
3629  result = bms_add_member(result, j->rtindex);
3630  }
3631  else
3632  elog(ERROR, "unrecognized node type: %d",
3633  (int) nodeTag(jtnode));
3634  return result;
3635 }
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:953
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739

References bms_add_member(), bms_join(), bms_make_singleton(), elog(), ERROR, FromExpr::fromlist, IsA, j, lfirst, and nodeTag.

Referenced by distribute_qual_to_rels(), find_dependent_phvs_in_jointree(), get_relids_for_join(), is_simple_subquery(), preprocess_rowmarks(), process_implied_equality(), pull_up_simple_subquery(), and remove_result_refs().

◆ get_result_relid()

static int get_result_relid ( PlannerInfo root,
Node jtnode 
)
static

Definition at line 3299 of file prepjointree.c.

3300 {
3301  int varno;
3302 
3303  if (!IsA(jtnode, RangeTblRef))
3304  return 0;
3305  varno = ((RangeTblRef *) jtnode)->rtindex;
3306  if (rt_fetch(varno, root->parse->rtable)->rtekind != RTE_RESULT)
3307  return 0;
3308  return varno;
3309 }
@ RTE_RESULT
Definition: parsenodes.h:990

References IsA, PlannerInfo::parse, rt_fetch, Query::rtable, and RTE_RESULT.

Referenced by remove_useless_results_recurse().

◆ is_safe_append_member()

static bool is_safe_append_member ( Query subquery)
static

Definition at line 1978 of file prepjointree.c.

1979 {
1980  FromExpr *jtnode;
1981 
1982  /*
1983  * It's only safe to pull up the child if its jointree contains exactly
1984  * one RTE, else the AppendRelInfo data structure breaks. The one base RTE
1985  * could be buried in several levels of FromExpr, however. Also, if the
1986  * child's jointree is completely empty, we can pull up because
1987  * pull_up_simple_subquery will insert a single RTE_RESULT RTE instead.
1988  *
1989  * Also, the child can't have any WHERE quals because there's no place to
1990  * put them in an appendrel. (This is a bit annoying...) If we didn't
1991  * need to check this, we'd just test whether get_relids_in_jointree()
1992  * yields a singleton set, to be more consistent with the coding of
1993  * fix_append_rel_relids().
1994  */
1995  jtnode = subquery->jointree;
1996  Assert(IsA(jtnode, FromExpr));
1997  /* Check the completely-empty case */
1998  if (jtnode->fromlist == NIL && jtnode->quals == NULL)
1999  return true;
2000  /* Check the more general case */
2001  while (IsA(jtnode, FromExpr))
2002  {
2003  if (jtnode->quals != NULL)
2004  return false;
2005  if (list_length(jtnode->fromlist) != 1)
2006  return false;
2007  jtnode = linitial(jtnode->fromlist);
2008  }
2009  if (!IsA(jtnode, RangeTblRef))
2010  return false;
2011 
2012  return true;
2013 }
#define linitial(l)
Definition: pg_list.h:176
Node * quals
Definition: primnodes.h:1665

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

Referenced by pull_up_simple_subquery(), and pull_up_subqueries_recurse().

◆ is_simple_subquery()

static bool is_simple_subquery ( PlannerInfo root,
Query subquery,
RangeTblEntry rte,
JoinExpr lowest_outer_join 
)
static

Definition at line 1489 of file prepjointree.c.

1491 {
1492  /*
1493  * Let's just make sure it's a valid subselect ...
1494  */
1495  if (!IsA(subquery, Query) ||
1496  subquery->commandType != CMD_SELECT)
1497  elog(ERROR, "subquery is bogus");
1498 
1499  /*
1500  * Can't currently pull up a query with setops (unless it's simple UNION
1501  * ALL, which is handled by a different code path). Maybe after querytree
1502  * redesign...
1503  */
1504  if (subquery->setOperations)
1505  return false;
1506 
1507  /*
1508  * Can't pull up a subquery involving grouping, aggregation, SRFs,
1509  * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later)
1510  *
1511  * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE
1512  * clauses, because pullup would cause the locking to occur semantically
1513  * higher than it should. Implicit FOR UPDATE/SHARE is okay because in
1514  * that case the locking was originally declared in the upper query
1515  * anyway.
1516  */
1517  if (subquery->hasAggs ||
1518  subquery->hasWindowFuncs ||
1519  subquery->hasTargetSRFs ||
1520  subquery->groupClause ||
1521  subquery->groupingSets ||
1522  subquery->havingQual ||
1523  subquery->sortClause ||
1524  subquery->distinctClause ||
1525  subquery->limitOffset ||
1526  subquery->limitCount ||
1527  subquery->hasForUpdate ||
1528  subquery->cteList)
1529  return false;
1530 
1531  /*
1532  * Don't pull up if the RTE represents a security-barrier view; we
1533  * couldn't prevent information leakage once the RTE's Vars are scattered
1534  * about in the upper query.
1535  */
1536  if (rte->security_barrier)
1537  return false;
1538 
1539  /*
1540  * If the subquery is LATERAL, check for pullup restrictions from that.
1541  */
1542  if (rte->lateral)
1543  {
1544  bool restricted;
1545  Relids safe_upper_varnos;
1546 
1547  /*
1548  * The subquery's WHERE and JOIN/ON quals mustn't contain any lateral
1549  * references to rels outside a higher outer join (including the case
1550  * where the outer join is within the subquery itself). In such a
1551  * case, pulling up would result in a situation where we need to
1552  * postpone quals from below an outer join to above it, which is
1553  * probably completely wrong and in any case is a complication that
1554  * doesn't seem worth addressing at the moment.
1555  */
1556  if (lowest_outer_join != NULL)
1557  {
1558  restricted = true;
1559  safe_upper_varnos = get_relids_in_jointree((Node *) lowest_outer_join,
1560  true);
1561  }
1562  else
1563  {
1564  restricted = false;
1565  safe_upper_varnos = NULL; /* doesn't matter */
1566  }
1567 
1569  (Node *) subquery->jointree,
1570  restricted, safe_upper_varnos))
1571  return false;
1572 
1573  /*
1574  * If there's an outer join above the LATERAL subquery, also disallow
1575  * pullup if the subquery's targetlist has any references to rels
1576  * outside the outer join, since these might get pulled into quals
1577  * above the subquery (but in or below the outer join) and then lead
1578  * to qual-postponement issues similar to the case checked for above.
1579  * (We wouldn't need to prevent pullup if no such references appear in
1580  * outer-query quals, but we don't have enough info here to check
1581  * that. Also, maybe this restriction could be removed if we forced
1582  * such refs to be wrapped in PlaceHolderVars, even when they're below
1583  * the nearest outer join? But it's a pretty hokey usage, so not
1584  * clear this is worth sweating over.)
1585  */
1586  if (lowest_outer_join != NULL)
1587  {
1588  Relids lvarnos = pull_varnos_of_level(root,
1589  (Node *) subquery->targetList,
1590  1);
1591 
1592  if (!bms_is_subset(lvarnos, safe_upper_varnos))
1593  return false;
1594  }
1595  }
1596 
1597  /*
1598  * Don't pull up a subquery that has any volatile functions in its
1599  * targetlist. Otherwise we might introduce multiple evaluations of these
1600  * functions, if they get copied to multiple places in the upper query,
1601  * leading to surprising results. (Note: the PlaceHolderVar mechanism
1602  * doesn't quite guarantee single evaluation; else we could pull up anyway
1603  * and just wrap such items in PlaceHolderVars ...)
1604  */
1605  if (contain_volatile_functions((Node *) subquery->targetList))
1606  return false;
1607 
1608  return true;
1609 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:316
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
@ CMD_SELECT
Definition: nodes.h:265
static bool jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode, bool restricted, Relids safe_upper_varnos)
bool hasWindowFuncs
Definition: parsenodes.h:142
Node * limitCount
Definition: parsenodes.h:186
Node * setOperations
Definition: parsenodes.h:191
List * cteList
Definition: parsenodes.h:153
bool hasTargetSRFs
Definition: parsenodes.h:143
List * groupClause
Definition: parsenodes.h:172
Node * havingQual
Definition: parsenodes.h:177
Node * limitOffset
Definition: parsenodes.h:185
bool hasAggs
Definition: parsenodes.h:141
CmdType commandType
Definition: parsenodes.h:124
List * targetList
Definition: parsenodes.h:164
bool hasForUpdate
Definition: parsenodes.h:148
List * groupingSets
Definition: parsenodes.h:175
List * distinctClause
Definition: parsenodes.h:181
List * sortClause
Definition: parsenodes.h:183
bool security_barrier
Definition: parsenodes.h:1042
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition: var.c:126

References bms_is_subset(), CMD_SELECT, Query::commandType, contain_volatile_functions(), Query::cteList, Query::distinctClause, elog(), ERROR, 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, pull_varnos_of_level(), RangeTblEntry::security_barrier, Query::setOperations, Query::sortClause, and Query::targetList.

Referenced by pull_up_simple_subquery(), and pull_up_subqueries_recurse().

◆ is_simple_union_all()

static bool is_simple_union_all ( Query subquery)
static

Definition at line 1910 of file prepjointree.c.

1911 {
1912  SetOperationStmt *topop;
1913 
1914  /* Let's just make sure it's a valid subselect ... */
1915  if (!IsA(subquery, Query) ||
1916  subquery->commandType != CMD_SELECT)
1917  elog(ERROR, "subquery is bogus");
1918 
1919  /* Is it a set-operation query at all? */
1920  topop = castNode(SetOperationStmt, subquery->setOperations);
1921  if (!topop)
1922  return false;
1923 
1924  /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
1925  if (subquery->sortClause ||
1926  subquery->limitOffset ||
1927  subquery->limitCount ||
1928  subquery->rowMarks ||
1929  subquery->cteList)
1930  return false;
1931 
1932  /* Recursively check the tree of set operations */
1933  return is_simple_union_all_recurse((Node *) topop, subquery,
1934  topop->colTypes);
1935 }
List * rowMarks
Definition: parsenodes.h:189

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().

◆ is_simple_union_all_recurse()

static bool is_simple_union_all_recurse ( Node setOp,
Query setOpQuery,
List colTypes 
)
static

Definition at line 1938 of file prepjointree.c.

1939 {
1940  if (IsA(setOp, RangeTblRef))
1941  {
1942  RangeTblRef *rtr = (RangeTblRef *) setOp;
1943  RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
1944  Query *subquery = rte->subquery;
1945 
1946  Assert(subquery != NULL);
1947 
1948  /* Leaf nodes are OK if they match the toplevel column types */
1949  /* We don't have to compare typmods or collations here */
1950  return tlist_same_datatypes(subquery->targetList, colTypes, true);
1951  }
1952  else if (IsA(setOp, SetOperationStmt))
1953  {
1954  SetOperationStmt *op = (SetOperationStmt *) setOp;
1955 
1956  /* Must be UNION ALL */
1957  if (op->op != SETOP_UNION || !op->all)
1958  return false;
1959 
1960  /* Recurse to check inputs */
1961  return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
1962  is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
1963  }
1964  else
1965  {
1966  elog(ERROR, "unrecognized node type: %d",
1967  (int) nodeTag(setOp));
1968  return false; /* keep compiler quiet */
1969  }
1970 }
@ SETOP_UNION
Definition: parsenodes.h:1745
Query * subquery
Definition: parsenodes.h:1041
SetOperation op
Definition: parsenodes.h:1822
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition: tlist.c:248

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().

◆ is_simple_values()

static bool is_simple_values ( PlannerInfo root,
RangeTblEntry rte 
)
static

Definition at line 1722 of file prepjointree.c.

1723 {
1724  Assert(rte->rtekind == RTE_VALUES);
1725 
1726  /*
1727  * There must be exactly one VALUES list, else it's not semantically
1728  * correct to replace the VALUES RTE with a RESULT RTE, nor would we have
1729  * a unique set of expressions to substitute into the parent query.
1730  */
1731  if (list_length(rte->values_lists) != 1)
1732  return false;
1733 
1734  /*
1735  * Because VALUES can't appear under an outer join (or at least, we won't
1736  * try to pull it up if it does), we need not worry about LATERAL, nor
1737  * about validity of PHVs for the VALUES' outputs.
1738  */
1739 
1740  /*
1741  * Don't pull up a VALUES that contains any set-returning or volatile
1742  * functions. The considerations here are basically identical to the
1743  * restrictions on a pull-able subquery's targetlist.
1744  */
1745  if (expression_returns_set((Node *) rte->values_lists) ||
1747  return false;
1748 
1749  /*
1750  * Do not pull up a VALUES that's not the only RTE in its parent query.
1751  * This is actually the only case that the parser will generate at the
1752  * moment, and assuming this is true greatly simplifies
1753  * pull_up_simple_values().
1754  */
1755  if (list_length(root->parse->rtable) != 1 ||
1756  rte != (RangeTblEntry *) linitial(root->parse->rtable))
1757  return false;
1758 
1759  return true;
1760 }
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:706
@ RTE_VALUES
Definition: parsenodes.h:987
List * values_lists
Definition: parsenodes.h:1111

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().

◆ jointree_contains_lateral_outer_refs()

static bool jointree_contains_lateral_outer_refs ( PlannerInfo root,
Node jtnode,
bool  restricted,
Relids  safe_upper_varnos 
)
static

Definition at line 2026 of file prepjointree.c.

2029 {
2030  if (jtnode == NULL)
2031  return false;
2032  if (IsA(jtnode, RangeTblRef))
2033  return false;
2034  else if (IsA(jtnode, FromExpr))
2035  {
2036  FromExpr *f = (FromExpr *) jtnode;
2037  ListCell *l;
2038 
2039  /* First, recurse to check child joins */
2040  foreach(l, f->fromlist)
2041  {
2043  lfirst(l),
2044  restricted,
2045  safe_upper_varnos))
2046  return true;
2047  }
2048 
2049  /* Then check the top-level quals */
2050  if (restricted &&
2052  safe_upper_varnos))
2053  return true;
2054  }
2055  else if (IsA(jtnode, JoinExpr))
2056  {
2057  JoinExpr *j = (JoinExpr *) jtnode;
2058 
2059  /*
2060  * If this is an outer join, we mustn't allow any upper lateral
2061  * references in or below it.
2062  */
2063  if (j->jointype != JOIN_INNER)
2064  {
2065  restricted = true;
2066  safe_upper_varnos = NULL;
2067  }
2068 
2069  /* Check the child joins */
2071  j->larg,
2072  restricted,
2073  safe_upper_varnos))
2074  return true;
2076  j->rarg,
2077  restricted,
2078  safe_upper_varnos))
2079  return true;
2080 
2081  /* Check the JOIN's qual clauses */
2082  if (restricted &&
2083  !bms_is_subset(pull_varnos_of_level(root, j->quals, 1),
2084  safe_upper_varnos))
2085  return true;
2086  }
2087  else
2088  elog(ERROR, "unrecognized node type: %d",
2089  (int) nodeTag(jtnode));
2090  return false;
2091 }
@ JOIN_INNER
Definition: nodes.h:293

References bms_is_subset(), elog(), ERROR, FromExpr::fromlist, IsA, j, JOIN_INNER, lfirst, nodeTag, pull_varnos_of_level(), and FromExpr::quals.

Referenced by is_simple_subquery().

◆ make_setop_translation_list()

static void make_setop_translation_list ( Query query,
int  newvarno,
AppendRelInfo appinfo 
)
static

Definition at line 1451 of file prepjointree.c.

1453 {
1454  List *vars = NIL;
1455  AttrNumber *pcolnos;
1456  ListCell *l;
1457 
1458  /* Initialize reverse-translation array with all entries zero */
1459  /* (entries for resjunk columns will stay that way) */
1460  appinfo->num_child_cols = list_length(query->targetList);
1461  appinfo->parent_colnos = pcolnos =
1462  (AttrNumber *) palloc0(appinfo->num_child_cols * sizeof(AttrNumber));
1463 
1464  foreach(l, query->targetList)
1465  {
1466  TargetEntry *tle = (TargetEntry *) lfirst(l);
1467 
1468  if (tle->resjunk)
1469  continue;
1470 
1471  vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1472  pcolnos[tle->resno - 1] = tle->resno;
1473  }
1474 
1475  appinfo->translated_vars = vars;
1476 }
int16 AttrNumber
Definition: attnum.h:21
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:103
void * palloc0(Size size)
Definition: mcxt.c:1230
int num_child_cols
Definition: pathnodes.h:2793
Definition: pg_list.h:52
AttrNumber resno
Definition: primnodes.h:1556
bool resjunk
Definition: primnodes.h:1562
Definition: regcomp.c:282

References lappend(), lfirst, list_length(), makeVarFromTargetEntry(), NIL, AppendRelInfo::num_child_cols, palloc0(), TargetEntry::resjunk, TargetEntry::resno, Query::targetList, and AppendRelInfo::translated_vars.

Referenced by pull_up_union_leaf_queries().

◆ perform_pullup_replace_vars()

static void perform_pullup_replace_vars ( PlannerInfo root,
pullup_replace_vars_context rvcontext,
JoinExpr lowest_nulling_outer_join,
AppendRelInfo containing_appendrel 
)
static

Definition at line 2102 of file prepjointree.c.

2106 {
2107  Query *parse = root->parse;
2108  ListCell *lc;
2109 
2110  /*
2111  * Replace all of the top query's references to the subquery's outputs
2112  * with copies of the adjusted subtlist items, being careful not to
2113  * replace any of the jointree structure. (This'd be a lot cleaner if we
2114  * could use query_tree_mutator.) We have to use PHVs in the targetList,
2115  * returningList, and havingQual, since those are certainly above any
2116  * outer join. replace_vars_in_jointree tracks its location in the
2117  * jointree and uses PHVs or not appropriately.
2118  */
2119  parse->targetList = (List *)
2120  pullup_replace_vars((Node *) parse->targetList, rvcontext);
2121  parse->returningList = (List *)
2122  pullup_replace_vars((Node *) parse->returningList, rvcontext);
2123  if (parse->onConflict)
2124  {
2125  parse->onConflict->onConflictSet = (List *)
2126  pullup_replace_vars((Node *) parse->onConflict->onConflictSet,
2127  rvcontext);
2128  parse->onConflict->onConflictWhere =
2129  pullup_replace_vars(parse->onConflict->onConflictWhere,
2130  rvcontext);
2131 
2132  /*
2133  * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
2134  * can't contain any references to a subquery.
2135  */
2136  }
2137  if (parse->mergeActionList)
2138  {
2139  foreach(lc, parse->mergeActionList)
2140  {
2141  MergeAction *action = lfirst(lc);
2142 
2143  action->qual = pullup_replace_vars(action->qual, rvcontext);
2144  action->targetList = (List *)
2145  pullup_replace_vars((Node *) action->targetList, rvcontext);
2146  }
2147  }
2148  replace_vars_in_jointree((Node *) parse->jointree, rvcontext,
2149  lowest_nulling_outer_join);
2150  Assert(parse->setOperations == NULL);
2151  parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
2152 
2153  /*
2154  * Replace references in the translated_vars lists of appendrels. When
2155  * pulling up an appendrel member, we do not need PHVs in the list of the
2156  * parent appendrel --- there isn't any outer join between. Elsewhere,
2157  * use PHVs for safety. (This analysis could be made tighter but it seems
2158  * unlikely to be worth much trouble.)
2159  */
2160  foreach(lc, root->append_rel_list)
2161  {
2162  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
2163  bool save_need_phvs = rvcontext->need_phvs;
2164 
2165  if (appinfo == containing_appendrel)
2166  rvcontext->need_phvs = false;
2167  appinfo->translated_vars = (List *)
2168  pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
2169  rvcontext->need_phvs = save_need_phvs;
2170  }
2171 
2172  /*
2173  * Replace references in the joinaliasvars lists of join RTEs.
2174  *
2175  * You might think that we could avoid using PHVs for alias vars of joins
2176  * below lowest_nulling_outer_join, but that doesn't work because the
2177  * alias vars could be referenced above that join; we need the PHVs to be
2178  * present in such references after the alias vars get flattened. (It
2179  * might be worth trying to be smarter here, someday.)
2180  */
2181  foreach(lc, parse->rtable)
2182  {
2183  RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
2184 
2185  if (otherrte->rtekind == RTE_JOIN)
2186  otherrte->joinaliasvars = (List *)
2187  pullup_replace_vars((Node *) otherrte->joinaliasvars,
2188  rvcontext);
2189  }
2190 }
@ RTE_JOIN
Definition: parsenodes.h:984
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
List * append_rel_list
Definition: pathnodes.h:355
List * joinaliasvars
Definition: parsenodes.h:1081

References generate_unaccent_rules::action, PlannerInfo::append_rel_list, Assert(), RangeTblEntry::joinaliasvars, lfirst, pullup_replace_vars_context::need_phvs, parse(), PlannerInfo::parse, pullup_replace_vars(), replace_vars_in_jointree(), RTE_JOIN, RangeTblEntry::rtekind, and AppendRelInfo::translated_vars.

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

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 712 of file prepjointree.c.

713 {
714  ListCell *rt;
715 
716  foreach(rt, root->parse->rtable)
717  {
718  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
719 
720  if (rte->rtekind == RTE_FUNCTION)
721  {
722  Query *funcquery;
723 
724  /* Apply const-simplification */
725  rte->functions = (List *)
726  eval_const_expressions(root, (Node *) rte->functions);
727 
728  /* Check safety of expansion, and expand if possible */
729  funcquery = inline_set_returning_function(root, rte);
730  if (funcquery)
731  {
732  /* Successful expansion, convert the RTE to a subquery */
733  rte->rtekind = RTE_SUBQUERY;
734  rte->subquery = funcquery;
735  rte->security_barrier = false;
736  /* Clear fields that should not be set in a subquery RTE */
737  rte->functions = NIL;
738  rte->funcordinality = false;
739  }
740  }
741  }
742 }
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4899
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2132
@ RTE_FUNCTION
Definition: parsenodes.h:985
bool funcordinality
Definition: parsenodes.h:1101
List * functions
Definition: parsenodes.h:1100

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ pull_up_constant_function()

static Node * pull_up_constant_function ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte,
JoinExpr lowest_nulling_outer_join,
AppendRelInfo containing_appendrel 
)
static

Definition at line 1781 of file prepjointree.c.

1785 {
1786  Query *parse = root->parse;
1787  RangeTblFunction *rtf;
1788  TypeFuncClass functypclass;
1789  Oid funcrettype;
1790  TupleDesc tupdesc;
1791  pullup_replace_vars_context rvcontext;
1792 
1793  /* Fail if the RTE has ORDINALITY - we don't implement that here. */
1794  if (rte->funcordinality)
1795  return jtnode;
1796 
1797  /* Fail if RTE isn't a single, simple Const expr */
1798  if (list_length(rte->functions) != 1)
1799  return jtnode;
1801  if (!IsA(rtf->funcexpr, Const))
1802  return jtnode;
1803 
1804  /*
1805  * If the function's result is not a scalar, we punt. In principle we
1806  * could break the composite constant value apart into per-column
1807  * constants, but for now it seems not worth the work.
1808  */
1809  if (rtf->funccolcount != 1)
1810  return jtnode; /* definitely composite */
1811 
1812  functypclass = get_expr_result_type(rtf->funcexpr,
1813  &funcrettype,
1814  &tupdesc);
1815  if (functypclass != TYPEFUNC_SCALAR)
1816  return jtnode; /* must be a one-column composite type */
1817 
1818  /* Create context for applying pullup_replace_vars */
1819  rvcontext.root = root;
1820  rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr,
1821  1, /* resno */
1822  NULL, /* resname */
1823  false)); /* resjunk */
1824  rvcontext.target_rte = rte;
1825 
1826  /*
1827  * Since this function was reduced to a Const, it doesn't contain any
1828  * lateral references, even if it's marked as LATERAL. This means we
1829  * don't need to fill relids.
1830  */
1831  rvcontext.relids = NULL;
1832 
1833  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1834  rvcontext.varno = ((RangeTblRef *) jtnode)->rtindex;
1835  /* these flags will be set below, if needed */
1836  rvcontext.need_phvs = false;
1837  rvcontext.wrap_non_vars = false;
1838  /* initialize cache array with indexes 0 .. length(tlist) */
1839  rvcontext.rv_cache = palloc0((list_length(rvcontext.targetlist) + 1) *
1840  sizeof(Node *));
1841 
1842  /*
1843  * If we are under an outer join then non-nullable items and lateral
1844  * references may have to be turned into PlaceHolderVars.
1845  */
1846  if (lowest_nulling_outer_join != NULL)
1847  rvcontext.need_phvs = true;
1848 
1849  /*
1850  * If we are dealing with an appendrel member then anything that's not a
1851  * simple Var has to be turned into a PlaceHolderVar. (See comments in
1852  * pull_up_simple_subquery().)
1853  */
1854  if (containing_appendrel != NULL)
1855  {
1856  rvcontext.need_phvs = true;
1857  rvcontext.wrap_non_vars = true;
1858  }
1859 
1860  /*
1861  * If the parent query uses grouping sets, we need a PlaceHolderVar for
1862  * anything that's not a simple Var.
1863  */
1864  if (parse->groupingSets)
1865  {
1866  rvcontext.need_phvs = true;
1867  rvcontext.wrap_non_vars = true;
1868  }
1869 
1870  /*
1871  * Replace all of the top query's references to the RTE's output with
1872  * copies of the funcexpr, being careful not to replace any of the
1873  * jointree structure.
1874  */
1875  perform_pullup_replace_vars(root, &rvcontext,
1876  lowest_nulling_outer_join,
1877  containing_appendrel);
1878 
1879  /*
1880  * We don't need to bother with changing PlaceHolderVars in the parent
1881  * query. Their references to the RT index are still good for now, and
1882  * will get removed later if we're able to drop the RTE_RESULT.
1883  */
1884 
1885  /*
1886  * Convert the RTE to be RTE_RESULT type, signifying that we don't need to
1887  * scan it anymore, and zero out RTE_FUNCTION-specific fields. Also make
1888  * sure the RTE is not marked LATERAL, since elsewhere we don't expect
1889  * RTE_RESULTs to be LATERAL.
1890  */
1891  rte->rtekind = RTE_RESULT;
1892  rte->functions = NIL;
1893  rte->lateral = false;
1894 
1895  /*
1896  * We can reuse the RangeTblRef node.
1897  */
1898  return jtnode;
1899 }
TypeFuncClass get_expr_result_type(Node *expr, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:292
TypeFuncClass
Definition: funcapi.h:147
@ TYPEFUNC_SCALAR
Definition: funcapi.h:148
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
#define linitial_node(type, l)
Definition: pg_list.h:179
unsigned int Oid
Definition: postgres_ext.h:31
static void perform_pullup_replace_vars(PlannerInfo *root, pullup_replace_vars_context *rvcontext, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
RangeTblEntry * target_rte
Definition: prepjointree.c:48

References RangeTblFunction::funccolcount, RangeTblFunction::funcexpr, RangeTblEntry::funcordinality, RangeTblEntry::functions, get_expr_result_type(), IsA, RangeTblEntry::lateral, linitial_node, list_length(), list_make1, makeTargetEntry(), pullup_replace_vars_context::need_phvs, NIL, pullup_replace_vars_context::outer_hasSubLinks, palloc0(), parse(), PlannerInfo::parse, perform_pullup_replace_vars(), pullup_replace_vars_context::relids, pullup_replace_vars_context::root, RTE_RESULT, RangeTblEntry::rtekind, pullup_replace_vars_context::rv_cache, pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, TYPEFUNC_SCALAR, pullup_replace_vars_context::varno, and pullup_replace_vars_context::wrap_non_vars.

Referenced by pull_up_subqueries_recurse().

◆ pull_up_simple_subquery()

static Node * pull_up_simple_subquery ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte,
JoinExpr lowest_outer_join,
JoinExpr lowest_nulling_outer_join,
AppendRelInfo containing_appendrel 
)
static

Definition at line 955 of file prepjointree.c.

959 {
960  Query *parse = root->parse;
961  int varno = ((RangeTblRef *) jtnode)->rtindex;
962  Query *subquery;
963  PlannerInfo *subroot;
964  int rtoffset;
965  pullup_replace_vars_context rvcontext;
966  ListCell *lc;
967 
968  /*
969  * Make a modifiable copy of the subquery to hack on, so that the RTE will
970  * be left unchanged in case we decide below that we can't pull it up
971  * after all.
972  */
973  subquery = copyObject(rte->subquery);
974 
975  /*
976  * Create a PlannerInfo data structure for this subquery.
977  *
978  * NOTE: the next few steps should match the first processing in
979  * subquery_planner(). Can we refactor to avoid code duplication, or
980  * would that just make things uglier?
981  */
982  subroot = makeNode(PlannerInfo);
983  subroot->parse = subquery;
984  subroot->glob = root->glob;
985  subroot->query_level = root->query_level;
986  subroot->parent_root = root->parent_root;
987  subroot->plan_params = NIL;
988  subroot->outer_params = NULL;
989  subroot->planner_cxt = CurrentMemoryContext;
990  subroot->init_plans = NIL;
991  subroot->cte_plan_ids = NIL;
992  subroot->multiexpr_params = NIL;
993  subroot->eq_classes = NIL;
994  subroot->ec_merging_done = false;
995  subroot->all_result_relids = NULL;
996  subroot->leaf_result_relids = NULL;
997  subroot->append_rel_list = NIL;
998  subroot->row_identity_vars = NIL;
999  subroot->rowMarks = NIL;
1000  memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels));
1001  memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets));
1002  subroot->processed_tlist = NIL;
1003  subroot->update_colnos = NIL;
1004  subroot->grouping_map = NULL;
1005  subroot->minmax_aggs = NIL;
1006  subroot->qual_security_level = 0;
1007  subroot->placeholdersFrozen = false;
1008  subroot->hasRecursion = false;
1009  subroot->wt_param_id = -1;
1010  subroot->non_recursive_path = NULL;
1011 
1012  /* No CTEs to worry about */
1013  Assert(subquery->cteList == NIL);
1014 
1015  /*
1016  * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
1017  * that we don't need so many special cases to deal with that situation.
1018  */
1019  replace_empty_jointree(subquery);
1020 
1021  /*
1022  * Pull up any SubLinks within the subquery's quals, so that we don't
1023  * leave unoptimized SubLinks behind.
1024  */
1025  if (subquery->hasSubLinks)
1026  pull_up_sublinks(subroot);
1027 
1028  /*
1029  * Similarly, preprocess its function RTEs to inline any set-returning
1030  * functions in its rangetable.
1031  */
1032  preprocess_function_rtes(subroot);
1033 
1034  /*
1035  * Recursively pull up the subquery's subqueries, so that
1036  * pull_up_subqueries' processing is complete for its jointree and
1037  * rangetable.
1038  *
1039  * Note: it's okay that the subquery's recursion starts with NULL for
1040  * containing-join info, even if we are within an outer join in the upper
1041  * query; the lower query starts with a clean slate for outer-join
1042  * semantics. Likewise, we needn't pass down appendrel state.
1043  */
1044  pull_up_subqueries(subroot);
1045 
1046  /*
1047  * Now we must recheck whether the subquery is still simple enough to pull
1048  * up. If not, abandon processing it.
1049  *
1050  * We don't really need to recheck all the conditions involved, but it's
1051  * easier just to keep this "if" looking the same as the one in
1052  * pull_up_subqueries_recurse.
1053  */
1054  if (is_simple_subquery(root, subquery, rte, lowest_outer_join) &&
1055  (containing_appendrel == NULL || is_safe_append_member(subquery)))
1056  {
1057  /* good to go */
1058  }
1059  else
1060  {
1061  /*
1062  * Give up, return unmodified RangeTblRef.
1063  *
1064  * Note: The work we just did will be redone when the subquery gets
1065  * planned on its own. Perhaps we could avoid that by storing the
1066  * modified subquery back into the rangetable, but I'm not gonna risk
1067  * it now.
1068  */
1069  return jtnode;
1070  }
1071 
1072  /*
1073  * We must flatten any join alias Vars in the subquery's targetlist,
1074  * because pulling up the subquery's subqueries might have changed their
1075  * expansions into arbitrary expressions, which could affect
1076  * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
1077  * are needed for tlist entries. (Likely it'd be better to do
1078  * flatten_join_alias_vars on the whole query tree at some earlier stage,
1079  * maybe even in the rewriter; but for now let's just fix this case here.)
1080  */
1081  subquery->targetList = (List *)
1082  flatten_join_alias_vars(subroot->parse, (Node *) subquery->targetList);
1083 
1084  /*
1085  * Adjust level-0 varnos in subquery so that we can append its rangetable
1086  * to upper query's. We have to fix the subquery's append_rel_list as
1087  * well.
1088  */
1089  rtoffset = list_length(parse->rtable);
1090  OffsetVarNodes((Node *) subquery, rtoffset, 0);
1091  OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);
1092 
1093  /*
1094  * Upper-level vars in subquery are now one level closer to their parent
1095  * than before.
1096  */
1097  IncrementVarSublevelsUp((Node *) subquery, -1, 1);
1098  IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
1099 
1100  /*
1101  * The subquery's targetlist items are now in the appropriate form to
1102  * insert into the top query, except that we may need to wrap them in
1103  * PlaceHolderVars. Set up required context data for pullup_replace_vars.
1104  */
1105  rvcontext.root = root;
1106  rvcontext.targetlist = subquery->targetList;
1107  rvcontext.target_rte = rte;
1108  if (rte->lateral)
1109  rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree,
1110  true);
1111  else /* won't need relids */
1112  rvcontext.relids = NULL;
1113  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1114  rvcontext.varno = varno;
1115  /* these flags will be set below, if needed */
1116  rvcontext.need_phvs = false;
1117  rvcontext.wrap_non_vars = false;
1118  /* initialize cache array with indexes 0 .. length(tlist) */
1119  rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
1120  sizeof(Node *));
1121 
1122  /*
1123  * If we are under an outer join then non-nullable items and lateral
1124  * references may have to be turned into PlaceHolderVars.
1125  */
1126  if (lowest_nulling_outer_join != NULL)
1127  rvcontext.need_phvs = true;
1128 
1129  /*
1130  * If we are dealing with an appendrel member then anything that's not a
1131  * simple Var has to be turned into a PlaceHolderVar. We force this to
1132  * ensure that what we pull up doesn't get merged into a surrounding
1133  * expression during later processing and then fail to match the
1134  * expression actually available from the appendrel.
1135  */
1136  if (containing_appendrel != NULL)
1137  {
1138  rvcontext.need_phvs = true;
1139  rvcontext.wrap_non_vars = true;
1140  }
1141 
1142  /*
1143  * If the parent query uses grouping sets, we need a PlaceHolderVar for
1144  * anything that's not a simple Var. Again, this ensures that expressions
1145  * retain their separate identity so that they will match grouping set
1146  * columns when appropriate. (It'd be sufficient to wrap values used in
1147  * grouping set columns, and do so only in non-aggregated portions of the
1148  * tlist and havingQual, but that would require a lot of infrastructure
1149  * that pullup_replace_vars hasn't currently got.)
1150  */
1151  if (parse->groupingSets)
1152  {
1153  rvcontext.need_phvs = true;
1154  rvcontext.wrap_non_vars = true;
1155  }
1156 
1157  /*
1158  * Replace all of the top query's references to the subquery's outputs
1159  * with copies of the adjusted subtlist items, being careful not to
1160  * replace any of the jointree structure.
1161  */
1162  perform_pullup_replace_vars(root, &rvcontext,
1163  lowest_nulling_outer_join,
1164  containing_appendrel);
1165 
1166  /*
1167  * If the subquery had a LATERAL marker, propagate that to any of its
1168  * child RTEs that could possibly now contain lateral cross-references.
1169  * The children might or might not contain any actual lateral
1170  * cross-references, but we have to mark the pulled-up child RTEs so that
1171  * later planner stages will check for such.
1172  */
1173  if (rte->lateral)
1174  {
1175  foreach(lc, subquery->rtable)
1176  {
1177  RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc);
1178 
1179  switch (child_rte->rtekind)
1180  {
1181  case RTE_RELATION:
1182  if (child_rte->tablesample)
1183  child_rte->lateral = true;
1184  break;
1185  case RTE_SUBQUERY:
1186  case RTE_FUNCTION:
1187  case RTE_VALUES:
1188  case RTE_TABLEFUNC:
1189  child_rte->lateral = true;
1190  break;
1191  case RTE_JOIN:
1192  case RTE_CTE:
1193  case RTE_NAMEDTUPLESTORE:
1194  case RTE_RESULT:
1195  /* these can't contain any lateral references */
1196  break;
1197  }
1198  }
1199  }
1200 
1201  /*
1202  * Now append the adjusted rtable entries and their perminfos to upper
1203  * query. (We hold off until after fixing the upper rtable entries; no
1204  * point in running that code on the subquery ones too.)
1205  */
1206  CombineRangeTables(&parse->rtable, &parse->rteperminfos,
1207  subquery->rtable, subquery->rteperminfos);
1208 
1209  /*
1210  * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already
1211  * adjusted the marker rtindexes, so just concat the lists.)
1212  */
1213  parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
1214 
1215  /*
1216  * We also have to fix the relid sets of any PlaceHolderVar nodes in the
1217  * parent query. (This could perhaps be done by pullup_replace_vars(),
1218  * but it seems cleaner to use two passes.) Note in particular that any
1219  * PlaceHolderVar nodes just created by pullup_replace_vars() will be
1220  * adjusted, so having created them with the subquery's varno is correct.
1221  *
1222  * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We
1223  * already checked that this won't require introducing multiple subrelids
1224  * into the single-slot AppendRelInfo structs.
1225  */
1226  if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
1227  root->append_rel_list)
1228  {
1229  Relids subrelids;
1230 
1231  subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
1232  substitute_phv_relids((Node *) parse, varno, subrelids);
1233  fix_append_rel_relids(root->append_rel_list, varno, subrelids);
1234  }
1235 
1236  /*
1237  * And now add subquery's AppendRelInfos to our list.
1238  */
1240  subroot->append_rel_list);
1241 
1242  /*
1243  * We don't have to do the equivalent bookkeeping for outer-join info,
1244  * because that hasn't been set up yet. placeholder_list likewise.
1245  */
1246  Assert(root->join_info_list == NIL);
1247  Assert(subroot->join_info_list == NIL);
1248  Assert(root->placeholder_list == NIL);
1249  Assert(subroot->placeholder_list == NIL);
1250 
1251  /*
1252  * We no longer need the RTE's copy of the subquery's query tree. Getting
1253  * rid of it saves nothing in particular so far as this level of query is
1254  * concerned; but if this query level is in turn pulled up into a parent,
1255  * we'd waste cycles copying the now-unused query tree.
1256  */
1257  rte->subquery = NULL;
1258 
1259  /*
1260  * Miscellaneous housekeeping.
1261  *
1262  * Although replace_rte_variables() faithfully updated parse->hasSubLinks
1263  * if it copied any SubLinks out of the subquery's targetlist, we still
1264  * could have SubLinks added to the query in the expressions of FUNCTION
1265  * and VALUES RTEs copied up from the subquery. So it's necessary to copy
1266  * subquery->hasSubLinks anyway. Perhaps this can be improved someday.
1267  */
1268  parse->hasSubLinks |= subquery->hasSubLinks;
1269 
1270  /* If subquery had any RLS conditions, now main query does too */
1271  parse->hasRowSecurity |= subquery->hasRowSecurity;
1272 
1273  /*
1274  * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
1275  * hasTargetSRFs, so no work needed on those flags
1276  */
1277 
1278  /*
1279  * Return the adjusted subquery jointree to replace the RangeTblRef entry
1280  * in parent's jointree; or, if the FromExpr is degenerate, just return
1281  * its single member.
1282  */
1283  Assert(IsA(subquery->jointree, FromExpr));
1284  Assert(subquery->jointree->fromlist != NIL);
1285  if (subquery->jointree->quals == NULL &&
1286  list_length(subquery->jointree->fromlist) == 1)
1287  return (Node *) linitial(subquery->jointree->fromlist);
1288 
1289  return (Node *) subquery->jointree;
1290 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
@ RTE_CTE
Definition: parsenodes.h:988
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:989
@ RTE_TABLEFUNC
Definition: parsenodes.h:986
@ RTE_RELATION
Definition: parsenodes.h:982
void preprocess_function_rtes(PlannerInfo *root)
Definition: prepjointree.c:712
static bool is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join)
void pull_up_sublinks(PlannerInfo *root)
Definition: prepjointree.c:281
void replace_empty_jointree(Query *parse)
Definition: prepjointree.c:223
void pull_up_subqueries(PlannerInfo *root)
Definition: prepjointree.c:753
static void fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
static bool is_safe_append_member(Query *subquery)
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:458
void CombineRangeTables(List **dst_rtable, List **dst_perminfos, List *src_rtable, List *src_perminfos)
Definition: rewriteManip.c:332
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:809
List * minmax_aggs
Definition: pathnodes.h:434
List * processed_tlist
Definition: pathnodes.h:418
List * cte_plan_ids
Definition: pathnodes.h:301
Index qual_security_level
Definition: pathnodes.h:451
List * init_plans
Definition: pathnodes.h:295
List * multiexpr_params
Definition: pathnodes.h:304
List * row_identity_vars
Definition: pathnodes.h:358
bool ec_merging_done
Definition: pathnodes.h:310
Bitmapset * outer_params
Definition: pathnodes.h:221
Index query_level
Definition: pathnodes.h:208
struct Path * non_recursive_path
Definition: pathnodes.h:488
List * placeholder_list
Definition: pathnodes.h:364
List * eq_classes
Definition: pathnodes.h:307
int wt_param_id
Definition: pathnodes.h:486
List * plan_params
Definition: pathnodes.h:220
List * rowMarks
Definition: pathnodes.h:361
List * update_colnos
Definition: pathnodes.h:426
bool placeholdersFrozen
Definition: pathnodes.h:464
List * join_info_list
Definition: pathnodes.h:333
Relids all_result_relids
Definition: pathnodes.h:344
Relids leaf_result_relids
Definition: pathnodes.h:346
bool hasRowSecurity
Definition: parsenodes.h:149
List * rteperminfos
Definition: parsenodes.h:156
bool hasSubLinks
Definition: parsenodes.h:144
struct TableSampleClause * tablesample
Definition: parsenodes.h:1035
Node * flatten_join_alias_vars(Query *query, Node *node)
Definition: var.c:726

References PlannerInfo::all_result_relids, PlannerInfo::append_rel_list, Assert(), CombineRangeTables(), copyObject, PlannerInfo::cte_plan_ids, Query::cteList, CurrentMemoryContext, PlannerInfo::ec_merging_done, PlannerInfo::eq_classes, fix_append_rel_relids(), flatten_join_alias_vars(), FromExpr::fromlist, get_relids_in_jointree(), PlannerInfo::glob, PlannerInfo::hasRecursion, Query::hasRowSecurity, Query::hasSubLinks, IncrementVarSublevelsUp(), PlannerInfo::init_plans, is_safe_append_member(), is_simple_subquery(), IsA, PlannerInfo::join_info_list, Query::jointree, PlannerGlobal::lastPHId, RangeTblEntry::lateral, PlannerInfo::leaf_result_relids, lfirst, linitial, list_concat(), list_length(), makeNode, PlannerInfo::minmax_aggs, PlannerInfo::multiexpr_params, pullup_replace_vars_context::need_phvs, NIL, PlannerInfo::non_recursive_path, OffsetVarNodes(), pullup_replace_vars_context::outer_hasSubLinks, PlannerInfo::outer_params, palloc0(), parse(), PlannerInfo::parse, perform_pullup_replace_vars(), PlannerInfo::placeholder_list, PlannerInfo::placeholdersFrozen, PlannerInfo::plan_params, preprocess_function_rtes(), PlannerInfo::processed_tlist, pull_up_sublinks(), pull_up_subqueries(), PlannerInfo::qual_security_level, FromExpr::quals, PlannerInfo::query_level, pullup_replace_vars_context::relids, replace_empty_jointree(), pullup_replace_vars_context::root, PlannerInfo::row_identity_vars, Query::rowMarks, PlannerInfo::rowMarks, Query::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, Query::rteperminfos, pullup_replace_vars_context::rv_cache, RangeTblEntry::subquery, substitute_phv_relids(), RangeTblEntry::tablesample, pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, Query::targetList, PlannerInfo::update_colnos, pullup_replace_vars_context::varno, pullup_replace_vars_context::wrap_non_vars, and PlannerInfo::wt_param_id.

Referenced by pull_up_subqueries_recurse().

◆ pull_up_simple_union_all()

static Node * pull_up_simple_union_all ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte 
)
static

Definition at line 1302 of file prepjointree.c.

1303 {
1304  int varno = ((RangeTblRef *) jtnode)->rtindex;
1305  Query *subquery = rte->subquery;
1306  int rtoffset = list_length(root->parse->rtable);
1307  List *rtable;
1308 
1309  /*
1310  * Make a modifiable copy of the subquery's rtable, so we can adjust
1311  * upper-level Vars in it. There are no such Vars in the setOperations
1312  * tree proper, so fixing the rtable should be sufficient.
1313  */
1314  rtable = copyObject(subquery->rtable);
1315 
1316  /*
1317  * Upper-level vars in subquery are now one level closer to their parent
1318  * than before. We don't have to worry about offsetting varnos, though,
1319  * because the UNION leaf queries can't cross-reference each other.
1320  */
1321  IncrementVarSublevelsUp_rtable(rtable, -1, 1);
1322 
1323  /*
1324  * If the UNION ALL subquery had a LATERAL marker, propagate that to all
1325  * its children. The individual children might or might not contain any
1326  * actual lateral cross-references, but we have to mark the pulled-up
1327  * child RTEs so that later planner stages will check for such.
1328  */
1329  if (rte->lateral)
1330  {
1331  ListCell *rt;
1332 
1333  foreach(rt, rtable)
1334  {
1335  RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
1336 
1337  Assert(child_rte->rtekind == RTE_SUBQUERY);
1338  child_rte->lateral = true;
1339  }
1340  }
1341 
1342  /*
1343  * Append child RTEs (and their perminfos) to parent rtable.
1344  */
1346  rtable, subquery->rteperminfos);
1347 
1348  /*
1349  * Recursively scan the subquery's setOperations tree and add
1350  * AppendRelInfo nodes for leaf subqueries to the parent's
1351  * append_rel_list. Also apply pull_up_subqueries to the leaf subqueries.
1352  */
1353  Assert(subquery->setOperations);
1354  pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery,
1355  rtoffset);
1356 
1357  /*
1358  * Mark the parent as an append relation.
1359  */
1360  rte->inh = true;
1361 
1362  return jtnode;
1363 }
void IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:832

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

Referenced by pull_up_subqueries_recurse().

◆ pull_up_simple_values()

static Node * pull_up_simple_values ( PlannerInfo root,
Node jtnode,
RangeTblEntry rte 
)
static

Definition at line 1626 of file prepjointree.c.

1627 {
1628  Query *parse = root->parse;
1629  int varno = ((RangeTblRef *) jtnode)->rtindex;
1630  List *values_list;
1631  List *tlist;
1632  AttrNumber attrno;
1633  pullup_replace_vars_context rvcontext;
1634  ListCell *lc;
1635 
1636  Assert(rte->rtekind == RTE_VALUES);
1637  Assert(list_length(rte->values_lists) == 1);
1638 
1639  /*
1640  * Need a modifiable copy of the VALUES list to hack on, just in case it's
1641  * multiply referenced.
1642  */
1643  values_list = copyObject(linitial(rte->values_lists));
1644 
1645  /*
1646  * The VALUES RTE can't contain any Vars of level zero, let alone any that
1647  * are join aliases, so no need to flatten join alias Vars.
1648  */
1649  Assert(!contain_vars_of_level((Node *) values_list, 0));
1650 
1651  /*
1652  * Set up required context data for pullup_replace_vars. In particular,
1653  * we have to make the VALUES list look like a subquery targetlist.
1654  */
1655  tlist = NIL;
1656  attrno = 1;
1657  foreach(lc, values_list)
1658  {
1659  tlist = lappend(tlist,
1660  makeTargetEntry((Expr *) lfirst(lc),
1661  attrno,
1662  NULL,
1663  false));
1664  attrno++;
1665  }
1666  rvcontext.root = root;
1667  rvcontext.targetlist = tlist;
1668  rvcontext.target_rte = rte;
1669  rvcontext.relids = NULL;
1670  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1671  rvcontext.varno = varno;
1672  rvcontext.need_phvs = false;
1673  rvcontext.wrap_non_vars = false;
1674  /* initialize cache array with indexes 0 .. length(tlist) */
1675  rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1676  sizeof(Node *));
1677 
1678  /*
1679  * Replace all of the top query's references to the RTE's outputs with
1680  * copies of the adjusted VALUES expressions, being careful not to replace
1681  * any of the jointree structure. We can assume there's no outer joins or
1682  * appendrels in the dummy Query that surrounds a VALUES RTE.
1683  */
1684  perform_pullup_replace_vars(root, &rvcontext, NULL, NULL);
1685 
1686  /*
1687  * There should be no appendrels to fix, nor any outer joins and hence no
1688  * PlaceHolderVars.
1689  */
1690  Assert(root->append_rel_list == NIL);
1691  Assert(root->join_info_list == NIL);
1692  Assert(root->placeholder_list == NIL);
1693 
1694  /*
1695  * Replace the VALUES RTE with a RESULT RTE. The VALUES RTE is the only
1696  * rtable entry in the current query level, so this is easy.
1697  */
1698  Assert(list_length(parse->rtable) == 1);
1699 
1700  /* Create suitable RTE */
1701  rte = makeNode(RangeTblEntry);
1702  rte->rtekind = RTE_RESULT;
1703  rte->eref = makeAlias("*RESULT*", NIL);
1704 
1705  /* Replace rangetable */
1706  parse->rtable = list_make1(rte);
1707 
1708  /* We could manufacture a new RangeTblRef, but the one we have is fine */
1709  Assert(varno == 1);
1710 
1711  return jtnode;
1712 }
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
Alias * eref
Definition: parsenodes.h:1152
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:431

References PlannerInfo::append_rel_list, Assert(), contain_vars_of_level(), copyObject, RangeTblEntry::eref, PlannerInfo::join_info_list, lappend(), lfirst, linitial, list_length(), list_make1, makeAlias(), makeNode, makeTargetEntry(), pullup_replace_vars_context::need_phvs, NIL, pullup_replace_vars_context::outer_hasSubLinks, palloc0(), parse(), PlannerInfo::parse, perform_pullup_replace_vars(), PlannerInfo::placeholder_list, pullup_replace_vars_context::relids, pullup_replace_vars_context::root, RTE_RESULT, RTE_VALUES, RangeTblEntry::rtekind, pullup_replace_vars_context::rv_cache, pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, RangeTblEntry::values_lists, pullup_replace_vars_context::varno, and pullup_replace_vars_context::wrap_non_vars.

Referenced by pull_up_subqueries_recurse().

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 281 of file prepjointree.c.

282 {
283  Node *jtnode;
284  Relids relids;
285 
286  /* Begin recursion through the jointree */
287  jtnode = pull_up_sublinks_jointree_recurse(root,
288  (Node *) root->parse->jointree,
289  &relids);
290 
291  /*
292  * root->parse->jointree must always be a FromExpr, so insert a dummy one
293  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
294  */
295  if (IsA(jtnode, FromExpr))
296  root->parse->jointree = (FromExpr *) jtnode;
297  else
298  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
299 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:308

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ pull_up_sublinks_jointree_recurse()

static Node * pull_up_sublinks_jointree_recurse ( PlannerInfo root,
Node jtnode,
Relids relids 
)
static

Definition at line 308 of file prepjointree.c.

310 {
311  if (jtnode == NULL)
312  {
313  *relids = NULL;
314  }
315  else if (IsA(jtnode, RangeTblRef))
316  {
317  int varno = ((RangeTblRef *) jtnode)->rtindex;
318 
319  *relids = bms_make_singleton(varno);
320  /* jtnode is returned unmodified */
321  }
322  else if (IsA(jtnode, FromExpr))
323  {
324  FromExpr *f = (FromExpr *) jtnode;
325  List *newfromlist = NIL;
326  Relids frelids = NULL;
327  FromExpr *newf;
328  Node *jtlink;
329  ListCell *l;
330 
331  /* First, recurse to process children and collect their relids */
332  foreach(l, f->fromlist)
333  {
334  Node *newchild;
335  Relids childrelids;
336 
337  newchild = pull_up_sublinks_jointree_recurse(root,
338  lfirst(l),
339  &childrelids);
340  newfromlist = lappend(newfromlist, newchild);
341  frelids = bms_join(frelids, childrelids);
342  }
343  /* Build the replacement FromExpr; no quals yet */
344  newf = makeFromExpr(newfromlist, NULL);
345  /* Set up a link representing the rebuilt jointree */
346  jtlink = (Node *) newf;
347  /* Now process qual --- all children are available for use */
348  newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
349  &jtlink, frelids,
350  NULL, NULL);
351 
352  /*
353  * Note that the result will be either newf, or a stack of JoinExprs
354  * with newf at the base. We rely on subsequent optimization steps to
355  * flatten this and rearrange the joins as needed.
356  *
357  * Although we could include the pulled-up subqueries in the returned
358  * relids, there's no need since upper quals couldn't refer to their
359  * outputs anyway.
360  */
361  *relids = frelids;
362  jtnode = jtlink;
363  }
364  else if (IsA(jtnode, JoinExpr))
365  {
366  JoinExpr *j;
367  Relids leftrelids;
368  Relids rightrelids;
369  Node *jtlink;
370 
371  /*
372  * Make a modifiable copy of join node, but don't bother copying its
373  * subnodes (yet).
374  */
375  j = (JoinExpr *) palloc(sizeof(JoinExpr));
376  memcpy(j, jtnode, sizeof(JoinExpr));
377  jtlink = (Node *) j;
378 
379  /* Recurse to process children and collect their relids */
380  j->larg = pull_up_sublinks_jointree_recurse(root, j->larg,
381  &leftrelids);
382  j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg,
383  &rightrelids);
384 
385  /*
386  * Now process qual, showing appropriate child relids as available,
387  * and attach any pulled-up jointree items at the right place. In the
388  * inner-join case we put new JoinExprs above the existing one (much
389  * as for a FromExpr-style join). In outer-join cases the new
390  * JoinExprs must go into the nullable side of the outer join. The
391  * point of the available_rels machinations is to ensure that we only
392  * pull up quals for which that's okay.
393  *
394  * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI
395  * nodes here.
396  */
397  switch (j->jointype)
398  {
399  case JOIN_INNER:
400  j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
401  &jtlink,
402  bms_union(leftrelids,
403  rightrelids),
404  NULL, NULL);
405  break;
406  case JOIN_LEFT:
407  j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
408  &j->rarg,
409  rightrelids,
410  NULL, NULL);
411  break;
412  case JOIN_FULL:
413  /* can't do anything with full-join quals */
414  break;
415  case JOIN_RIGHT:
416  j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
417  &j->larg,
418  leftrelids,
419  NULL, NULL);
420  break;
421  default:
422  elog(ERROR, "unrecognized join type: %d",
423  (int) j->jointype);
424  break;
425  }
426 
427  /*
428  * Although we could include the pulled-up subqueries in the returned
429  * relids, there's no need since upper quals couldn't refer to their
430  * outputs anyway. But we *do* need to include the join's own rtindex
431  * because we haven't yet collapsed join alias variables, so upper
432  * levels would mistakenly think they couldn't use references to this
433  * join.
434  */
435  *relids = bms_join(leftrelids, rightrelids);
436  if (j->rtindex)
437  *relids = bms_add_member(*relids, j->rtindex);
438  jtnode = jtlink;
439  }
440  else
441  elog(ERROR, "unrecognized node type: %d",
442  (int) nodeTag(jtnode));
443  return jtnode;
444 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:226
void * palloc(Size size)
Definition: mcxt.c:1199
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_LEFT
Definition: nodes.h:294
static Node * pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, Node **jtlink1, Relids available_rels1, Node **jtlink2, Relids available_rels2)
Definition: prepjointree.c:462

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

Referenced by pull_up_sublinks(), and pull_up_sublinks_qual_recurse().

◆ pull_up_sublinks_qual_recurse()

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 462 of file prepjointree.c.

465 {
466  if (node == NULL)
467  return NULL;
468  if (IsA(node, SubLink))
469  {
470  SubLink *sublink = (SubLink *) node;
471  JoinExpr *j;
472  Relids child_rels;
473 
474  /* Is it a convertible ANY or EXISTS clause? */
475  if (sublink->subLinkType == ANY_SUBLINK)
476  {
477  if ((j = convert_ANY_sublink_to_join(root, sublink,
478  available_rels1)) != NULL)
479  {
480  /* Yes; insert the new join node into the join tree */
481  j->larg = *jtlink1;
482  *jtlink1 = (Node *) j;
483  /* Recursively process pulled-up jointree nodes */
485  j->rarg,
486  &child_rels);
487 
488  /*
489  * Now recursively process the pulled-up quals. Any inserted
490  * joins can get stacked onto either j->larg or j->rarg,
491  * depending on which rels they reference.
492  */
493  j->quals = pull_up_sublinks_qual_recurse(root,
494  j->quals,
495  &j->larg,
496  available_rels1,
497  &j->rarg,
498  child_rels);
499  /* Return NULL representing constant TRUE */
500  return NULL;
501  }
502  if (available_rels2 != NULL &&
503  (j = convert_ANY_sublink_to_join(root, sublink,
504  available_rels2)) != NULL)
505  {
506  /* Yes; insert the new join node into the join tree */
507  j->larg = *jtlink2;
508  *jtlink2 = (Node *) j;
509  /* Recursively process pulled-up jointree nodes */
511  j->rarg,
512  &child_rels);
513 
514  /*
515  * Now recursively process the pulled-up quals. Any inserted
516  * joins can get stacked onto either j->larg or j->rarg,
517  * depending on which rels they reference.
518  */
519  j->quals = pull_up_sublinks_qual_recurse(root,
520  j->quals,
521  &j->larg,
522  available_rels2,
523  &j->rarg,
524  child_rels);
525  /* Return NULL representing constant TRUE */
526  return NULL;
527  }
528  }
529  else if (sublink->subLinkType == EXISTS_SUBLINK)
530  {
531  if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
532  available_rels1)) != NULL)
533  {
534  /* Yes; insert the new join node into the join tree */
535  j->larg = *jtlink1;
536  *jtlink1 = (Node *) j;
537  /* Recursively process pulled-up jointree nodes */
539  j->rarg,
540  &child_rels);
541 
542  /*
543  * Now recursively process the pulled-up quals. Any inserted
544  * joins can get stacked onto either j->larg or j->rarg,
545  * depending on which rels they reference.
546  */
547  j->quals = pull_up_sublinks_qual_recurse(root,
548  j->quals,
549  &j->larg,
550  available_rels1,
551  &j->rarg,
552  child_rels);
553  /* Return NULL representing constant TRUE */
554  return NULL;
555  }
556  if (available_rels2 != NULL &&
557  (j = convert_EXISTS_sublink_to_join(root, sublink, false,
558  available_rels2)) != NULL)
559  {
560  /* Yes; insert the new join node into the join tree */
561  j->larg = *jtlink2;
562  *jtlink2 = (Node *) j;
563  /* Recursively process pulled-up jointree nodes */
565  j->rarg,
566  &child_rels);
567 
568  /*
569  * Now recursively process the pulled-up quals. Any inserted
570  * joins can get stacked onto either j->larg or j->rarg,
571  * depending on which rels they reference.
572  */
573  j->quals = pull_up_sublinks_qual_recurse(root,
574  j->quals,
575  &j->larg,
576  available_rels2,
577  &j->rarg,
578  child_rels);
579  /* Return NULL representing constant TRUE */
580  return NULL;
581  }
582  }
583  /* Else return it unmodified */
584  return node;
585  }
586  if (is_notclause(node))
587  {
588  /* If the immediate argument of NOT is EXISTS, try to convert */
589  SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
590  JoinExpr *j;
591  Relids child_rels;
592 
593  if (sublink && IsA(sublink, SubLink))
594  {
595  if (sublink->subLinkType == EXISTS_SUBLINK)
596  {
597  if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
598  available_rels1)) != NULL)
599  {
600  /* Yes; insert the new join node into the join tree */
601  j->larg = *jtlink1;
602  *jtlink1 = (Node *) j;
603  /* Recursively process pulled-up jointree nodes */
605  j->rarg,
606  &child_rels);
607 
608  /*
609  * Now recursively process the pulled-up quals. Because
610  * we are underneath a NOT, we can't pull up sublinks that
611  * reference the left-hand stuff, but it's still okay to
612  * pull up sublinks referencing j->rarg.
613  */
614  j->quals = pull_up_sublinks_qual_recurse(root,
615  j->quals,
616  &j->rarg,
617  child_rels,
618  NULL, NULL);
619  /* Return NULL representing constant TRUE */
620  return NULL;
621  }
622  if (available_rels2 != NULL &&
623  (j = convert_EXISTS_sublink_to_join(root, sublink, true,
624  available_rels2)) != NULL)
625  {
626  /* Yes; insert the new join node into the join tree */
627  j->larg = *jtlink2;
628  *jtlink2 = (Node *) j;
629  /* Recursively process pulled-up jointree nodes */
631  j->rarg,
632  &child_rels);
633 
634  /*
635  * Now recursively process the pulled-up quals. Because
636  * we are underneath a NOT, we can't pull up sublinks that
637  * reference the left-hand stuff, but it's still okay to
638  * pull up sublinks referencing j->rarg.
639  */
640  j->quals = pull_up_sublinks_qual_recurse(root,
641  j->quals,
642  &j->rarg,
643  child_rels,
644  NULL, NULL);
645  /* Return NULL representing constant TRUE */
646  return NULL;
647  }
648  }
649  }
650  /* Else return it unmodified */
651  return node;
652  }
653  if (is_andclause(node))
654  {
655  /* Recurse into AND clause */
656  List *newclauses = NIL;
657  ListCell *l;
658 
659  foreach(l, ((BoolExpr *) node)->args)
660  {
661  Node *oldclause = (Node *) lfirst(l);
662  Node *newclause;
663 
664  newclause = pull_up_sublinks_qual_recurse(root,
665  oldclause,
666  jtlink1,
667  available_rels1,
668  jtlink2,
669  available_rels2);
670  if (newclause)
671  newclauses = lappend(newclauses, newclause);
672  }
673  /* We might have got back fewer clauses than we started with */
674  if (newclauses == NIL)
675  return NULL;
676  else if (list_length(newclauses) == 1)
677  return (Node *) linitial(newclauses);
678  else
679  return (Node *) make_andclause(newclauses);
680  }
681  /* Stop if not an AND */
682  return node;
683 }
Expr * make_andclause(List *andclauses)
Definition: makefuncs.c:636
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:105
static Expr * get_notclausearg(const void *notclause)
Definition: nodeFuncs.h:132
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:123
@ ANY_SUBLINK
Definition: primnodes.h:826
@ EXISTS_SUBLINK
Definition: primnodes.h:824
JoinExpr * convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink, Relids available_rels)
Definition: subselect.c:1268
JoinExpr * convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, bool under_not, Relids available_rels)
Definition: subselect.c:1376

References ANY_SUBLINK, generate_unaccent_rules::args, convert_ANY_sublink_to_join(), convert_EXISTS_sublink_to_join(), EXISTS_SUBLINK, get_notclausearg(), is_andclause(), is_notclause(), IsA, j, lappend(), lfirst, linitial, list_length(), make_andclause(), NIL, pull_up_sublinks_jointree_recurse(), and SubLink::subLinkType.

Referenced by pull_up_sublinks_jointree_recurse().

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 753 of file prepjointree.c.

754 {
755  /* Top level of jointree must always be a FromExpr */
756  Assert(IsA(root->parse->jointree, FromExpr));
757  /* Recursion starts with no containing join nor appendrel */
758  root->parse->jointree = (FromExpr *)
760  NULL, NULL, NULL);
761  /* We should still have a FromExpr */
762  Assert(IsA(root->parse->jointree, FromExpr));
763 }
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
Definition: prepjointree.c:803

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ pull_up_subqueries_recurse()

static Node * pull_up_subqueries_recurse ( PlannerInfo root,
Node jtnode,
JoinExpr lowest_outer_join,
JoinExpr lowest_nulling_outer_join,
AppendRelInfo containing_appendrel 
)
static

Definition at line 803 of file prepjointree.c.

807 {
808  Assert(jtnode != NULL);
809  if (IsA(jtnode, RangeTblRef))
810  {
811  int varno = ((RangeTblRef *) jtnode)->rtindex;
812  RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
813 
814  /*
815  * Is this a subquery RTE, and if so, is the subquery simple enough to
816  * pull up?
817  *
818  * If we are looking at an append-relation member, we can't pull it up
819  * unless is_safe_append_member says so.
820  */
821  if (rte->rtekind == RTE_SUBQUERY &&
822  is_simple_subquery(root, rte->subquery, rte, lowest_outer_join) &&
823  (containing_appendrel == NULL ||
825  return pull_up_simple_subquery(root, jtnode, rte,
826  lowest_outer_join,
827  lowest_nulling_outer_join,
828  containing_appendrel);
829 
830  /*
831  * Alternatively, is it a simple UNION ALL subquery? If so, flatten
832  * into an "append relation".
833  *
834  * It's safe to do this regardless of whether this query is itself an
835  * appendrel member. (If you're thinking we should try to flatten the
836  * two levels of appendrel together, you're right; but we handle that
837  * in set_append_rel_pathlist, not here.)
838  */
839  if (rte->rtekind == RTE_SUBQUERY &&
841  return pull_up_simple_union_all(root, jtnode, rte);
842 
843  /*
844  * Or perhaps it's a simple VALUES RTE?
845  *
846  * We don't allow VALUES pullup below an outer join nor into an
847  * appendrel (such cases are impossible anyway at the moment).
848  */
849  if (rte->rtekind == RTE_VALUES &&
850  lowest_outer_join == NULL &&
851  containing_appendrel == NULL &&
852  is_simple_values(root, rte))
853  return pull_up_simple_values(root, jtnode, rte);
854 
855  /*
856  * Or perhaps it's a FUNCTION RTE that we could inline?
857  */
858  if (rte->rtekind == RTE_FUNCTION)
859  return pull_up_constant_function(root, jtnode, rte,
860  lowest_nulling_outer_join,
861  containing_appendrel);
862 
863  /* Otherwise, do nothing at this node. */
864  }
865  else if (IsA(jtnode, FromExpr))
866  {
867  FromExpr *f = (FromExpr *) jtnode;
868  ListCell *l;
869 
870  Assert(containing_appendrel == NULL);
871  /* Recursively transform all the child nodes */
872  foreach(l, f->fromlist)
873  {
875  lowest_outer_join,
876  lowest_nulling_outer_join,
877  NULL);
878  }
879  }
880  else if (IsA(jtnode, JoinExpr))
881  {
882  JoinExpr *j = (JoinExpr *) jtnode;
883 
884  Assert(containing_appendrel == NULL);
885  /* Recurse, being careful to tell myself when inside outer join */
886  switch (j->jointype)
887  {
888  case JOIN_INNER:
889  j->larg = pull_up_subqueries_recurse(root, j->larg,
890  lowest_outer_join,
891  lowest_nulling_outer_join,
892  NULL);
893  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
894  lowest_outer_join,
895  lowest_nulling_outer_join,
896  NULL);
897  break;
898  case JOIN_LEFT:
899  case JOIN_SEMI:
900  case JOIN_ANTI:
901  j->larg = pull_up_subqueries_recurse(root, j->larg,
902  j,
903  lowest_nulling_outer_join,
904  NULL);
905  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
906  j,
907  j,
908  NULL);
909  break;
910  case JOIN_FULL:
911  j->larg = pull_up_subqueries_recurse(root, j->larg,
912  j,
913  j,
914  NULL);
915  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
916  j,
917  j,
918  NULL);
919  break;
920  case JOIN_RIGHT:
921  j->larg = pull_up_subqueries_recurse(root, j->larg,
922  j,
923  j,
924  NULL);
925  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
926  j,
927  lowest_nulling_outer_join,
928  NULL);
929  break;
930  default:
931  elog(ERROR, "unrecognized join type: %d",
932  (int) j->jointype);
933  break;
934  }
935  }
936  else
937  elog(ERROR, "unrecognized node type: %d",
938  (int) nodeTag(jtnode));
939  return jtnode;
940 }
@ JOIN_SEMI
Definition: nodes.h:307
@ JOIN_ANTI
Definition: nodes.h:308
static Node * pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
static bool is_simple_values(PlannerInfo *root, RangeTblEntry *rte)
static Node * pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
Definition: prepjointree.c:955
static Node * pull_up_constant_function(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
static Node * pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
static bool is_simple_union_all(Query *subquery)

References Assert(), elog(), ERROR, FromExpr::fromlist, is_safe_append_member(), is_simple_subquery(), is_simple_union_all(), is_simple_values(), IsA, j, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, lfirst, nodeTag, PlannerInfo::parse, pull_up_constant_function(), pull_up_simple_subquery(), pull_up_simple_union_all(), pull_up_simple_values(), rt_fetch, Query::rtable, RTE_FUNCTION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by pull_up_subqueries(), and pull_up_union_leaf_queries().

◆ pull_up_union_leaf_queries()

static void pull_up_union_leaf_queries ( Node setOp,
PlannerInfo root,
int  parentRTindex,
Query setOpQuery,
int  childRToffset 
)
static

Definition at line 1384 of file prepjointree.c.

1386 {
1387  if (IsA(setOp, RangeTblRef))
1388  {
1389  RangeTblRef *rtr = (RangeTblRef *) setOp;
1390  int childRTindex;
1391  AppendRelInfo *appinfo;
1392 
1393  /*
1394  * Calculate the index in the parent's range table
1395  */
1396  childRTindex = childRToffset + rtr->rtindex;
1397 
1398  /*
1399  * Build a suitable AppendRelInfo, and attach to parent's list.
1400  */
1401  appinfo = makeNode(AppendRelInfo);
1402  appinfo->parent_relid = parentRTindex;
1403  appinfo->child_relid = childRTindex;
1404  appinfo->parent_reltype = InvalidOid;
1405  appinfo->child_reltype = InvalidOid;
1406  make_setop_translation_list(setOpQuery, childRTindex, appinfo);
1407  appinfo->parent_reloid = InvalidOid;
1408  root->append_rel_list = lappend(root->append_rel_list, appinfo);
1409 
1410  /*
1411  * Recursively apply pull_up_subqueries to the new child RTE. (We
1412  * must build the AppendRelInfo first, because this will modify it.)
1413  * Note that we can pass NULL for containing-join info even if we're
1414  * actually under an outer join, because the child's expressions
1415  * aren't going to propagate up to the join. Also, we ignore the
1416  * possibility that pull_up_subqueries_recurse() returns a different
1417  * jointree node than what we pass it; if it does, the important thing
1418  * is that it replaced the child relid in the AppendRelInfo node.
1419  */
1420  rtr = makeNode(RangeTblRef);
1421  rtr->rtindex = childRTindex;
1422  (void) pull_up_subqueries_recurse(root, (Node *) rtr,
1423  NULL, NULL, appinfo);
1424  }
1425  else if (IsA(setOp, SetOperationStmt))
1426  {
1427  SetOperationStmt *op = (SetOperationStmt *) setOp;
1428 
1429  /* Recurse to reach leaf queries */
1430  pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
1431  childRToffset);
1432  pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
1433  childRToffset);
1434  }
1435  else
1436  {
1437  elog(ERROR, "unrecognized node type: %d",
1438  (int) nodeTag(setOp));
1439  }
1440 }
#define InvalidOid
Definition: postgres_ext.h:36
static void make_setop_translation_list(Query *query, int newvarno, AppendRelInfo *appinfo)
Oid parent_reltype
Definition: pathnodes.h:2766

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, and RangeTblRef::rtindex.

Referenced by flatten_simple_union_all(), and pull_up_simple_union_all().

◆ pullup_replace_vars()

static Node * pullup_replace_vars ( Node expr,
pullup_replace_vars_context context 
)
static

Definition at line 2322 of file prepjointree.c.

2323 {
2324  return replace_rte_variables(expr,
2325  context->varno, 0,
2327  (void *) context,
2328  context->outer_hasSubLinks);
2329 }
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)

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

Referenced by perform_pullup_replace_vars(), and replace_vars_in_jointree().

◆ pullup_replace_vars_callback()

static Node * pullup_replace_vars_callback ( Var var,
replace_rte_variables_context context 
)
static

Definition at line 2332 of file prepjointree.c.

2334 {
2336  int varattno = var->varattno;
2337  Node *newnode;
2338 
2339  /*
2340  * If PlaceHolderVars are needed, we cache the modified expressions in
2341  * rcon->rv_cache[]. This is not in hopes of any material speed gain
2342  * within this function, but to avoid generating identical PHVs with
2343  * different IDs. That would result in duplicate evaluations at runtime,
2344  * and possibly prevent optimizations that rely on recognizing different
2345  * references to the same subquery output as being equal(). So it's worth
2346  * a bit of extra effort to avoid it.
2347  */
2348  if (rcon->need_phvs &&
2349  varattno >= InvalidAttrNumber &&
2350  varattno <= list_length(rcon->targetlist) &&
2351  rcon->rv_cache[varattno] != NULL)
2352  {
2353  /* Just copy the entry and fall through to adjust its varlevelsup */
2354  newnode = copyObject(rcon->rv_cache[varattno]);
2355  }
2356  else if (varattno == InvalidAttrNumber)
2357  {
2358  /* Must expand whole-tuple reference into RowExpr */
2359  RowExpr *rowexpr;
2360  List *colnames;
2361  List *fields;
2362  bool save_need_phvs = rcon->need_phvs;
2363  int save_sublevelsup = context->sublevels_up;
2364 
2365  /*
2366  * If generating an expansion for a var of a named rowtype (ie, this
2367  * is a plain relation RTE), then we must include dummy items for
2368  * dropped columns. If the var is RECORD (ie, this is a JOIN), then
2369  * omit dropped columns. In the latter case, attach column names to
2370  * the RowExpr for use of the executor and ruleutils.c.
2371  *
2372  * In order to be able to cache the results, we always generate the
2373  * expansion with varlevelsup = 0, and then adjust if needed.
2374  */
2375  expandRTE(rcon->target_rte,
2376  var->varno, 0 /* not varlevelsup */ , var->location,
2377  (var->vartype != RECORDOID),
2378  &colnames, &fields);
2379  /* Adjust the generated per-field Vars, but don't insert PHVs */
2380  rcon->need_phvs = false;
2381  context->sublevels_up = 0; /* to match the expandRTE output */
2382  fields = (List *) replace_rte_variables_mutator((Node *) fields,
2383  context);
2384  rcon->need_phvs = save_need_phvs;
2385  context->sublevels_up = save_sublevelsup;
2386 
2387  rowexpr = makeNode(RowExpr);
2388  rowexpr->args = fields;
2389  rowexpr->row_typeid = var->vartype;
2390  rowexpr->row_format = COERCE_IMPLICIT_CAST;
2391  rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
2392  rowexpr->location = var->location;
2393  newnode = (Node *) rowexpr;
2394 
2395  /*
2396  * Insert PlaceHolderVar if needed. Notice that we are wrapping one
2397  * PlaceHolderVar around the whole RowExpr, rather than putting one
2398  * around each element of the row. This is because we need the
2399  * expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
2400  * to null by an outer join.
2401  */
2402  if (rcon->need_phvs)
2403  {
2404  /* RowExpr is certainly not strict, so always need PHV */
2405  newnode = (Node *)
2407  (Expr *) newnode,
2408  bms_make_singleton(rcon->varno));
2409  /* cache it with the PHV, and with varlevelsup still zero */
2410  rcon->rv_cache[InvalidAttrNumber] = copyObject(newnode);
2411  }
2412  }
2413  else
2414  {
2415  /* Normal case referencing one targetlist element */
2416  TargetEntry *tle = get_tle_by_resno(rcon->targetlist, varattno);
2417 
2418  if (tle == NULL) /* shouldn't happen */
2419  elog(ERROR, "could not find attribute %d in subquery targetlist",
2420  varattno);
2421 
2422  /* Make a copy of the tlist item to return */
2423  newnode = (Node *) copyObject(tle->expr);
2424 
2425  /* Insert PlaceHolderVar if needed */
2426  if (rcon->need_phvs)
2427  {
2428  bool wrap;
2429 
2430  if (newnode && IsA(newnode, Var) &&
2431  ((Var *) newnode)->varlevelsup == 0)
2432  {
2433  /*
2434  * Simple Vars always escape being wrapped, unless they are
2435  * lateral references to something outside the subquery being
2436  * pulled up. (Even then, we could omit the PlaceHolderVar if
2437  * the referenced rel is under the same lowest outer join, but
2438  * it doesn't seem worth the trouble to check that.)
2439  */
2440  if (rcon->target_rte->lateral &&
2441  !bms_is_member(((Var *) newnode)->varno, rcon->relids))
2442  wrap = true;
2443  else
2444  wrap = false;
2445  }
2446  else if (newnode && IsA(newnode, PlaceHolderVar) &&
2447  ((PlaceHolderVar *) newnode)->phlevelsup == 0)
2448  {
2449  /* No need to wrap a PlaceHolderVar with another one, either */
2450  wrap = false;
2451  }
2452  else if (rcon->wrap_non_vars)
2453  {
2454  /* Wrap all non-Vars in a PlaceHolderVar */
2455  wrap = true;
2456  }
2457  else
2458  {
2459  /*
2460  * If it contains a Var of the subquery being pulled up, and
2461  * does not contain any non-strict constructs, then it's
2462  * certainly nullable so we don't need to insert a
2463  * PlaceHolderVar.
2464  *
2465  * This analysis could be tighter: in particular, a non-strict
2466  * construct hidden within a lower-level PlaceHolderVar is not
2467  * reason to add another PHV. But for now it doesn't seem
2468  * worth the code to be more exact.
2469  *
2470  * Note: in future maybe we should insert a PlaceHolderVar
2471  * anyway, if the tlist item is expensive to evaluate?
2472  *
2473  * For a LATERAL subquery, we have to check the actual var
2474  * membership of the node, but if it's non-lateral then any
2475  * level-zero var must belong to the subquery.
2476  */
2477  if ((rcon->target_rte->lateral ?
2478  bms_overlap(pull_varnos(rcon->root, (Node *) newnode),
2479  rcon->relids) :
2480  contain_vars_of_level((Node *) newnode, 0)) &&
2481  !contain_nonstrict_functions((Node *) newnode))
2482  {
2483  /* No wrap needed */
2484  wrap = false;
2485  }
2486  else
2487  {
2488  /* Else wrap it in a PlaceHolderVar */
2489  wrap = true;
2490  }
2491  }
2492 
2493  if (wrap)
2494  newnode = (Node *)
2496  (Expr *) newnode,
2497  bms_make_singleton(rcon->varno));
2498 
2499  /*
2500  * Cache it if possible (ie, if the attno is in range, which it
2501  * probably always should be). We can cache the value even if we
2502  * decided we didn't need a PHV, since this result will be
2503  * suitable for any request that has need_phvs.
2504  */
2505  if (varattno > InvalidAttrNumber &&
2506  varattno <= list_length(rcon->targetlist))
2507  rcon->rv_cache[varattno] = copyObject(newnode);
2508  }
2509  }
2510 
2511  /* Must adjust varlevelsup if tlist item is from higher query */
2512  if (var->varlevelsup > 0)
2513  IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
2514 
2515  return newnode;
2516 }
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:428
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:495
bool contain_nonstrict_functions(Node *clause)
Definition: clauses.c:874
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
Definition: placeholder.c:39
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:588
Node * replace_rte_variables_mutator(Node *node, replace_rte_variables_context *context)
Oid row_typeid
Definition: primnodes.h:1208
int location
Definition: primnodes.h:1224
List * args
Definition: primnodes.h:1207
CoercionForm row_format
Definition: primnodes.h:1222
List * colnames
Definition: primnodes.h:1223
Expr * expr
Definition: primnodes.h:1555
Definition: primnodes.h:205
Oid vartype
Definition: primnodes.h:220
AttrNumber varattno
Definition: primnodes.h:217
int varno
Definition: primnodes.h:212
Index varlevelsup
Definition: primnodes.h:230
int location
Definition: primnodes.h:243
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:100

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(), if(), IncrementVarSublevelsUp(), InvalidAttrNumber, IsA, RangeTblEntry::lateral, list_length(), Var::location, RowExpr::location, make_placeholder_expr(), makeNode, pullup_replace_vars_context::need_phvs, NIL, pull_varnos(), 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().

◆ pullup_replace_vars_subquery()

static Query * pullup_replace_vars_subquery ( Query query,
pullup_replace_vars_context context 
)
static

Definition at line 2526 of file prepjointree.c.

2528 {
2529  Assert(IsA(query, Query));
2530  return (Query *) replace_rte_variables((Node *) query,
2531  context->varno, 1,
2533  (void *) context,
2534  NULL);
2535 }

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

Referenced by replace_vars_in_jointree().

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 2671 of file prepjointree.c.

2672 {
2674 
2675  /*
2676  * To avoid doing strictness checks on more quals than necessary, we want
2677  * to stop descending the jointree as soon as there are no outer joins
2678  * below our current point. This consideration forces a two-pass process.
2679  * The first pass gathers information about which base rels appear below
2680  * each side of each join clause, and about whether there are outer
2681  * join(s) below each side of each join clause. The second pass examines
2682  * qual clauses and changes join types as it descends the tree.
2683  */
2685 
2686  /* planner.c shouldn't have called me if no outer joins */
2687  if (state == NULL || !state->contains_outer)
2688  elog(ERROR, "so where are the outer joins?");
2689 
2691  state, root, NULL, NIL);
2692 }
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *forced_null_vars)
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
Definition: regguts.h:318

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

Referenced by subquery_planner().

◆ reduce_outer_joins_pass1()

static reduce_outer_joins_state * reduce_outer_joins_pass1 ( Node jtnode)
static

Definition at line 2700 of file prepjointree.c.

2701 {
2702  reduce_outer_joins_state *result;
2703 
2704  result = (reduce_outer_joins_state *)
2706  result->relids = NULL;
2707  result->contains_outer = false;
2708  result->sub_states = NIL;
2709 
2710  if (jtnode == NULL)
2711  return result;
2712  if (IsA(jtnode, RangeTblRef))
2713  {
2714  int varno = ((RangeTblRef *) jtnode)->rtindex;
2715 
2716  result->relids = bms_make_singleton(varno);
2717  }
2718  else if (IsA(jtnode, FromExpr))
2719  {
2720  FromExpr *f = (FromExpr *) jtnode;
2721  ListCell *l;
2722 
2723  foreach(l, f->fromlist)
2724  {
2725  reduce_outer_joins_state *sub_state;
2726 
2727  sub_state = reduce_outer_joins_pass1(lfirst(l));
2728  result->relids = bms_add_members(result->relids,
2729  sub_state->relids);
2730  result->contains_outer |= sub_state->contains_outer;
2731  result->sub_states = lappend(result->sub_states, sub_state);
2732  }
2733  }
2734  else if (IsA(jtnode, JoinExpr))
2735  {
2736  JoinExpr *j = (JoinExpr *) jtnode;
2737  reduce_outer_joins_state *sub_state;
2738 
2739  /* join's own RT index is not wanted in result->relids */
2740  if (IS_OUTER_JOIN(j->jointype))
2741  result->contains_outer = true;
2742 
2743  sub_state = reduce_outer_joins_pass1(j->larg);
2744  result->relids = bms_add_members(result->relids,
2745  sub_state->relids);
2746  result->contains_outer |= sub_state->contains_outer;
2747  result->sub_states = lappend(result->sub_states, sub_state);
2748 
2749  sub_state = reduce_outer_joins_pass1(j->rarg);
2750  result->relids = bms_add_members(result->relids,
2751  sub_state->relids);
2752  result->contains_outer |= sub_state->contains_outer;
2753  result->sub_states = lappend(result->sub_states, sub_state);
2754  }
2755  else
2756  elog(ERROR, "unrecognized node type: %d",
2757  (int) nodeTag(jtnode));
2758  return result;
2759 }
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:796
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:336

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

Referenced by reduce_outer_joins().

◆ reduce_outer_joins_pass2()

static void reduce_outer_joins_pass2 ( Node jtnode,
reduce_outer_joins_state state,
PlannerInfo root,
Relids  nonnullable_rels,
List forced_null_vars 
)
static

Definition at line 2771 of file prepjointree.c.

2776 {
2777  /*
2778  * pass 2 should never descend as far as an empty subnode or base rel,
2779  * because it's only called on subtrees marked as contains_outer.
2780  */
2781  if (jtnode == NULL)
2782  elog(ERROR, "reached empty jointree");
2783  if (IsA(jtnode, RangeTblRef))
2784  elog(ERROR, "reached base rel");
2785  else if (IsA(jtnode, FromExpr))
2786  {
2787  FromExpr *f = (FromExpr *) jtnode;
2788  ListCell *l;
2789  ListCell *s;
2790  Relids pass_nonnullable_rels;
2791  List *pass_forced_null_vars;
2792 
2793  /* Scan quals to see if we can add any constraints */
2794  pass_nonnullable_rels = find_nonnullable_rels(f->quals);
2795  pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
2796  nonnullable_rels);
2797  pass_forced_null_vars = find_forced_null_vars(f->quals);
2798  pass_forced_null_vars = mbms_add_members(pass_forced_null_vars,
2799  forced_null_vars);
2800  /* And recurse --- but only into interesting subtrees */
2801  Assert(list_length(f->fromlist) == list_length(state->sub_states));
2802  forboth(l, f->fromlist, s, state->sub_states)
2803  {
2804  reduce_outer_joins_state *sub_state = lfirst(s);
2805 
2806  if (sub_state->contains_outer)
2807  reduce_outer_joins_pass2(lfirst(l), sub_state, root,
2808  pass_nonnullable_rels,
2809  pass_forced_null_vars);
2810  }
2811  bms_free(pass_nonnullable_rels);
2812  /* can't so easily clean up var lists, unfortunately */
2813  }
2814  else if (IsA(jtnode, JoinExpr))
2815  {
2816  JoinExpr *j = (JoinExpr *) jtnode;
2817  int rtindex = j->rtindex;
2818  JoinType jointype = j->jointype;
2819  reduce_outer_joins_state *left_state = linitial(state->sub_states);
2820  reduce_outer_joins_state *right_state = lsecond(state->sub_states);
2821 
2822  /* Can we simplify this join? */
2823  switch (jointype)
2824  {
2825  case JOIN_INNER:
2826  break;
2827  case JOIN_LEFT:
2828  if (bms_overlap(nonnullable_rels, right_state->relids))
2829  jointype = JOIN_INNER;
2830  break;
2831  case JOIN_RIGHT:
2832  if (bms_overlap(nonnullable_rels, left_state->relids))
2833  jointype = JOIN_INNER;
2834  break;
2835  case JOIN_FULL:
2836  if (bms_overlap(nonnullable_rels, left_state->relids))
2837  {
2838  if (bms_overlap(nonnullable_rels, right_state->relids))
2839  jointype = JOIN_INNER;
2840  else
2841  jointype = JOIN_LEFT;
2842  }
2843  else
2844  {
2845  if (bms_overlap(nonnullable_rels, right_state->relids))
2846  jointype = JOIN_RIGHT;
2847  }
2848  break;
2849  case JOIN_SEMI:
2850  case JOIN_ANTI:
2851 
2852  /*
2853  * These could only have been introduced by pull_up_sublinks,
2854  * so there's no way that upper quals could refer to their
2855  * righthand sides, and no point in checking.
2856  */
2857  break;
2858  default:
2859  elog(ERROR, "unrecognized join type: %d",
2860  (int) jointype);
2861  break;
2862  }
2863 
2864  /*
2865  * Convert JOIN_RIGHT to JOIN_LEFT. Note that in the case where we
2866  * reduced JOIN_FULL to JOIN_RIGHT, this will mean the JoinExpr no
2867  * longer matches the internal ordering of any CoalesceExpr's built to
2868  * represent merged join variables. We don't care about that at
2869  * present, but be wary of it ...
2870  */
2871  if (jointype == JOIN_RIGHT)
2872  {
2873  Node *tmparg;
2874 
2875  tmparg = j->larg;
2876  j->larg = j->rarg;
2877  j->rarg = tmparg;
2878  jointype = JOIN_LEFT;
2879  right_state = linitial(state->sub_states);
2880  left_state = lsecond(state->sub_states);
2881  }
2882 
2883  /*
2884  * See if we can reduce JOIN_LEFT to JOIN_ANTI. This is the case if
2885  * the join's own quals are strict for any var that was forced null by
2886  * higher qual levels. NOTE: there are other ways that we could
2887  * detect an anti-join, in particular if we were to check whether Vars
2888  * coming from the RHS must be non-null because of table constraints.
2889  * That seems complicated and expensive though (in particular, one
2890  * would have to be wary of lower outer joins). For the moment this
2891  * seems sufficient.
2892  */
2893  if (jointype == JOIN_LEFT)
2894  {
2895  List *nonnullable_vars;
2896  Bitmapset *overlap;
2897 
2898  /* Find Vars in j->quals that must be non-null in joined rows */
2899  nonnullable_vars = find_nonnullable_vars(j->quals);
2900 
2901  /*
2902  * It's not sufficient to check whether nonnullable_vars and
2903  * forced_null_vars overlap: we need to know if the overlap
2904  * includes any RHS variables.
2905  */
2906  overlap = mbms_overlap_sets(nonnullable_vars, forced_null_vars);
2907  if (bms_overlap(overlap, right_state->relids))
2908  jointype = JOIN_ANTI;
2909  }
2910 
2911  /* Apply the jointype change, if any, to both jointree node and RTE */
2912  if (rtindex && jointype != j->jointype)
2913  {
2914  RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
2915 
2916  Assert(rte->rtekind == RTE_JOIN);
2917  Assert(rte->jointype == j->jointype);
2918  rte->jointype = jointype;
2919  }
2920  j->jointype = jointype;
2921 
2922  /* Only recurse if there's more to do below here */
2923  if (left_state->contains_outer || right_state->contains_outer)
2924  {
2925  Relids local_nonnullable_rels;
2926  List *local_forced_null_vars;
2927  Relids pass_nonnullable_rels;
2928  List *pass_forced_null_vars;
2929 
2930  /*
2931  * If this join is (now) inner, we can add any constraints its
2932  * quals provide to those we got from above. But if it is outer,
2933  * we can pass down the local constraints only into the nullable
2934  * side, because an outer join never eliminates any rows from its
2935  * non-nullable side. Also, there is no point in passing upper
2936  * constraints into the nullable side, since if there were any
2937  * we'd have been able to reduce the join. (In the case of upper
2938  * forced-null constraints, we *must not* pass them into the
2939  * nullable side --- they either applied here, or not.) The upshot
2940  * is that we pass either the local or the upper constraints,
2941  * never both, to the children of an outer join.
2942  *
2943  * Note that a SEMI join works like an inner join here: it's okay
2944  * to pass down both local and upper constraints. (There can't be
2945  * any upper constraints affecting its inner side, but it's not
2946  * worth having a separate code path to avoid passing them.)
2947  *
2948  * At a FULL join we just punt and pass nothing down --- is it
2949  * possible to be smarter?
2950  */
2951  if (jointype != JOIN_FULL)
2952  {
2953  local_nonnullable_rels = find_nonnullable_rels(j->quals);
2954  local_forced_null_vars = find_forced_null_vars(j->quals);
2955  if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2956  {
2957  /* OK to merge upper and local constraints */
2958  local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
2959  nonnullable_rels);
2960  local_forced_null_vars = mbms_add_members(local_forced_null_vars,
2961  forced_null_vars);
2962  }
2963  }
2964  else
2965  {
2966  /* no use in calculating these */
2967  local_nonnullable_rels = NULL;
2968  local_forced_null_vars = NIL;
2969  }
2970 
2971  if (left_state->contains_outer)
2972  {
2973  if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2974  {
2975  /* pass union of local and upper constraints */
2976  pass_nonnullable_rels = local_nonnullable_rels;
2977  pass_forced_null_vars = local_forced_null_vars;
2978  }
2979  else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
2980  {
2981  /* can't pass local constraints to non-nullable side */
2982  pass_nonnullable_rels = nonnullable_rels;
2983  pass_forced_null_vars = forced_null_vars;
2984  }
2985  else
2986  {
2987  /* no constraints pass through JOIN_FULL */
2988  pass_nonnullable_rels = NULL;
2989  pass_forced_null_vars = NIL;
2990  }
2991  reduce_outer_joins_pass2(j->larg, left_state, root,
2992  pass_nonnullable_rels,
2993  pass_forced_null_vars);
2994  }
2995 
2996  if (right_state->contains_outer)
2997  {
2998  if (jointype != JOIN_FULL) /* ie, INNER/LEFT/SEMI/ANTI */
2999  {
3000  /* pass appropriate constraints, per comment above */
3001  pass_nonnullable_rels = local_nonnullable_rels;
3002  pass_forced_null_vars = local_forced_null_vars;
3003  }
3004  else
3005  {
3006  /* no constraints pass through JOIN_FULL */
3007  pass_nonnullable_rels = NULL;
3008  pass_forced_null_vars = NIL;
3009  }
3010  reduce_outer_joins_pass2(j->rarg, right_state, root,
3011  pass_nonnullable_rels,
3012  pass_forced_null_vars);
3013  }
3014  bms_free(local_nonnullable_rels);
3015  }
3016  }
3017  else
3018  elog(ERROR, "unrecognized node type: %d",
3019  (int) nodeTag(jtnode));
3020 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
List * find_forced_null_vars(Node *node)
Definition: clauses.c:1796
Relids find_nonnullable_rels(Node *clause)
Definition: clauses.c:1336
List * find_nonnullable_vars(Node *clause)
Definition: clauses.c:1587
Bitmapset * mbms_overlap_sets(const List *a, const List *b)
List * mbms_add_members(List *a, const List *b)
JoinType
Definition: nodes.h:288
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:465
#define lsecond(l)
Definition: pg_list.h:181
JoinType jointype
Definition: parsenodes.h:1079

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, j, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, RangeTblEntry::jointype, lfirst, linitial, list_length(), lsecond, mbms_add_members(), mbms_overlap_sets(), NIL, nodeTag, PlannerInfo::parse, FromExpr::quals, reduce_outer_joins_state::relids, rt_fetch, Query::rtable, RTE_JOIN, and RangeTblEntry::rtekind.

Referenced by reduce_outer_joins().

◆ remove_result_refs()

static void remove_result_refs ( PlannerInfo root,
int  varno,
Node newjtloc 
)
static

Definition at line 3329 of file prepjointree.c.

3330 {
3331  /* Fix up PlaceHolderVars as needed */
3332  /* If there are no PHVs anywhere, we can skip this bit */
3333  if (root->glob->lastPHId != 0)
3334  {
3335  Relids subrelids;
3336 
3337  subrelids = get_relids_in_jointree(newjtloc, false);
3338  Assert(!bms_is_empty(subrelids));
3339  substitute_phv_relids((Node *) root->parse, varno, subrelids);
3340  fix_append_rel_relids(root->append_rel_list, varno, subrelids);
3341  }
3342 
3343  /*
3344  * We also need to remove any PlanRowMark referencing the RTE, but we
3345  * postpone that work until we return to remove_useless_result_rtes.
3346  */
3347 }
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:704

References PlannerInfo::append_rel_list, Assert(), bms_is_empty(), fix_append_rel_relids(), get_relids_in_jointree(), PlannerInfo::glob, PlannerGlobal::lastPHId, PlannerInfo::parse, and substitute_phv_relids().

Referenced by remove_useless_results_recurse().

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

Definition at line 3061 of file prepjointree.c.

3062 {
3063  ListCell *cell;
3064 
3065  /* Top level of jointree must always be a FromExpr */
3066  Assert(IsA(root->parse->jointree, FromExpr));
3067  /* Recurse ... */
3068  root->parse->jointree = (FromExpr *)
3070  /* We should still have a FromExpr */
3071  Assert(IsA(root->parse->jointree, FromExpr));
3072 
3073  /*
3074  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3075  * must do that for any RTE_RESULT that we just removed. But one for a
3076  * RTE that we did not remove can be dropped anyway: since the RTE has
3077  * only one possible output row, there is no need for EPQ to mark and
3078  * restore that row.
3079  *
3080  * It's necessary, not optional, to remove the PlanRowMark for a surviving
3081  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3082  * RTE_RESULT, which the executor has no support for.
3083  */
3084  foreach(cell, root->rowMarks)
3085  {
3086  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3087 
3088  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3089  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3090  }
3091 }
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:388
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode)

References Assert(), foreach_delete_current, IsA, Query::jointree, lfirst, PlannerInfo::parse, remove_useless_results_recurse(), PlannerInfo::rowMarks, rt_fetch, Query::rtable, RTE_RESULT, and PlanRowMark::rti.

Referenced by subquery_planner().

◆ remove_useless_results_recurse()

static Node * remove_useless_results_recurse ( PlannerInfo root,
Node jtnode 
)
static

Definition at line 3100 of file prepjointree.c.

3101 {
3102  Assert(jtnode != NULL);
3103  if (IsA(jtnode, RangeTblRef))
3104  {
3105  /* Can't immediately do anything with a RangeTblRef */
3106  }
3107  else if (IsA(jtnode, FromExpr))
3108  {
3109  FromExpr *f = (FromExpr *) jtnode;
3110  Relids result_relids = NULL;
3111  ListCell *cell;
3112 
3113  /*
3114  * We can drop RTE_RESULT rels from the fromlist so long as at least
3115  * one child remains, since joining to a one-row table changes
3116  * nothing. (But we can't drop a RTE_RESULT that computes PHV(s) that
3117  * are needed by some sibling. The cleanup transformation below would
3118  * reassign the PHVs to be computed at the join, which is too late for
3119  * the sibling's use.) The easiest way to mechanize this rule is to
3120  * modify the list in-place.
3121  */
3122  foreach(cell, f->fromlist)
3123  {
3124  Node *child = (Node *) lfirst(cell);
3125  int varno;
3126 
3127  /* Recursively transform child ... */
3128  child = remove_useless_results_recurse(root, child);
3129  /* ... and stick it back into the tree */
3130  lfirst(cell) = child;
3131 
3132  /*
3133  * If it's an RTE_RESULT with at least one sibling, and no sibling
3134  * references dependent PHVs, we can drop it. We don't yet know
3135  * what the inner join's final relid set will be, so postpone
3136  * cleanup of PHVs etc till after this loop.
3137  */
3138  if (list_length(f->fromlist) > 1 &&
3139  (varno = get_result_relid(root, child)) != 0 &&
3140  !find_dependent_phvs_in_jointree(root, (Node *) f, varno))
3141  {
3142  f->fromlist = foreach_delete_current(f->fromlist, cell);
3143  result_relids = bms_add_member(result_relids, varno);
3144  }
3145  }
3146 
3147  /*
3148  * Clean up if we dropped any RTE_RESULT RTEs. This is a bit
3149  * inefficient if there's more than one, but it seems better to
3150  * optimize the support code for the single-relid case.
3151  */
3152  if (result_relids)
3153  {
3154  int varno = -1;
3155 
3156  while ((varno = bms_next_member(result_relids, varno)) >= 0)
3157  remove_result_refs(root, varno, (Node *) f);
3158  }
3159 
3160  /*
3161  * If we're not at the top of the jointree, it's valid to simplify a
3162  * degenerate FromExpr into its single child. (At the top, we must
3163  * keep the FromExpr since Query.jointree is required to point to a
3164  * FromExpr.)
3165  */
3166  if (f != root->parse->jointree &&
3167  f->quals == NULL &&
3168  list_length(f->fromlist) == 1)
3169  return (Node *) linitial(f->fromlist);
3170  }
3171  else if (IsA(jtnode, JoinExpr))
3172  {
3173  JoinExpr *j = (JoinExpr *) jtnode;
3174  int varno;
3175 
3176  /* First, recurse */
3177  j->larg = remove_useless_results_recurse(root, j->larg);
3178  j->rarg = remove_useless_results_recurse(root, j->rarg);
3179 
3180  /* Apply join-type-specific optimization rules */
3181  switch (j->jointype)
3182  {
3183  case JOIN_INNER:
3184 
3185  /*
3186  * An inner join is equivalent to a FromExpr, so if either
3187  * side was simplified to an RTE_RESULT rel, we can replace
3188  * the join with a FromExpr with just the other side; and if
3189  * the qual is empty (JOIN ON TRUE) then we can omit the
3190  * FromExpr as well.
3191  *
3192  * Just as in the FromExpr case, we can't simplify if the
3193  * other input rel references any PHVs that are marked as to
3194  * be evaluated at the RTE_RESULT rel, because we can't
3195  * postpone their evaluation in that case. But we only have
3196  * to check this in cases where it's syntactically legal for
3197  * the other input to have a LATERAL reference to the
3198  * RTE_RESULT rel. Only RHSes of inner and left joins are
3199  * allowed to have such refs.
3200  */
3201  if ((varno = get_result_relid(root, j->larg)) != 0 &&
3202  !find_dependent_phvs_in_jointree(root, j->rarg, varno))
3203  {
3204  remove_result_refs(root, varno, j->rarg);
3205  if (j->quals)
3206  jtnode = (Node *)
3207  makeFromExpr(list_make1(j->rarg), j->quals);
3208  else
3209  jtnode = j->rarg;
3210  }
3211  else if ((varno = get_result_relid(root, j->rarg)) != 0)
3212  {
3213  remove_result_refs(root, varno, j->larg);
3214  if (j->quals)
3215  jtnode = (Node *)
3216  makeFromExpr(list_make1(j->larg), j->quals);
3217  else
3218  jtnode = j->larg;
3219  }
3220  break;
3221  case JOIN_LEFT:
3222 
3223  /*
3224  * We can simplify this case if the RHS is an RTE_RESULT, with
3225  * two different possibilities:
3226  *
3227  * If the qual is empty (JOIN ON TRUE), then the join can be
3228  * strength-reduced to a plain inner join, since each LHS row
3229  * necessarily has exactly one join partner. So we can always
3230  * discard the RHS, much as in the JOIN_INNER case above.
3231  * (Again, the LHS could not contain a lateral reference to
3232  * the RHS.)
3233  *
3234  * Otherwise, it's still true that each LHS row should be
3235  * returned exactly once, and since the RHS returns no columns
3236  * (unless there are PHVs that have to be evaluated there), we
3237  * don't much care if it's null-extended or not. So in this
3238  * case also, we can just ignore the qual and discard the left
3239  * join.
3240  */
3241  if ((varno = get_result_relid(root, j->rarg)) != 0 &&
3242  (j->quals == NULL ||
3243  !find_dependent_phvs(root, varno)))
3244  {
3245  remove_result_refs(root, varno, j->larg);
3246  jtnode = j->larg;
3247  }
3248  break;
3249  case JOIN_SEMI:
3250 
3251  /*
3252  * We may simplify this case if the RHS is an RTE_RESULT; the
3253  * join qual becomes effectively just a filter qual for the
3254  * LHS, since we should either return the LHS row or not. For
3255  * simplicity we inject the filter qual into a new FromExpr.
3256  *
3257  * There is a fine point about PHVs that are supposed to be
3258  * evaluated at the RHS. Such PHVs could only appear in the
3259  * semijoin's qual, since the rest of the query cannot
3260  * reference any outputs of the semijoin's RHS. Therefore,
3261  * they can't actually go to null before being examined, and
3262  * it'd be OK to just remove the PHV wrapping. We don't have
3263  * infrastructure for that, but remove_result_refs() will
3264  * relabel them as to be evaluated at the LHS, which is fine.
3265  */
3266  if ((varno = get_result_relid(root, j->rarg)) != 0)
3267  {
3268  remove_result_refs(root, varno, j->larg);
3269  if (j->quals)
3270  jtnode = (Node *)
3271  makeFromExpr(list_make1(j->larg), j->quals);
3272  else
3273  jtnode = j->larg;
3274  }
3275  break;
3276  case JOIN_FULL:
3277  case JOIN_ANTI:
3278  /* We have no special smarts for these cases */
3279  break;
3280  default:
3281  /* Note: JOIN_RIGHT should be gone at this point */
3282  elog(ERROR, "unrecognized join type: %d",
3283  (int) j->jointype);
3284  break;
3285  }
3286  }
3287  else
3288  elog(ERROR, "unrecognized node type: %d",
3289  (int) nodeTag(jtnode));
3290  return jtnode;
3291 }
static void remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
static int get_result_relid(PlannerInfo *root, Node *jtnode)
static bool find_dependent_phvs(PlannerInfo *root, int varno)
static bool find_dependent_phvs_in_jointree(PlannerInfo *root, Node *node, int varno)

References Assert(), bms_add_member(), bms_next_member(), elog(), ERROR, find_dependent_phvs(), find_dependent_phvs_in_jointree(), foreach_delete_current, FromExpr::fromlist, get_result_relid(), IsA, j, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, Query::jointree, lfirst, linitial, list_length(), list_make1, makeFromExpr(), nodeTag, PlannerInfo::parse, FromExpr::quals, and remove_result_refs().

Referenced by remove_useless_result_rtes().

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 223 of file prepjointree.c.

224 {
225  RangeTblEntry *rte;
226  Index rti;
227  RangeTblRef *rtr;
228 
229  /* Nothing to do if jointree is already nonempty */
230  if (parse->jointree->fromlist != NIL)
231  return;
232 
233  /* We mustn't change it in the top level of a setop tree, either */
234  if (parse->setOperations)
235  return;
236 
237  /* Create suitable RTE */
238  rte = makeNode(RangeTblEntry);
239  rte->rtekind = RTE_RESULT;
240  rte->eref = makeAlias("*RESULT*", NIL);
241 
242  /* Add it to rangetable */
243  parse->rtable = lappend(parse->rtable, rte);
244  rti = list_length(parse->rtable);
245 
246  /* And jam a reference into the jointree */
247  rtr = makeNode(RangeTblRef);
248  rtr->rtindex = rti;
249  parse->jointree->fromlist = list_make1(rtr);
250 }
unsigned int Index
Definition: c.h:550

References RangeTblEntry::eref, lappend(), list_length(), list_make1, makeAlias(), makeNode, NIL, parse(), RTE_RESULT, RangeTblEntry::rtekind, and RangeTblRef::rtindex.

Referenced by convert_EXISTS_sublink_to_join(), pull_up_simple_subquery(), and subquery_planner().

◆ replace_vars_in_jointree()

static void replace_vars_in_jointree ( Node jtnode,
pullup_replace_vars_context context,
JoinExpr lowest_nulling_outer_join 
)
static

Definition at line 2201 of file prepjointree.c.

2204 {
2205  if (jtnode == NULL)
2206  return;
2207  if (IsA(jtnode, RangeTblRef))
2208  {
2209  /*
2210  * If the RangeTblRef refers to a LATERAL subquery (that isn't the
2211  * same subquery we're pulling up), it might contain references to the
2212  * target subquery, which we must replace. We drive this from the
2213  * jointree scan, rather than a scan of the rtable, for a couple of
2214  * reasons: we can avoid processing no-longer-referenced RTEs, and we
2215  * can use the appropriate setting of need_phvs depending on whether
2216  * the RTE is above possibly-nulling outer joins or not.
2217  */
2218  int varno = ((RangeTblRef *) jtnode)->rtindex;
2219 
2220  if (varno != context->varno) /* ignore target subquery itself */
2221  {
2222  RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable);
2223 
2224  Assert(rte != context->target_rte);
2225  if (rte->lateral)
2226  {
2227  switch (rte->rtekind)
2228  {
2229  case RTE_RELATION:
2230  /* shouldn't be marked LATERAL unless tablesample */
2231  Assert(rte->tablesample);
2232  rte->tablesample = (TableSampleClause *)
2234  context);
2235  break;
2236  case RTE_SUBQUERY:
2237  rte->subquery =
2239  context);
2240  break;
2241  case RTE_FUNCTION:
2242  rte->functions = (List *)
2244  context);
2245  break;
2246  case RTE_TABLEFUNC:
2247  rte->tablefunc = (TableFunc *)
2249  context);
2250  break;
2251  case RTE_VALUES:
2252  rte->values_lists = (List *)
2254  context);
2255  break;
2256  case RTE_JOIN:
2257  case RTE_CTE:
2258  case RTE_NAMEDTUPLESTORE:
2259  case RTE_RESULT:
2260  /* these shouldn't be marked LATERAL */
2261  Assert(false);
2262  break;
2263  }
2264  }
2265  }
2266  }
2267  else if (IsA(jtnode, FromExpr))
2268  {
2269  FromExpr *f = (FromExpr *) jtnode;
2270  ListCell *l;
2271 
2272  foreach(l, f->fromlist)
2273  replace_vars_in_jointree(lfirst(l), context,
2274  lowest_nulling_outer_join);
2275  f->quals = pullup_replace_vars(f->quals, context);
2276  }
2277  else if (IsA(jtnode, JoinExpr))
2278  {
2279  JoinExpr *j = (JoinExpr *) jtnode;
2280  bool save_need_phvs = context->need_phvs;
2281 
2282  if (j == lowest_nulling_outer_join)
2283  {
2284  /* no more PHVs in or below this join */
2285  context->need_phvs = false;
2286  lowest_nulling_outer_join = NULL;
2287  }
2288  replace_vars_in_jointree(j->larg, context, lowest_nulling_outer_join);
2289  replace_vars_in_jointree(j->rarg, context, lowest_nulling_outer_join);
2290 
2291  /*
2292  * Use PHVs within the join quals of a full join, even when it's the
2293  * lowest nulling outer join. Otherwise, we cannot identify which
2294  * side of the join a pulled-up var-free expression came from, which
2295  * can lead to failure to make a plan at all because none of the quals
2296  * appear to be mergeable or hashable conditions. For this purpose we
2297  * don't care about the state of wrap_non_vars, so leave it alone.
2298  */
2299  if (j->jointype == JOIN_FULL)
2300  context->need_phvs = true;
2301 
2302  j->quals = pullup_replace_vars(j->quals, context);
2303 
2304  /*
2305  * We don't bother to update the colvars list, since it won't be used
2306  * again ...
2307  */
2308  context->need_phvs = save_need_phvs;
2309  }
2310  else
2311  elog(ERROR, "unrecognized node type: %d",
2312  (int) nodeTag(jtnode));
2313 }
static Query * pullup_replace_vars_subquery(Query *query, pullup_replace_vars_context *context)
TableFunc * tablefunc
Definition: parsenodes.h:1106

References Assert(), elog(), ERROR, FromExpr::fromlist, RangeTblEntry::functions, IsA, j, JOIN_FULL, RangeTblEntry::lateral, lfirst, pullup_replace_vars_context::need_phvs, nodeTag, PlannerInfo::parse, pullup_replace_vars(), pullup_replace_vars_subquery(), FromExpr::quals, pullup_replace_vars_context::root, rt_fetch, Query::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, 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 perform_pullup_replace_vars().

◆ substitute_phv_relids()

static void substitute_phv_relids ( Node node,
int  varno,
Relids  subrelids 
)
static

Definition at line 3531 of file prepjointree.c.

3532 {
3534 
3535  context.varno = varno;
3536  context.sublevels_up = 0;
3537  context.subrelids = subrelids;
3538 
3539  /*
3540  * Must be prepared to start with a Query or a bare expression tree.
3541  */
3544  (void *) &context,
3545  0);
3546 }
#define query_or_expression_tree_walker(n, w, c, f)
Definition: nodeFuncs.h:169
static bool substitute_phv_relids_walker(Node *node, substitute_phv_relids_context *context)

References query_or_expression_tree_walker, substitute_phv_relids_context::sublevels_up, substitute_phv_relids_context::subrelids, substitute_phv_relids_walker(), and substitute_phv_relids_context::varno.

Referenced by fix_append_rel_relids(), pull_up_simple_subquery(), and remove_result_refs().

◆ substitute_phv_relids_walker()

static bool substitute_phv_relids_walker ( Node node,
substitute_phv_relids_context context 
)
static

Definition at line 3487 of file prepjointree.c.

3489 {
3490  if (node == NULL)
3491  return false;
3492  if (IsA(node, PlaceHolderVar))
3493  {
3494  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3495 
3496  if (phv->phlevelsup == context->sublevels_up &&
3497  bms_is_member(context->varno, phv->phrels))
3498  {
3499  phv->phrels = bms_union(phv->phrels,
3500  context->subrelids);
3501  phv->phrels = bms_del_member(phv->phrels,
3502  context->varno);
3503  /* Assert we haven't broken the PHV */
3504  Assert(!bms_is_empty(phv->phrels));
3505  }
3506  /* fall through to examine children */
3507  }
3508  if (IsA(node, Query))
3509  {
3510  /* Recurse into subselects */
3511  bool result;
3512 
3513  context->sublevels_up++;
3514  result = query_tree_walker((Query *) node,
3516  (void *) context, 0);
3517  context->sublevels_up--;
3518  return result;
3519  }
3520  /* Shouldn't need to handle planner auxiliary nodes here */
3521  Assert(!IsA(node, SpecialJoinInfo));
3522  Assert(!IsA(node, AppendRelInfo));
3523  Assert(!IsA(node, PlaceHolderInfo));
3524  Assert(!IsA(node, MinMaxAggInfo));
3525 
3527  (void *) context);
3528 }
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:776

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

Referenced by substitute_phv_relids().

◆ transform_MERGE_to_join()

void transform_MERGE_to_join ( Query parse)

Definition at line 140 of file prepjointree.c.

141 {
142  RangeTblEntry *joinrte;
143  JoinExpr *joinexpr;
144  JoinType jointype;
145  int joinrti;
146  List *vars;
147 
148  if (parse->commandType != CMD_MERGE)
149  return;
150 
151  /* XXX probably bogus */
152  vars = NIL;
153 
154  /*
155  * When any WHEN NOT MATCHED THEN INSERT clauses exist, we need to use an
156  * outer join so that we process all unmatched tuples from the source
157  * relation. If none exist, we can use an inner join.
158  */
159  if (parse->mergeUseOuterJoin)
160  jointype = JOIN_RIGHT;
161  else
162  jointype = JOIN_INNER;
163 
164  /* Manufacture a join RTE to use. */
165  joinrte = makeNode(RangeTblEntry);
166  joinrte->rtekind = RTE_JOIN;
167  joinrte->jointype = jointype;
168  joinrte->joinmergedcols = 0;
169  joinrte->joinaliasvars = vars;
170  joinrte->joinleftcols = NIL; /* MERGE does not allow JOIN USING */
171  joinrte->joinrightcols = NIL; /* ditto */
172  joinrte->join_using_alias = NULL;
173 
174  joinrte->alias = NULL;
175  joinrte->eref = makeAlias("*MERGE*", NIL);
176  joinrte->lateral = false;
177  joinrte->inh = false;
178  joinrte->inFromCl = true;
179 
180  /*
181  * Add completed RTE to pstate's range table list, so that we know its
182  * index.
183  */
184  parse->rtable = lappend(parse->rtable, joinrte);
185  joinrti = list_length(parse->rtable);
186 
187  /*
188  * Create a JOIN between the target and the source relation.
189  */
190  joinexpr = makeNode(JoinExpr);
191  joinexpr->jointype = jointype;
192  joinexpr->isNatural = false;
193  joinexpr->larg = (Node *) makeNode(RangeTblRef);
194  ((RangeTblRef *) joinexpr->larg)->rtindex = parse->resultRelation;
195  joinexpr->rarg = linitial(parse->jointree->fromlist); /* original join */
196  joinexpr->usingClause = NIL;
197  joinexpr->join_using_alias = NULL;
198  /* The quals are removed from the jointree and into this specific join */
199  joinexpr->quals = parse->jointree->quals;
200  joinexpr->alias = NULL;
201  joinexpr->rtindex = joinrti;
202 
203  /* Make the new join be the sole entry in the query's jointree */
204  parse->jointree->fromlist = list_make1(joinexpr);
205  parse->jointree->quals = NULL;
206 }
@ CMD_MERGE
Definition: nodes.h:269
Node * quals
Definition: primnodes.h:1647
JoinType jointype
Definition: primnodes.h:1641
Alias * alias
Definition: primnodes.h:1648
int rtindex
Definition: primnodes.h:1649
List * usingClause
Definition: primnodes.h:1645
Alias * join_using_alias
Definition: primnodes.h:1646
Node * larg
Definition: primnodes.h:1643
bool isNatural
Definition: primnodes.h:1642
Node * rarg
Definition: primnodes.h:1644
Alias * join_using_alias
Definition: parsenodes.h:1090
List * joinrightcols
Definition: parsenodes.h:1083
Alias * alias
Definition: parsenodes.h:1151
List * joinleftcols
Definition: parsenodes.h:1082

References RangeTblEntry::alias, JoinExpr::alias, CMD_MERGE, RangeTblEntry::eref, RangeTblEntry::inFromCl, RangeTblEntry::inh, JoinExpr::isNatural, JOIN_INNER, JOIN_RIGHT, RangeTblEntry::join_using_alias, JoinExpr::join_using_alias, RangeTblEntry::joinaliasvars, RangeTblEntry::joinleftcols, RangeTblEntry::joinmergedcols, RangeTblEntry::joinrightcols, RangeTblEntry::jointype, JoinExpr::jointype, lappend(), JoinExpr::larg, RangeTblEntry::lateral, linitial, list_length(), list_make1, makeAlias(), makeNode, NIL, parse(), JoinExpr::quals, JoinExpr::rarg, RTE_JOIN, RangeTblEntry::rtekind, JoinExpr::rtindex, and JoinExpr::usingClause.

Referenced by subquery_planner().