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

3324 {
3326 
3327  /* If there are no PHVs anywhere, we needn't work hard */
3328  if (root->glob->lastPHId == 0)
3329  return false;
3330 
3331  context.relids = bms_make_singleton(varno);
3332  context.sublevels_up = 0;
3333 
3334  return query_tree_walker(root->parse,
3336  (void *) &context,
3337  0);
3338 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
Query * parse
Definition: pathnodes.h:179
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:181
Index lastPHId
Definition: pathnodes.h:133

◆ find_dependent_phvs_in_jointree()

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

Definition at line 3341 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().

3342 {
3344  Relids subrelids;
3345  int relid;
3346 
3347  /* If there are no PHVs anywhere, we needn't work hard */
3348  if (root->glob->lastPHId == 0)
3349  return false;
3350 
3351  context.relids = bms_make_singleton(varno);
3352  context.sublevels_up = 0;
3353 
3354  /*
3355  * See if the jointree fragment itself contains references (in join quals)
3356  */
3357  if (find_dependent_phvs_walker(node, &context))
3358  return true;
3359 
3360  /*
3361  * Otherwise, identify the set of referenced RTEs (we can ignore joins,
3362  * since they should be flattened already, so their join alias lists no
3363  * longer matter), and tediously check each RTE. We can ignore RTEs that
3364  * are not marked LATERAL, though, since they couldn't possibly contain
3365  * any cross-references to other RTEs.
3366  */
3367  subrelids = get_relids_in_jointree(node, false);
3368  relid = -1;
3369  while ((relid = bms_next_member(subrelids, relid)) >= 0)
3370  {
3371  RangeTblEntry *rte = rt_fetch(relid, root->parse->rtable);
3372 
3373  if (rte->lateral &&
3376  (void *) &context,
3377  0))
3378  return true;
3379  }
3380 
3381  return false;
3382 }
Query * parse
Definition: pathnodes.h:179
bool range_table_entry_walker(RangeTblEntry *rte, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2393
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:137
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:181
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Index lastPHId
Definition: pathnodes.h:133

◆ find_dependent_phvs_walker()

static bool find_dependent_phvs_walker ( Node node,
find_dependent_phvs_context context 
)
static

Definition at line 3286 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().

3288 {
3289  if (node == NULL)
3290  return false;
3291  if (IsA(node, PlaceHolderVar))
3292  {
3293  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3294 
3295  if (phv->phlevelsup == context->sublevels_up &&
3296  bms_equal(context->relids, phv->phrels))
3297  return true;
3298  /* fall through to examine children */
3299  }
3300  if (IsA(node, Query))
3301  {
3302  /* Recurse into subselects */
3303  bool result;
3304 
3305  context->sublevels_up++;
3306  result = query_tree_walker((Query *) node,
3308  (void *) context, 0);
3309  context->sublevels_up--;
3310  return result;
3311  }
3312  /* Shouldn't need to handle planner auxiliary nodes here */
3313  Assert(!IsA(node, SpecialJoinInfo));
3314  Assert(!IsA(node, AppendRelInfo));
3315  Assert(!IsA(node, PlaceHolderInfo));
3316  Assert(!IsA(node, MinMaxAggInfo));
3317 
3319  (void *) context);
3320 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
static bool find_dependent_phvs_walker(Node *node, find_dependent_phvs_context *context)
#define Assert(condition)
Definition: c.h:738
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
Index phlevelsup
Definition: pathnodes.h:2067
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 3576 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().

3577 {
3578  if (jtnode == NULL)
3579  return NULL;
3580  if (IsA(jtnode, RangeTblRef))
3581  {
3582  int varno = ((RangeTblRef *) jtnode)->rtindex;
3583 
3584  if (relid == varno)
3585  return jtnode;
3586  }
3587  else if (IsA(jtnode, FromExpr))
3588  {
3589  FromExpr *f = (FromExpr *) jtnode;
3590  ListCell *l;
3591 
3592  foreach(l, f->fromlist)
3593  {
3594  jtnode = find_jointree_node_for_rel(lfirst(l), relid);
3595  if (jtnode)
3596  return jtnode;
3597  }
3598  }
3599  else if (IsA(jtnode, JoinExpr))
3600  {
3601  JoinExpr *j = (JoinExpr *) jtnode;
3602 
3603  if (relid == j->rtindex)
3604  return jtnode;
3605  jtnode = find_jointree_node_for_rel(j->larg, relid);
3606  if (jtnode)
3607  return jtnode;
3608  jtnode = find_jointree_node_for_rel(j->rarg, relid);
3609  if (jtnode)
3610  return jtnode;
3611  }
3612  else
3613  elog(ERROR, "unrecognized node type: %d",
3614  (int) nodeTag(jtnode));
3615  return NULL;
3616 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * fromlist
Definition: primnodes.h:1510
Node * larg
Definition: primnodes.h:1490
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:43
Node * rarg
Definition: primnodes.h:1491
#define lfirst(lc)
Definition: pg_list.h:190
#define nodeTag(nodeptr)
Definition: nodes.h:530
#define elog(elevel,...)
Definition: elog.h:228
int rtindex
Definition: primnodes.h:1495

◆ fix_append_rel_relids()

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

Definition at line 3477 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().

3478 {
3479  ListCell *l;
3480  int subvarno = -1;
3481 
3482  /*
3483  * We only want to extract the member relid once, but we mustn't fail
3484  * immediately if there are multiple members; it could be that none of the
3485  * AppendRelInfo nodes refer to it. So compute it on first use. Note that
3486  * bms_singleton_member will complain if set is not singleton.
3487  */
3488  foreach(l, append_rel_list)
3489  {
3490  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
3491 
3492  /* The parent_relid shouldn't ever be a pullup target */
3493  Assert(appinfo->parent_relid != varno);
3494 
3495  if (appinfo->child_relid == varno)
3496  {
3497  if (subvarno < 0)
3498  subvarno = bms_singleton_member(subrelids);
3499  appinfo->child_relid = subvarno;
3500  }
3501 
3502  /* Also fix up any PHVs in its translated vars */
3504  varno, subrelids);
3505  }
3506 }
static void substitute_phv_relids(Node *node, int varno, Relids subrelids)
Definition: nodes.h:525
List * translated_vars
Definition: pathnodes.h:2217
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:577
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
Index child_relid
Definition: pathnodes.h:2190
Index parent_relid
Definition: pathnodes.h:2189

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2443 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().

2444 {
2445  Query *parse = root->parse;
2446  SetOperationStmt *topop;
2447  Node *leftmostjtnode;
2448  int leftmostRTI;
2449  RangeTblEntry *leftmostRTE;
2450  int childRTI;
2451  RangeTblEntry *childRTE;
2452  RangeTblRef *rtr;
2453 
2454  /* Shouldn't be called unless query has setops */
2455  topop = castNode(SetOperationStmt, parse->setOperations);
2456  Assert(topop);
2457 
2458  /* Can't optimize away a recursive UNION */
2459  if (root->hasRecursion)
2460  return;
2461 
2462  /*
2463  * Recursively check the tree of set operations. If not all UNION ALL
2464  * with identical column types, punt.
2465  */
2466  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2467  return;
2468 
2469  /*
2470  * Locate the leftmost leaf query in the setops tree. The upper query's
2471  * Vars all refer to this RTE (see transformSetOperationStmt).
2472  */
2473  leftmostjtnode = topop->larg;
2474  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2475  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2476  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2477  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2478  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2479  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2480 
2481  /*
2482  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2483  * will represent the leftmost leaf query in its capacity as a member of
2484  * the appendrel. The original will represent the appendrel as a whole.
2485  * (We must do things this way because the upper query's Vars have to be
2486  * seen as referring to the whole appendrel.)
2487  */
2488  childRTE = copyObject(leftmostRTE);
2489  parse->rtable = lappend(parse->rtable, childRTE);
2490  childRTI = list_length(parse->rtable);
2491 
2492  /* Modify the setops tree to reference the child copy */
2493  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2494 
2495  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2496  leftmostRTE->inh = true;
2497 
2498  /*
2499  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2500  * Query of a setops tree should have had an empty FromClause initially.
2501  */
2502  rtr = makeNode(RangeTblRef);
2503  rtr->rtindex = leftmostRTI;
2504  Assert(parse->jointree->fromlist == NIL);
2505  parse->jointree->fromlist = list_make1(rtr);
2506 
2507  /*
2508  * Now pretend the query has no setops. We must do this before trying to
2509  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2510  */
2511  parse->setOperations = NULL;
2512 
2513  /*
2514  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2515  * leaf queries of the UNION ALL. (We must do that now because they
2516  * weren't previously referenced by the jointree, and so were missed by
2517  * the main invocation of pull_up_subqueries.)
2518  */
2519  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2520 }
#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:576
Query * parse
Definition: pathnodes.h:179
FromExpr * jointree
Definition: parsenodes.h:138
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Definition: nodes.h:525
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * fromlist
Definition: primnodes.h:1510
bool hasRecursion
Definition: pathnodes.h:350
#define list_make1(x1)
Definition: pg_list.h:227
List * rtable
Definition: parsenodes.h:137
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:322
#define makeNode(_type_)
Definition: nodes.h:573
#define Assert(condition)
Definition: c.h:738
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
Node * setOperations
Definition: parsenodes.h:165
#define copyObject(obj)
Definition: nodes.h:641
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:648

◆ get_relids_for_join()

Relids get_relids_for_join ( Query query,
int  joinrelid 
)

Definition at line 3559 of file prepjointree.c.

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

Referenced by alias_relid_set().

3560 {
3561  Node *jtnode;
3562 
3563  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3564  joinrelid);
3565  if (!jtnode)
3566  elog(ERROR, "could not find join node %d", joinrelid);
3567  return get_relids_in_jointree(jtnode, false);
3568 }
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:525
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:43
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define elog(elevel,...)
Definition: elog.h:228

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 3515 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(), pull_up_simple_subquery(), and remove_result_refs().

