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 (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 ( Node node,
int  varno 
)
static

Definition at line 3295 of file prepjointree.c.

References bms_make_singleton(), find_dependent_phvs_walker(), query_or_expression_tree_walker(), find_dependent_phvs_context::relids, and find_dependent_phvs_context::sublevels_up.

Referenced by remove_useless_results_recurse().

3296 {
3298 
3299  context.relids = bms_make_singleton(varno);
3300  context.sublevels_up = 0;
3301 
3302  /*
3303  * Must be prepared to start with a Query or a bare expression tree.
3304  */
3305  return query_or_expression_tree_walker(node,
3307  (void *) &context,
3308  0);
3309 }
static bool find_dependent_phvs_walker(Node *node, find_dependent_phvs_context *context)
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
bool query_or_expression_tree_walker(Node *node, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:3348

◆ find_dependent_phvs_walker()

static bool find_dependent_phvs_walker ( Node node,
find_dependent_phvs_context context 
)
static

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

3260 {
3261  if (node == NULL)
3262  return false;
3263  if (IsA(node, PlaceHolderVar))
3264  {
3265  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3266 
3267  if (phv->phlevelsup == context->sublevels_up &&
3268  bms_equal(context->relids, phv->phrels))
3269  return true;
3270  /* fall through to examine children */
3271  }
3272  if (IsA(node, Query))
3273  {
3274  /* Recurse into subselects */
3275  bool result;
3276 
3277  context->sublevels_up++;
3278  result = query_tree_walker((Query *) node,
3280  (void *) context, 0);
3281  context->sublevels_up--;
3282  return result;
3283  }
3284  /* Shouldn't need to handle planner auxiliary nodes here */
3285  Assert(!IsA(node, SpecialJoinInfo));
3286  Assert(!IsA(node, AppendRelInfo));
3287  Assert(!IsA(node, PlaceHolderInfo));
3288  Assert(!IsA(node, MinMaxAggInfo));
3289 
3291  (void *) context);
3292 }
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:739
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 3503 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().

3504 {
3505  if (jtnode == NULL)
3506  return NULL;
3507  if (IsA(jtnode, RangeTblRef))
3508  {
3509  int varno = ((RangeTblRef *) jtnode)->rtindex;
3510 
3511  if (relid == varno)
3512  return jtnode;
3513  }
3514  else if (IsA(jtnode, FromExpr))
3515  {
3516  FromExpr *f = (FromExpr *) jtnode;
3517  ListCell *l;
3518 
3519  foreach(l, f->fromlist)
3520  {
3521  jtnode = find_jointree_node_for_rel(lfirst(l), relid);
3522  if (jtnode)
3523  return jtnode;
3524  }
3525  }
3526  else if (IsA(jtnode, JoinExpr))
3527  {
3528  JoinExpr *j = (JoinExpr *) jtnode;
3529 
3530  if (relid == j->rtindex)
3531  return jtnode;
3532  jtnode = find_jointree_node_for_rel(j->larg, relid);
3533  if (jtnode)
3534  return jtnode;
3535  jtnode = find_jointree_node_for_rel(j->rarg, relid);
3536  if (jtnode)
3537  return jtnode;
3538  }
3539  else
3540  elog(ERROR, "unrecognized node type: %d",
3541  (int) nodeTag(jtnode));
3542  return NULL;
3543 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * fromlist
Definition: primnodes.h:1496
Node * larg
Definition: primnodes.h:1476
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:43
Node * rarg
Definition: primnodes.h:1477
#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:1481

◆ fix_append_rel_relids()

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

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

3405 {
3406  ListCell *l;
3407  int subvarno = -1;
3408 
3409  /*
3410  * We only want to extract the member relid once, but we mustn't fail
3411  * immediately if there are multiple members; it could be that none of the
3412  * AppendRelInfo nodes refer to it. So compute it on first use. Note that
3413  * bms_singleton_member will complain if set is not singleton.
3414  */
3415  foreach(l, append_rel_list)
3416  {
3417  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
3418 
3419  /* The parent_relid shouldn't ever be a pullup target */
3420  Assert(appinfo->parent_relid != varno);
3421 
3422  if (appinfo->child_relid == varno)
3423  {
3424  if (subvarno < 0)
3425  subvarno = bms_singleton_member(subrelids);
3426  appinfo->child_relid = subvarno;
3427  }
3428 
3429  /* Also fix up any PHVs in its translated vars */
3431  varno, subrelids);
3432  }
3433 }
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:739
#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 2441 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().

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

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

Referenced by alias_relid_set().

3487 {
3488  Node *jtnode;
3489 
3490  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3491  joinrelid);
3492  if (!jtnode)
3493  elog(ERROR, "could not find join node %d", joinrelid);
3494  return get_relids_in_jointree(jtnode, false);
3495 }
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 3442 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(), get_relids_for_join(), get_relids_in_jointree(), is_simple_subquery(), preprocess_rowmarks(), pull_up_simple_subquery(), and remove_result_refs().

