PostgreSQL Source Code  git master
prepjointree.c File Reference
#include "postgres.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "optimizer/placeholder.h"
#include "optimizer/prep.h"
#include "optimizer/subselect.h"
#include "optimizer/tlist.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
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, Index 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 *nonnullable_vars, 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 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 3337 of file prepjointree.c.

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

3338 {
3340 
3341  /* If there are no PHVs anywhere, we needn't work hard */
3342  if (root->glob->lastPHId == 0)
3343  return false;
3344 
3345  context.relids = bms_make_singleton(varno);
3346  context.sublevels_up = 0;
3347 
3348  return query_tree_walker(root->parse,
3350  (void *) &context,
3351  0);
3352 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
Query * parse
Definition: pathnodes.h:161
static bool find_dependent_phvs_walker(Node *node, find_dependent_phvs_context *context)
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
PlannerGlobal * glob
Definition: pathnodes.h:163
Index lastPHId
Definition: pathnodes.h:115

◆ find_dependent_phvs_in_jointree()

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

Definition at line 3355 of file prepjointree.c.

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

3356 {
3358  Relids subrelids;
3359  int relid;
3360 
3361  /* If there are no PHVs anywhere, we needn't work hard */
3362  if (root->glob->lastPHId == 0)
3363  return false;
3364 
3365  context.relids = bms_make_singleton(varno);
3366  context.sublevels_up = 0;
3367 
3368  /*
3369  * See if the jointree fragment itself contains references (in join quals)
3370  */
3371  if (find_dependent_phvs_walker(node, &context))
3372  return true;
3373 
3374  /*
3375  * Otherwise, identify the set of referenced RTEs (we can ignore joins,
3376  * since they should be flattened already, so their join alias lists no
3377  * longer matter), and tediously check each RTE. We can ignore RTEs that
3378  * are not marked LATERAL, though, since they couldn't possibly contain
3379  * any cross-references to other RTEs.
3380  */
3381  subrelids = get_relids_in_jointree(node, false);
3382  relid = -1;
3383  while ((relid = bms_next_member(subrelids, relid)) >= 0)
3384  {
3385  RangeTblEntry *rte = rt_fetch(relid, root->parse->rtable);
3386 
3387  if (rte->lateral &&
3390  (void *) &context,
3391  0))
3392  return true;
3393  }
3394 
3395  return false;
3396 }
Query * parse
Definition: pathnodes.h:161
bool range_table_entry_walker(RangeTblEntry *rte, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2475
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
static bool find_dependent_phvs_walker(Node *node, find_dependent_phvs_context *context)
List * rtable
Definition: parsenodes.h:147
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
PlannerGlobal * glob
Definition: pathnodes.h:163
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Index lastPHId
Definition: pathnodes.h:115

◆ find_dependent_phvs_walker()

static bool find_dependent_phvs_walker ( Node node,
find_dependent_phvs_context context 
)
static

Definition at line 3300 of file prepjointree.c.

References Assert, bms_equal(), expression_tree_walker(), IsA, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, 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().

3302 {
3303  if (node == NULL)
3304  return false;
3305  if (IsA(node, PlaceHolderVar))
3306  {
3307  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3308 
3309  if (phv->phlevelsup == context->sublevels_up &&
3310  bms_equal(context->relids, phv->phrels))
3311  return true;
3312  /* fall through to examine children */
3313  }
3314  if (IsA(node, Query))
3315  {
3316  /* Recurse into subselects */
3317  bool result;
3318 
3319  context->sublevels_up++;
3320  result = query_tree_walker((Query *) node,
3322  (void *) context, 0);
3323  context->sublevels_up--;
3324  return result;
3325  }
3326  /* Shouldn't need to handle planner auxiliary nodes here */
3327  Assert(!IsA(node, SpecialJoinInfo));
3328  Assert(!IsA(node, AppendRelInfo));
3329  Assert(!IsA(node, PlaceHolderInfo));
3330  Assert(!IsA(node, MinMaxAggInfo));
3331 
3333  (void *) context);
3334 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static bool find_dependent_phvs_walker(Node *node, find_dependent_phvs_context *context)
#define Assert(condition)
Definition: c.h:804
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
Index phlevelsup
Definition: pathnodes.h:2173
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:94

◆ find_jointree_node_for_rel()

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

Definition at line 3590 of file prepjointree.c.

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

Referenced by get_relids_for_join().

3591 {
3592  if (jtnode == NULL)
3593  return NULL;
3594  if (IsA(jtnode, RangeTblRef))
3595  {
3596  int varno = ((RangeTblRef *) jtnode)->rtindex;
3597 
3598  if (relid == varno)
3599  return jtnode;
3600  }
3601  else if (IsA(jtnode, FromExpr))
3602  {
3603  FromExpr *f = (FromExpr *) jtnode;
3604  ListCell *l;
3605 
3606  foreach(l, f->fromlist)
3607  {
3608  jtnode = find_jointree_node_for_rel(lfirst(l), relid);
3609  if (jtnode)
3610  return jtnode;
3611  }
3612  }
3613  else if (IsA(jtnode, JoinExpr))
3614  {
3615  JoinExpr *j = (JoinExpr *) jtnode;
3616 
3617  if (relid == j->rtindex)
3618  return jtnode;
3619  jtnode = find_jointree_node_for_rel(j->larg, relid);
3620  if (jtnode)
3621  return jtnode;
3622  jtnode = find_jointree_node_for_rel(j->rarg, relid);
3623  if (jtnode)
3624  return jtnode;
3625  }
3626  else
3627  elog(ERROR, "unrecognized node type: %d",
3628  (int) nodeTag(jtnode));
3629  return NULL;
3630 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * fromlist
Definition: primnodes.h:1553
Node * larg
Definition: primnodes.h:1532
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:46
Node * rarg
Definition: primnodes.h:1533
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
int rtindex
Definition: primnodes.h:1538

◆ fix_append_rel_relids()

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

Definition at line 3491 of file prepjointree.c.

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

3492 {
3493  ListCell *l;
3494  int subvarno = -1;
3495 
3496  /*
3497  * We only want to extract the member relid once, but we mustn't fail
3498  * immediately if there are multiple members; it could be that none of the
3499  * AppendRelInfo nodes refer to it. So compute it on first use. Note that
3500  * bms_singleton_member will complain if set is not singleton.
3501  */
3502  foreach(l, append_rel_list)
3503  {
3504  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
3505 
3506  /* The parent_relid shouldn't ever be a pullup target */
3507  Assert(appinfo->parent_relid != varno);
3508 
3509  if (appinfo->child_relid == varno)
3510  {
3511  if (subvarno < 0)
3512  subvarno = bms_singleton_member(subrelids);
3513  appinfo->child_relid = subvarno;
3514  }
3515 
3516  /* Also fix up any PHVs in its translated vars */
3518  varno, subrelids);
3519  }
3520 }
static void substitute_phv_relids(Node *node, int varno, Relids subrelids)
Definition: nodes.h:539
List * translated_vars
Definition: pathnodes.h:2323
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:577
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Index child_relid
Definition: pathnodes.h:2296
Index parent_relid
Definition: pathnodes.h:2295

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2456 of file prepjointree.c.

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

Referenced by subquery_planner().

2457 {
2458  Query *parse = root->parse;
2459  SetOperationStmt *topop;
2460  Node *leftmostjtnode;
2461  int leftmostRTI;
2462  RangeTblEntry *leftmostRTE;
2463  int childRTI;
2464  RangeTblEntry *childRTE;
2465  RangeTblRef *rtr;
2466 
2467  /* Shouldn't be called unless query has setops */
2468  topop = castNode(SetOperationStmt, parse->setOperations);
2469  Assert(topop);
2470 
2471  /* Can't optimize away a recursive UNION */
2472  if (root->hasRecursion)
2473  return;
2474 
2475  /*
2476  * Recursively check the tree of set operations. If not all UNION ALL
2477  * with identical column types, punt.
2478  */
2479  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2480  return;
2481 
2482  /*
2483  * Locate the leftmost leaf query in the setops tree. The upper query's
2484  * Vars all refer to this RTE (see transformSetOperationStmt).
2485  */
2486  leftmostjtnode = topop->larg;
2487  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2488  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2489  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2490  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2491  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2492  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2493 
2494  /*
2495  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2496  * will represent the leftmost leaf query in its capacity as a member of
2497  * the appendrel. The original will represent the appendrel as a whole.
2498  * (We must do things this way because the upper query's Vars have to be
2499  * seen as referring to the whole appendrel.)
2500  */
2501  childRTE = copyObject(leftmostRTE);
2502  parse->rtable = lappend(parse->rtable, childRTE);
2503  childRTI = list_length(parse->rtable);
2504 
2505  /* Modify the setops tree to reference the child copy */
2506  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2507 
2508  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2509  leftmostRTE->inh = true;
2510 
2511  /*
2512  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2513  * Query of a setops tree should have had an empty FromClause initially.
2514  */
2515  rtr = makeNode(RangeTblRef);
2516  rtr->rtindex = leftmostRTI;
2517  Assert(parse->jointree->fromlist == NIL);
2518  parse->jointree->fromlist = list_make1(rtr);
2519 
2520  /*
2521  * Now pretend the query has no setops. We must do this before trying to
2522  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2523  */
2524  parse->setOperations = NULL;
2525 
2526  /*
2527  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2528  * leaf queries of the UNION ALL. (We must do that now because they
2529  * weren't previously referenced by the jointree, and so were missed by
2530  * the main invocation of pull_up_subqueries.)
2531  */
2532  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2533 }
#define NIL
Definition: pg_list.h:65
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Definition: nodes.h:539
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * fromlist
Definition: primnodes.h:1553
bool hasRecursion
Definition: pathnodes.h:351
#define list_make1(x1)
Definition: pg_list.h:206
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
Node * setOperations
Definition: parsenodes.h:177
#define copyObject(obj)
Definition: nodes.h:655
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665

◆ get_relids_for_join()

Relids get_relids_for_join ( Query query,
int  joinrelid 
)

Definition at line 3573 of file prepjointree.c.

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

Referenced by alias_relid_set().

3574 {
3575  Node *jtnode;
3576 
3577  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3578  joinrelid);
3579  if (!jtnode)
3580  elog(ERROR, "could not find join node %d", joinrelid);
3581  return get_relids_in_jointree(jtnode, false);
3582 }
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:46
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define elog(elevel,...)
Definition: elog.h:232

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 3529 of file prepjointree.c.

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

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

3530 {
3531  Relids result = NULL;
3532 
3533  if (jtnode == NULL)
3534  return result;
3535  if (IsA(jtnode, RangeTblRef))
3536  {
3537  int varno = ((RangeTblRef *) jtnode)->rtindex;
3538 
3539  result = bms_make_singleton(varno);
3540  }
3541  else if (IsA(jtnode, FromExpr))
3542  {
3543  FromExpr *f = (FromExpr *) jtnode;
3544  ListCell *l;
3545 
3546  foreach(l, f->fromlist)
3547  {
3548  result = bms_join(result,
3550  include_joins));
3551  }
3552  }
3553  else if (IsA(jtnode, JoinExpr))
3554  {
3555  JoinExpr *j = (JoinExpr *) jtnode;
3556 
3557  result = get_relids_in_jointree(j->larg, include_joins);
3558  result = bms_join(result,
3559  get_relids_in_jointree(j->rarg, include_joins));
3560  if (include_joins && j->rtindex)
3561  result = bms_add_member(result, j->rtindex);
3562  }
3563  else
3564  elog(ERROR, "unrecognized node type: %d",
3565  (int) nodeTag(jtnode));
3566  return result;
3567 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * fromlist
Definition: primnodes.h:1553
Node * larg
Definition: primnodes.h:1532
#define ERROR
Definition: elog.h:46
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:949
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
Node * rarg
Definition: primnodes.h:1533
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
int rtindex
Definition: primnodes.h:1538

◆ get_result_relid()

static int get_result_relid ( PlannerInfo root,
Node jtnode 
)
static

Definition at line 3231 of file prepjointree.c.

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

Referenced by remove_useless_results_recurse().