3516 {
3517  Relids result = NULL;
3518 
3519  if (jtnode == NULL)
3520  return result;
3521  if (IsA(jtnode, RangeTblRef))
3522  {
3523  int varno = ((RangeTblRef *) jtnode)->rtindex;
3524 
3525  result = bms_make_singleton(varno);
3526  }
3527  else if (IsA(jtnode, FromExpr))
3528  {
3529  FromExpr *f = (FromExpr *) jtnode;
3530  ListCell *l;
3531 
3532  foreach(l, f->fromlist)
3533  {
3534  result = bms_join(result,
3536  include_joins));
3537  }
3538  }
3539  else if (IsA(jtnode, JoinExpr))
3540  {
3541  JoinExpr *j = (JoinExpr *) jtnode;
3542 
3543  result = get_relids_in_jointree(j->larg, include_joins);
3544  result = bms_join(result,
3545  get_relids_in_jointree(j->rarg, include_joins));
3546  if (include_joins && j->rtindex)
3547  result = bms_add_member(result, j->rtindex);
3548  }
3549  else
3550  elog(ERROR, "unrecognized node type: %d",
3551  (int) nodeTag(jtnode));
3552  return result;
3553 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * fromlist
Definition: primnodes.h:1510
Node * larg
Definition: primnodes.h:1490
#define ERROR
Definition: elog.h:43
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:1491
#define lfirst(lc)
Definition: pg_list.h:190
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:530
#define elog(elevel,...)
Definition: elog.h:228
int rtindex
Definition: primnodes.h:1495