3443 {
3444  Relids result = NULL;
3445 
3446  if (jtnode == NULL)
3447  return result;
3448  if (IsA(jtnode, RangeTblRef))
3449  {
3450  int varno = ((RangeTblRef *) jtnode)->rtindex;
3451 
3452  result = bms_make_singleton(varno);
3453  }
3454  else if (IsA(jtnode, FromExpr))
3455  {
3456  FromExpr *f = (FromExpr *) jtnode;
3457  ListCell *l;
3458 
3459  foreach(l, f->fromlist)
3460  {
3461  result = bms_join(result,
3463  include_joins));
3464  }
3465  }
3466  else if (IsA(jtnode, JoinExpr))
3467  {
3468  JoinExpr *j = (JoinExpr *) jtnode;
3469 
3470  result = get_relids_in_jointree(j->larg, include_joins);
3471  result = bms_join(result,
3472  get_relids_in_jointree(j->rarg, include_joins));
3473  if (include_joins && j->rtindex)
3474  result = bms_add_member(result, j->rtindex);
3475  }
3476  else
3477  elog(ERROR, "unrecognized node type: %d",
3478  (int) nodeTag(jtnode));
3479  return result;
3480 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * fromlist
Definition: primnodes.h:1496
Node * larg
Definition: primnodes.h:1476
#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:1477
#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:1481

◆ get_result_relid()

static int get_result_relid ( PlannerInfo root,
Node jtnode 
)
static

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

3197 {
3198  int varno;
3199 
3200  if (!IsA(jtnode, RangeTblRef))
3201  return 0;
3202  varno = ((RangeTblRef *) jtnode)->rtindex;
3203  if (rt_fetch(varno, root->parse->rtable)->rtekind != RTE_RESULT)
3204  return 0;
3205  return varno;
3206 }
#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 1882 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().

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

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

1815 {
1816  SetOperationStmt *topop;
1817 
1818  /* Let's just make sure it's a valid subselect ... */
1819  if (!IsA(subquery, Query) ||
1820  subquery->commandType != CMD_SELECT)
1821  elog(ERROR, "subquery is bogus");
1822 
1823  /* Is it a set-operation query at all? */
1824  topop = castNode(SetOperationStmt, subquery->setOperations);
1825  if (!topop)
1826  return false;
1827 
1828  /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
1829  if (subquery->sortClause ||
1830  subquery->limitOffset ||
1831  subquery->limitCount ||
1832  subquery->rowMarks ||
1833  subquery->cteList)
1834  return false;
1835 
1836  /* Recursively check the tree of set operations */
1837  return is_simple_union_all_recurse((Node *) topop, subquery,
1838  topop->colTypes);
1839 }
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 1842 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().