3232 {
3233  int varno;
3234 
3235  if (!IsA(jtnode, RangeTblRef))
3236  return 0;
3237  varno = ((RangeTblRef *) jtnode)->rtindex;
3238  if (rt_fetch(varno, root->parse->rtable)->rtekind != RTE_RESULT)
3239  return 0;
3240  return varno;
3241 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31

◆ is_safe_append_member()

static bool is_safe_append_member ( Query subquery)
static

Definition at line 1892 of file prepjointree.c.

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

1893 {
1894  FromExpr *jtnode;
1895 
1896  /*
1897  * It's only safe to pull up the child if its jointree contains exactly
1898  * one RTE, else the AppendRelInfo data structure breaks. The one base RTE
1899  * could be buried in several levels of FromExpr, however. Also, if the
1900  * child's jointree is completely empty, we can pull up because
1901  * pull_up_simple_subquery will insert a single RTE_RESULT RTE instead.
1902  *
1903  * Also, the child can't have any WHERE quals because there's no place to
1904  * put them in an appendrel. (This is a bit annoying...) If we didn't
1905  * need to check this, we'd just test whether get_relids_in_jointree()
1906  * yields a singleton set, to be more consistent with the coding of
1907  * fix_append_rel_relids().
1908  */
1909  jtnode = subquery->jointree;
1910  Assert(IsA(jtnode, FromExpr));
1911  /* Check the completely-empty case */
1912  if (jtnode->fromlist == NIL && jtnode->quals == NULL)
1913  return true;
1914  /* Check the more general case */
1915  while (IsA(jtnode, FromExpr))
1916  {
1917  if (jtnode->quals != NULL)
1918  return false;
1919  if (list_length(jtnode->fromlist) != 1)
1920  return false;
1921  jtnode = linitial(jtnode->fromlist);
1922  }
1923  if (!IsA(jtnode, RangeTblRef))
1924  return false;
1925 
1926  return true;
1927 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
FromExpr * jointree
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1553
Node * quals
Definition: primnodes.h:1554
#define linitial(l)
Definition: pg_list.h:174
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149

◆ is_simple_subquery()

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

Definition at line 1406 of file prepjointree.c.

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

1408 {
1409  /*
1410  * Let's just make sure it's a valid subselect ...
1411  */
1412  if (!IsA(subquery, Query) ||
1413  subquery->commandType != CMD_SELECT)
1414  elog(ERROR, "subquery is bogus");
1415 
1416  /*
1417  * Can't currently pull up a query with setops (unless it's simple UNION
1418  * ALL, which is handled by a different code path). Maybe after querytree
1419  * redesign...
1420  */
1421  if (subquery->setOperations)
1422  return false;
1423 
1424  /*
1425  * Can't pull up a subquery involving grouping, aggregation, SRFs,
1426  * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later)
1427  *
1428  * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE
1429  * clauses, because pullup would cause the locking to occur semantically
1430  * higher than it should. Implicit FOR UPDATE/SHARE is okay because in
1431  * that case the locking was originally declared in the upper query
1432  * anyway.
1433  */
1434  if (subquery->hasAggs ||
1435  subquery->hasWindowFuncs ||
1436  subquery->hasTargetSRFs ||
1437  subquery->groupClause ||
1438  subquery->groupingSets ||
1439  subquery->havingQual ||
1440  subquery->sortClause ||
1441  subquery->distinctClause ||
1442  subquery->limitOffset ||
1443  subquery->limitCount ||
1444  subquery->hasForUpdate ||
1445  subquery->cteList)
1446  return false;
1447 
1448  /*
1449  * Don't pull up if the RTE represents a security-barrier view; we
1450  * couldn't prevent information leakage once the RTE's Vars are scattered
1451  * about in the upper query.
1452  */
1453  if (rte->security_barrier)
1454  return false;
1455 
1456  /*
1457  * If the subquery is LATERAL, check for pullup restrictions from that.
1458  */
1459  if (rte->lateral)
1460  {
1461  bool restricted;
1462  Relids safe_upper_varnos;
1463 
1464  /*
1465  * The subquery's WHERE and JOIN/ON quals mustn't contain any lateral
1466  * references to rels outside a higher outer join (including the case
1467  * where the outer join is within the subquery itself). In such a
1468  * case, pulling up would result in a situation where we need to
1469  * postpone quals from below an outer join to above it, which is
1470  * probably completely wrong and in any case is a complication that
1471  * doesn't seem worth addressing at the moment.
1472  */
1473  if (lowest_outer_join != NULL)
1474  {
1475  restricted = true;
1476  safe_upper_varnos = get_relids_in_jointree((Node *) lowest_outer_join,
1477  true);
1478  }
1479  else
1480  {
1481  restricted = false;
1482  safe_upper_varnos = NULL; /* doesn't matter */
1483  }
1484 
1486  (Node *) subquery->jointree,
1487  restricted, safe_upper_varnos))
1488  return false;
1489 
1490  /*
1491  * If there's an outer join above the LATERAL subquery, also disallow
1492  * pullup if the subquery's targetlist has any references to rels
1493  * outside the outer join, since these might get pulled into quals
1494  * above the subquery (but in or below the outer join) and then lead
1495  * to qual-postponement issues similar to the case checked for above.
1496  * (We wouldn't need to prevent pullup if no such references appear in
1497  * outer-query quals, but we don't have enough info here to check
1498  * that. Also, maybe this restriction could be removed if we forced
1499  * such refs to be wrapped in PlaceHolderVars, even when they're below
1500  * the nearest outer join? But it's a pretty hokey usage, so not
1501  * clear this is worth sweating over.)
1502  */
1503  if (lowest_outer_join != NULL)
1504  {
1505  Relids lvarnos = pull_varnos_of_level(root,
1506  (Node *) subquery->targetList,
1507  1);
1508 
1509  if (!bms_is_subset(lvarnos, safe_upper_varnos))
1510  return false;
1511  }
1512  }
1513 
1514  /*
1515  * Don't pull up a subquery that has any volatile functions in its
1516  * targetlist. Otherwise we might introduce multiple evaluations of these
1517  * functions, if they get copied to multiple places in the upper query,
1518  * leading to surprising results. (Note: the PlaceHolderVar mechanism
1519  * doesn't quite guarantee single evaluation; else we could pull up anyway
1520  * and just wrap such items in PlaceHolderVars ...)
1521  */
1522  if (contain_volatile_functions((Node *) subquery->targetList))
1523  return false;
1524 
1525  return true;
1526 }
Node * limitOffset
Definition: parsenodes.h:171
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * sortClause
Definition: parsenodes.h:169
FromExpr * jointree
Definition: parsenodes.h:148
bool hasAggs
Definition: parsenodes.h:133
List * groupingSets
Definition: parsenodes.h:161
Definition: nodes.h:539
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
List * targetList
Definition: parsenodes.h:150
List * distinctClause
Definition: parsenodes.h:167
#define ERROR
Definition: elog.h:46
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
Node * limitCount
Definition: parsenodes.h:172
bool security_barrier
Definition: parsenodes.h:1031
CmdType commandType
Definition: parsenodes.h:120
bool hasTargetSRFs
Definition: parsenodes.h:135
bool hasWindowFuncs
Definition: parsenodes.h:134
List * cteList
Definition: parsenodes.h:145
Node * setOperations
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:158
#define elog(elevel,...)
Definition: elog.h:232
bool hasForUpdate
Definition: parsenodes.h:140
static bool jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode, bool restricted, Relids safe_upper_varnos)
Node * havingQual
Definition: parsenodes.h:163
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition: var.c:123

◆ is_simple_union_all()

static bool is_simple_union_all ( Query subquery)
static

Definition at line 1824 of file prepjointree.c.

References castNode, CMD_SELECT, 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().

1825 {
1826  SetOperationStmt *topop;
1827 
1828  /* Let's just make sure it's a valid subselect ... */
1829  if (!IsA(subquery, Query) ||
1830  subquery->commandType != CMD_SELECT)
1831  elog(ERROR, "subquery is bogus");
1832 
1833  /* Is it a set-operation query at all? */
1834  topop = castNode(SetOperationStmt, subquery->setOperations);
1835  if (!topop)
1836  return false;
1837 
1838  /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
1839  if (subquery->sortClause ||
1840  subquery->limitOffset ||
1841  subquery->limitCount ||
1842  subquery->rowMarks ||
1843  subquery->cteList)
1844  return false;
1845 
1846  /* Recursively check the tree of set operations */
1847  return is_simple_union_all_recurse((Node *) topop, subquery,
1848  topop->colTypes);
1849 }
Node * limitOffset
Definition: parsenodes.h:171
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * sortClause
Definition: parsenodes.h:169
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Definition: nodes.h:539
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * rowMarks
Definition: parsenodes.h:175
#define ERROR
Definition: elog.h:46
Node * limitCount
Definition: parsenodes.h:172
CmdType commandType
Definition: parsenodes.h:120
List * cteList
Definition: parsenodes.h:145
Node * setOperations
Definition: parsenodes.h:177
#define elog(elevel,...)
Definition: elog.h:232

◆ is_simple_union_all_recurse()

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

Definition at line 1852 of file prepjointree.c.

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

Referenced by flatten_simple_union_all(), and is_simple_union_all().

1853 {
1854  if (IsA(setOp, RangeTblRef))
1855  {
1856  RangeTblRef *rtr = (RangeTblRef *) setOp;
1857  RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
1858  Query *subquery = rte->subquery;
1859 
1860  Assert(subquery != NULL);
1861 
1862  /* Leaf nodes are OK if they match the toplevel column types */
1863  /* We don't have to compare typmods or collations here */
1864  return tlist_same_datatypes(subquery->targetList, colTypes, true);
1865  }
1866  else if (IsA(setOp, SetOperationStmt))
1867  {
1868  SetOperationStmt *op = (SetOperationStmt *) setOp;
1869 
1870  /* Must be UNION ALL */
1871  if (op->op != SETOP_UNION || !op->all)
1872  return false;
1873 
1874  /* Recurse to check inputs */
1875  return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
1876  is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
1877  }
1878  else
1879  {
1880  elog(ERROR, "unrecognized node type: %d",
1881  (int) nodeTag(setOp));
1882  return false; /* keep compiler quiet */
1883  }
1884 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition: tlist.c:237
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define Assert(condition)
Definition: c.h:804
SetOperation op
Definition: parsenodes.h:1711
#define nodeTag(nodeptr)
Definition: nodes.h:544
Query * subquery
Definition: parsenodes.h:1030
#define elog(elevel,...)
Definition: elog.h:232

◆ is_simple_values()

static bool is_simple_values ( PlannerInfo root,
RangeTblEntry rte 
)
static

Definition at line 1639 of file prepjointree.c.

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

Referenced by pull_up_subqueries_recurse().

1640 {
1641  Assert(rte->rtekind == RTE_VALUES);
1642 
1643  /*
1644  * There must be exactly one VALUES list, else it's not semantically
1645  * correct to replace the VALUES RTE with a RESULT RTE, nor would we have
1646  * a unique set of expressions to substitute into the parent query.
1647  */
1648  if (list_length(rte->values_lists) != 1)
1649  return false;
1650 
1651  /*
1652  * Because VALUES can't appear under an outer join (or at least, we won't
1653  * try to pull it up if it does), we need not worry about LATERAL, nor
1654  * about validity of PHVs for the VALUES' outputs.
1655  */
1656 
1657  /*
1658  * Don't pull up a VALUES that contains any set-returning or volatile
1659  * functions. The considerations here are basically identical to the
1660  * restrictions on a pull-able subquery's targetlist.
1661  */
1662  if (expression_returns_set((Node *) rte->values_lists) ||
1664  return false;
1665 
1666  /*
1667  * Do not pull up a VALUES that's not the only RTE in its parent query.
1668  * This is actually the only case that the parser will generate at the
1669  * moment, and assuming this is true greatly simplifies
1670  * pull_up_simple_values().
1671  */
1672  if (list_length(root->parse->rtable) != 1 ||
1673  rte != (RangeTblEntry *) linitial(root->parse->rtable))
1674  return false;
1675 
1676  return true;
1677 }
Query * parse
Definition: pathnodes.h:161
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:709
Definition: nodes.h:539
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
List * values_lists
Definition: parsenodes.h:1100
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995

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

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

Referenced by is_simple_subquery().

1943 {
1944  if (jtnode == NULL)
1945  return false;
1946  if (IsA(jtnode, RangeTblRef))
1947  return false;
1948  else if (IsA(jtnode, FromExpr))
1949  {
1950  FromExpr *f = (FromExpr *) jtnode;
1951  ListCell *l;
1952 
1953  /* First, recurse to check child joins */
1954  foreach(l, f->fromlist)
1955  {
1957  lfirst(l),
1958  restricted,
1959  safe_upper_varnos))
1960  return true;
1961  }
1962 
1963  /* Then check the top-level quals */
1964  if (restricted &&
1966  safe_upper_varnos))
1967  return true;
1968  }
1969  else if (IsA(jtnode, JoinExpr))
1970  {
1971  JoinExpr *j = (JoinExpr *) jtnode;
1972 
1973  /*
1974  * If this is an outer join, we mustn't allow any upper lateral
1975  * references in or below it.
1976  */
1977  if (j->jointype != JOIN_INNER)
1978  {
1979  restricted = true;
1980  safe_upper_varnos = NULL;
1981  }
1982 
1983  /* Check the child joins */
1985  j->larg,
1986  restricted,
1987  safe_upper_varnos))
1988  return true;
1990  j->rarg,
1991  restricted,
1992  safe_upper_varnos))
1993  return true;
1994 
1995  /* Check the JOIN's qual clauses */
1996  if (restricted &&
1998  safe_upper_varnos))
1999  return true;
2000  }
2001  else
2002  elog(ERROR, "unrecognized node type: %d",
2003  (int) nodeTag(jtnode));
2004  return false;
2005 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * fromlist
Definition: primnodes.h:1553
Node * quals
Definition: primnodes.h:1554
Node * larg
Definition: primnodes.h:1532
#define ERROR
Definition: elog.h:46
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Node * quals
Definition: primnodes.h:1536
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
static bool jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode, bool restricted, Relids safe_upper_varnos)
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition: var.c:123

◆ make_setop_translation_list()

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

Definition at line 1368 of file prepjointree.c.

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

Referenced by pull_up_union_leaf_queries().

1370 {
1371  List *vars = NIL;
1372  AttrNumber *pcolnos;
1373  ListCell *l;
1374 
1375  /* Initialize reverse-translation array with all entries zero */
1376  /* (entries for resjunk columns will stay that way) */
1377  appinfo->num_child_cols = list_length(query->targetList);
1378  appinfo->parent_colnos = pcolnos =
1379  (AttrNumber *) palloc0(appinfo->num_child_cols * sizeof(AttrNumber));
1380 
1381  foreach(l, query->targetList)
1382  {
1383  TargetEntry *tle = (TargetEntry *) lfirst(l);
1384 
1385  if (tle->resjunk)
1386  continue;
1387 
1388  vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1389  pcolnos[tle->resno - 1] = tle->resno;
1390  }
1391 
1392  appinfo->translated_vars = vars;
1393 }
#define NIL
Definition: pg_list.h:65
int num_child_cols
Definition: pathnodes.h:2331
AttrNumber * parent_colnos
Definition: pathnodes.h:2332
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:103
List * translated_vars
Definition: pathnodes.h:2323
List * targetList
Definition: parsenodes.h:150
bool resjunk
Definition: primnodes.h:1451
AttrNumber resno
Definition: primnodes.h:1445
List * lappend(List *list, void *datum)
Definition: list.c:336
void * palloc0(Size size)
Definition: mcxt.c:1093
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Definition: regcomp.c:237
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

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

References PlannerInfo::append_rel_list, Assert, Query::havingQual, RangeTblEntry::joinaliasvars, Query::jointree, lfirst, pullup_replace_vars_context::need_phvs, Query::onConflict, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, parse(), PlannerInfo::parse, pullup_replace_vars(), replace_vars_in_jointree(), Query::returningList, Query::rtable, RTE_JOIN, RangeTblEntry::rtekind, Query::setOperations, Query::targetList, and AppendRelInfo::translated_vars.

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

2020 {
2021  Query *parse = root->parse;
2022  ListCell *lc;
2023 
2024  /*
2025  * Replace all of the top query's references to the subquery's outputs
2026  * with copies of the adjusted subtlist items, being careful not to
2027  * replace any of the jointree structure. (This'd be a lot cleaner if we
2028  * could use query_tree_mutator.) We have to use PHVs in the targetList,
2029  * returningList, and havingQual, since those are certainly above any
2030  * outer join. replace_vars_in_jointree tracks its location in the
2031  * jointree and uses PHVs or not appropriately.
2032  */
2033  parse->targetList = (List *)
2034  pullup_replace_vars((Node *) parse->targetList, rvcontext);
2035  parse->returningList = (List *)
2036  pullup_replace_vars((Node *) parse->returningList, rvcontext);
2037  if (parse->onConflict)
2038  {
2039  parse->onConflict->onConflictSet = (List *)
2041  rvcontext);
2042  parse->onConflict->onConflictWhere =
2044  rvcontext);
2045 
2046  /*
2047  * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
2048  * can't contain any references to a subquery.
2049  */
2050  }
2051  replace_vars_in_jointree((Node *) parse->jointree, rvcontext,
2052  lowest_nulling_outer_join);
2053  Assert(parse->setOperations == NULL);
2054  parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
2055 
2056  /*
2057  * Replace references in the translated_vars lists of appendrels. When
2058  * pulling up an appendrel member, we do not need PHVs in the list of the
2059  * parent appendrel --- there isn't any outer join between. Elsewhere,
2060  * use PHVs for safety. (This analysis could be made tighter but it seems
2061  * unlikely to be worth much trouble.)
2062  */
2063  foreach(lc, root->append_rel_list)
2064  {
2065  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
2066  bool save_need_phvs = rvcontext->need_phvs;
2067 
2068  if (appinfo == containing_appendrel)
2069  rvcontext->need_phvs = false;
2070  appinfo->translated_vars = (List *)
2071  pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
2072  rvcontext->need_phvs = save_need_phvs;
2073  }
2074 
2075  /*
2076  * Replace references in the joinaliasvars lists of join RTEs.
2077  *
2078  * You might think that we could avoid using PHVs for alias vars of joins
2079  * below lowest_nulling_outer_join, but that doesn't work because the
2080  * alias vars could be referenced above that join; we need the PHVs to be
2081  * present in such references after the alias vars get flattened. (It
2082  * might be worth trying to be smarter here, someday.)
2083  */
2084  foreach(lc, parse->rtable)
2085  {
2086  RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
2087 
2088  if (otherrte->rtekind == RTE_JOIN)
2089  otherrte->joinaliasvars = (List *)
2090  pullup_replace_vars((Node *) otherrte->joinaliasvars,
2091  rvcontext);
2092  }
2093 }
Query * parse
Definition: pathnodes.h:161
List * joinaliasvars
Definition: parsenodes.h:1070
FromExpr * jointree
Definition: parsenodes.h:148
OnConflictExpr * onConflict
Definition: parsenodes.h:154
Definition: nodes.h:539
List * translated_vars
Definition: pathnodes.h:2323
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
List * returningList
Definition: parsenodes.h:156
List * append_rel_list
Definition: pathnodes.h:283
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:995
Node * setOperations
Definition: parsenodes.h:177
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
List * onConflictSet
Definition: primnodes.h:1578
Node * havingQual
Definition: parsenodes.h:163
Node * onConflictWhere
Definition: primnodes.h:1579
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
Definition: pg_list.h:50
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 639 of file prepjointree.c.

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