◆ get_result_relid()

static int get_result_relid ( PlannerInfo root,
Node jtnode 
)
static

Definition at line 3218 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().

3219 {
3220  int varno;
3221 
3222  if (!IsA(jtnode, RangeTblRef))
3223  return 0;
3224  varno = ((RangeTblRef *) jtnode)->rtindex;
3225  if (rt_fetch(varno, root->parse->rtable)->rtekind != RTE_RESULT)
3226  return 0;
3227  return varno;
3228 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:179
List * rtable
Definition: parsenodes.h:137
#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 1884 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().

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

◆ is_simple_subquery()

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

Definition at line 1401 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().

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

◆ is_simple_union_all()

static bool is_simple_union_all ( Query subquery)
static

Definition at line 1816 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().

1817 {
1818  SetOperationStmt *topop;
1819 
1820  /* Let's just make sure it's a valid subselect ... */
1821  if (!IsA(subquery, Query) ||
1822  subquery->commandType != CMD_SELECT)
1823  elog(ERROR, "subquery is bogus");
1824 
1825  /* Is it a set-operation query at all? */
1826  topop = castNode(SetOperationStmt, subquery->setOperations);
1827  if (!topop)
1828  return false;
1829 
1830  /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
1831  if (subquery->sortClause ||
1832  subquery->limitOffset ||
1833  subquery->limitCount ||
1834  subquery->rowMarks ||
1835  subquery->cteList)
1836  return false;
1837 
1838  /* Recursively check the tree of set operations */
1839  return is_simple_union_all_recurse((Node *) topop, subquery,
1840  topop->colTypes);
1841 }
Node * limitOffset
Definition: parsenodes.h:160
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * sortClause
Definition: parsenodes.h:158
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Definition: nodes.h:525
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * rowMarks
Definition: parsenodes.h:163
#define ERROR
Definition: elog.h:43
Node * limitCount
Definition: parsenodes.h:161
CmdType commandType
Definition: parsenodes.h:112
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
#define elog(elevel,...)
Definition: elog.h:228

◆ is_simple_union_all_recurse()

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

Definition at line 1844 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().

1845 {
1846  if (IsA(setOp, RangeTblRef))
1847  {
1848  RangeTblRef *rtr = (RangeTblRef *) setOp;
1849  RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
1850  Query *subquery = rte->subquery;
1851 
1852  Assert(subquery != NULL);
1853 
1854  /* Leaf nodes are OK if they match the toplevel column types */
1855  /* We don't have to compare typmods or collations here */
1856  return tlist_same_datatypes(subquery->targetList, colTypes, true);
1857  }
1858  else if (IsA(setOp, SetOperationStmt))
1859  {
1860  SetOperationStmt *op = (SetOperationStmt *) setOp;
1861 
1862  /* Must be UNION ALL */
1863  if (op->op != SETOP_UNION || !op->all)
1864  return false;
1865 
1866  /* Recurse to check inputs */
1867  return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
1868  is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
1869  }
1870  else
1871  {
1872  elog(ERROR, "unrecognized node type: %d",
1873  (int) nodeTag(setOp));
1874  return false; /* keep compiler quiet */
1875  }
1876 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition: tlist.c:270
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define Assert(condition)
Definition: c.h:738
SetOperation op
Definition: parsenodes.h:1655
#define nodeTag(nodeptr)
Definition: nodes.h:530
Query * subquery
Definition: parsenodes.h:1009
#define elog(elevel,...)
Definition: elog.h:228

◆ is_simple_values()

static bool is_simple_values ( PlannerInfo root,
RangeTblEntry rte 
)
static

Definition at line 1631 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().

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

◆ jointree_contains_lateral_outer_refs()

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

Definition at line 1932 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().

1934 {
1935  if (jtnode == NULL)
1936  return false;
1937  if (IsA(jtnode, RangeTblRef))
1938  return false;
1939  else if (IsA(jtnode, FromExpr))
1940  {
1941  FromExpr *f = (FromExpr *) jtnode;
1942  ListCell *l;
1943 
1944  /* First, recurse to check child joins */
1945  foreach(l, f->fromlist)
1946  {
1948  restricted,
1949  safe_upper_varnos))
1950  return true;
1951  }
1952 
1953  /* Then check the top-level quals */
1954  if (restricted &&
1956  safe_upper_varnos))
1957  return true;
1958  }
1959  else if (IsA(jtnode, JoinExpr))
1960  {
1961  JoinExpr *j = (JoinExpr *) jtnode;
1962 
1963  /*
1964  * If this is an outer join, we mustn't allow any upper lateral
1965  * references in or below it.
1966  */
1967  if (j->jointype != JOIN_INNER)
1968  {
1969  restricted = true;
1970  safe_upper_varnos = NULL;
1971  }
1972 
1973  /* Check the child joins */
1975  restricted,
1976  safe_upper_varnos))
1977  return true;
1979  restricted,
1980  safe_upper_varnos))
1981  return true;
1982 
1983  /* Check the JOIN's qual clauses */
1984  if (restricted &&
1986  safe_upper_varnos))
1987  return true;
1988  }
1989  else
1990  elog(ERROR, "unrecognized node type: %d",
1991  (int) nodeTag(jtnode));
1992  return false;
1993 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * fromlist
Definition: primnodes.h:1510
Node * quals
Definition: primnodes.h:1511
Node * larg
Definition: primnodes.h:1490
#define ERROR
Definition: elog.h:43
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Node * quals
Definition: primnodes.h:1493
static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, Relids safe_upper_varnos)
Node * rarg
Definition: primnodes.h:1491
JoinType jointype
Definition: primnodes.h:1488
#define lfirst(lc)
Definition: pg_list.h:190
#define nodeTag(nodeptr)
Definition: nodes.h:530
#define elog(elevel,...)
Definition: elog.h:228
Relids pull_varnos_of_level(Node *node, int levelsup)
Definition: var.c:120