1843 {
1844  if (IsA(setOp, RangeTblRef))
1845  {
1846  RangeTblRef *rtr = (RangeTblRef *) setOp;
1847  RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
1848  Query *subquery = rte->subquery;
1849 
1850  Assert(subquery != NULL);
1851 
1852  /* Leaf nodes are OK if they match the toplevel column types */
1853  /* We don't have to compare typmods or collations here */
1854  return tlist_same_datatypes(subquery->targetList, colTypes, true);
1855  }
1856  else if (IsA(setOp, SetOperationStmt))
1857  {
1858  SetOperationStmt *op = (SetOperationStmt *) setOp;
1859 
1860  /* Must be UNION ALL */
1861  if (op->op != SETOP_UNION || !op->all)
1862  return false;
1863 
1864  /* Recurse to check inputs */
1865  return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
1866  is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
1867  }
1868  else
1869  {
1870  elog(ERROR, "unrecognized node type: %d",
1871  (int) nodeTag(setOp));
1872  return false; /* keep compiler quiet */
1873  }
1874 }
#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:739
SetOperation op
Definition: parsenodes.h:1634
#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 1629 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().

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

1932 {
1933  if (jtnode == NULL)
1934  return false;
1935  if (IsA(jtnode, RangeTblRef))
1936  return false;
1937  else if (IsA(jtnode, FromExpr))
1938  {
1939  FromExpr *f = (FromExpr *) jtnode;
1940  ListCell *l;
1941 
1942  /* First, recurse to check child joins */
1943  foreach(l, f->fromlist)
1944  {
1946  restricted,
1947  safe_upper_varnos))
1948  return true;
1949  }
1950 
1951  /* Then check the top-level quals */
1952  if (restricted &&
1954  safe_upper_varnos))
1955  return true;
1956  }
1957  else if (IsA(jtnode, JoinExpr))
1958  {
1959  JoinExpr *j = (JoinExpr *) jtnode;
1960 
1961  /*
1962  * If this is an outer join, we mustn't allow any upper lateral
1963  * references in or below it.
1964  */
1965  if (j->jointype != JOIN_INNER)
1966  {
1967  restricted = true;
1968  safe_upper_varnos = NULL;
1969  }
1970 
1971  /* Check the child joins */
1973  restricted,
1974  safe_upper_varnos))
1975  return true;
1977  restricted,
1978  safe_upper_varnos))
1979  return true;
1980 
1981  /* Check the JOIN's qual clauses */
1982  if (restricted &&
1984  safe_upper_varnos))
1985  return true;
1986  }
1987  else
1988  elog(ERROR, "unrecognized node type: %d",
1989  (int) nodeTag(jtnode));
1990  return false;
1991 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * fromlist
Definition: primnodes.h:1496
Node * quals
Definition: primnodes.h:1497
Node * larg
Definition: primnodes.h:1476
#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:1479
static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, Relids safe_upper_varnos)
Node * rarg
Definition: primnodes.h:1477
JoinType jointype
Definition: primnodes.h:1474
#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 1361 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().

1363 {
1364  List *vars = NIL;
1365  AttrNumber *pcolnos;
1366  ListCell *l;
1367 
1368  /* Initialize reverse-translation array with all entries zero */
1369  /* (entries for resjunk columns will stay that way) */
1370  appinfo->num_child_cols = list_length(query->targetList);
1371  appinfo->parent_colnos = pcolnos =
1372  (AttrNumber *) palloc0(appinfo->num_child_cols * sizeof(AttrNumber));
1373 
1374  foreach(l, query->targetList)
1375  {
1376  TargetEntry *tle = (TargetEntry *) lfirst(l);
1377 
1378  if (tle->resjunk)
1379  continue;
1380 
1381  vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1382  pcolnos[tle->resno - 1] = tle->resno;
1383  }
1384 
1385  appinfo->translated_vars = vars;
1386 }
#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:1400
AttrNumber resno
Definition: primnodes.h:1394
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 2002 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().

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

636 {
637  ListCell *rt;
638 
639  foreach(rt, root->parse->rtable)
640  {
641  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
642 
643  if (rte->rtekind == RTE_FUNCTION)
644  {
645  Query *funcquery;
646 
647  /* Apply const-simplification */
648  rte->functions = (List *)
649  eval_const_expressions(root, (Node *) rte->functions);
650 
651  /* Check safety of expansion, and expand if possible */
652  funcquery = inline_set_returning_function(root, rte);
653  if (funcquery)
654  {
655  /* Successful expansion, convert the RTE to a subquery */
656  rte->rtekind = RTE_SUBQUERY;
657  rte->subquery = funcquery;
658  rte->security_barrier = false;
659  /* Clear fields that should not be set in a subquery RTE */
660  rte->functions = NIL;
661  rte->funcordinality = false;
662  }
663  }
664  }
665 }
#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:4870
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2253
bool funcordinality
Definition: parsenodes.h:1041
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:1040
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 1688 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().

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

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

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

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