640 {
641  ListCell *rt;
642 
643  foreach(rt, root->parse->rtable)
644  {
645  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
646 
647  if (rte->rtekind == RTE_FUNCTION)
648  {
649  Query *funcquery;
650 
651  /* Apply const-simplification */
652  rte->functions = (List *)
653  eval_const_expressions(root, (Node *) rte->functions);
654 
655  /* Check safety of expansion, and expand if possible */
656  funcquery = inline_set_returning_function(root, rte);
657  if (funcquery)
658  {
659  /* Successful expansion, convert the RTE to a subquery */
660  rte->rtekind = RTE_SUBQUERY;
661  rte->subquery = funcquery;
662  rte->security_barrier = false;
663  /* Clear fields that should not be set in a subquery RTE */
664  rte->functions = NIL;
665  rte->funcordinality = false;
666  }
667  }
668  }
669 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:161
Definition: nodes.h:539
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4772
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2090
bool funcordinality
Definition: parsenodes.h:1090
List * rtable
Definition: parsenodes.h:147
bool security_barrier
Definition: parsenodes.h:1031
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1089
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
Definition: pg_list.h:50

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

References RangeTblFunction::funccolcount, RangeTblFunction::funcexpr, RangeTblEntry::funcordinality, RangeTblEntry::functions, get_expr_result_type(), Query::groupingSets, Query::hasSubLinks, IsA, 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().

1702 {
1703  Query *parse = root->parse;
1704  RangeTblFunction *rtf;
1705  TypeFuncClass functypclass;
1706  Oid funcrettype;
1707  TupleDesc tupdesc;
1708  pullup_replace_vars_context rvcontext;
1709 
1710  /* Fail if the RTE has ORDINALITY - we don't implement that here. */
1711  if (rte->funcordinality)
1712  return jtnode;
1713 
1714  /* Fail if RTE isn't a single, simple Const expr */
1715  if (list_length(rte->functions) != 1)
1716  return jtnode;
1718  if (!IsA(rtf->funcexpr, Const))
1719  return jtnode;
1720 
1721  /*
1722  * If the function's result is not a scalar, we punt. In principle we
1723  * could break the composite constant value apart into per-column
1724  * constants, but for now it seems not worth the work.
1725  */
1726  if (rtf->funccolcount != 1)
1727  return jtnode; /* definitely composite */
1728 
1729  functypclass = get_expr_result_type(rtf->funcexpr,
1730  &funcrettype,
1731  &tupdesc);
1732  if (functypclass != TYPEFUNC_SCALAR)
1733  return jtnode; /* must be a one-column composite type */
1734 
1735  /* Create context for applying pullup_replace_vars */
1736  rvcontext.root = root;
1737  rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr,
1738  1, /* resno */
1739  NULL, /* resname */
1740  false)); /* resjunk */
1741  rvcontext.target_rte = rte;
1742 
1743  /*
1744  * Since this function was reduced to a Const, it doesn't contain any
1745  * lateral references, even if it's marked as LATERAL. This means we
1746  * don't need to fill relids.
1747  */
1748  rvcontext.relids = NULL;
1749 
1750  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1751  rvcontext.varno = ((RangeTblRef *) jtnode)->rtindex;
1752  /* these flags will be set below, if needed */
1753  rvcontext.need_phvs = false;
1754  rvcontext.wrap_non_vars = false;
1755  /* initialize cache array with indexes 0 .. length(tlist) */
1756  rvcontext.rv_cache = palloc0((list_length(rvcontext.targetlist) + 1) *
1757  sizeof(Node *));
1758 
1759  /*
1760  * If we are under an outer join then non-nullable items and lateral
1761  * references may have to be turned into PlaceHolderVars.
1762  */
1763  if (lowest_nulling_outer_join != NULL)
1764  rvcontext.need_phvs = true;
1765 
1766  /*
1767  * If we are dealing with an appendrel member then anything that's not a
1768  * simple Var has to be turned into a PlaceHolderVar. (See comments in
1769  * pull_up_simple_subquery().)
1770  */
1771  if (containing_appendrel != NULL)
1772  {
1773  rvcontext.need_phvs = true;
1774  rvcontext.wrap_non_vars = true;
1775  }
1776 
1777  /*
1778  * If the parent query uses grouping sets, we need a PlaceHolderVar for
1779  * anything that's not a simple Var.
1780  */
1781  if (parse->groupingSets)
1782  {
1783  rvcontext.need_phvs = true;
1784  rvcontext.wrap_non_vars = true;
1785  }
1786 
1787  /*
1788  * Replace all of the top query's references to the RTE's output with
1789  * copies of the funcexpr, being careful not to replace any of the
1790  * jointree structure.
1791  */
1792  perform_pullup_replace_vars(root, &rvcontext,
1793  lowest_nulling_outer_join,
1794  containing_appendrel);
1795 
1796  /*
1797  * We don't need to bother with changing PlaceHolderVars in the parent
1798  * query. Their references to the RT index are still good for now, and
1799  * will get removed later if we're able to drop the RTE_RESULT.
1800  */
1801 
1802  /*
1803  * Convert the RTE to be RTE_RESULT type, signifying that we don't need to
1804  * scan it anymore, and zero out RTE_FUNCTION-specific fields.
1805  */
1806  rte->rtekind = RTE_RESULT;
1807  rte->functions = NIL;
1808 
1809  /*
1810  * We can reuse the RangeTblRef node.
1811  */
1812  return jtnode;
1813 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
List * groupingSets
Definition: parsenodes.h:161
Definition: nodes.h:539
bool funcordinality
Definition: parsenodes.h:1090
unsigned int Oid
Definition: postgres_ext.h:31
#define linitial_node(type, l)
Definition: pg_list.h:177
TypeFuncClass get_expr_result_type(Node *expr, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:223
#define list_make1(x1)
Definition: pg_list.h:206
RangeTblEntry * target_rte
Definition: prepjointree.c:47
TypeFuncClass
Definition: funcapi.h:146
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
void * palloc0(Size size)
Definition: mcxt.c:1093
static void perform_pullup_replace_vars(PlannerInfo *root, pullup_replace_vars_context *rvcontext, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
List * functions
Definition: parsenodes.h:1089
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
bool hasSubLinks
Definition: parsenodes.h:136
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665

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

References PlannerInfo::all_result_relids, PlannerInfo::append_rel_list, Assert, copyObject, PlannerInfo::cte_plan_ids, Query::cteList, CurrentMemoryContext, PlannerInfo::ec_merging_done, PlannerInfo::eq_classes, fix_append_rel_relids(), flatten_join_alias_vars(), get_relids_in_jointree(), PlannerInfo::glob, PlannerInfo::grouping_map, Query::groupingSets, PlannerInfo::hasRecursion, Query::hasRowSecurity, Query::hasSubLinks, IncrementVarSublevelsUp(), PlannerInfo::init_plans, is_safe_append_member(), is_simple_subquery(), IsA, PlannerInfo::join_info_list, 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(), PlannerInfo::parent_root, parse(), PlannerInfo::parse, perform_pullup_replace_vars(), PlannerInfo::placeholder_list, PlannerInfo::plan_params, PlannerInfo::planner_cxt, preprocess_function_rtes(), PlannerInfo::processed_tlist, pull_up_sublinks(), pull_up_subqueries(), PlannerInfo::qual_security_level, 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, 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, PlannerInfo::upper_rels, PlannerInfo::upper_targets, pullup_replace_vars_context::varno, pullup_replace_vars_context::wrap_non_vars, and PlannerInfo::wt_param_id.

Referenced by pull_up_subqueries_recurse().

886 {
887  Query *parse = root->parse;
888  int varno = ((RangeTblRef *) jtnode)->rtindex;
889  Query *subquery;
890  PlannerInfo *subroot;
891  int rtoffset;
892  pullup_replace_vars_context rvcontext;
893  ListCell *lc;
894 
895  /*
896  * Need a modifiable copy of the subquery to hack on. Even if we didn't
897  * sometimes choose not to pull up below, we must do this to avoid
898  * problems if the same subquery is referenced from multiple jointree
899  * items (which can't happen normally, but might after rule rewriting).
900  */
901  subquery = copyObject(rte->subquery);
902 
903  /*
904  * Create a PlannerInfo data structure for this subquery.
905  *
906  * NOTE: the next few steps should match the first processing in
907  * subquery_planner(). Can we refactor to avoid code duplication, or
908  * would that just make things uglier?
909  */
910  subroot = makeNode(PlannerInfo);
911  subroot->parse = subquery;
912  subroot->glob = root->glob;
913  subroot->query_level = root->query_level;
914  subroot->parent_root = root->parent_root;
915  subroot->plan_params = NIL;
916  subroot->outer_params = NULL;
918  subroot->init_plans = NIL;
919  subroot->cte_plan_ids = NIL;
920  subroot->multiexpr_params = NIL;
921  subroot->eq_classes = NIL;
922  subroot->ec_merging_done = false;
923  subroot->all_result_relids = NULL;
924  subroot->leaf_result_relids = NULL;
925  subroot->append_rel_list = NIL;
926  subroot->row_identity_vars = NIL;
927  subroot->rowMarks = NIL;
928  memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels));
929  memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets));
930  subroot->processed_tlist = NIL;
931  subroot->update_colnos = NIL;
932  subroot->grouping_map = NULL;
933  subroot->minmax_aggs = NIL;
934  subroot->qual_security_level = 0;
935  subroot->hasRecursion = false;
936  subroot->wt_param_id = -1;
937  subroot->non_recursive_path = NULL;
938 
939  /* No CTEs to worry about */
940  Assert(subquery->cteList == NIL);
941 
942  /*
943  * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
944  * that we don't need so many special cases to deal with that situation.
945  */
946  replace_empty_jointree(subquery);
947 
948  /*
949  * Pull up any SubLinks within the subquery's quals, so that we don't
950  * leave unoptimized SubLinks behind.
951  */
952  if (subquery->hasSubLinks)
953  pull_up_sublinks(subroot);
954 
955  /*
956  * Similarly, preprocess its function RTEs to inline any set-returning
957  * functions in its rangetable.
958  */
959  preprocess_function_rtes(subroot);
960 
961  /*
962  * Recursively pull up the subquery's subqueries, so that
963  * pull_up_subqueries' processing is complete for its jointree and
964  * rangetable.
965  *
966  * Note: it's okay that the subquery's recursion starts with NULL for
967  * containing-join info, even if we are within an outer join in the upper
968  * query; the lower query starts with a clean slate for outer-join
969  * semantics. Likewise, we needn't pass down appendrel state.
970  */
971  pull_up_subqueries(subroot);
972 
973  /*
974  * Now we must recheck whether the subquery is still simple enough to pull
975  * up. If not, abandon processing it.
976  *
977  * We don't really need to recheck all the conditions involved, but it's
978  * easier just to keep this "if" looking the same as the one in
979  * pull_up_subqueries_recurse.
980  */
981  if (is_simple_subquery(root, subquery, rte, lowest_outer_join) &&
982  (containing_appendrel == NULL || is_safe_append_member(subquery)))
983  {
984  /* good to go */
985  }
986  else
987  {
988  /*
989  * Give up, return unmodified RangeTblRef.
990  *
991  * Note: The work we just did will be redone when the subquery gets
992  * planned on its own. Perhaps we could avoid that by storing the
993  * modified subquery back into the rangetable, but I'm not gonna risk
994  * it now.
995  */
996  return jtnode;
997  }
998 
999  /*
1000  * We must flatten any join alias Vars in the subquery's targetlist,
1001  * because pulling up the subquery's subqueries might have changed their
1002  * expansions into arbitrary expressions, which could affect
1003  * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
1004  * are needed for tlist entries. (Likely it'd be better to do
1005  * flatten_join_alias_vars on the whole query tree at some earlier stage,
1006  * maybe even in the rewriter; but for now let's just fix this case here.)
1007  */
1008  subquery->targetList = (List *)
1009  flatten_join_alias_vars(subroot->parse, (Node *) subquery->targetList);
1010 
1011  /*
1012  * Adjust level-0 varnos in subquery so that we can append its rangetable
1013  * to upper query's. We have to fix the subquery's append_rel_list as
1014  * well.
1015  */
1016  rtoffset = list_length(parse->rtable);
1017  OffsetVarNodes((Node *) subquery, rtoffset, 0);
1018  OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);
1019 
1020  /*
1021  * Upper-level vars in subquery are now one level closer to their parent
1022  * than before.
1023  */
1024  IncrementVarSublevelsUp((Node *) subquery, -1, 1);
1025  IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
1026 
1027  /*
1028  * The subquery's targetlist items are now in the appropriate form to
1029  * insert into the top query, except that we may need to wrap them in
1030  * PlaceHolderVars. Set up required context data for pullup_replace_vars.
1031  */
1032  rvcontext.root = root;
1033  rvcontext.targetlist = subquery->targetList;
1034  rvcontext.target_rte = rte;
1035  if (rte->lateral)
1036  rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree,
1037  true);
1038  else /* won't need relids */
1039  rvcontext.relids = NULL;
1040  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1041  rvcontext.varno = varno;
1042  /* these flags will be set below, if needed */
1043  rvcontext.need_phvs = false;
1044  rvcontext.wrap_non_vars = false;
1045  /* initialize cache array with indexes 0 .. length(tlist) */
1046  rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
1047  sizeof(Node *));
1048 
1049  /*
1050  * If we are under an outer join then non-nullable items and lateral
1051  * references may have to be turned into PlaceHolderVars.
1052  */
1053  if (lowest_nulling_outer_join != NULL)
1054  rvcontext.need_phvs = true;
1055 
1056  /*
1057  * If we are dealing with an appendrel member then anything that's not a
1058  * simple Var has to be turned into a PlaceHolderVar. We force this to
1059  * ensure that what we pull up doesn't get merged into a surrounding
1060  * expression during later processing and then fail to match the
1061  * expression actually available from the appendrel.
1062  */
1063  if (containing_appendrel != NULL)
1064  {
1065  rvcontext.need_phvs = true;
1066  rvcontext.wrap_non_vars = true;
1067  }
1068 
1069  /*
1070  * If the parent query uses grouping sets, we need a PlaceHolderVar for
1071  * anything that's not a simple Var. Again, this ensures that expressions
1072  * retain their separate identity so that they will match grouping set
1073  * columns when appropriate. (It'd be sufficient to wrap values used in
1074  * grouping set columns, and do so only in non-aggregated portions of the
1075  * tlist and havingQual, but that would require a lot of infrastructure
1076  * that pullup_replace_vars hasn't currently got.)
1077  */
1078  if (parse->groupingSets)
1079  {
1080  rvcontext.need_phvs = true;
1081  rvcontext.wrap_non_vars = true;
1082  }
1083 
1084  /*
1085  * Replace all of the top query's references to the subquery's outputs
1086  * with copies of the adjusted subtlist items, being careful not to
1087  * replace any of the jointree structure.
1088  */
1089  perform_pullup_replace_vars(root, &rvcontext,
1090  lowest_nulling_outer_join,
1091  containing_appendrel);
1092 
1093  /*
1094  * If the subquery had a LATERAL marker, propagate that to any of its
1095  * child RTEs that could possibly now contain lateral cross-references.
1096  * The children might or might not contain any actual lateral
1097  * cross-references, but we have to mark the pulled-up child RTEs so that
1098  * later planner stages will check for such.
1099  */
1100  if (rte->lateral)
1101  {
1102  foreach(lc, subquery->rtable)
1103  {
1104  RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc);
1105 
1106  switch (child_rte->rtekind)
1107  {
1108  case RTE_RELATION:
1109  if (child_rte->tablesample)
1110  child_rte->lateral = true;
1111  break;
1112  case RTE_SUBQUERY:
1113  case RTE_FUNCTION:
1114  case RTE_VALUES:
1115  case RTE_TABLEFUNC:
1116  child_rte->lateral = true;
1117  break;
1118  case RTE_JOIN:
1119  case RTE_CTE:
1120  case RTE_NAMEDTUPLESTORE:
1121  case RTE_RESULT:
1122  /* these can't contain any lateral references */
1123  break;
1124  }
1125  }
1126  }
1127 
1128  /*
1129  * Now append the adjusted rtable entries to upper query. (We hold off
1130  * until after fixing the upper rtable entries; no point in running that
1131  * code on the subquery ones too.)
1132  */
1133  parse->rtable = list_concat(parse->rtable, subquery->rtable);
1134 
1135  /*
1136  * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already
1137  * adjusted the marker rtindexes, so just concat the lists.)
1138  */
1139  parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
1140 
1141  /*
1142  * We also have to fix the relid sets of any PlaceHolderVar nodes in the
1143  * parent query. (This could perhaps be done by pullup_replace_vars(),
1144  * but it seems cleaner to use two passes.) Note in particular that any
1145  * PlaceHolderVar nodes just created by pullup_replace_vars() will be
1146  * adjusted, so having created them with the subquery's varno is correct.
1147  *
1148  * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We
1149  * already checked that this won't require introducing multiple subrelids
1150  * into the single-slot AppendRelInfo structs.
1151  */
1152  if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
1153  root->append_rel_list)
1154  {
1155  Relids subrelids;
1156 
1157  subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
1158  substitute_phv_relids((Node *) parse, varno, subrelids);
1159  fix_append_rel_relids(root->append_rel_list, varno, subrelids);
1160  }
1161 
1162  /*
1163  * And now add subquery's AppendRelInfos to our list.
1164  */
1166  subroot->append_rel_list);
1167 
1168  /*
1169  * We don't have to do the equivalent bookkeeping for outer-join info,
1170  * because that hasn't been set up yet. placeholder_list likewise.
1171  */
1172  Assert(root->join_info_list == NIL);
1173  Assert(subroot->join_info_list == NIL);
1174  Assert(root->placeholder_list == NIL);
1175  Assert(subroot->placeholder_list == NIL);
1176 
1177  /*
1178  * Miscellaneous housekeeping.
1179  *
1180  * Although replace_rte_variables() faithfully updated parse->hasSubLinks
1181  * if it copied any SubLinks out of the subquery's targetlist, we still
1182  * could have SubLinks added to the query in the expressions of FUNCTION
1183  * and VALUES RTEs copied up from the subquery. So it's necessary to copy
1184  * subquery->hasSubLinks anyway. Perhaps this can be improved someday.
1185  */
1186  parse->hasSubLinks |= subquery->hasSubLinks;
1187 
1188  /* If subquery had any RLS conditions, now main query does too */
1189  parse->hasRowSecurity |= subquery->hasRowSecurity;
1190 
1191  /*
1192  * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
1193  * hasTargetSRFs, so no work needed on those flags
1194  */
1195 
1196  /*
1197  * Return the adjusted subquery jointree to replace the RangeTblRef entry
1198  * in parent's jointree; or, if the FromExpr is degenerate, just return
1199  * its single member.
1200  */
1201  Assert(IsA(subquery->jointree, FromExpr));
1202  Assert(subquery->jointree->fromlist != NIL);
1203  if (subquery->jointree->quals == NULL &&
1204  list_length(subquery->jointree->fromlist) == 1)
1205  return (Node *) linitial(subquery->jointree->fromlist);
1206 
1207  return (Node *) subquery->jointree;
1208 }
#define NIL
Definition: pg_list.h:65
static void substitute_phv_relids(Node *node, int varno, Relids subrelids)
List * rowMarks
Definition: pathnodes.h:287
Relids all_result_relids
Definition: pathnodes.h:275
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:425
List * plan_params
Definition: pathnodes.h:175
bool ec_merging_done
Definition: pathnodes.h:250
List * join_info_list
Definition: pathnodes.h:265
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:776
FromExpr * jointree
Definition: parsenodes.h:148
PlannerInfo * parent_root
Definition: pathnodes.h:167
List * groupingSets
Definition: parsenodes.h:161
Definition: nodes.h:539
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
List * minmax_aggs
Definition: pathnodes.h:332
List * fromlist
Definition: primnodes.h:1553
List * rowMarks
Definition: parsenodes.h:175
AttrNumber * grouping_map
Definition: pathnodes.h:331
bool hasRecursion
Definition: pathnodes.h:351
void pull_up_subqueries(PlannerInfo *root)
Definition: prepjointree.c:680
void replace_empty_jointree(Query *parse)
Definition: prepjointree.c:150
Node * quals
Definition: primnodes.h:1554
List * targetList
Definition: parsenodes.h:150
List * multiexpr_params
Definition: pathnodes.h:245
void preprocess_function_rtes(PlannerInfo *root)
Definition: prepjointree.c:639
int wt_param_id
Definition: pathnodes.h:363
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
RangeTblEntry * target_rte
Definition: prepjointree.c:47
List * row_identity_vars
Definition: pathnodes.h:285
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
PlannerGlobal * glob
Definition: pathnodes.h:163
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc0(Size size)
Definition: mcxt.c:1093
List * append_rel_list
Definition: pathnodes.h:283
Index lastPHId
Definition: pathnodes.h:115
List * cte_plan_ids
Definition: pathnodes.h:243
List * init_plans
Definition: pathnodes.h:241
Node * flatten_join_alias_vars(Query *query, Node *node)
Definition: var.c:697
static bool is_safe_append_member(Query *subquery)
#define makeNode(_type_)
Definition: nodes.h:587
static void perform_pullup_replace_vars(PlannerInfo *root, pullup_replace_vars_context *rvcontext, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
static void fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
List * eq_classes
Definition: pathnodes.h:248
Bitmapset * outer_params
Definition: pathnodes.h:176
struct Path * non_recursive_path
Definition: pathnodes.h:364
static int list_length(const List *l)
Definition: pg_list.h:149
Index qual_security_level
Definition: pathnodes.h:342
Index query_level
Definition: pathnodes.h:165
void pull_up_sublinks(PlannerInfo *root)
Definition: prepjointree.c:208
RTEKind rtekind
Definition: parsenodes.h:995
static bool is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join)
List * cteList
Definition: parsenodes.h:145
Query * subquery
Definition: parsenodes.h:1030
bool hasSubLinks
Definition: parsenodes.h:136
Relids leaf_result_relids
Definition: pathnodes.h:276
List * placeholder_list
Definition: pathnodes.h:289
MemoryContext planner_cxt
Definition: pathnodes.h:334
#define copyObject(obj)
Definition: nodes.h:655
List * processed_tlist
Definition: pathnodes.h:320
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1025
List * update_colnos
Definition: pathnodes.h:328
bool hasRowSecurity
Definition: parsenodes.h:141
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665
struct PathTarget * upper_targets[UPPERREL_FINAL+1]
Definition: pathnodes.h:309
List * upper_rels[UPPERREL_FINAL+1]
Definition: pathnodes.h:306