◆ make_setop_translation_list()

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

Definition at line 1363 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().

1365 {
1366  List *vars = NIL;
1367  AttrNumber *pcolnos;
1368  ListCell *l;
1369 
1370  /* Initialize reverse-translation array with all entries zero */
1371  /* (entries for resjunk columns will stay that way) */
1372  appinfo->num_child_cols = list_length(query->targetList);
1373  appinfo->parent_colnos = pcolnos =
1374  (AttrNumber *) palloc0(appinfo->num_child_cols * sizeof(AttrNumber));
1375 
1376  foreach(l, query->targetList)
1377  {
1378  TargetEntry *tle = (TargetEntry *) lfirst(l);
1379 
1380  if (tle->resjunk)
1381  continue;
1382 
1383  vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1384  pcolnos[tle->resno - 1] = tle->resno;
1385  }
1386 
1387  appinfo->translated_vars = vars;
1388 }
#define NIL
Definition: pg_list.h:65
int num_child_cols
Definition: pathnodes.h:2225
AttrNumber * parent_colnos
Definition: pathnodes.h:2226
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:103
List * translated_vars
Definition: pathnodes.h:2217
List * targetList
Definition: parsenodes.h:140
bool resjunk
Definition: primnodes.h:1414
AttrNumber resno
Definition: primnodes.h:1408
List * lappend(List *list, void *datum)
Definition: list.c:322
void * palloc0(Size size)
Definition: mcxt.c:980
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
Definition: regcomp.c:224
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 2004 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().