205 {
206  Node *jtnode;
207  Relids relids;
208 
209  /* Begin recursion through the jointree */
210  jtnode = pull_up_sublinks_jointree_recurse(root,
211  (Node *) root->parse->jointree,
212  &relids);
213 
214  /*
215  * root->parse->jointree must always be a FromExpr, so insert a dummy one
216  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
217  */
218  if (IsA(jtnode, FromExpr))
219  root->parse->jointree = (FromExpr *) jtnode;
220  else
221  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
222 }
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:231

◆ pull_up_sublinks_jointree_recurse()

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

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

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

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

677 {
678  /* Top level of jointree must always be a FromExpr */
679  Assert(IsA(root->parse->jointree, FromExpr));
680  /* Recursion starts with no containing join nor appendrel */
681  root->parse->jointree = (FromExpr *)
683  NULL, NULL, NULL);
684  /* We should still have a FromExpr */
685  Assert(IsA(root->parse->jointree, FromExpr));
686 }
#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:726
Definition: nodes.h:525
#define Assert(condition)
Definition: c.h:739

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

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

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

2212 {
2213  return replace_rte_variables(expr,
2214  context->varno, 0,
2216  (void *) context,
2217  context->outer_hasSubLinks);
2218 }
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 2221 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().

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

2416 {
2417  Assert(IsA(query, Query));
2418  return (Query *) replace_rte_variables((Node *) query,
2419  context->varno, 1,
2421  (void *) context,
2422  NULL);
2423 }
#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:739
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 2559 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().

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

2589 {
2590  reduce_outer_joins_state *result;
2591 
2592  result = (reduce_outer_joins_state *)
2594  result->relids = NULL;
2595  result->contains_outer = false;
2596  result->sub_states = NIL;
2597 
2598  if (jtnode == NULL)
2599  return result;
2600  if (IsA(jtnode, RangeTblRef))
2601  {
2602  int varno = ((RangeTblRef *) jtnode)->rtindex;
2603 
2604  result->relids = bms_make_singleton(varno);
2605  }
2606  else if (IsA(jtnode, FromExpr))
2607  {
2608  FromExpr *f = (FromExpr *) jtnode;
2609  ListCell *l;
2610 
2611  foreach(l, f->fromlist)
2612  {
2613  reduce_outer_joins_state *sub_state;
2614 
2615  sub_state = reduce_outer_joins_pass1(lfirst(l));
2616  result->relids = bms_add_members(result->relids,
2617  sub_state->relids);
2618  result->contains_outer |= sub_state->contains_outer;
2619  result->sub_states = lappend(result->sub_states, sub_state);
2620  }
2621  }
2622  else if (IsA(jtnode, JoinExpr))
2623  {
2624  JoinExpr *j = (JoinExpr *) jtnode;
2625  reduce_outer_joins_state *sub_state;
2626 
2627  /* join's own RT index is not wanted in result->relids */
2628  if (IS_OUTER_JOIN(j->jointype))
2629  result->contains_outer = true;
2630 
2631  sub_state = reduce_outer_joins_pass1(j->larg);
2632  result->relids = bms_add_members(result->relids,
2633  sub_state->relids);
2634  result->contains_outer |= sub_state->contains_outer;
2635  result->sub_states = lappend(result->sub_states, sub_state);
2636 
2637  sub_state = reduce_outer_joins_pass1(j->rarg);
2638  result->relids = bms_add_members(result->relids,
2639  sub_state->relids);
2640  result->contains_outer |= sub_state->contains_outer;
2641  result->sub_states = lappend(result->sub_states, sub_state);
2642  }
2643  else
2644  elog(ERROR, "unrecognized node type: %d",
2645  (int) nodeTag(jtnode));
2646  return result;
2647 }
#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:1496
Node * larg
Definition: primnodes.h:1476
#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:1477
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
JoinType jointype
Definition: primnodes.h:1474
#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 2660 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().

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