◆ pull_up_simple_union_all()

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

Definition at line 1220 of file prepjointree.c.

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

Referenced by pull_up_subqueries_recurse().

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

◆ pull_up_simple_values()

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

Definition at line 1543 of file prepjointree.c.

References PlannerInfo::append_rel_list, Assert, contain_vars_of_level(), copyObject, RangeTblEntry::eref, Query::hasSubLinks, 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, Query::rtable, 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().

1544 {
1545  Query *parse = root->parse;
1546  int varno = ((RangeTblRef *) jtnode)->rtindex;
1547  List *values_list;
1548  List *tlist;
1549  AttrNumber attrno;
1550  pullup_replace_vars_context rvcontext;
1551  ListCell *lc;
1552 
1553  Assert(rte->rtekind == RTE_VALUES);
1554  Assert(list_length(rte->values_lists) == 1);
1555 
1556  /*
1557  * Need a modifiable copy of the VALUES list to hack on, just in case it's
1558  * multiply referenced.
1559  */
1560  values_list = copyObject(linitial(rte->values_lists));
1561 
1562  /*
1563  * The VALUES RTE can't contain any Vars of level zero, let alone any that
1564  * are join aliases, so no need to flatten join alias Vars.
1565  */
1566  Assert(!contain_vars_of_level((Node *) values_list, 0));
1567 
1568  /*
1569  * Set up required context data for pullup_replace_vars. In particular,
1570  * we have to make the VALUES list look like a subquery targetlist.
1571  */
1572  tlist = NIL;
1573  attrno = 1;
1574  foreach(lc, values_list)
1575  {
1576  tlist = lappend(tlist,
1577  makeTargetEntry((Expr *) lfirst(lc),
1578  attrno,
1579  NULL,
1580  false));
1581  attrno++;
1582  }
1583  rvcontext.root = root;
1584  rvcontext.targetlist = tlist;
1585  rvcontext.target_rte = rte;
1586  rvcontext.relids = NULL;
1587  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1588  rvcontext.varno = varno;
1589  rvcontext.need_phvs = false;
1590  rvcontext.wrap_non_vars = false;
1591  /* initialize cache array with indexes 0 .. length(tlist) */
1592  rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1593  sizeof(Node *));
1594 
1595  /*
1596  * Replace all of the top query's references to the RTE's outputs with
1597  * copies of the adjusted VALUES expressions, being careful not to replace
1598  * any of the jointree structure. We can assume there's no outer joins or
1599  * appendrels in the dummy Query that surrounds a VALUES RTE.
1600  */
1601  perform_pullup_replace_vars(root, &rvcontext, NULL, NULL);
1602 
1603  /*
1604  * There should be no appendrels to fix, nor any outer joins and hence no
1605  * PlaceHolderVars.
1606  */
1607  Assert(root->append_rel_list == NIL);
1608  Assert(root->join_info_list == NIL);
1609  Assert(root->placeholder_list == NIL);
1610 
1611  /*
1612  * Replace the VALUES RTE with a RESULT RTE. The VALUES RTE is the only
1613  * rtable entry in the current query level, so this is easy.
1614  */
1615  Assert(list_length(parse->rtable) == 1);
1616 
1617  /* Create suitable RTE */
1618  rte = makeNode(RangeTblEntry);
1619  rte->rtekind = RTE_RESULT;
1620  rte->eref = makeAlias("*RESULT*", NIL);
1621 
1622  /* Replace rangetable */
1623  parse->rtable = list_make1(rte);
1624 
1625  /* We could manufacture a new RangeTblRef, but the one we have is fine */
1626  Assert(varno == 1);
1627 
1628  return jtnode;
1629 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:161
List * join_info_list
Definition: pathnodes.h:265
Definition: nodes.h:539
List * values_lists
Definition: parsenodes.h:1100
#define list_make1(x1)
Definition: pg_list.h:206
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
RangeTblEntry * target_rte
Definition: prepjointree.c:47
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lappend(List *list, void *datum)
Definition: list.c:336
void * palloc0(Size size)
Definition: mcxt.c:1093
List * append_rel_list
Definition: pathnodes.h:283
#define makeNode(_type_)
Definition: nodes.h:587
static void perform_pullup_replace_vars(PlannerInfo *root, pullup_replace_vars_context *rvcontext, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:396
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
bool hasSubLinks
Definition: parsenodes.h:136
List * placeholder_list
Definition: pathnodes.h:289
Alias * eref
Definition: parsenodes.h:1141
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 208 of file prepjointree.c.

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

209 {
210  Node *jtnode;
211  Relids relids;
212 
213  /* Begin recursion through the jointree */
214  jtnode = pull_up_sublinks_jointree_recurse(root,
215  (Node *) root->parse->jointree,
216  &relids);
217 
218  /*
219  * root->parse->jointree must always be a FromExpr, so insert a dummy one
220  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
221  */
222  if (IsA(jtnode, FromExpr))
223  root->parse->jointree = (FromExpr *) jtnode;
224  else
225  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
226 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
#define list_make1(x1)
Definition: pg_list.h:206
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:235

◆ pull_up_sublinks_jointree_recurse()

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

Definition at line 235 of file prepjointree.c.

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

Referenced by pull_up_sublinks(), and pull_up_sublinks_qual_recurse().

237 {
238  if (jtnode == NULL)
239  {
240  *relids = NULL;
241  }
242  else if (IsA(jtnode, RangeTblRef))
243  {
244  int varno = ((RangeTblRef *) jtnode)->rtindex;
245 
246  *relids = bms_make_singleton(varno);
247  /* jtnode is returned unmodified */
248  }
249  else if (IsA(jtnode, FromExpr))
250  {
251  FromExpr *f = (FromExpr *) jtnode;
252  List *newfromlist = NIL;
253  Relids frelids = NULL;
254  FromExpr *newf;
255  Node *jtlink;
256  ListCell *l;
257 
258  /* First, recurse to process children and collect their relids */
259  foreach(l, f->fromlist)
260  {
261  Node *newchild;
262  Relids childrelids;
263 
264  newchild = pull_up_sublinks_jointree_recurse(root,
265  lfirst(l),
266  &childrelids);
267  newfromlist = lappend(newfromlist, newchild);
268  frelids = bms_join(frelids, childrelids);
269  }
270  /* Build the replacement FromExpr; no quals yet */
271  newf = makeFromExpr(newfromlist, NULL);
272  /* Set up a link representing the rebuilt jointree */
273  jtlink = (Node *) newf;
274  /* Now process qual --- all children are available for use */
275  newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
276  &jtlink, frelids,
277  NULL, NULL);
278 
279  /*
280  * Note that the result will be either newf, or a stack of JoinExprs
281  * with newf at the base. We rely on subsequent optimization steps to
282  * flatten this and rearrange the joins as needed.
283  *
284  * Although we could include the pulled-up subqueries in the returned
285  * relids, there's no need since upper quals couldn't refer to their
286  * outputs anyway.
287  */
288  *relids = frelids;
289  jtnode = jtlink;
290  }
291  else if (IsA(jtnode, JoinExpr))
292  {
293  JoinExpr *j;
294  Relids leftrelids;
295  Relids rightrelids;
296  Node *jtlink;
297 
298  /*
299  * Make a modifiable copy of join node, but don't bother copying its
300  * subnodes (yet).
301  */
302  j = (JoinExpr *) palloc(sizeof(JoinExpr));
303  memcpy(j, jtnode, sizeof(JoinExpr));
304  jtlink = (Node *) j;
305 
306  /* Recurse to process children and collect their relids */
308  &leftrelids);
310  &rightrelids);
311 
312  /*
313  * Now process qual, showing appropriate child relids as available,
314  * and attach any pulled-up jointree items at the right place. In the
315  * inner-join case we put new JoinExprs above the existing one (much
316  * as for a FromExpr-style join). In outer-join cases the new
317  * JoinExprs must go into the nullable side of the outer join. The
318  * point of the available_rels machinations is to ensure that we only
319  * pull up quals for which that's okay.
320  *
321  * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI
322  * nodes here.
323  */
324  switch (j->jointype)
325  {
326  case JOIN_INNER:
328  &jtlink,
329  bms_union(leftrelids,
330  rightrelids),
331  NULL, NULL);
332  break;
333  case JOIN_LEFT:
335  &j->rarg,
336  rightrelids,
337  NULL, NULL);
338  break;
339  case JOIN_FULL:
340  /* can't do anything with full-join quals */
341  break;
342  case JOIN_RIGHT:
344  &j->larg,
345  leftrelids,
346  NULL, NULL);
347  break;
348  default:
349  elog(ERROR, "unrecognized join type: %d",
350  (int) j->jointype);
351  break;
352  }
353 
354  /*
355  * Although we could include the pulled-up subqueries in the returned
356  * relids, there's no need since upper quals couldn't refer to their
357  * outputs anyway. But we *do* need to include the join's own rtindex
358  * because we haven't yet collapsed join alias variables, so upper
359  * levels would mistakenly think they couldn't use references to this
360  * join.
361  */
362  *relids = bms_join(leftrelids, rightrelids);
363  if (j->rtindex)
364  *relids = bms_add_member(*relids, j->rtindex);
365  jtnode = jtlink;
366  }
367  else
368  elog(ERROR, "unrecognized node type: %d",
369  (int) nodeTag(jtnode));
370  return jtnode;
371 }
#define NIL
Definition: pg_list.h:65
static Node * pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, Node **jtlink1, Relids available_rels1, Node **jtlink2, Relids available_rels2)
Definition: prepjointree.c:389
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Definition: nodes.h:539
List * fromlist
Definition: primnodes.h:1553
Node * quals
Definition: primnodes.h:1554
Node * larg
Definition: primnodes.h:1532
#define ERROR
Definition: elog.h:46
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:949
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:235
List * lappend(List *list, void *datum)
Definition: list.c:336
Node * quals
Definition: primnodes.h:1536
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:544
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int rtindex
Definition: primnodes.h:1538
Definition: pg_list.h:50

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

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, lappend(), JoinExpr::larg, lfirst, linitial, list_length(), make_andclause(), NIL, pull_up_sublinks_jointree_recurse(), JoinExpr::quals, JoinExpr::rarg, and SubLink::subLinkType.