2008 {
2009  Query *parse = root->parse;
2010  ListCell *lc;
2011 
2012  /*
2013  * Replace all of the top query's references to the subquery's outputs
2014  * with copies of the adjusted subtlist items, being careful not to
2015  * replace any of the jointree structure. (This'd be a lot cleaner if we
2016  * could use query_tree_mutator.) We have to use PHVs in the targetList,
2017  * returningList, and havingQual, since those are certainly above any
2018  * outer join. replace_vars_in_jointree tracks its location in the
2019  * jointree and uses PHVs or not appropriately.
2020  */
2021  parse->targetList = (List *)
2022  pullup_replace_vars((Node *) parse->targetList, rvcontext);
2023  parse->returningList = (List *)
2024  pullup_replace_vars((Node *) parse->returningList, rvcontext);
2025  if (parse->onConflict)
2026  {
2027  parse->onConflict->onConflictSet = (List *)
2029  rvcontext);
2030  parse->onConflict->onConflictWhere =
2032  rvcontext);
2033 
2034  /*
2035  * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
2036  * can't contain any references to a subquery.
2037  */
2038  }
2039  replace_vars_in_jointree((Node *) parse->jointree, rvcontext,
2040  lowest_nulling_outer_join);
2041  Assert(parse->setOperations == NULL);
2042  parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
2043 
2044  /*
2045  * Replace references in the translated_vars lists of appendrels. When
2046  * pulling up an appendrel member, we do not need PHVs in the list of the
2047  * parent appendrel --- there isn't any outer join between. Elsewhere,
2048  * use PHVs for safety. (This analysis could be made tighter but it seems
2049  * unlikely to be worth much trouble.)
2050  */
2051  foreach(lc, root->append_rel_list)
2052  {
2053  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
2054  bool save_need_phvs = rvcontext->need_phvs;
2055 
2056  if (appinfo == containing_appendrel)
2057  rvcontext->need_phvs = false;
2058  appinfo->translated_vars = (List *)
2059  pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
2060  rvcontext->need_phvs = save_need_phvs;
2061  }
2062 
2063  /*
2064  * Replace references in the joinaliasvars lists of join RTEs.
2065  *
2066  * You might think that we could avoid using PHVs for alias vars of joins
2067  * below lowest_nulling_outer_join, but that doesn't work because the
2068  * alias vars could be referenced above that join; we need the PHVs to be
2069  * present in such references after the alias vars get flattened. (It
2070  * might be worth trying to be smarter here, someday.)
2071  */
2072  foreach(lc, parse->rtable)
2073  {
2074  RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
2075 
2076  if (otherrte->rtekind == RTE_JOIN)
2077  otherrte->joinaliasvars = (List *)
2078  pullup_replace_vars((Node *) otherrte->joinaliasvars,
2079  rvcontext);
2080  }
2081 }
Query * parse
Definition: pathnodes.h:179
List * joinaliasvars
Definition: parsenodes.h:1049
FromExpr * jointree
Definition: parsenodes.h:138
OnConflictExpr * onConflict
Definition: parsenodes.h:144
Definition: nodes.h:525
List * translated_vars
Definition: pathnodes.h:2217
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
List * returningList
Definition: parsenodes.h:146
List * append_rel_list
Definition: pathnodes.h:290
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
RTEKind rtekind
Definition: parsenodes.h:974
Node * setOperations
Definition: parsenodes.h:165
static void replace_vars_in_jointree(Node *jtnode, pullup_replace_vars_context *context, JoinExpr *lowest_nulling_outer_join)
List * onConflictSet
Definition: primnodes.h:1535
Node * havingQual
Definition: parsenodes.h:152
Node * onConflictWhere
Definition: primnodes.h:1536
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:648

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 637 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().