3227 {
3228  /* Fix up PlaceHolderVars as needed */
3229  /* If there are no PHVs anywhere, we can skip this bit */
3230  if (root->glob->lastPHId != 0)
3231  {
3232  Relids subrelids;
3233 
3234  subrelids = get_relids_in_jointree(newjtloc, false);
3235  Assert(!bms_is_empty(subrelids));
3236  substitute_phv_relids((Node *) root->parse, varno, subrelids);
3237  }
3238 
3239  /*
3240  * We also need to remove any PlanRowMark referencing the RTE, but we
3241  * postpone that work until we return to remove_useless_result_rtes.
3242  */
3243 }
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:739

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

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

2970 {
2971  ListCell *cell;
2972 
2973  /* Top level of jointree must always be a FromExpr */
2974  Assert(IsA(root->parse->jointree, FromExpr));
2975  /* Recurse ... */
2976  root->parse->jointree = (FromExpr *)
2978  /* We should still have a FromExpr */
2979  Assert(IsA(root->parse->jointree, FromExpr));
2980 
2981  /*
2982  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
2983  * must do that for any RTE_RESULT that we just removed. But one for a
2984  * RTE that we did not remove can be dropped anyway: since the RTE has
2985  * only one possible output row, there is no need for EPQ to mark and
2986  * restore that row.
2987  *
2988  * It's necessary, not optional, to remove the PlanRowMark for a surviving
2989  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
2990  * RTE_RESULT, which the executor has no support for.
2991  */
2992  foreach(cell, root->rowMarks)
2993  {
2994  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
2995 
2996  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
2997  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
2998  }
2999 }
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:739
#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 3008 of file prepjointree.c.

References Assert, bms_add_member(), bms_next_member(), elog, ERROR, find_dependent_phvs(), 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().