Referenced by pull_up_sublinks_jointree_recurse().

392 {
393  if (node == NULL)
394  return NULL;
395  if (IsA(node, SubLink))
396  {
397  SubLink *sublink = (SubLink *) node;
398  JoinExpr *j;
399  Relids child_rels;
400 
401  /* Is it a convertible ANY or EXISTS clause? */
402  if (sublink->subLinkType == ANY_SUBLINK)
403  {
404  if ((j = convert_ANY_sublink_to_join(root, sublink,
405  available_rels1)) != NULL)
406  {
407  /* Yes; insert the new join node into the join tree */
408  j->larg = *jtlink1;
409  *jtlink1 = (Node *) j;
410  /* Recursively process pulled-up jointree nodes */
412  j->rarg,
413  &child_rels);
414 
415  /*
416  * Now recursively process the pulled-up quals. Any inserted
417  * joins can get stacked onto either j->larg or j->rarg,
418  * depending on which rels they reference.
419  */
421  j->quals,
422  &j->larg,
423  available_rels1,
424  &j->rarg,
425  child_rels);
426  /* Return NULL representing constant TRUE */
427  return NULL;
428  }
429  if (available_rels2 != NULL &&
430  (j = convert_ANY_sublink_to_join(root, sublink,
431  available_rels2)) != NULL)
432  {
433  /* Yes; insert the new join node into the join tree */
434  j->larg = *jtlink2;
435  *jtlink2 = (Node *) j;
436  /* Recursively process pulled-up jointree nodes */
438  j->rarg,
439  &child_rels);
440 
441  /*
442  * Now recursively process the pulled-up quals. Any inserted
443  * joins can get stacked onto either j->larg or j->rarg,
444  * depending on which rels they reference.
445  */
447  j->quals,
448  &j->larg,
449  available_rels2,
450  &j->rarg,
451  child_rels);
452  /* Return NULL representing constant TRUE */
453  return NULL;
454  }
455  }
456  else if (sublink->subLinkType == EXISTS_SUBLINK)
457  {
458  if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
459  available_rels1)) != NULL)
460  {
461  /* Yes; insert the new join node into the join tree */
462  j->larg = *jtlink1;
463  *jtlink1 = (Node *) j;
464  /* Recursively process pulled-up jointree nodes */
466  j->rarg,
467  &child_rels);
468 
469  /*
470  * Now recursively process the pulled-up quals. Any inserted
471  * joins can get stacked onto either j->larg or j->rarg,
472  * depending on which rels they reference.
473  */
475  j->quals,
476  &j->larg,
477  available_rels1,
478  &j->rarg,
479  child_rels);
480  /* Return NULL representing constant TRUE */
481  return NULL;
482  }
483  if (available_rels2 != NULL &&
484  (j = convert_EXISTS_sublink_to_join(root, sublink, false,
485  available_rels2)) != NULL)
486  {
487  /* Yes; insert the new join node into the join tree */
488  j->larg = *jtlink2;
489  *jtlink2 = (Node *) j;
490  /* Recursively process pulled-up jointree nodes */
492  j->rarg,
493  &child_rels);
494 
495  /*
496  * Now recursively process the pulled-up quals. Any inserted
497  * joins can get stacked onto either j->larg or j->rarg,
498  * depending on which rels they reference.
499  */
501  j->quals,
502  &j->larg,
503  available_rels2,
504  &j->rarg,
505  child_rels);
506  /* Return NULL representing constant TRUE */
507  return NULL;
508  }
509  }
510  /* Else return it unmodified */
511  return node;
512  }
513  if (is_notclause(node))
514  {
515  /* If the immediate argument of NOT is EXISTS, try to convert */
516  SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
517  JoinExpr *j;
518  Relids child_rels;
519 
520  if (sublink && IsA(sublink, SubLink))
521  {
522  if (sublink->subLinkType == EXISTS_SUBLINK)
523  {
524  if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
525  available_rels1)) != NULL)
526  {
527  /* Yes; insert the new join node into the join tree */
528  j->larg = *jtlink1;
529  *jtlink1 = (Node *) j;
530  /* Recursively process pulled-up jointree nodes */
532  j->rarg,
533  &child_rels);
534 
535  /*
536  * Now recursively process the pulled-up quals. Because
537  * we are underneath a NOT, we can't pull up sublinks that
538  * reference the left-hand stuff, but it's still okay to
539  * pull up sublinks referencing j->rarg.
540  */
542  j->quals,
543  &j->rarg,
544  child_rels,
545  NULL, NULL);
546  /* Return NULL representing constant TRUE */
547  return NULL;
548  }
549  if (available_rels2 != NULL &&
550  (j = convert_EXISTS_sublink_to_join(root, sublink, true,
551  available_rels2)) != NULL)
552  {
553  /* Yes; insert the new join node into the join tree */
554  j->larg = *jtlink2;
555  *jtlink2 = (Node *) j;
556  /* Recursively process pulled-up jointree nodes */
558  j->rarg,
559  &child_rels);
560 
561  /*
562  * Now recursively process the pulled-up quals. Because
563  * we are underneath a NOT, we can't pull up sublinks that
564  * reference the left-hand stuff, but it's still okay to
565  * pull up sublinks referencing j->rarg.
566  */
568  j->quals,
569  &j->rarg,
570  child_rels,
571  NULL, NULL);
572  /* Return NULL representing constant TRUE */
573  return NULL;
574  }
575  }
576  }
577  /* Else return it unmodified */
578  return node;
579  }
580  if (is_andclause(node))
581  {
582  /* Recurse into AND clause */
583  List *newclauses = NIL;
584  ListCell *l;
585 
586  foreach(l, ((BoolExpr *) node)->args)
587  {
588  Node *oldclause = (Node *) lfirst(l);
589  Node *newclause;
590 
591  newclause = pull_up_sublinks_qual_recurse(root,
592  oldclause,
593  jtlink1,
594  available_rels1,
595  jtlink2,
596  available_rels2);
597  if (newclause)
598  newclauses = lappend(newclauses, newclause);
599  }
600  /* We might have got back fewer clauses than we started with */
601  if (newclauses == NIL)
602  return NULL;
603  else if (list_length(newclauses) == 1)
604  return (Node *) linitial(newclauses);
605  else
606  return (Node *) make_andclause(newclauses);
607  }
608  /* Stop if not an AND */
609  return node;
610 }
#define NIL
Definition: pg_list.h:65
static Node * pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, Node **jtlink1, Relids available_rels1, Node **jtlink2, Relids available_rels2)
Definition: prepjointree.c:389
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:97
Definition: nodes.h:539
JoinExpr * convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink, Relids available_rels)
Definition: subselect.c:1276
JoinExpr * convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, bool under_not, Relids available_rels)
Definition: subselect.c:1384
Node * larg
Definition: primnodes.h:1532
#define linitial(l)
Definition: pg_list.h:174
Expr * make_andclause(List *andclauses)
Definition: makefuncs.c:636
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:235
List * lappend(List *list, void *datum)
Definition: list.c:336
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:115
Node * quals
Definition: primnodes.h:1536
static Expr * get_notclausearg(const void *notclause)
Definition: nodeFuncs.h:124
Node * rarg
Definition: primnodes.h:1533
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Definition: pg_list.h:50

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 680 of file prepjointree.c.

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

681 {
682  /* Top level of jointree must always be a FromExpr */
683  Assert(IsA(root->parse->jointree, FromExpr));
684  /* Recursion starts with no containing join nor appendrel */
685  root->parse->jointree = (FromExpr *)
687  NULL, NULL, NULL);
688  /* We should still have a FromExpr */
689  Assert(IsA(root->parse->jointree, FromExpr));
690 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
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:730
Definition: nodes.h:539
#define Assert(condition)
Definition: c.h:804

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

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

Referenced by pull_up_subqueries(), and pull_up_union_leaf_queries().

734 {
735  Assert(jtnode != NULL);
736  if (IsA(jtnode, RangeTblRef))
737  {
738  int varno = ((RangeTblRef *) jtnode)->rtindex;
739  RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
740 
741  /*
742  * Is this a subquery RTE, and if so, is the subquery simple enough to
743  * pull up?
744  *
745  * If we are looking at an append-relation member, we can't pull it up
746  * unless is_safe_append_member says so.
747  */
748  if (rte->rtekind == RTE_SUBQUERY &&
749  is_simple_subquery(root, rte->subquery, rte, lowest_outer_join) &&
750  (containing_appendrel == NULL ||
752  return pull_up_simple_subquery(root, jtnode, rte,
753  lowest_outer_join,
754  lowest_nulling_outer_join,
755  containing_appendrel);
756 
757  /*
758  * Alternatively, is it a simple UNION ALL subquery? If so, flatten
759  * into an "append relation".
760  *
761  * It's safe to do this regardless of whether this query is itself an
762  * appendrel member. (If you're thinking we should try to flatten the
763  * two levels of appendrel together, you're right; but we handle that
764  * in set_append_rel_pathlist, not here.)
765  */
766  if (rte->rtekind == RTE_SUBQUERY &&
768  return pull_up_simple_union_all(root, jtnode, rte);
769 
770  /*
771  * Or perhaps it's a simple VALUES RTE?
772  *
773  * We don't allow VALUES pullup below an outer join nor into an
774  * appendrel (such cases are impossible anyway at the moment).
775  */
776  if (rte->rtekind == RTE_VALUES &&
777  lowest_outer_join == NULL &&
778  containing_appendrel == NULL &&
779  is_simple_values(root, rte))
780  return pull_up_simple_values(root, jtnode, rte);
781 
782  /*
783  * Or perhaps it's a FUNCTION RTE that we could inline?
784  */
785  if (rte->rtekind == RTE_FUNCTION)
786  return pull_up_constant_function(root, jtnode, rte,
787  lowest_nulling_outer_join,
788  containing_appendrel);
789 
790  /* Otherwise, do nothing at this node. */
791  }
792  else if (IsA(jtnode, FromExpr))
793  {
794  FromExpr *f = (FromExpr *) jtnode;
795  ListCell *l;
796 
797  Assert(containing_appendrel == NULL);
798  /* Recursively transform all the child nodes */
799  foreach(l, f->fromlist)
800  {
802  lowest_outer_join,
803  lowest_nulling_outer_join,
804  NULL);
805  }
806  }
807  else if (IsA(jtnode, JoinExpr))
808  {
809  JoinExpr *j = (JoinExpr *) jtnode;
810 
811  Assert(containing_appendrel == NULL);
812  /* Recurse, being careful to tell myself when inside outer join */
813  switch (j->jointype)
814  {
815  case JOIN_INNER:
816  j->larg = pull_up_subqueries_recurse(root, j->larg,
817  lowest_outer_join,
818  lowest_nulling_outer_join,
819  NULL);
820  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
821  lowest_outer_join,
822  lowest_nulling_outer_join,
823  NULL);
824  break;
825  case JOIN_LEFT:
826  case JOIN_SEMI:
827  case JOIN_ANTI:
828  j->larg = pull_up_subqueries_recurse(root, j->larg,
829  j,
830  lowest_nulling_outer_join,
831  NULL);
832  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
833  j,
834  j,
835  NULL);
836  break;
837  case JOIN_FULL:
838  j->larg = pull_up_subqueries_recurse(root, j->larg,
839  j,
840  j,
841  NULL);
842  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
843  j,
844  j,
845  NULL);
846  break;
847  case JOIN_RIGHT:
848  j->larg = pull_up_subqueries_recurse(root, j->larg,
849  j,
850  j,
851  NULL);
852  j->rarg = pull_up_subqueries_recurse(root, j->rarg,
853  j,
854  lowest_nulling_outer_join,
855  NULL);
856  break;
857  default:
858  elog(ERROR, "unrecognized join type: %d",
859  (int) j->jointype);
860  break;
861  }
862  }
863  else
864  elog(ERROR, "unrecognized node type: %d",
865  (int) nodeTag(jtnode));
866  return jtnode;
867 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
static bool is_simple_values(PlannerInfo *root, RangeTblEntry *rte)
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:730
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:882
List * fromlist
Definition: primnodes.h:1553
static bool is_simple_union_all(Query *subquery)
Node * larg
Definition: primnodes.h:1532
static Node * pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static bool is_safe_append_member(Query *subquery)
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
RTEKind rtekind
Definition: parsenodes.h:995
static bool is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join)
static Node * pull_up_constant_function(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
Query * subquery
Definition: parsenodes.h:1030
#define elog(elevel,...)
Definition: elog.h:232
static Node * pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)

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

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

Referenced by flatten_simple_union_all(), and pull_up_simple_union_all().