638 {
639  ListCell *rt;
640 
641  foreach(rt, root->parse->rtable)
642  {
643  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
644 
645  if (rte->rtekind == RTE_FUNCTION)
646  {
647  Query *funcquery;
648 
649  /* Apply const-simplification */
650  rte->functions = (List *)
651  eval_const_expressions(root, (Node *) rte->functions);
652 
653  /* Check safety of expansion, and expand if possible */
654  funcquery = inline_set_returning_function(root, rte);
655  if (funcquery)
656  {
657  /* Successful expansion, convert the RTE to a subquery */
658  rte->rtekind = RTE_SUBQUERY;
659  rte->subquery = funcquery;
660  rte->security_barrier = false;
661  /* Clear fields that should not be set in a subquery RTE */
662  rte->functions = NIL;
663  rte->funcordinality = false;
664  }
665  }
666  }
667 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:179
Definition: nodes.h:525
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4880
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2252
bool funcordinality
Definition: parsenodes.h:1062
List * rtable
Definition: parsenodes.h:137
bool security_barrier
Definition: parsenodes.h:1010
#define lfirst(lc)
Definition: pg_list.h:190
List * functions
Definition: parsenodes.h:1061
RTEKind rtekind
Definition: parsenodes.h:974
Query * subquery
Definition: parsenodes.h:1009
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 1690 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().

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

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

References 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(), INHKIND_NONE, PlannerInfo::inhTargetKind, PlannerInfo::init_plans, is_safe_append_member(), is_simple_subquery(), IsA, PlannerInfo::join_info_list, PlannerGlobal::lastPHId, RangeTblEntry::lateral, 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, 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::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().

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

◆ pull_up_simple_union_all()

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

Definition at line 1215 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().

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

1536 {
1537  Query *parse = root->parse;
1538  int varno = ((RangeTblRef *) jtnode)->rtindex;
1539  List *values_list;
1540  List *tlist;
1541  AttrNumber attrno;
1542  pullup_replace_vars_context rvcontext;
1543  ListCell *lc;
1544 
1545  Assert(rte->rtekind == RTE_VALUES);
1546  Assert(list_length(rte->values_lists) == 1);
1547 
1548  /*
1549  * Need a modifiable copy of the VALUES list to hack on, just in case it's
1550  * multiply referenced.
1551  */
1552  values_list = copyObject(linitial(rte->values_lists));
1553 
1554  /*
1555  * The VALUES RTE can't contain any Vars of level zero, let alone any that
1556  * are join aliases, so no need to flatten join alias Vars.
1557  */
1558  Assert(!contain_vars_of_level((Node *) values_list, 0));
1559 
1560  /*
1561  * Set up required context data for pullup_replace_vars. In particular,
1562  * we have to make the VALUES list look like a subquery targetlist.
1563  */
1564  tlist = NIL;
1565  attrno = 1;
1566  foreach(lc, values_list)
1567  {
1568  tlist = lappend(tlist,
1569  makeTargetEntry((Expr *) lfirst(lc),
1570  attrno,
1571  NULL,
1572  false));
1573  attrno++;
1574  }
1575  rvcontext.root = root;
1576  rvcontext.targetlist = tlist;
1577  rvcontext.target_rte = rte;
1578  rvcontext.relids = NULL;
1579  rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1580  rvcontext.varno = varno;
1581  rvcontext.need_phvs = false;
1582  rvcontext.wrap_non_vars = false;
1583  /* initialize cache array with indexes 0 .. length(tlist) */
1584  rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1585  sizeof(Node *));
1586 
1587  /*
1588  * Replace all of the top query's references to the RTE's outputs with
1589  * copies of the adjusted VALUES expressions, being careful not to replace
1590  * any of the jointree structure. We can assume there's no outer joins or
1591  * appendrels in the dummy Query that surrounds a VALUES RTE.
1592  */
1593  perform_pullup_replace_vars(root, &rvcontext, NULL, NULL);
1594 
1595  /*
1596  * There should be no appendrels to fix, nor any outer joins and hence no
1597  * PlaceHolderVars.
1598  */
1599  Assert(root->append_rel_list == NIL);
1600  Assert(root->join_info_list == NIL);
1601  Assert(root->placeholder_list == NIL);
1602 
1603  /*
1604  * Replace the VALUES RTE with a RESULT RTE. The VALUES RTE is the only
1605  * rtable entry in the current query level, so this is easy.
1606  */
1607  Assert(list_length(parse->rtable) == 1);
1608 
1609  /* Create suitable RTE */
1610  rte = makeNode(RangeTblEntry);
1611  rte->rtekind = RTE_RESULT;
1612  rte->eref = makeAlias("*RESULT*", NIL);
1613 
1614  /* Replace rangetable */
1615  parse->rtable = list_make1(rte);
1616 
1617  /* We could manufacture a new RangeTblRef, but the one we have is fine */
1618  Assert(varno == 1);
1619 
1620  return jtnode;
1621 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:179
List * join_info_list
Definition: pathnodes.h:283
Definition: nodes.h:525
List * values_lists
Definition: parsenodes.h:1072
#define list_make1(x1)
Definition: pg_list.h:227
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:385
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
RangeTblEntry * target_rte
Definition: prepjointree.c:47
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
List * lappend(List *list, void *datum)
Definition: list.c:322
void * palloc0(Size size)
Definition: mcxt.c:980
List * append_rel_list
Definition: pathnodes.h:290
#define makeNode(_type_)
Definition: nodes.h:573
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:738
#define lfirst(lc)
Definition: pg_list.h:190
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:369
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
bool hasSubLinks
Definition: parsenodes.h:128
List * placeholder_list
Definition: pathnodes.h:294
Alias * eref
Definition: parsenodes.h:1113
#define copyObject(obj)
Definition: nodes.h:641
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:648

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 206 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().

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

◆ pull_up_sublinks_jointree_recurse()

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

Definition at line 233 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().

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

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

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 678 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().

679 {
680  /* Top level of jointree must always be a FromExpr */
681  Assert(IsA(root->parse->jointree, FromExpr));
682  /* Recursion starts with no containing join nor appendrel */
683  root->parse->jointree = (FromExpr *)
685  NULL, NULL, NULL);
686  /* We should still have a FromExpr */
687  Assert(IsA(root->parse->jointree, FromExpr));
688 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:179
FromExpr * jointree
Definition: parsenodes.h:138
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:728
Definition: nodes.h:525
#define Assert(condition)
Definition: c.h:738

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

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

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

◆ pullup_replace_vars()

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

Definition at line 2213 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().

2214 {
2215  return replace_rte_variables(expr,
2216  context->varno, 0,
2218  (void *) context,
2219  context->outer_hasSubLinks);
2220 }
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 2223 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().

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

2418 {
2419  Assert(IsA(query, Query));
2420  return (Query *) replace_rte_variables((Node *) query,
2421  context->varno, 1,
2423  (void *) context,
2424  NULL);
2425 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
static Node * pullup_replace_vars_callback(Var *var, replace_rte_variables_context *context)
Definition: nodes.h:525
#define Assert(condition)
Definition: c.h:738
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 2561 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().

2562 {
2564 
2565  /*
2566  * To avoid doing strictness checks on more quals than necessary, we want
2567  * to stop descending the jointree as soon as there are no outer joins
2568  * below our current point. This consideration forces a two-pass process.
2569  * The first pass gathers information about which base rels appear below
2570  * each side of each join clause, and about whether there are outer
2571  * join(s) below each side of each join clause. The second pass examines
2572  * qual clauses and changes join types as it descends the tree.
2573  */
2574  state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2575 
2576  /* planner.c shouldn't have called me if no outer joins */
2577  if (state == NULL || !state->contains_outer)
2578  elog(ERROR, "so where are the outer joins?");
2579 
2581  state, root, NULL, NIL, NIL);
2582 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:179
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:525
#define ERROR
Definition: elog.h:43
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
Definition: regguts.h:298
#define elog(elevel,...)
Definition: elog.h:228
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 2590 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().

2591 {
2592  reduce_outer_joins_state *result;
2593 
2594  result = (reduce_outer_joins_state *)
2596  result->relids = NULL;
2597  result->contains_outer = false;
2598  result->sub_states = NIL;
2599 
2600  if (jtnode == NULL)
2601  return result;
2602  if (IsA(jtnode, RangeTblRef))
2603  {
2604  int varno = ((RangeTblRef *) jtnode)->rtindex;
2605 
2606  result->relids = bms_make_singleton(varno);
2607  }
2608  else if (IsA(jtnode, FromExpr))
2609  {
2610  FromExpr *f = (FromExpr *) jtnode;
2611  ListCell *l;
2612 
2613  foreach(l, f->fromlist)
2614  {
2615  reduce_outer_joins_state *sub_state;
2616 
2617  sub_state = reduce_outer_joins_pass1(lfirst(l));
2618  result->relids = bms_add_members(result->relids,
2619  sub_state->relids);
2620  result->contains_outer |= sub_state->contains_outer;
2621  result->sub_states = lappend(result->sub_states, sub_state);
2622  }
2623  }
2624  else if (IsA(jtnode, JoinExpr))
2625  {
2626  JoinExpr *j = (JoinExpr *) jtnode;
2627  reduce_outer_joins_state *sub_state;
2628 
2629  /* join's own RT index is not wanted in result->relids */
2630  if (IS_OUTER_JOIN(j->jointype))
2631  result->contains_outer = true;
2632 
2633  sub_state = reduce_outer_joins_pass1(j->larg);
2634  result->relids = bms_add_members(result->relids,
2635  sub_state->relids);
2636  result->contains_outer |= sub_state->contains_outer;
2637  result->sub_states = lappend(result->sub_states, sub_state);
2638 
2639  sub_state = reduce_outer_joins_pass1(j->rarg);
2640  result->relids = bms_add_members(result->relids,
2641  sub_state->relids);
2642  result->contains_outer |= sub_state->contains_outer;
2643  result->sub_states = lappend(result->sub_states, sub_state);
2644  }
2645  else
2646  elog(ERROR, "unrecognized node type: %d",
2647  (int) nodeTag(jtnode));
2648  return result;
2649 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:741
List * fromlist
Definition: primnodes.h:1510
Node * larg
Definition: primnodes.h:1490
#define ERROR
Definition: elog.h:43
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
List * lappend(List *list, void *datum)
Definition: list.c:322
Node * rarg
Definition: primnodes.h:1491
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
JoinType jointype
Definition: primnodes.h:1488
#define lfirst(lc)
Definition: pg_list.h:190
#define nodeTag(nodeptr)
Definition: nodes.h:530
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
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 2662 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().

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

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

Referenced by remove_useless_results_recurse().

3249 {
3250  /* Fix up PlaceHolderVars as needed */
3251  /* If there are no PHVs anywhere, we can skip this bit */
3252  if (root->glob->lastPHId != 0)
3253  {
3254  Relids subrelids;
3255 
3256  subrelids = get_relids_in_jointree(newjtloc, false);
3257  Assert(!bms_is_empty(subrelids));
3258  substitute_phv_relids((Node *) root->parse, varno, subrelids);
3259  }
3260 
3261  /*
3262  * We also need to remove any PlanRowMark referencing the RTE, but we
3263  * postpone that work until we return to remove_useless_result_rtes.
3264  */
3265 }
static void substitute_phv_relids(Node *node, int varno, Relids subrelids)
Query * parse
Definition: pathnodes.h:179
Definition: nodes.h:525
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
PlannerGlobal * glob
Definition: pathnodes.h:181
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
Index lastPHId
Definition: pathnodes.h:133
#define Assert(condition)
Definition: c.h:738

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

Definition at line 2974 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().

2975 {
2976  ListCell *cell;
2977 
2978  /* Top level of jointree must always be a FromExpr */
2979  Assert(IsA(root->parse->jointree, FromExpr));
2980  /* Recurse ... */
2981  root->parse->jointree = (FromExpr *)
2983  /* We should still have a FromExpr */
2984  Assert(IsA(root->parse->jointree, FromExpr));
2985 
2986  /*
2987  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
2988  * must do that for any RTE_RESULT that we just removed. But one for a
2989  * RTE that we did not remove can be dropped anyway: since the RTE has
2990  * only one possible output row, there is no need for EPQ to mark and
2991  * restore that row.
2992  *
2993  * It's necessary, not optional, to remove the PlanRowMark for a surviving
2994  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
2995  * RTE_RESULT, which the executor has no support for.
2996  */
2997  foreach(cell, root->rowMarks)
2998  {
2999  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3000 
3001  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3002  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3003  }
3004 }
List * rowMarks
Definition: pathnodes.h:292
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:179
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:525
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:368
List * rtable
Definition: parsenodes.h:137
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
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 3013 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().

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

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 148 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().

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

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

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

◆ substitute_phv_relids()

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

Definition at line 3449 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().

3450 {
3452 
3453  context.varno = varno;
3454  context.sublevels_up = 0;
3455  context.subrelids = subrelids;
3456 
3457  /*
3458  * Must be prepared to start with a Query or a bare expression tree.
3459  */
3462  (void *) &context,
3463  0);
3464 }
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:3363

◆ substitute_phv_relids_walker()

static bool substitute_phv_relids_walker ( Node node,
substitute_phv_relids_context context 
)
static

Definition at line 3405 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().

3407 {
3408  if (node == NULL)
3409  return false;
3410  if (IsA(node, PlaceHolderVar))
3411  {
3412  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3413 
3414  if (phv->phlevelsup == context->sublevels_up &&
3415  bms_is_member(context->varno, phv->phrels))
3416  {
3417  phv->phrels = bms_union(phv->phrels,
3418  context->subrelids);
3419  phv->phrels = bms_del_member(phv->phrels,
3420  context->varno);
3421  /* Assert we haven't broken the PHV */
3422  Assert(!bms_is_empty(phv->phrels));
3423  }
3424  /* fall through to examine children */
3425  }
3426  if (IsA(node, Query))
3427  {
3428  /* Recurse into subselects */
3429  bool result;
3430 
3431  context->sublevels_up++;
3432  result = query_tree_walker((Query *) node,
3434  (void *) context, 0);
3435  context->sublevels_up--;
3436  return result;
3437  }
3438  /* Shouldn't need to handle planner auxiliary nodes here */
3439  Assert(!IsA(node, SpecialJoinInfo));
3440  Assert(!IsA(node, AppendRelInfo));
3441  Assert(!IsA(node, PlaceHolderInfo));
3442  Assert(!IsA(node, MinMaxAggInfo));
3443 
3445  (void *) context);
3446 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
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:738
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:1839
Index phlevelsup
Definition: pathnodes.h:2067
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