3009 {
3010  Assert(jtnode != NULL);
3011  if (IsA(jtnode, RangeTblRef))
3012  {
3013  /* Can't immediately do anything with a RangeTblRef */
3014  }
3015  else if (IsA(jtnode, FromExpr))
3016  {
3017  FromExpr *f = (FromExpr *) jtnode;
3018  Relids result_relids = NULL;
3019  ListCell *cell;
3020 
3021  /*
3022  * We can drop RTE_RESULT rels from the fromlist so long as at least
3023  * one child remains, since joining to a one-row table changes
3024  * nothing. The easiest way to mechanize this rule is to modify the
3025  * list in-place.
3026  */
3027  foreach(cell, f->fromlist)
3028  {
3029  Node *child = (Node *) lfirst(cell);
3030  int varno;
3031 
3032  /* Recursively transform child ... */
3033  child = remove_useless_results_recurse(root, child);
3034  /* ... and stick it back into the tree */
3035  lfirst(cell) = child;
3036 
3037  /*
3038  * If it's an RTE_RESULT with at least one sibling, we can drop
3039  * it. We don't yet know what the inner join's final relid set
3040  * will be, so postpone cleanup of PHVs etc till after this loop.
3041  */
3042  if (list_length(f->fromlist) > 1 &&
3043  (varno = get_result_relid(root, child)) != 0)
3044  {
3045  f->fromlist = foreach_delete_current(f->fromlist, cell);
3046  result_relids = bms_add_member(result_relids, varno);
3047  }
3048  }
3049 
3050  /*
3051  * Clean up if we dropped any RTE_RESULT RTEs. This is a bit
3052  * inefficient if there's more than one, but it seems better to
3053  * optimize the support code for the single-relid case.
3054  */
3055  if (result_relids)
3056  {
3057  int varno = -1;
3058 
3059  while ((varno = bms_next_member(result_relids, varno)) >= 0)
3060  remove_result_refs(root, varno, (Node *) f);
3061  }
3062 
3063  /*
3064  * If we're not at the top of the jointree, it's valid to simplify a
3065  * degenerate FromExpr into its single child. (At the top, we must
3066  * keep the FromExpr since Query.jointree is required to point to a
3067  * FromExpr.)
3068  */
3069  if (f != root->parse->jointree &&
3070  f->quals == NULL &&
3071  list_length(f->fromlist) == 1)
3072  return (Node *) linitial(f->fromlist);
3073  }
3074  else if (IsA(jtnode, JoinExpr))
3075  {
3076  JoinExpr *j = (JoinExpr *) jtnode;
3077  int varno;
3078 
3079  /* First, recurse */
3080  j->larg = remove_useless_results_recurse(root, j->larg);
3081  j->rarg = remove_useless_results_recurse(root, j->rarg);
3082 
3083  /* Apply join-type-specific optimization rules */
3084  switch (j->jointype)
3085  {
3086  case JOIN_INNER:
3087 
3088  /*
3089  * An inner join is equivalent to a FromExpr, so if either
3090  * side was simplified to an RTE_RESULT rel, we can replace
3091  * the join with a FromExpr with just the other side; and if
3092  * the qual is empty (JOIN ON TRUE) then we can omit the
3093  * FromExpr as well.
3094  */
3095  if ((varno = get_result_relid(root, j->larg)) != 0)
3096  {
3097  remove_result_refs(root, varno, j->rarg);
3098  if (j->quals)
3099  jtnode = (Node *)
3100  makeFromExpr(list_make1(j->rarg), j->quals);
3101  else
3102  jtnode = j->rarg;
3103  }
3104  else if ((varno = get_result_relid(root, j->rarg)) != 0)
3105  {
3106  remove_result_refs(root, varno, j->larg);
3107  if (j->quals)
3108  jtnode = (Node *)
3109  makeFromExpr(list_make1(j->larg), j->quals);
3110  else
3111  jtnode = j->larg;
3112  }
3113  break;
3114  case JOIN_LEFT:
3115 
3116  /*
3117  * We can simplify this case if the RHS is an RTE_RESULT, with
3118  * two different possibilities:
3119  *
3120  * If the qual is empty (JOIN ON TRUE), then the join can be
3121  * strength-reduced to a plain inner join, since each LHS row
3122  * necessarily has exactly one join partner. So we can always
3123  * discard the RHS, much as in the JOIN_INNER case above.
3124  *
3125  * Otherwise, it's still true that each LHS row should be
3126  * returned exactly once, and since the RHS returns no columns
3127  * (unless there are PHVs that have to be evaluated there), we
3128  * don't much care if it's null-extended or not. So in this
3129  * case also, we can just ignore the qual and discard the left
3130  * join.
3131  */
3132  if ((varno = get_result_relid(root, j->rarg)) != 0 &&
3133  (j->quals == NULL ||
3134  !find_dependent_phvs((Node *) root->parse, varno)))
3135  {
3136  remove_result_refs(root, varno, j->larg);
3137  jtnode = j->larg;
3138  }
3139  break;
3140  case JOIN_RIGHT:
3141  /* Mirror-image of the JOIN_LEFT case */
3142  if ((varno = get_result_relid(root, j->larg)) != 0 &&
3143  (j->quals == NULL ||
3144  !find_dependent_phvs((Node *) root->parse, varno)))
3145  {
3146  remove_result_refs(root, varno, j->rarg);
3147  jtnode = j->rarg;
3148  }
3149  break;
3150  case JOIN_SEMI:
3151 
3152  /*
3153  * We may simplify this case if the RHS is an RTE_RESULT; the
3154  * join qual becomes effectively just a filter qual for the
3155  * LHS, since we should either return the LHS row or not. For
3156  * simplicity we inject the filter qual into a new FromExpr.
3157  *
3158  * Unlike the LEFT/RIGHT cases, we just Assert that there are
3159  * no PHVs that need to be evaluated at the semijoin's RHS,
3160  * since the rest of the query couldn't reference any outputs
3161  * of the semijoin's RHS.
3162  */
3163  if ((varno = get_result_relid(root, j->rarg)) != 0)
3164  {
3165  Assert(!find_dependent_phvs((Node *) root->parse, varno));
3166  remove_result_refs(root, varno, j->larg);
3167  if (j->quals)
3168  jtnode = (Node *)
3169  makeFromExpr(list_make1(j->larg), j->quals);
3170  else
3171  jtnode = j->larg;
3172  }
3173  break;
3174  case JOIN_FULL:
3175  case JOIN_ANTI:
3176  /* We have no special smarts for these cases */
3177  break;
3178  default:
3179  elog(ERROR, "unrecognized join type: %d",
3180  (int) j->jointype);
3181  break;
3182  }
3183  }
3184  else
3185  elog(ERROR, "unrecognized node type: %d",
3186  (int) nodeTag(jtnode));
3187  return jtnode;
3188 }
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:1496
static void remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
Node * quals
Definition: primnodes.h:1497
Node * larg
Definition: primnodes.h:1476
#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
static bool find_dependent_phvs(Node *node, int varno)
Node * quals
Definition: primnodes.h:1479
Node * rarg
Definition: primnodes.h:1477
JoinType jointype
Definition: primnodes.h:1474
#define Assert(condition)
Definition: c.h:739
#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 146 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().