1303 {
1304  if (IsA(setOp, RangeTblRef))
1305  {
1306  RangeTblRef *rtr = (RangeTblRef *) setOp;
1307  int childRTindex;
1308  AppendRelInfo *appinfo;
1309 
1310  /*
1311  * Calculate the index in the parent's range table
1312  */
1313  childRTindex = childRToffset + rtr->rtindex;
1314 
1315  /*
1316  * Build a suitable AppendRelInfo, and attach to parent's list.
1317  */
1318  appinfo = makeNode(AppendRelInfo);
1319  appinfo->parent_relid = parentRTindex;
1320  appinfo->child_relid = childRTindex;
1321  appinfo->parent_reltype = InvalidOid;
1322  appinfo->child_reltype = InvalidOid;
1323  make_setop_translation_list(setOpQuery, childRTindex, appinfo);
1324  appinfo->parent_reloid = InvalidOid;
1325  root->append_rel_list = lappend(root->append_rel_list, appinfo);
1326 
1327  /*
1328  * Recursively apply pull_up_subqueries to the new child RTE. (We
1329  * must build the AppendRelInfo first, because this will modify it.)
1330  * Note that we can pass NULL for containing-join info even if we're
1331  * actually under an outer join, because the child's expressions
1332  * aren't going to propagate up to the join. Also, we ignore the
1333  * possibility that pull_up_subqueries_recurse() returns a different
1334  * jointree node than what we pass it; if it does, the important thing
1335  * is that it replaced the child relid in the AppendRelInfo node.
1336  */
1337  rtr = makeNode(RangeTblRef);
1338  rtr->rtindex = childRTindex;
1339  (void) pull_up_subqueries_recurse(root, (Node *) rtr,
1340  NULL, NULL, appinfo);
1341  }
1342  else if (IsA(setOp, SetOperationStmt))
1343  {
1344  SetOperationStmt *op = (SetOperationStmt *) setOp;
1345 
1346  /* Recurse to reach leaf queries */
1347  pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
1348  childRToffset);
1349  pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
1350  childRToffset);
1351  }
1352  else
1353  {
1354  elog(ERROR, "unrecognized node type: %d",
1355  (int) nodeTag(setOp));
1356  }
1357 }
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
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:730
Definition: nodes.h:539
Oid parent_reltype
Definition: pathnodes.h:2304
#define ERROR
Definition: elog.h:46
List * lappend(List *list, void *datum)
Definition: list.c:336
List * append_rel_list
Definition: pathnodes.h:283
#define InvalidOid
Definition: postgres_ext.h:36
#define makeNode(_type_)
Definition: nodes.h:587
static void make_setop_translation_list(Query *query, Index newvarno, AppendRelInfo *appinfo)
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
Index child_relid
Definition: pathnodes.h:2296
Index parent_relid
Definition: pathnodes.h:2295

◆ pullup_replace_vars()

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

Definition at line 2225 of file prepjointree.c.

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

Referenced by perform_pullup_replace_vars(), and replace_vars_in_jointree().

2226 {
2227  return replace_rte_variables(expr,
2228  context->varno, 0,
2230  (void *) context,
2231  context->outer_hasSubLinks);
2232 }
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)

◆ pullup_replace_vars_callback()

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

Definition at line 2235 of file prepjointree.c.

References RowExpr::args, bms_is_member(), bms_make_singleton(), bms_overlap(), replace_rte_variables_context::callback_arg, COERCE_IMPLICIT_CAST, RowExpr::colnames, contain_nonstrict_functions(), contain_vars_of_level(), copyObject, elog, ERROR, expandRTE(), TargetEntry::expr, get_tle_by_resno(), IncrementVarSublevelsUp(), InvalidAttrNumber, IsA, RangeTblEntry::lateral, list_length(), Var::location, RowExpr::location, make_placeholder_expr(), makeNode, pullup_replace_vars_context::need_phvs, pull_varnos(), 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().

2237 {
2239  int varattno = var->varattno;
2240  Node *newnode;
2241 
2242  /*
2243  * If PlaceHolderVars are needed, we cache the modified expressions in
2244  * rcon->rv_cache[]. This is not in hopes of any material speed gain
2245  * within this function, but to avoid generating identical PHVs with
2246  * different IDs. That would result in duplicate evaluations at runtime,
2247  * and possibly prevent optimizations that rely on recognizing different
2248  * references to the same subquery output as being equal(). So it's worth
2249  * a bit of extra effort to avoid it.
2250  */
2251  if (rcon->need_phvs &&
2252  varattno >= InvalidAttrNumber &&
2253  varattno <= list_length(rcon->targetlist) &&
2254  rcon->rv_cache[varattno] != NULL)
2255  {
2256  /* Just copy the entry and fall through to adjust its varlevelsup */
2257  newnode = copyObject(rcon->rv_cache[varattno]);
2258  }
2259  else if (varattno == InvalidAttrNumber)
2260  {
2261  /* Must expand whole-tuple reference into RowExpr */
2262  RowExpr *rowexpr;
2263  List *colnames;
2264  List *fields;
2265  bool save_need_phvs = rcon->need_phvs;
2266  int save_sublevelsup = context->sublevels_up;
2267 
2268  /*
2269  * If generating an expansion for a var of a named rowtype (ie, this
2270  * is a plain relation RTE), then we must include dummy items for
2271  * dropped columns. If the var is RECORD (ie, this is a JOIN), then
2272  * omit dropped columns. Either way, attach column names to the
2273  * RowExpr for use of ruleutils.c.
2274  *
2275  * In order to be able to cache the results, we always generate the
2276  * expansion with varlevelsup = 0, and then adjust if needed.
2277  */
2278  expandRTE(rcon->target_rte,
2279  var->varno, 0 /* not varlevelsup */ , var->location,
2280  (var->vartype != RECORDOID),
2281  &colnames, &fields);
2282  /* Adjust the generated per-field Vars, but don't insert PHVs */
2283  rcon->need_phvs = false;
2284  context->sublevels_up = 0; /* to match the expandRTE output */
2285  fields = (List *) replace_rte_variables_mutator((Node *) fields,
2286  context);
2287  rcon->need_phvs = save_need_phvs;
2288  context->sublevels_up = save_sublevelsup;
2289 
2290  rowexpr = makeNode(RowExpr);
2291  rowexpr->args = fields;
2292  rowexpr->row_typeid = var->vartype;
2293  rowexpr->row_format = COERCE_IMPLICIT_CAST;
2294  rowexpr->colnames = colnames;
2295  rowexpr->location = var->location;
2296  newnode = (Node *) rowexpr;
2297 
2298  /*
2299  * Insert PlaceHolderVar if needed. Notice that we are wrapping one
2300  * PlaceHolderVar around the whole RowExpr, rather than putting one
2301  * around each element of the row. This is because we need the
2302  * expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
2303  * to null by an outer join.
2304  */
2305  if (rcon->need_phvs)
2306  {
2307  /* RowExpr is certainly not strict, so always need PHV */
2308  newnode = (Node *)
2310  (Expr *) newnode,
2311  bms_make_singleton(rcon->varno));
2312  /* cache it with the PHV, and with varlevelsup still zero */
2313  rcon->rv_cache[InvalidAttrNumber] = copyObject(newnode);
2314  }
2315  }
2316  else
2317  {
2318  /* Normal case referencing one targetlist element */
2319  TargetEntry *tle = get_tle_by_resno(rcon->targetlist, varattno);
2320 
2321  if (tle == NULL) /* shouldn't happen */
2322  elog(ERROR, "could not find attribute %d in subquery targetlist",
2323  varattno);
2324 
2325  /* Make a copy of the tlist item to return */
2326  newnode = (Node *) copyObject(tle->expr);
2327 
2328  /* Insert PlaceHolderVar if needed */
2329  if (rcon->need_phvs)
2330  {
2331  bool wrap;
2332 
2333  if (newnode && IsA(newnode, Var) &&
2334  ((Var *) newnode)->varlevelsup == 0)
2335  {
2336  /*
2337  * Simple Vars always escape being wrapped, unless they are
2338  * lateral references to something outside the subquery being
2339  * pulled up. (Even then, we could omit the PlaceHolderVar if
2340  * the referenced rel is under the same lowest outer join, but
2341  * it doesn't seem worth the trouble to check that.)
2342  */
2343  if (rcon->target_rte->lateral &&
2344  !bms_is_member(((Var *) newnode)->varno, rcon->relids))
2345  wrap = true;
2346  else
2347  wrap = false;
2348  }
2349  else if (newnode && IsA(newnode, PlaceHolderVar) &&
2350  ((PlaceHolderVar *) newnode)->phlevelsup == 0)
2351  {
2352  /* No need to wrap a PlaceHolderVar with another one, either */
2353  wrap = false;
2354  }
2355  else if (rcon->wrap_non_vars)
2356  {
2357  /* Wrap all non-Vars in a PlaceHolderVar */
2358  wrap = true;
2359  }
2360  else
2361  {
2362  /*
2363  * If it contains a Var of the subquery being pulled up, and
2364  * does not contain any non-strict constructs, then it's
2365  * certainly nullable so we don't need to insert a
2366  * PlaceHolderVar.
2367  *
2368  * This analysis could be tighter: in particular, a non-strict
2369  * construct hidden within a lower-level PlaceHolderVar is not
2370  * reason to add another PHV. But for now it doesn't seem
2371  * worth the code to be more exact.
2372  *
2373  * Note: in future maybe we should insert a PlaceHolderVar
2374  * anyway, if the tlist item is expensive to evaluate?
2375  *
2376  * For a LATERAL subquery, we have to check the actual var
2377  * membership of the node, but if it's non-lateral then any
2378  * level-zero var must belong to the subquery.
2379  */
2380  if ((rcon->target_rte->lateral ?
2381  bms_overlap(pull_varnos(rcon->root, (Node *) newnode),
2382  rcon->relids) :
2383  contain_vars_of_level((Node *) newnode, 0)) &&
2384  !contain_nonstrict_functions((Node *) newnode))
2385  {
2386  /* No wrap needed */
2387  wrap = false;
2388  }
2389  else
2390  {
2391  /* Else wrap it in a PlaceHolderVar */
2392  wrap = true;
2393  }
2394  }
2395 
2396  if (wrap)
2397  newnode = (Node *)
2399  (Expr *) newnode,
2400  bms_make_singleton(rcon->varno));
2401 
2402  /*
2403  * Cache it if possible (ie, if the attno is in range, which it
2404  * probably always should be). We can cache the value even if we
2405  * decided we didn't need a PHV, since this result will be
2406  * suitable for any request that has need_phvs.
2407  */
2408  if (varattno > InvalidAttrNumber &&
2409  varattno <= list_length(rcon->targetlist))
2410  rcon->rv_cache[varattno] = copyObject(newnode);
2411  }
2412  }
2413 
2414  /* Must adjust varlevelsup if tlist item is from higher query */
2415  if (var->varlevelsup > 0)
2416  IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
2417 
2418  return newnode;
2419 }
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
List * args
Definition: primnodes.h:1058
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Index varlevelsup
Definition: primnodes.h:196
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:776
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
Definition: placeholder.c:39
#define ERROR
Definition: elog.h:46
List * colnames
Definition: primnodes.h:1074
RangeTblEntry * target_rte
Definition: prepjointree.c:47
Node * replace_rte_variables_mutator(Node *node, replace_rte_variables_context *context)
Oid vartype
Definition: primnodes.h:193
int location
Definition: primnodes.h:201
int location
Definition: primnodes.h:1075
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
Index varno
Definition: primnodes.h:189
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
#define makeNode(_type_)
Definition: nodes.h:587
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:396
Expr * expr
Definition: primnodes.h:1444
Oid row_typeid
Definition: primnodes.h:1059
static int list_length(const List *l)
Definition: pg_list.h:149
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
#define elog(elevel,...)
Definition: elog.h:232
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
bool contain_nonstrict_functions(Node *clause)
Definition: clauses.c:875
#define copyObject(obj)
Definition: nodes.h:655
CoercionForm row_format
Definition: primnodes.h:1073
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ pullup_replace_vars_subquery()

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

Definition at line 2429 of file prepjointree.c.

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

Referenced by replace_vars_in_jointree().

2431 {
2432  Assert(IsA(query, Query));
2433  return (Query *) replace_rte_variables((Node *) query,
2434  context->varno, 1,
2436  (void *) context,
2437  NULL);
2438 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static Node * pullup_replace_vars_callback(Var *var, replace_rte_variables_context *context)
Definition: nodes.h:539
#define Assert(condition)
Definition: c.h:804
Node * replace_rte_variables(Node *node, int target_varno, int sublevels_up, replace_rte_variables_callback callback, void *callback_arg, bool *outer_hasSubLinks)

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 2574 of file prepjointree.c.

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

Referenced by subquery_planner().

2575 {
2577 
2578  /*
2579  * To avoid doing strictness checks on more quals than necessary, we want
2580  * to stop descending the jointree as soon as there are no outer joins
2581  * below our current point. This consideration forces a two-pass process.
2582  * The first pass gathers information about which base rels appear below
2583  * each side of each join clause, and about whether there are outer
2584  * join(s) below each side of each join clause. The second pass examines
2585  * qual clauses and changes join types as it descends the tree.
2586  */
2587  state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2588 
2589  /* planner.c shouldn't have called me if no outer joins */
2590  if (state == NULL || !state->contains_outer)
2591  elog(ERROR, "so where are the outer joins?");
2592 
2594  state, root, NULL, NIL, NIL);
2595 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
#define ERROR
Definition: elog.h:46
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
Definition: regguts.h:317
#define elog(elevel,...)
Definition: elog.h:232
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *nonnullable_vars, List *forced_null_vars)

◆ reduce_outer_joins_pass1()

static reduce_outer_joins_state * reduce_outer_joins_pass1 ( Node jtnode)
static

Definition at line 2603 of file prepjointree.c.

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

Referenced by reduce_outer_joins().

2604 {
2605  reduce_outer_joins_state *result;
2606 
2607  result = (reduce_outer_joins_state *)
2609  result->relids = NULL;
2610  result->contains_outer = false;
2611  result->sub_states = NIL;
2612 
2613  if (jtnode == NULL)
2614  return result;
2615  if (IsA(jtnode, RangeTblRef))
2616  {
2617  int varno = ((RangeTblRef *) jtnode)->rtindex;
2618 
2619  result->relids = bms_make_singleton(varno);
2620  }
2621  else if (IsA(jtnode, FromExpr))
2622  {
2623  FromExpr *f = (FromExpr *) jtnode;
2624  ListCell *l;
2625 
2626  foreach(l, f->fromlist)
2627  {
2628  reduce_outer_joins_state *sub_state;
2629 
2630  sub_state = reduce_outer_joins_pass1(lfirst(l));
2631  result->relids = bms_add_members(result->relids,
2632  sub_state->relids);
2633  result->contains_outer |= sub_state->contains_outer;
2634  result->sub_states = lappend(result->sub_states, sub_state);
2635  }
2636  }
2637  else if (IsA(jtnode, JoinExpr))
2638  {
2639  JoinExpr *j = (JoinExpr *) jtnode;
2640  reduce_outer_joins_state *sub_state;
2641 
2642  /* join's own RT index is not wanted in result->relids */
2643  if (IS_OUTER_JOIN(j->jointype))
2644  result->contains_outer = true;
2645 
2646  sub_state = reduce_outer_joins_pass1(j->larg);
2647  result->relids = bms_add_members(result->relids,
2648  sub_state->relids);
2649  result->contains_outer |= sub_state->contains_outer;
2650  result->sub_states = lappend(result->sub_states, sub_state);
2651 
2652  sub_state = reduce_outer_joins_pass1(j->rarg);
2653  result->relids = bms_add_members(result->relids,
2654  sub_state->relids);
2655  result->contains_outer |= sub_state->contains_outer;
2656  result->sub_states = lappend(result->sub_states, sub_state);
2657  }
2658  else
2659  elog(ERROR, "unrecognized node type: %d",
2660  (int) nodeTag(jtnode));
2661  return result;
2662 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:755
List * fromlist
Definition: primnodes.h:1553
Node * larg
Definition: primnodes.h:1532
#define ERROR
Definition: elog.h:46
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
List * lappend(List *list, void *datum)
Definition: list.c:336
Node * rarg
Definition: primnodes.h:1533
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
JoinType jointype
Definition: primnodes.h:1530
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ reduce_outer_joins_pass2()

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

Definition at line 2675 of file prepjointree.c.

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

Referenced by reduce_outer_joins().

2681 {
2682  /*
2683  * pass 2 should never descend as far as an empty subnode or base rel,
2684  * because it's only called on subtrees marked as contains_outer.
2685  */
2686  if (jtnode == NULL)
2687  elog(ERROR, "reached empty jointree");
2688  if (IsA(jtnode, RangeTblRef))
2689  elog(ERROR, "reached base rel");
2690  else if (IsA(jtnode, FromExpr))
2691  {
2692  FromExpr *f = (FromExpr *) jtnode;
2693  ListCell *l;
2694  ListCell *s;
2695  Relids pass_nonnullable_rels;
2696  List *pass_nonnullable_vars;
2697  List *pass_forced_null_vars;
2698 
2699  /* Scan quals to see if we can add any constraints */
2700  pass_nonnullable_rels = find_nonnullable_rels(f->quals);
2701  pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
2702  nonnullable_rels);
2703  pass_nonnullable_vars = find_nonnullable_vars(f->quals);
2704  pass_nonnullable_vars = list_concat(pass_nonnullable_vars,
2705  nonnullable_vars);
2706  pass_forced_null_vars = find_forced_null_vars(f->quals);
2707  pass_forced_null_vars = list_concat(pass_forced_null_vars,
2708  forced_null_vars);
2709  /* And recurse --- but only into interesting subtrees */
2711  forboth(l, f->fromlist, s, state->sub_states)
2712  {
2713  reduce_outer_joins_state *sub_state = lfirst(s);
2714 
2715  if (sub_state->contains_outer)
2716  reduce_outer_joins_pass2(lfirst(l), sub_state, root,
2717  pass_nonnullable_rels,
2718  pass_nonnullable_vars,
2719  pass_forced_null_vars);
2720  }
2721  bms_free(pass_nonnullable_rels);
2722  /* can't so easily clean up var lists, unfortunately */
2723  }
2724  else if (IsA(jtnode, JoinExpr))
2725  {
2726  JoinExpr *j = (JoinExpr *) jtnode;
2727  int rtindex = j->rtindex;
2728  JoinType jointype = j->jointype;
2729  reduce_outer_joins_state *left_state = linitial(state->sub_states);
2730  reduce_outer_joins_state *right_state = lsecond(state->sub_states);
2731  List *local_nonnullable_vars = NIL;
2732  bool computed_local_nonnullable_vars = false;
2733 
2734  /* Can we simplify this join? */
2735  switch (jointype)
2736  {
2737  case JOIN_INNER:
2738  break;
2739  case JOIN_LEFT:
2740  if (bms_overlap(nonnullable_rels, right_state->relids))
2741  jointype = JOIN_INNER;
2742  break;
2743  case JOIN_RIGHT:
2744  if (bms_overlap(nonnullable_rels, left_state->relids))
2745  jointype = JOIN_INNER;
2746  break;
2747  case JOIN_FULL:
2748  if (bms_overlap(nonnullable_rels, left_state->relids))
2749  {
2750  if (bms_overlap(nonnullable_rels, right_state->relids))
2751  jointype = JOIN_INNER;
2752  else
2753  jointype = JOIN_LEFT;
2754  }
2755  else
2756  {
2757  if (bms_overlap(nonnullable_rels, right_state->relids))
2758  jointype = JOIN_RIGHT;
2759  }
2760  break;
2761  case JOIN_SEMI:
2762  case JOIN_ANTI:
2763 
2764  /*
2765  * These could only have been introduced by pull_up_sublinks,
2766  * so there's no way that upper quals could refer to their
2767  * righthand sides, and no point in checking.
2768  */
2769  break;
2770  default:
2771  elog(ERROR, "unrecognized join type: %d",
2772  (int) jointype);
2773  break;
2774  }
2775 
2776  /*
2777  * Convert JOIN_RIGHT to JOIN_LEFT. Note that in the case where we
2778  * reduced JOIN_FULL to JOIN_RIGHT, this will mean the JoinExpr no
2779  * longer matches the internal ordering of any CoalesceExpr's built to
2780  * represent merged join variables. We don't care about that at
2781  * present, but be wary of it ...
2782  */
2783  if (jointype == JOIN_RIGHT)
2784  {
2785  Node *tmparg;
2786 
2787  tmparg = j->larg;
2788  j->larg = j->rarg;
2789  j->rarg = tmparg;
2790  jointype = JOIN_LEFT;
2791  right_state = linitial(state->sub_states);
2792  left_state = lsecond(state->sub_states);
2793  }
2794 
2795  /*
2796  * See if we can reduce JOIN_LEFT to JOIN_ANTI. This is the case if
2797  * the join's own quals are strict for any var that was forced null by
2798  * higher qual levels. NOTE: there are other ways that we could
2799  * detect an anti-join, in particular if we were to check whether Vars
2800  * coming from the RHS must be non-null because of table constraints.
2801  * That seems complicated and expensive though (in particular, one
2802  * would have to be wary of lower outer joins). For the moment this
2803  * seems sufficient.
2804  */
2805  if (jointype == JOIN_LEFT)
2806  {
2807  List *overlap;
2808 
2809  local_nonnullable_vars = find_nonnullable_vars(j->quals);
2810  computed_local_nonnullable_vars = true;
2811 
2812  /*
2813  * It's not sufficient to check whether local_nonnullable_vars and
2814  * forced_null_vars overlap: we need to know if the overlap
2815  * includes any RHS variables.
2816  */
2817  overlap = list_intersection(local_nonnullable_vars,
2818  forced_null_vars);
2819  if (overlap != NIL &&
2820  bms_overlap(pull_varnos(root, (Node *) overlap),
2821  right_state->relids))
2822  jointype = JOIN_ANTI;
2823  }
2824 
2825  /* Apply the jointype change, if any, to both jointree node and RTE */
2826  if (rtindex && jointype != j->jointype)
2827  {
2828  RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
2829 
2830  Assert(rte->rtekind == RTE_JOIN);
2831  Assert(rte->jointype == j->jointype);
2832  rte->jointype = jointype;
2833  }
2834  j->jointype = jointype;
2835 
2836  /* Only recurse if there's more to do below here */
2837  if (left_state->contains_outer || right_state->contains_outer)
2838  {
2839  Relids local_nonnullable_rels;
2840  List *local_forced_null_vars;
2841  Relids pass_nonnullable_rels;
2842  List *pass_nonnullable_vars;
2843  List *pass_forced_null_vars;
2844 
2845  /*
2846  * If this join is (now) inner, we can add any constraints its
2847  * quals provide to those we got from above. But if it is outer,
2848  * we can pass down the local constraints only into the nullable
2849  * side, because an outer join never eliminates any rows from its
2850  * non-nullable side. Also, there is no point in passing upper
2851  * constraints into the nullable side, since if there were any
2852  * we'd have been able to reduce the join. (In the case of upper
2853  * forced-null constraints, we *must not* pass them into the
2854  * nullable side --- they either applied here, or not.) The upshot
2855  * is that we pass either the local or the upper constraints,
2856  * never both, to the children of an outer join.
2857  *
2858  * Note that a SEMI join works like an inner join here: it's okay
2859  * to pass down both local and upper constraints. (There can't be
2860  * any upper constraints affecting its inner side, but it's not
2861  * worth having a separate code path to avoid passing them.)
2862  *
2863  * At a FULL join we just punt and pass nothing down --- is it
2864  * possible to be smarter?
2865  */
2866  if (jointype != JOIN_FULL)
2867  {
2868  local_nonnullable_rels = find_nonnullable_rels(j->quals);
2869  if (!computed_local_nonnullable_vars)
2870  local_nonnullable_vars = find_nonnullable_vars(j->quals);
2871  local_forced_null_vars = find_forced_null_vars(j->quals);
2872  if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2873  {
2874  /* OK to merge upper and local constraints */
2875  local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
2876  nonnullable_rels);
2877  local_nonnullable_vars = list_concat(local_nonnullable_vars,
2878  nonnullable_vars);
2879  local_forced_null_vars = list_concat(local_forced_null_vars,
2880  forced_null_vars);
2881  }
2882  }
2883  else
2884  {
2885  /* no use in calculating these */
2886  local_nonnullable_rels = NULL;
2887  local_forced_null_vars = NIL;
2888  }
2889 
2890  if (left_state->contains_outer)
2891  {
2892  if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2893  {
2894  /* pass union of local and upper constraints */
2895  pass_nonnullable_rels = local_nonnullable_rels;
2896  pass_nonnullable_vars = local_nonnullable_vars;
2897  pass_forced_null_vars = local_forced_null_vars;
2898  }
2899  else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
2900  {
2901  /* can't pass local constraints to non-nullable side */
2902  pass_nonnullable_rels = nonnullable_rels;
2903  pass_nonnullable_vars = nonnullable_vars;
2904  pass_forced_null_vars = forced_null_vars;
2905  }
2906  else
2907  {
2908  /* no constraints pass through JOIN_FULL */
2909  pass_nonnullable_rels = NULL;
2910  pass_nonnullable_vars = NIL;
2911  pass_forced_null_vars = NIL;
2912  }
2913  reduce_outer_joins_pass2(j->larg, left_state, root,
2914  pass_nonnullable_rels,
2915  pass_nonnullable_vars,
2916  pass_forced_null_vars);
2917  }
2918 
2919  if (right_state->contains_outer)
2920  {
2921  if (jointype != JOIN_FULL) /* ie, INNER/LEFT/SEMI/ANTI */
2922  {
2923  /* pass appropriate constraints, per comment above */
2924  pass_nonnullable_rels = local_nonnullable_rels;
2925  pass_nonnullable_vars = local_nonnullable_vars;
2926  pass_forced_null_vars = local_forced_null_vars;
2927  }
2928  else
2929  {
2930  /* no constraints pass through JOIN_FULL */
2931  pass_nonnullable_rels = NULL;
2932  pass_nonnullable_vars = NIL;
2933  pass_forced_null_vars = NIL;
2934  }
2935  reduce_outer_joins_pass2(j->rarg, right_state, root,
2936  pass_nonnullable_rels,
2937  pass_nonnullable_vars,
2938  pass_forced_null_vars);
2939  }
2940  bms_free(local_nonnullable_rels);
2941  }
2942  }
2943  else
2944  elog(ERROR, "unrecognized node type: %d",
2945  (int) nodeTag(jtnode));
2946 }
#define NIL
Definition: pg_list.h:65
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
Definition: nodes.h:539
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
List * fromlist
Definition: primnodes.h:1553
Node * quals
Definition: primnodes.h:1554
#define lsecond(l)
Definition: pg_list.h:179
JoinType
Definition: nodes.h:706
Node * larg
Definition: primnodes.h:1532
List * find_forced_null_vars(Node *node)
Definition: clauses.c:1756
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
Relids find_nonnullable_rels(Node *clause)
Definition: clauses.c:1338
JoinType jointype
Definition: parsenodes.h:1068
List * list_intersection(const List *list1, const List *list2)
Definition: list.c:1033
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * quals
Definition: primnodes.h:1536
List * find_nonnullable_vars(Node *clause)
Definition: clauses.c:1563
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define nodeTag(nodeptr)
Definition: nodes.h:544
RTEKind rtekind
Definition: parsenodes.h:995
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
#define elog(elevel,...)
Definition: elog.h:232
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *nonnullable_vars, List *forced_null_vars)
int rtindex
Definition: primnodes.h:1538
Definition: pg_list.h:50
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ remove_result_refs()

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

Definition at line 3261 of file prepjointree.c.

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

3262 {
3263  /* Fix up PlaceHolderVars as needed */
3264  /* If there are no PHVs anywhere, we can skip this bit */
3265  if (root->glob->lastPHId != 0)
3266  {
3267  Relids subrelids;
3268 
3269  subrelids = get_relids_in_jointree(newjtloc, false);
3270  Assert(!bms_is_empty(subrelids));
3271  substitute_phv_relids((Node *) root->parse, varno, subrelids);
3272  fix_append_rel_relids(root->append_rel_list, varno, subrelids);
3273  }
3274 
3275  /*
3276  * We also need to remove any PlanRowMark referencing the RTE, but we
3277  * postpone that work until we return to remove_useless_result_rtes.
3278  */
3279 }
static void substitute_phv_relids(Node *node, int varno, Relids subrelids)
Query * parse
Definition: pathnodes.h:161
Definition: nodes.h:539
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
PlannerGlobal * glob
Definition: pathnodes.h:163
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
List * append_rel_list
Definition: pathnodes.h:283
Index lastPHId
Definition: pathnodes.h:115
static void fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
#define Assert(condition)
Definition: c.h:804

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

Definition at line 2987 of file prepjointree.c.

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

2988 {
2989  ListCell *cell;
2990 
2991  /* Top level of jointree must always be a FromExpr */
2992  Assert(IsA(root->parse->jointree, FromExpr));
2993  /* Recurse ... */
2994  root->parse->jointree = (FromExpr *)
2996  /* We should still have a FromExpr */
2997  Assert(IsA(root->parse->jointree, FromExpr));
2998 
2999  /*
3000  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3001  * must do that for any RTE_RESULT that we just removed. But one for a
3002  * RTE that we did not remove can be dropped anyway: since the RTE has
3003  * only one possible output row, there is no need for EPQ to mark and
3004  * restore that row.
3005  *
3006  * It's necessary, not optional, to remove the PlanRowMark for a surviving
3007  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3008  * RTE_RESULT, which the executor has no support for.
3009  */
3010  foreach(cell, root->rowMarks)
3011  {
3012  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3013 
3014  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3015  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3016  }
3017 }
List * rowMarks
Definition: pathnodes.h:287
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode)

◆ remove_useless_results_recurse()

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

Definition at line 3026 of file prepjointree.c.

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, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, Query::jointree, JoinExpr::jointype, JoinExpr::larg, lfirst, linitial, list_length(), list_make1, makeFromExpr(), nodeTag, PlannerInfo::parse, JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, remove_result_refs(), and pullup_replace_vars_context::varno.

Referenced by remove_useless_result_rtes().