147 {
148  RangeTblEntry *rte;
149  Index rti;
150  RangeTblRef *rtr;
151 
152  /* Nothing to do if jointree is already nonempty */
153  if (parse->jointree->fromlist != NIL)
154  return;
155 
156  /* We mustn't change it in the top level of a setop tree, either */
157  if (parse->setOperations)
158  return;
159 
160  /* Create suitable RTE */
161  rte = makeNode(RangeTblEntry);
162  rte->rtekind = RTE_RESULT;
163  rte->eref = makeAlias("*RESULT*", NIL);
164 
165  /* Add it to rangetable */
166  parse->rtable = lappend(parse->rtable, rte);
167  rti = list_length(parse->rtable);
168 
169  /* And jam a reference into the jointree */
170  rtr = makeNode(RangeTblRef);
171  rtr->rtindex = rti;
172  parse->jointree->fromlist = list_make1(rtr);
173 }
#define NIL
Definition: pg_list.h:65
FromExpr * jointree
Definition: parsenodes.h:138
List * fromlist
Definition: primnodes.h:1496
#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:476
#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:1092

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

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

3377 {
3379 
3380  context.varno = varno;
3381  context.sublevels_up = 0;
3382  context.subrelids = subrelids;
3383 
3384  /*
3385  * Must be prepared to start with a Query or a bare expression tree.
3386  */
3389  (void *) &context,
3390  0);
3391 }
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:3348

◆ substitute_phv_relids_walker()

static bool substitute_phv_relids_walker ( Node node,
substitute_phv_relids_context context 
)
static

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

3334 {
3335  if (node == NULL)
3336  return false;
3337  if (IsA(node, PlaceHolderVar))
3338  {
3339  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3340 
3341  if (phv->phlevelsup == context->sublevels_up &&
3342  bms_is_member(context->varno, phv->phrels))
3343  {
3344  phv->phrels = bms_union(phv->phrels,
3345  context->subrelids);
3346  phv->phrels = bms_del_member(phv->phrels,
3347  context->varno);
3348  /* Assert we haven't broken the PHV */
3349  Assert(!bms_is_empty(phv->phrels));
3350  }
3351  /* fall through to examine children */
3352  }
3353  if (IsA(node, Query))
3354  {
3355  /* Recurse into subselects */
3356  bool result;
3357 
3358  context->sublevels_up++;
3359  result = query_tree_walker((Query *) node,
3361  (void *) context, 0);
3362  context->sublevels_up--;
3363  return result;
3364  }
3365  /* Shouldn't need to handle planner auxiliary nodes here */
3366  Assert(!IsA(node, SpecialJoinInfo));
3367  Assert(!IsA(node, AppendRelInfo));
3368  Assert(!IsA(node, PlaceHolderInfo));
3369  Assert(!IsA(node, MinMaxAggInfo));
3370 
3372  (void *) context);
3373 }
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:739
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