3027 {
3028  Assert(jtnode != NULL);
3029  if (IsA(jtnode, RangeTblRef))
3030  {
3031  /* Can't immediately do anything with a RangeTblRef */
3032  }
3033  else if (IsA(jtnode, FromExpr))
3034  {
3035  FromExpr *f = (FromExpr *) jtnode;
3036  Relids result_relids = NULL;
3037  ListCell *cell;
3038 
3039  /*
3040  * We can drop RTE_RESULT rels from the fromlist so long as at least
3041  * one child remains, since joining to a one-row table changes
3042  * nothing. (But we can't drop a RTE_RESULT that computes PHV(s) that
3043  * are needed by some sibling. The cleanup transformation below would
3044  * reassign the PHVs to be computed at the join, which is too late for
3045  * the sibling's use.) The easiest way to mechanize this rule is to
3046  * modify the list in-place.
3047  */
3048  foreach(cell, f->fromlist)
3049  {
3050  Node *child = (Node *) lfirst(cell);
3051  int varno;
3052 
3053  /* Recursively transform child ... */
3054  child = remove_useless_results_recurse(root, child);
3055  /* ... and stick it back into the tree */
3056  lfirst(cell) = child;
3057 
3058  /*
3059  * If it's an RTE_RESULT with at least one sibling, and no sibling
3060  * references dependent PHVs, we can drop it. We don't yet know
3061  * what the inner join's final relid set will be, so postpone
3062  * cleanup of PHVs etc till after this loop.
3063  */
3064  if (list_length(f->fromlist) > 1 &&
3065  (varno = get_result_relid(root, child)) != 0 &&
3066  !find_dependent_phvs_in_jointree(root, (Node *) f, varno))
3067  {
3068  f->fromlist = foreach_delete_current(f->fromlist, cell);
3069  result_relids = bms_add_member(result_relids, varno);
3070  }
3071  }
3072 
3073  /*
3074  * Clean up if we dropped any RTE_RESULT RTEs. This is a bit
3075  * inefficient if there's more than one, but it seems better to
3076  * optimize the support code for the single-relid case.
3077  */
3078  if (result_relids)
3079  {
3080  int varno = -1;
3081 
3082  while ((varno = bms_next_member(result_relids, varno)) >= 0)
3083  remove_result_refs(root, varno, (Node *) f);
3084  }
3085 
3086  /*
3087  * If we're not at the top of the jointree, it's valid to simplify a
3088  * degenerate FromExpr into its single child. (At the top, we must
3089  * keep the FromExpr since Query.jointree is required to point to a
3090  * FromExpr.)
3091  */
3092  if (f != root->parse->jointree &&
3093  f->quals == NULL &&
3094  list_length(f->fromlist) == 1)
3095  return (Node *) linitial(f->fromlist);
3096  }
3097  else if (IsA(jtnode, JoinExpr))
3098  {
3099  JoinExpr *j = (JoinExpr *) jtnode;
3100  int varno;
3101 
3102  /* First, recurse */
3103  j->larg = remove_useless_results_recurse(root, j->larg);
3104  j->rarg = remove_useless_results_recurse(root, j->rarg);
3105 
3106  /* Apply join-type-specific optimization rules */
3107  switch (j->jointype)
3108  {
3109  case JOIN_INNER:
3110 
3111  /*
3112  * An inner join is equivalent to a FromExpr, so if either
3113  * side was simplified to an RTE_RESULT rel, we can replace
3114  * the join with a FromExpr with just the other side; and if
3115  * the qual is empty (JOIN ON TRUE) then we can omit the
3116  * FromExpr as well.
3117  *
3118  * Just as in the FromExpr case, we can't simplify if the
3119  * other input rel references any PHVs that are marked as to
3120  * be evaluated at the RTE_RESULT rel, because we can't
3121  * postpone their evaluation in that case. But we only have
3122  * to check this in cases where it's syntactically legal for
3123  * the other input to have a LATERAL reference to the
3124  * RTE_RESULT rel. Only RHSes of inner and left joins are
3125  * allowed to have such refs.
3126  */
3127  if ((varno = get_result_relid(root, j->larg)) != 0 &&
3128  !find_dependent_phvs_in_jointree(root, j->rarg, varno))
3129  {
3130  remove_result_refs(root, varno, j->rarg);
3131  if (j->quals)
3132  jtnode = (Node *)
3133  makeFromExpr(list_make1(j->rarg), j->quals);
3134  else
3135  jtnode = j->rarg;
3136  }
3137  else if ((varno = get_result_relid(root, j->rarg)) != 0)
3138  {
3139  remove_result_refs(root, varno, j->larg);
3140  if (j->quals)
3141  jtnode = (Node *)
3142  makeFromExpr(list_make1(j->larg), j->quals);
3143  else
3144  jtnode = j->larg;
3145  }
3146  break;
3147  case JOIN_LEFT:
3148 
3149  /*
3150  * We can simplify this case if the RHS is an RTE_RESULT, with
3151  * two different possibilities:
3152  *
3153  * If the qual is empty (JOIN ON TRUE), then the join can be
3154  * strength-reduced to a plain inner join, since each LHS row
3155  * necessarily has exactly one join partner. So we can always
3156  * discard the RHS, much as in the JOIN_INNER case above.
3157  * (Again, the LHS could not contain a lateral reference to
3158  * the RHS.)
3159  *
3160  * Otherwise, it's still true that each LHS row should be
3161  * returned exactly once, and since the RHS returns no columns
3162  * (unless there are PHVs that have to be evaluated there), we
3163  * don't much care if it's null-extended or not. So in this
3164  * case also, we can just ignore the qual and discard the left
3165  * join.
3166  */
3167  if ((varno = get_result_relid(root, j->rarg)) != 0 &&
3168  (j->quals == NULL ||
3169  !find_dependent_phvs(root, varno)))
3170  {
3171  remove_result_refs(root, varno, j->larg);
3172  jtnode = j->larg;
3173  }
3174  break;
3175  case JOIN_RIGHT:
3176  /* Mirror-image of the JOIN_LEFT case */
3177  if ((varno = get_result_relid(root, j->larg)) != 0 &&
3178  (j->quals == NULL ||
3179  !find_dependent_phvs(root, varno)))
3180  {
3181  remove_result_refs(root, varno, j->rarg);
3182  jtnode = j->rarg;
3183  }
3184  break;
3185  case JOIN_SEMI:
3186 
3187  /*
3188  * We may simplify this case if the RHS is an RTE_RESULT; the
3189  * join qual becomes effectively just a filter qual for the
3190  * LHS, since we should either return the LHS row or not. For
3191  * simplicity we inject the filter qual into a new FromExpr.
3192  *
3193  * Unlike the LEFT/RIGHT cases, we just Assert that there are
3194  * no PHVs that need to be evaluated at the semijoin's RHS,
3195  * since the rest of the query couldn't reference any outputs
3196  * of the semijoin's RHS.
3197  */
3198  if ((varno = get_result_relid(root, j->rarg)) != 0)
3199  {
3200  Assert(!find_dependent_phvs(root, varno));
3201  remove_result_refs(root, varno, j->larg);
3202  if (j->quals)
3203  jtnode = (Node *)
3204  makeFromExpr(list_make1(j->larg), j->quals);
3205  else
3206  jtnode = j->larg;
3207  }
3208  break;
3209  case JOIN_FULL:
3210  case JOIN_ANTI:
3211  /* We have no special smarts for these cases */
3212  break;
3213  default:
3214  elog(ERROR, "unrecognized join type: %d",
3215  (int) j->jointype);
3216  break;
3217  }
3218  }
3219  else
3220  elog(ERROR, "unrecognized node type: %d",
3221  (int) nodeTag(jtnode));
3222  return jtnode;
3223 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
static int get_result_relid(PlannerInfo *root, Node *jtnode)
FromExpr * jointree
Definition: parsenodes.h:148
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
Definition: nodes.h:539
List * fromlist
Definition: primnodes.h:1553
static bool find_dependent_phvs(PlannerInfo *root, int varno)
static void remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
Node * quals
Definition: primnodes.h:1554
static bool find_dependent_phvs_in_jointree(PlannerInfo *root, Node *node, int varno)
Node * larg
Definition: primnodes.h:1532
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
#define list_make1(x1)
Definition: pg_list.h:206
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
Node * quals
Definition: primnodes.h:1536
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode)

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 150 of file prepjointree.c.

References RangeTblEntry::eref, FromExpr::fromlist, Query::jointree, lappend(), list_length(), list_make1, makeAlias(), makeNode, NIL, Query::rtable, RTE_RESULT, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.

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

151 {
152  RangeTblEntry *rte;
153  Index rti;
154  RangeTblRef *rtr;
155 
156  /* Nothing to do if jointree is already nonempty */
157  if (parse->jointree->fromlist != NIL)
158  return;
159 
160  /* We mustn't change it in the top level of a setop tree, either */
161  if (parse->setOperations)
162  return;
163 
164  /* Create suitable RTE */
165  rte = makeNode(RangeTblEntry);
166  rte->rtekind = RTE_RESULT;
167  rte->eref = makeAlias("*RESULT*", NIL);
168 
169  /* Add it to rangetable */
170  parse->rtable = lappend(parse->rtable, rte);
171  rti = list_length(parse->rtable);
172 
173  /* And jam a reference into the jointree */
174  rtr = makeNode(RangeTblRef);
175  rtr->rtindex = rti;
176  parse->jointree->fromlist = list_make1(rtr);
177 }
#define NIL
Definition: pg_list.h:65
FromExpr * jointree
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1553
#define list_make1(x1)
Definition: pg_list.h:206
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
List * rtable
Definition: parsenodes.h:147
List * lappend(List *list, void *datum)
Definition: list.c:336
unsigned int Index
Definition: c.h:549
#define makeNode(_type_)
Definition: nodes.h:587
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:995
Node * setOperations
Definition: parsenodes.h:177
Alias * eref
Definition: parsenodes.h:1141

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

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

2107 {
2108  if (jtnode == NULL)
2109  return;
2110  if (IsA(jtnode, RangeTblRef))
2111  {
2112  /*
2113  * If the RangeTblRef refers to a LATERAL subquery (that isn't the
2114  * same subquery we're pulling up), it might contain references to the
2115  * target subquery, which we must replace. We drive this from the
2116  * jointree scan, rather than a scan of the rtable, for a couple of
2117  * reasons: we can avoid processing no-longer-referenced RTEs, and we
2118  * can use the appropriate setting of need_phvs depending on whether
2119  * the RTE is above possibly-nulling outer joins or not.
2120  */
2121  int varno = ((RangeTblRef *) jtnode)->rtindex;
2122 
2123  if (varno != context->varno) /* ignore target subquery itself */
2124  {
2125  RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable);
2126 
2127  Assert(rte != context->target_rte);
2128  if (rte->lateral)
2129  {
2130  switch (rte->rtekind)
2131  {
2132  case RTE_RELATION:
2133  /* shouldn't be marked LATERAL unless tablesample */
2134  Assert(rte->tablesample);
2135  rte->tablesample = (TableSampleClause *)
2137  context);
2138  break;
2139  case RTE_SUBQUERY:
2140  rte->subquery =
2142  context);
2143  break;
2144  case RTE_FUNCTION:
2145  rte->functions = (List *)
2147  context);
2148  break;
2149  case RTE_TABLEFUNC:
2150  rte->tablefunc = (TableFunc *)
2152  context);
2153  break;
2154  case RTE_VALUES:
2155  rte->values_lists = (List *)
2157  context);
2158  break;
2159  case RTE_JOIN:
2160  case RTE_CTE:
2161  case RTE_NAMEDTUPLESTORE:
2162  case RTE_RESULT:
2163  /* these shouldn't be marked LATERAL */
2164  Assert(false);
2165  break;
2166  }
2167  }
2168  }
2169  }
2170  else if (IsA(jtnode, FromExpr))
2171  {
2172  FromExpr *f = (FromExpr *) jtnode;
2173  ListCell *l;
2174 
2175  foreach(l, f->fromlist)
2176  replace_vars_in_jointree(lfirst(l), context,
2177  lowest_nulling_outer_join);
2178  f->quals = pullup_replace_vars(f->quals, context);
2179  }
2180  else if (IsA(jtnode, JoinExpr))
2181  {
2182  JoinExpr *j = (JoinExpr *) jtnode;
2183  bool save_need_phvs = context->need_phvs;
2184 
2185  if (j == lowest_nulling_outer_join)
2186  {
2187  /* no more PHVs in or below this join */
2188  context->need_phvs = false;
2189  lowest_nulling_outer_join = NULL;
2190  }
2191  replace_vars_in_jointree(j->larg, context, lowest_nulling_outer_join);
2192  replace_vars_in_jointree(j->rarg, context, lowest_nulling_outer_join);
2193 
2194  /*
2195  * Use PHVs within the join quals of a full join, even when it's the
2196  * lowest nulling outer join. Otherwise, we cannot identify which
2197  * side of the join a pulled-up var-free expression came from, which
2198  * can lead to failure to make a plan at all because none of the quals
2199  * appear to be mergeable or hashable conditions. For this purpose we
2200  * don't care about the state of wrap_non_vars, so leave it alone.
2201  */
2202  if (j->jointype == JOIN_FULL)
2203  context->need_phvs = true;
2204 
2205  j->quals = pullup_replace_vars(j->quals, context);
2206 
2207  /*
2208  * We don't bother to update the colvars list, since it won't be used
2209  * again ...
2210  */
2211  context->need_phvs = save_need_phvs;
2212  }
2213  else
2214  elog(ERROR, "unrecognized node type: %d",
2215  (int) nodeTag(jtnode));
2216 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
Definition: nodes.h:539
List * fromlist
Definition: primnodes.h:1553
List * values_lists
Definition: parsenodes.h:1100
Node * quals
Definition: primnodes.h:1554
Node * larg
Definition: primnodes.h:1532
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
RangeTblEntry * target_rte
Definition: prepjointree.c:47
TableFunc * tablefunc
Definition: parsenodes.h:1095
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Node * quals
Definition: primnodes.h:1536
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1089
#define nodeTag(nodeptr)
Definition: nodes.h:544
RTEKind rtekind
Definition: parsenodes.h:995
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
Query * subquery
Definition: parsenodes.h:1030
static Query * pullup_replace_vars_subquery(Query *query, pullup_replace_vars_context *context)
#define elog(elevel,...)
Definition: elog.h:232
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1025

◆ substitute_phv_relids()

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

Definition at line 3463 of file prepjointree.c.

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

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

3464 {
3466 
3467  context.varno = varno;
3468  context.sublevels_up = 0;
3469  context.subrelids = subrelids;
3470 
3471  /*
3472  * Must be prepared to start with a Query or a bare expression tree.
3473  */
3476  (void *) &context,
3477  0);
3478 }
static bool substitute_phv_relids_walker(Node *node, substitute_phv_relids_context *context)
bool query_or_expression_tree_walker(Node *node, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:3461

◆ substitute_phv_relids_walker()

static bool substitute_phv_relids_walker ( Node node,
substitute_phv_relids_context context 
)
static

Definition at line 3419 of file prepjointree.c.

References Assert, bms_del_member(), bms_is_empty(), bms_is_member(), bms_union(), expression_tree_walker(), IsA, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, 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().

3421 {
3422  if (node == NULL)
3423  return false;
3424  if (IsA(node, PlaceHolderVar))
3425  {
3426  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3427 
3428  if (phv->phlevelsup == context->sublevels_up &&
3429  bms_is_member(context->varno, phv->phrels))
3430  {
3431  phv->phrels = bms_union(phv->phrels,
3432  context->subrelids);
3433  phv->phrels = bms_del_member(phv->phrels,
3434  context->varno);
3435  /* Assert we haven't broken the PHV */
3436  Assert(!bms_is_empty(phv->phrels));
3437  }
3438  /* fall through to examine children */
3439  }
3440  if (IsA(node, Query))
3441  {
3442  /* Recurse into subselects */
3443  bool result;
3444 
3445  context->sublevels_up++;
3446  result = query_tree_walker((Query *) node,
3448  (void *) context, 0);
3449  context->sublevels_up--;
3450  return result;
3451  }
3452  /* Shouldn't need to handle planner auxiliary nodes here */
3453  Assert(!IsA(node, SpecialJoinInfo));
3454  Assert(!IsA(node, AppendRelInfo));
3455  Assert(!IsA(node, PlaceHolderInfo));
3456  Assert(!IsA(node, MinMaxAggInfo));
3457 
3459  (void *) context);
3460 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static bool substitute_phv_relids_walker(Node *node, substitute_phv_relids_context *context)
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define Assert(condition)
Definition: c.h:804
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
Index phlevelsup
Definition: pathnodes.h:2173
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:773
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427