PostgreSQL Source Code  git master
initsplan.c File Reference
Include dependency graph for initsplan.c:

Go to the source code of this file.

Data Structures

struct  PostponedQual
 

Typedefs

typedef struct PostponedQual PostponedQual
 

Functions

static void extract_lateral_references (PlannerInfo *root, RelOptInfo *brel, Index rtindex)
 
static Listdeconstruct_recurse (PlannerInfo *root, Node *jtnode, bool below_outer_join, Relids *qualscope, Relids *inner_join_rels, List **postponed_qual_list)
 
static void process_security_barrier_quals (PlannerInfo *root, int rti, Relids qualscope, bool below_outer_join)
 
static SpecialJoinInfomake_outerjoininfo (PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, JoinType jointype, List *clause)
 
static void compute_semijoin_info (PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
 
static void distribute_qual_to_rels (PlannerInfo *root, Node *clause, bool below_outer_join, JoinType jointype, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, List **postponed_qual_list)
 
static bool check_outerjoin_delay (PlannerInfo *root, Relids *relids_p, Relids *nullable_relids_p, bool is_pushed_down)
 
static bool check_equivalence_delay (PlannerInfo *root, RestrictInfo *restrictinfo)
 
static bool check_redundant_nullability_qual (PlannerInfo *root, Node *clause)
 
static void check_mergejoinable (RestrictInfo *restrictinfo)
 
static void check_hashjoinable (RestrictInfo *restrictinfo)
 
static void check_resultcacheable (RestrictInfo *restrictinfo)
 
void add_base_rels_to_query (PlannerInfo *root, Node *jtnode)
 
void add_other_rels_to_query (PlannerInfo *root)
 
void build_base_rel_tlists (PlannerInfo *root, List *final_tlist)
 
void add_vars_to_targetlist (PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
 
void find_lateral_references (PlannerInfo *root)
 
void create_lateral_join_info (PlannerInfo *root)
 
Listdeconstruct_jointree (PlannerInfo *root)
 
void distribute_restrictinfo_to_rels (PlannerInfo *root, RestrictInfo *restrictinfo)
 
RestrictInfoprocess_implied_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids, Index security_level, bool below_outer_join, bool both_const)
 
RestrictInfobuild_implied_join_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids, Index security_level)
 
void match_foreign_keys_to_quals (PlannerInfo *root)
 

Variables

int from_collapse_limit
 
int join_collapse_limit
 

Typedef Documentation

◆ PostponedQual

typedef struct PostponedQual PostponedQual

Function Documentation

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 106 of file initsplan.c.

References add_base_rels_to_query(), build_simple_rel(), elog, ERROR, FromExpr::fromlist, IsA, JoinExpr::larg, lfirst, nodeTag, and JoinExpr::rarg.

Referenced by add_base_rels_to_query(), and query_planner().

107 {
108  if (jtnode == NULL)
109  return;
110  if (IsA(jtnode, RangeTblRef))
111  {
112  int varno = ((RangeTblRef *) jtnode)->rtindex;
113 
114  (void) build_simple_rel(root, varno, NULL);
115  }
116  else if (IsA(jtnode, FromExpr))
117  {
118  FromExpr *f = (FromExpr *) jtnode;
119  ListCell *l;
120 
121  foreach(l, f->fromlist)
122  add_base_rels_to_query(root, lfirst(l));
123  }
124  else if (IsA(jtnode, JoinExpr))
125  {
126  JoinExpr *j = (JoinExpr *) jtnode;
127 
128  add_base_rels_to_query(root, j->larg);
129  add_base_rels_to_query(root, j->rarg);
130  }
131  else
132  elog(ERROR, "unrecognized node type: %d",
133  (int) nodeTag(jtnode));
134 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:106
List * fromlist
Definition: primnodes.h:1553
Node * larg
Definition: primnodes.h:1532
#define ERROR
Definition: elog.h:46
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:194
Node * rarg
Definition: primnodes.h:1533
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 144 of file initsplan.c.

References expand_inherited_rtentry(), RangeTblEntry::inh, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, PlannerInfo::simple_rel_array_size, and PlannerInfo::simple_rte_array.

Referenced by query_planner().

145 {
146  int rti;
147 
148  for (rti = 1; rti < root->simple_rel_array_size; rti++)
149  {
150  RelOptInfo *rel = root->simple_rel_array[rti];
151  RangeTblEntry *rte = root->simple_rte_array[rti];
152 
153  /* there may be empty slots corresponding to non-baserel RTEs */
154  if (rel == NULL)
155  continue;
156 
157  /* Ignore any "otherrels" that were already added. */
158  if (rel->reloptkind != RELOPT_BASEREL)
159  continue;
160 
161  /* If it's marked as inheritable, look for children. */
162  if (rte->inh)
163  expand_inherited_rtentry(root, rel, rte, rti);
164  }
165 }
RelOptKind reloptkind
Definition: pathnodes.h:673
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
int simple_rel_array_size
Definition: pathnodes.h:186
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:193
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:79

◆ add_vars_to_targetlist()

void add_vars_to_targetlist ( PlannerInfo root,
List vars,
Relids  where_needed,
bool  create_new_ph 
)

Definition at line 230 of file initsplan.c.

References Assert, RelOptInfo::attr_needed, bms_add_members(), bms_is_empty(), bms_is_subset(), copyObject, elog, ERROR, PathTarget::exprs, find_base_rel(), find_placeholder_info(), IsA, lappend(), lfirst, RelOptInfo::min_attr, nodeTag, PlaceHolderInfo::ph_needed, RelOptInfo::relids, RelOptInfo::reltarget, Var::varattno, and Var::varno.

Referenced by build_base_rel_tlists(), distribute_qual_to_rels(), expand_inherited_rtentry(), extract_lateral_references(), fix_placeholder_input_needed_levels(), generate_base_implied_equalities_no_const(), and process_implied_equality().

232 {
233  ListCell *temp;
234 
235  Assert(!bms_is_empty(where_needed));
236 
237  foreach(temp, vars)
238  {
239  Node *node = (Node *) lfirst(temp);
240 
241  if (IsA(node, Var))
242  {
243  Var *var = (Var *) node;
244  RelOptInfo *rel = find_base_rel(root, var->varno);
245  int attno = var->varattno;
246 
247  if (bms_is_subset(where_needed, rel->relids))
248  continue;
249  Assert(attno >= rel->min_attr && attno <= rel->max_attr);
250  attno -= rel->min_attr;
251  if (rel->attr_needed[attno] == NULL)
252  {
253  /* Variable not yet requested, so add to rel's targetlist */
254  /* XXX is copyObject necessary here? */
255  rel->reltarget->exprs = lappend(rel->reltarget->exprs,
256  copyObject(var));
257  /* reltarget cost and width will be computed later */
258  }
259  rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
260  where_needed);
261  }
262  else if (IsA(node, PlaceHolderVar))
263  {
264  PlaceHolderVar *phv = (PlaceHolderVar *) node;
265  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
266  create_new_ph);
267 
268  phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
269  where_needed);
270  }
271  else
272  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
273  }
274 }
Relids ph_needed
Definition: pathnodes.h:2404
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Relids * attr_needed
Definition: pathnodes.h:709
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
#define ERROR
Definition: elog.h:46
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv, bool create_new_ph)
Definition: placeholder.c:69
Relids relids
Definition: pathnodes.h:676
List * lappend(List *list, void *datum)
Definition: list.c:336
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
Index varno
Definition: primnodes.h:189
List * exprs
Definition: pathnodes.h:1102
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
#define copyObject(obj)
Definition: nodes.h:655
struct PathTarget * reltarget
Definition: pathnodes.h:687
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
AttrNumber min_attr
Definition: pathnodes.h:707

◆ build_base_rel_tlists()

void build_base_rel_tlists ( PlannerInfo root,
List final_tlist 
)

Definition at line 183 of file initsplan.c.

References add_vars_to_targetlist(), bms_make_singleton(), Query::havingQual, list_free(), NIL, PlannerInfo::parse, pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, and PVC_RECURSE_WINDOWFUNCS.

Referenced by query_planner().

184 {
185  List *tlist_vars = pull_var_clause((Node *) final_tlist,
189 
190  if (tlist_vars != NIL)
191  {
192  add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0), true);
193  list_free(tlist_vars);
194  }
195 
196  /*
197  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
198  * that HAVING can contain Aggrefs but not WindowFuncs.
199  */
200  if (root->parse->havingQual)
201  {
202  List *having_vars = pull_var_clause(root->parse->havingQual,
205 
206  if (having_vars != NIL)
207  {
208  add_vars_to_targetlist(root, having_vars,
209  bms_make_singleton(0), true);
210  list_free(having_vars);
211  }
212  }
213 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:161
Definition: nodes.h:539
List * pull_var_clause(Node *node, int flags)
Definition: var.c:562
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:189
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:188
void list_free(List *list)
Definition: list.c:1391
Node * havingQual
Definition: parsenodes.h:163
Definition: pg_list.h:50
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:186

◆ build_implied_join_equality()

RestrictInfo* build_implied_join_equality ( PlannerInfo root,
Oid  opno,
Oid  collation,
Expr item1,
Expr item2,
Relids  qualscope,
Relids  nullable_relids,
Index  security_level 
)

Definition at line 2422 of file initsplan.c.

References check_hashjoinable(), check_mergejoinable(), check_resultcacheable(), copyObject, InvalidOid, make_opclause(), and make_restrictinfo().

Referenced by create_join_clause(), reconsider_full_join_clause(), and reconsider_outer_join_clause().

2430 {
2431  RestrictInfo *restrictinfo;
2432  Expr *clause;
2433 
2434  /*
2435  * Build the new clause. Copy to ensure it shares no substructure with
2436  * original (this is necessary in case there are subselects in there...)
2437  */
2438  clause = make_opclause(opno,
2439  BOOLOID, /* opresulttype */
2440  false, /* opretset */
2441  copyObject(item1),
2442  copyObject(item2),
2443  InvalidOid,
2444  collation);
2445 
2446  /*
2447  * Build the RestrictInfo node itself.
2448  */
2449  restrictinfo = make_restrictinfo(root,
2450  clause,
2451  true, /* is_pushed_down */
2452  false, /* outerjoin_delayed */
2453  false, /* pseudoconstant */
2454  security_level, /* security_level */
2455  qualscope, /* required_relids */
2456  NULL, /* outer_relids */
2457  nullable_relids); /* nullable_relids */
2458 
2459  /* Set mergejoinability/hashjoinability flags */
2460  check_mergejoinable(restrictinfo);
2461  check_hashjoinable(restrictinfo);
2462  check_resultcacheable(restrictinfo);
2463 
2464  return restrictinfo;
2465 }
static void check_resultcacheable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2718
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:610
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:61
#define InvalidOid
Definition: postgres_ext.h:36
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2653
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2690
#define copyObject(obj)
Definition: nodes.h:655

◆ check_equivalence_delay()

static bool check_equivalence_delay ( PlannerInfo root,
RestrictInfo restrictinfo 
)
static

Definition at line 2104 of file initsplan.c.

References bms_copy(), check_outerjoin_delay(), PlannerInfo::join_info_list, RestrictInfo::left_relids, NIL, PostponedQual::relids, and RestrictInfo::right_relids.

Referenced by distribute_qual_to_rels().

2106 {
2107  Relids relids;
2108  Relids nullable_relids;
2109 
2110  /* fast path if no special joins */
2111  if (root->join_info_list == NIL)
2112  return true;
2113 
2114  /* must copy restrictinfo's relids to avoid changing it */
2115  relids = bms_copy(restrictinfo->left_relids);
2116  /* check left side does not need delay */
2117  if (check_outerjoin_delay(root, &relids, &nullable_relids, true))
2118  return false;
2119 
2120  /* and similarly for the right side */
2121  relids = bms_copy(restrictinfo->right_relids);
2122  if (check_outerjoin_delay(root, &relids, &nullable_relids, true))
2123  return false;
2124 
2125  return true;
2126 }
#define NIL
Definition: pg_list.h:65
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p, Relids *nullable_relids_p, bool is_pushed_down)
Definition: initsplan.c:2020
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
List * join_info_list
Definition: pathnodes.h:265
Relids left_relids
Definition: pathnodes.h:2075
Relids right_relids
Definition: pathnodes.h:2076

◆ check_hashjoinable()

static void check_hashjoinable ( RestrictInfo restrictinfo)
static

Definition at line 2690 of file initsplan.c.

References generate_unaccent_rules::args, RestrictInfo::clause, contain_volatile_functions(), exprType(), is_opclause(), linitial, list_length(), op_hashjoinable(), and RestrictInfo::pseudoconstant.

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

2691 {
2692  Expr *clause = restrictinfo->clause;
2693  Oid opno;
2694  Node *leftarg;
2695 
2696  if (restrictinfo->pseudoconstant)
2697  return;
2698  if (!is_opclause(clause))
2699  return;
2700  if (list_length(((OpExpr *) clause)->args) != 2)
2701  return;
2702 
2703  opno = ((OpExpr *) clause)->opno;
2704  leftarg = linitial(((OpExpr *) clause)->args);
2705 
2706  if (op_hashjoinable(opno, exprType(leftarg)) &&
2707  !contain_volatile_functions((Node *) restrictinfo))
2708  restrictinfo->hashjoinoperator = opno;
2709 }
bool pseudoconstant
Definition: pathnodes.h:2053
Definition: nodes.h:539
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
unsigned int Oid
Definition: postgres_ext.h:31
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1408
#define linitial(l)
Definition: pg_list.h:174
Expr * clause
Definition: pathnodes.h:2045
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:66

◆ check_mergejoinable()

static void check_mergejoinable ( RestrictInfo restrictinfo)
static

Definition at line 2653 of file initsplan.c.

References generate_unaccent_rules::args, RestrictInfo::clause, contain_volatile_functions(), exprType(), get_mergejoin_opfamilies(), is_opclause(), linitial, list_length(), op_mergejoinable(), and RestrictInfo::pseudoconstant.

Referenced by build_implied_join_equality(), distribute_qual_to_rels(), and process_implied_equality().

2654 {
2655  Expr *clause = restrictinfo->clause;
2656  Oid opno;
2657  Node *leftarg;
2658 
2659  if (restrictinfo->pseudoconstant)
2660  return;
2661  if (!is_opclause(clause))
2662  return;
2663  if (list_length(((OpExpr *) clause)->args) != 2)
2664  return;
2665 
2666  opno = ((OpExpr *) clause)->opno;
2667  leftarg = linitial(((OpExpr *) clause)->args);
2668 
2669  if (op_mergejoinable(opno, exprType(leftarg)) &&
2670  !contain_volatile_functions((Node *) restrictinfo))
2671  restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
2672 
2673  /*
2674  * Note: op_mergejoinable is just a hint; if we fail to find the operator
2675  * in any btree opfamilies, mergeopfamilies remains NIL and so the clause
2676  * is not treated as mergejoinable.
2677  */
2678 }
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:364
bool pseudoconstant
Definition: pathnodes.h:2053
Definition: nodes.h:539
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1357
unsigned int Oid
Definition: postgres_ext.h:31
#define linitial(l)
Definition: pg_list.h:174
Expr * clause
Definition: pathnodes.h:2045
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:66

◆ check_outerjoin_delay()

static bool check_outerjoin_delay ( PlannerInfo root,
Relids relids_p,
Relids nullable_relids_p,
bool  is_pushed_down 
)
static

Definition at line 2020 of file initsplan.c.

References bms_add_members(), bms_copy(), bms_free(), bms_int_members(), bms_is_subset(), bms_overlap(), SpecialJoinInfo::delay_upper_joins, JOIN_FULL, PlannerInfo::join_info_list, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, NIL, and PostponedQual::relids.

Referenced by check_equivalence_delay(), and distribute_qual_to_rels().

2024 {
2025  Relids relids;
2026  Relids nullable_relids;
2027  bool outerjoin_delayed;
2028  bool found_some;
2029 
2030  /* fast path if no special joins */
2031  if (root->join_info_list == NIL)
2032  {
2033  *nullable_relids_p = NULL;
2034  return false;
2035  }
2036 
2037  /* must copy relids because we need the original value at the end */
2038  relids = bms_copy(*relids_p);
2039  nullable_relids = NULL;
2040  outerjoin_delayed = false;
2041  do
2042  {
2043  ListCell *l;
2044 
2045  found_some = false;
2046  foreach(l, root->join_info_list)
2047  {
2048  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
2049 
2050  /* do we reference any nullable rels of this OJ? */
2051  if (bms_overlap(relids, sjinfo->min_righthand) ||
2052  (sjinfo->jointype == JOIN_FULL &&
2053  bms_overlap(relids, sjinfo->min_lefthand)))
2054  {
2055  /* yes; have we included all its rels in relids? */
2056  if (!bms_is_subset(sjinfo->min_lefthand, relids) ||
2057  !bms_is_subset(sjinfo->min_righthand, relids))
2058  {
2059  /* no, so add them in */
2060  relids = bms_add_members(relids, sjinfo->min_lefthand);
2061  relids = bms_add_members(relids, sjinfo->min_righthand);
2062  outerjoin_delayed = true;
2063  /* we'll need another iteration */
2064  found_some = true;
2065  }
2066  /* track all the nullable rels of relevant OJs */
2067  nullable_relids = bms_add_members(nullable_relids,
2068  sjinfo->min_righthand);
2069  if (sjinfo->jointype == JOIN_FULL)
2070  nullable_relids = bms_add_members(nullable_relids,
2071  sjinfo->min_lefthand);
2072  /* set delay_upper_joins if needed */
2073  if (is_pushed_down && sjinfo->jointype != JOIN_FULL &&
2074  bms_overlap(relids, sjinfo->min_lefthand))
2075  sjinfo->delay_upper_joins = true;
2076  }
2077  }
2078  } while (found_some);
2079 
2080  /* identify just the actually-referenced nullable rels */
2081  nullable_relids = bms_int_members(nullable_relids, *relids_p);
2082 
2083  /* replace *relids_p, and return nullable_relids */
2084  bms_free(*relids_p);
2085  *relids_p = relids;
2086  *nullable_relids_p = nullable_relids;
2087  return outerjoin_delayed;
2088 }
#define NIL
Definition: pg_list.h:65
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
List * join_info_list
Definition: pathnodes.h:265
Relids min_righthand
Definition: pathnodes.h:2242
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
bool delay_upper_joins
Definition: pathnodes.h:2247
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define lfirst(lc)
Definition: pg_list.h:169
JoinType jointype
Definition: pathnodes.h:2245
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:902
Relids min_lefthand
Definition: pathnodes.h:2241
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ check_redundant_nullability_qual()

static bool check_redundant_nullability_qual ( PlannerInfo root,
Node clause 
)
static

Definition at line 2139 of file initsplan.c.

References bms_is_member(), find_forced_null_var(), JOIN_ANTI, PlannerInfo::join_info_list, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::syn_righthand, and Var::varno.

Referenced by distribute_qual_to_rels().

2140 {
2141  Var *forced_null_var;
2142  Index forced_null_rel;
2143  ListCell *lc;
2144 
2145  /* Check for IS NULL, and identify the Var forced to NULL */
2146  forced_null_var = find_forced_null_var(clause);
2147  if (forced_null_var == NULL)
2148  return false;
2149  forced_null_rel = forced_null_var->varno;
2150 
2151  /*
2152  * If the Var comes from the nullable side of a lower antijoin, the IS
2153  * NULL condition is necessarily true.
2154  */
2155  foreach(lc, root->join_info_list)
2156  {
2157  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
2158 
2159  if (sjinfo->jointype == JOIN_ANTI &&
2160  bms_is_member(forced_null_rel, sjinfo->syn_righthand))
2161  return true;
2162  }
2163 
2164  return false;
2165 }
List * join_info_list
Definition: pathnodes.h:265
Definition: primnodes.h:186
Relids syn_righthand
Definition: pathnodes.h:2244
Index varno
Definition: primnodes.h:189
unsigned int Index
Definition: c.h:549
#define lfirst(lc)
Definition: pg_list.h:169
JoinType jointype
Definition: pathnodes.h:2245
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
Var * find_forced_null_var(Node *node)
Definition: clauses.c:1815

◆ check_resultcacheable()

static void check_resultcacheable ( RestrictInfo restrictinfo)
static

Definition at line 2718 of file initsplan.c.

References generate_unaccent_rules::args, RestrictInfo::clause, TypeCacheEntry::eq_opr, exprType(), TypeCacheEntry::hash_proc, RestrictInfo::hasheqoperator, is_opclause(), linitial, list_length(), lookup_type_cache(), OidIsValid, RestrictInfo::pseudoconstant, TYPECACHE_EQ_OPR, and TYPECACHE_HASH_PROC.

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

2719 {
2720  TypeCacheEntry *typentry;
2721  Expr *clause = restrictinfo->clause;
2722  Node *leftarg;
2723 
2724  if (restrictinfo->pseudoconstant)
2725  return;
2726  if (!is_opclause(clause))
2727  return;
2728  if (list_length(((OpExpr *) clause)->args) != 2)
2729  return;
2730 
2731  leftarg = linitial(((OpExpr *) clause)->args);
2732 
2733  typentry = lookup_type_cache(exprType(leftarg), TYPECACHE_HASH_PROC |
2735 
2736  if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr))
2737  return;
2738 
2739  restrictinfo->hasheqoperator = typentry->eq_opr;
2740 }
bool pseudoconstant
Definition: pathnodes.h:2053
Definition: nodes.h:539
#define TYPECACHE_EQ_OPR
Definition: typcache.h:136
#define OidIsValid(objectId)
Definition: c.h:710
#define linitial(l)
Definition: pg_list.h:174
Oid hasheqoperator
Definition: pathnodes.h:2115
Expr * clause
Definition: pathnodes.h:2045
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:338
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:66
#define TYPECACHE_HASH_PROC
Definition: typcache.h:140

◆ compute_semijoin_info()

static void compute_semijoin_info ( PlannerInfo root,
SpecialJoinInfo sjinfo,
List clause 
)
static

Definition at line 1396 of file initsplan.c.

References OpExpr::args, bms_is_empty(), bms_is_subset(), bms_overlap(), bms_union(), contain_volatile_functions(), copyObject, enable_hashagg, exprType(), get_commutator(), get_mergejoin_opfamilies(), IsA, JOIN_SEMI, SpecialJoinInfo::jointype, lappend(), lappend_oid(), lfirst, linitial, list_length(), lsecond, NIL, OidIsValid, op_hashjoinable(), op_mergejoinable(), OpExpr::opno, pull_varnos(), SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, SpecialJoinInfo::semi_operators, SpecialJoinInfo::semi_rhs_exprs, and SpecialJoinInfo::syn_righthand.

Referenced by make_outerjoininfo().

1397 {
1398  List *semi_operators;
1399  List *semi_rhs_exprs;
1400  bool all_btree;
1401  bool all_hash;
1402  ListCell *lc;
1403 
1404  /* Initialize semijoin-related fields in case we can't unique-ify */
1405  sjinfo->semi_can_btree = false;
1406  sjinfo->semi_can_hash = false;
1407  sjinfo->semi_operators = NIL;
1408  sjinfo->semi_rhs_exprs = NIL;
1409 
1410  /* Nothing more to do if it's not a semijoin */
1411  if (sjinfo->jointype != JOIN_SEMI)
1412  return;
1413 
1414  /*
1415  * Look to see whether the semijoin's join quals consist of AND'ed
1416  * equality operators, with (only) RHS variables on only one side of each
1417  * one. If so, we can figure out how to enforce uniqueness for the RHS.
1418  *
1419  * Note that the input clause list is the list of quals that are
1420  * *syntactically* associated with the semijoin, which in practice means
1421  * the synthesized comparison list for an IN or the WHERE of an EXISTS.
1422  * Particularly in the latter case, it might contain clauses that aren't
1423  * *semantically* associated with the join, but refer to just one side or
1424  * the other. We can ignore such clauses here, as they will just drop
1425  * down to be processed within one side or the other. (It is okay to
1426  * consider only the syntactically-associated clauses here because for a
1427  * semijoin, no higher-level quals could refer to the RHS, and so there
1428  * can be no other quals that are semantically associated with this join.
1429  * We do things this way because it is useful to have the set of potential
1430  * unique-ification expressions before we can extract the list of quals
1431  * that are actually semantically associated with the particular join.)
1432  *
1433  * Note that the semi_operators list consists of the joinqual operators
1434  * themselves (but commuted if needed to put the RHS value on the right).
1435  * These could be cross-type operators, in which case the operator
1436  * actually needed for uniqueness is a related single-type operator. We
1437  * assume here that that operator will be available from the btree or hash
1438  * opclass when the time comes ... if not, create_unique_plan() will fail.
1439  */
1440  semi_operators = NIL;
1441  semi_rhs_exprs = NIL;
1442  all_btree = true;
1443  all_hash = enable_hashagg; /* don't consider hash if not enabled */
1444  foreach(lc, clause)
1445  {
1446  OpExpr *op = (OpExpr *) lfirst(lc);
1447  Oid opno;
1448  Node *left_expr;
1449  Node *right_expr;
1450  Relids left_varnos;
1451  Relids right_varnos;
1452  Relids all_varnos;
1453  Oid opinputtype;
1454 
1455  /* Is it a binary opclause? */
1456  if (!IsA(op, OpExpr) ||
1457  list_length(op->args) != 2)
1458  {
1459  /* No, but does it reference both sides? */
1460  all_varnos = pull_varnos(root, (Node *) op);
1461  if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
1462  bms_is_subset(all_varnos, sjinfo->syn_righthand))
1463  {
1464  /*
1465  * Clause refers to only one rel, so ignore it --- unless it
1466  * contains volatile functions, in which case we'd better
1467  * punt.
1468  */
1469  if (contain_volatile_functions((Node *) op))
1470  return;
1471  continue;
1472  }
1473  /* Non-operator clause referencing both sides, must punt */
1474  return;
1475  }
1476 
1477  /* Extract data from binary opclause */
1478  opno = op->opno;
1479  left_expr = linitial(op->args);
1480  right_expr = lsecond(op->args);
1481  left_varnos = pull_varnos(root, left_expr);
1482  right_varnos = pull_varnos(root, right_expr);
1483  all_varnos = bms_union(left_varnos, right_varnos);
1484  opinputtype = exprType(left_expr);
1485 
1486  /* Does it reference both sides? */
1487  if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
1488  bms_is_subset(all_varnos, sjinfo->syn_righthand))
1489  {
1490  /*
1491  * Clause refers to only one rel, so ignore it --- unless it
1492  * contains volatile functions, in which case we'd better punt.
1493  */
1494  if (contain_volatile_functions((Node *) op))
1495  return;
1496  continue;
1497  }
1498 
1499  /* check rel membership of arguments */
1500  if (!bms_is_empty(right_varnos) &&
1501  bms_is_subset(right_varnos, sjinfo->syn_righthand) &&
1502  !bms_overlap(left_varnos, sjinfo->syn_righthand))
1503  {
1504  /* typical case, right_expr is RHS variable */
1505  }
1506  else if (!bms_is_empty(left_varnos) &&
1507  bms_is_subset(left_varnos, sjinfo->syn_righthand) &&
1508  !bms_overlap(right_varnos, sjinfo->syn_righthand))
1509  {
1510  /* flipped case, left_expr is RHS variable */
1511  opno = get_commutator(opno);
1512  if (!OidIsValid(opno))
1513  return;
1514  right_expr = left_expr;
1515  }
1516  else
1517  {
1518  /* mixed membership of args, punt */
1519  return;
1520  }
1521 
1522  /* all operators must be btree equality or hash equality */
1523  if (all_btree)
1524  {
1525  /* oprcanmerge is considered a hint... */
1526  if (!op_mergejoinable(opno, opinputtype) ||
1527  get_mergejoin_opfamilies(opno) == NIL)
1528  all_btree = false;
1529  }
1530  if (all_hash)
1531  {
1532  /* ... but oprcanhash had better be correct */
1533  if (!op_hashjoinable(opno, opinputtype))
1534  all_hash = false;
1535  }
1536  if (!(all_btree || all_hash))
1537  return;
1538 
1539  /* so far so good, keep building lists */
1540  semi_operators = lappend_oid(semi_operators, opno);
1541  semi_rhs_exprs = lappend(semi_rhs_exprs, copyObject(right_expr));
1542  }
1543 
1544  /* Punt if we didn't find at least one column to unique-ify */
1545  if (semi_rhs_exprs == NIL)
1546  return;
1547 
1548  /*
1549  * The expressions we'd need to unique-ify mustn't be volatile.
1550  */
1551  if (contain_volatile_functions((Node *) semi_rhs_exprs))
1552  return;
1553 
1554  /*
1555  * If we get here, we can unique-ify the semijoin's RHS using at least one
1556  * of sorting and hashing. Save the information about how to do that.
1557  */
1558  sjinfo->semi_can_btree = all_btree;
1559  sjinfo->semi_can_hash = all_hash;
1560  sjinfo->semi_operators = semi_operators;
1561  sjinfo->semi_rhs_exprs = semi_rhs_exprs;
1562 }
#define NIL
Definition: pg_list.h:65
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1480
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:364
Definition: nodes.h:539
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1357
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
#define lsecond(l)
Definition: pg_list.h:179
Relids syn_righthand
Definition: pathnodes.h:2244
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1408
#define linitial(l)
Definition: pg_list.h:174
List * semi_rhs_exprs
Definition: pathnodes.h:2252
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
List * lappend(List *list, void *datum)
Definition: list.c:336
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define lfirst(lc)
Definition: pg_list.h:169
JoinType jointype
Definition: pathnodes.h:2245
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
bool enable_hashagg
Definition: costsize.c:140
List * semi_operators
Definition: pathnodes.h:2251
Oid opno
Definition: primnodes.h:542
#define copyObject(obj)
Definition: nodes.h:655
List * args
Definition: primnodes.h:548
Definition: pg_list.h:50

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 450 of file initsplan.c.

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_get_singleton_member(), bms_is_empty(), bms_is_member(), bms_next_member(), RelOptInfo::direct_lateral_relids, find_base_rel(), find_placeholder_info(), PlannerInfo::hasLateralRTEs, IsA, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, lfirst, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_lateral, PlannerInfo::placeholder_list, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, PlannerInfo::simple_rel_array_size, and Var::varno.

Referenced by query_planner().

451 {
452  bool found_laterals = false;
453  Index rti;
454  ListCell *lc;
455 
456  /* We need do nothing if the query contains no LATERAL RTEs */
457  if (!root->hasLateralRTEs)
458  return;
459 
460  /*
461  * Examine all baserels (the rel array has been set up by now).
462  */
463  for (rti = 1; rti < root->simple_rel_array_size; rti++)
464  {
465  RelOptInfo *brel = root->simple_rel_array[rti];
466  Relids lateral_relids;
467 
468  /* there may be empty slots corresponding to non-baserel RTEs */
469  if (brel == NULL)
470  continue;
471 
472  Assert(brel->relid == rti); /* sanity check on array */
473 
474  /* ignore RTEs that are "other rels" */
475  if (brel->reloptkind != RELOPT_BASEREL)
476  continue;
477 
478  lateral_relids = NULL;
479 
480  /* consider each laterally-referenced Var or PHV */
481  foreach(lc, brel->lateral_vars)
482  {
483  Node *node = (Node *) lfirst(lc);
484 
485  if (IsA(node, Var))
486  {
487  Var *var = (Var *) node;
488 
489  found_laterals = true;
490  lateral_relids = bms_add_member(lateral_relids,
491  var->varno);
492  }
493  else if (IsA(node, PlaceHolderVar))
494  {
495  PlaceHolderVar *phv = (PlaceHolderVar *) node;
496  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
497  false);
498 
499  found_laterals = true;
500  lateral_relids = bms_add_members(lateral_relids,
501  phinfo->ph_eval_at);
502  }
503  else
504  Assert(false);
505  }
506 
507  /* We now have all the simple lateral refs from this rel */
508  brel->direct_lateral_relids = lateral_relids;
509  brel->lateral_relids = bms_copy(lateral_relids);
510  }
511 
512  /*
513  * Now check for lateral references within PlaceHolderVars, and mark their
514  * eval_at rels as having lateral references to the source rels.
515  *
516  * For a PHV that is due to be evaluated at a baserel, mark its source(s)
517  * as direct lateral dependencies of the baserel (adding onto the ones
518  * recorded above). If it's due to be evaluated at a join, mark its
519  * source(s) as indirect lateral dependencies of each baserel in the join,
520  * ie put them into lateral_relids but not direct_lateral_relids. This is
521  * appropriate because we can't put any such baserel on the outside of a
522  * join to one of the PHV's lateral dependencies, but on the other hand we
523  * also can't yet join it directly to the dependency.
524  */
525  foreach(lc, root->placeholder_list)
526  {
527  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
528  Relids eval_at = phinfo->ph_eval_at;
529  int varno;
530 
531  if (phinfo->ph_lateral == NULL)
532  continue; /* PHV is uninteresting if no lateral refs */
533 
534  found_laterals = true;
535 
536  if (bms_get_singleton_member(eval_at, &varno))
537  {
538  /* Evaluation site is a baserel */
539  RelOptInfo *brel = find_base_rel(root, varno);
540 
541  brel->direct_lateral_relids =
543  phinfo->ph_lateral);
544  brel->lateral_relids =
546  phinfo->ph_lateral);
547  }
548  else
549  {
550  /* Evaluation site is a join */
551  varno = -1;
552  while ((varno = bms_next_member(eval_at, varno)) >= 0)
553  {
554  RelOptInfo *brel = find_base_rel(root, varno);
555 
557  phinfo->ph_lateral);
558  }
559  }
560  }
561 
562  /*
563  * If we found no actual lateral references, we're done; but reset the
564  * hasLateralRTEs flag to avoid useless work later.
565  */
566  if (!found_laterals)
567  {
568  root->hasLateralRTEs = false;
569  return;
570  }
571 
572  /*
573  * Calculate the transitive closure of the lateral_relids sets, so that
574  * they describe both direct and indirect lateral references. If relation
575  * X references Y laterally, and Y references Z laterally, then we will
576  * have to scan X on the inside of a nestloop with Z, so for all intents
577  * and purposes X is laterally dependent on Z too.
578  *
579  * This code is essentially Warshall's algorithm for transitive closure.
580  * The outer loop considers each baserel, and propagates its lateral
581  * dependencies to those baserels that have a lateral dependency on it.
582  */
583  for (rti = 1; rti < root->simple_rel_array_size; rti++)
584  {
585  RelOptInfo *brel = root->simple_rel_array[rti];
586  Relids outer_lateral_relids;
587  Index rti2;
588 
589  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
590  continue;
591 
592  /* need not consider baserel further if it has no lateral refs */
593  outer_lateral_relids = brel->lateral_relids;
594  if (outer_lateral_relids == NULL)
595  continue;
596 
597  /* else scan all baserels */
598  for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
599  {
600  RelOptInfo *brel2 = root->simple_rel_array[rti2];
601 
602  if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
603  continue;
604 
605  /* if brel2 has lateral ref to brel, propagate brel's refs */
606  if (bms_is_member(rti, brel2->lateral_relids))
608  outer_lateral_relids);
609  }
610  }
611 
612  /*
613  * Now that we've identified all lateral references, mark each baserel
614  * with the set of relids of rels that reference it laterally (possibly
615  * indirectly) --- that is, the inverse mapping of lateral_relids.
616  */
617  for (rti = 1; rti < root->simple_rel_array_size; rti++)
618  {
619  RelOptInfo *brel = root->simple_rel_array[rti];
620  Relids lateral_relids;
621  int rti2;
622 
623  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
624  continue;
625 
626  /* Nothing to do at rels with no lateral refs */
627  lateral_relids = brel->lateral_relids;
628  if (lateral_relids == NULL)
629  continue;
630 
631  /*
632  * We should not have broken the invariant that lateral_relids is
633  * exactly NULL if empty.
634  */
635  Assert(!bms_is_empty(lateral_relids));
636 
637  /* Also, no rel should have a lateral dependency on itself */
638  Assert(!bms_is_member(rti, lateral_relids));
639 
640  /* Mark this rel's referencees */
641  rti2 = -1;
642  while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
643  {
644  RelOptInfo *brel2 = root->simple_rel_array[rti2];
645 
646  Assert(brel2 != NULL && brel2->reloptkind == RELOPT_BASEREL);
647  brel2->lateral_referencers =
648  bms_add_member(brel2->lateral_referencers, rti);
649  }
650  }
651 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Relids ph_eval_at
Definition: pathnodes.h:2402
RelOptKind reloptkind
Definition: pathnodes.h:673
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
Definition: nodes.h:539
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:615
Definition: primnodes.h:186
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
Relids lateral_relids
Definition: pathnodes.h:701
bool hasLateralRTEs
Definition: pathnodes.h:346
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv, bool create_new_ph)
Definition: placeholder.c:69
int simple_rel_array_size
Definition: pathnodes.h:186
Index relid
Definition: pathnodes.h:704
Relids lateral_referencers
Definition: pathnodes.h:712
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
Index varno
Definition: primnodes.h:189
Relids direct_lateral_relids
Definition: pathnodes.h:700
Relids ph_lateral
Definition: pathnodes.h:2403
unsigned int Index
Definition: c.h:549
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
List * lateral_vars
Definition: pathnodes.h:711
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * placeholder_list
Definition: pathnodes.h:289
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ deconstruct_jointree()

List* deconstruct_jointree ( PlannerInfo root)

Definition at line 687 of file initsplan.c.

References Assert, deconstruct_recurse(), IsA, Query::jointree, NIL, PlannerInfo::nullable_baserels, and PlannerInfo::parse.

Referenced by query_planner().

688 {
689  List *result;
690  Relids qualscope;
691  Relids inner_join_rels;
692  List *postponed_qual_list = NIL;
693 
694  /* Start recursion at top of jointree */
695  Assert(root->parse->jointree != NULL &&
696  IsA(root->parse->jointree, FromExpr));
697 
698  /* this is filled as we scan the jointree */
699  root->nullable_baserels = NULL;
700 
701  result = deconstruct_recurse(root, (Node *) root->parse->jointree, false,
702  &qualscope, &inner_join_rels,
703  &postponed_qual_list);
704 
705  /* Shouldn't be any leftover quals */
706  Assert(postponed_qual_list == NIL);
707 
708  return result;
709 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
#define Assert(condition)
Definition: c.h:804
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, Relids *qualscope, Relids *inner_join_rels, List **postponed_qual_list)
Definition: initsplan.c:733
Relids nullable_baserels
Definition: pathnodes.h:217
Definition: pg_list.h:50

◆ deconstruct_recurse()

static List * deconstruct_recurse ( PlannerInfo root,
Node jtnode,
bool  below_outer_join,
Relids qualscope,
Relids inner_join_rels,
List **  postponed_qual_list 
)
static

Definition at line 733 of file initsplan.c.

References Assert, bms_add_members(), bms_is_subset(), bms_make_singleton(), bms_union(), distribute_qual_to_rels(), elog, ERROR, from_collapse_limit, FromExpr::fromlist, IsA, JOIN_ANTI, join_collapse_limit, JOIN_FULL, PlannerInfo::join_info_list, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, JoinExpr::jointype, lappend(), JoinExpr::larg, lfirst, linitial, list_concat(), list_length(), list_make1, list_make2, make_outerjoininfo(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, NIL, nodeTag, PlannerInfo::nullable_baserels, process_security_barrier_quals(), PostponedQual::qual, PlannerInfo::qual_security_level, JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, PostponedQual::relids, remaining, and update_placeholder_eval_levels().

Referenced by deconstruct_jointree().

736 {
737  List *joinlist;
738 
739  if (jtnode == NULL)
740  {
741  *qualscope = NULL;
742  *inner_join_rels = NULL;
743  return NIL;
744  }
745  if (IsA(jtnode, RangeTblRef))
746  {
747  int varno = ((RangeTblRef *) jtnode)->rtindex;
748 
749  /* qualscope is just the one RTE */
750  *qualscope = bms_make_singleton(varno);
751  /* Deal with any securityQuals attached to the RTE */
752  if (root->qual_security_level > 0)
754  varno,
755  *qualscope,
756  below_outer_join);
757  /* A single baserel does not create an inner join */
758  *inner_join_rels = NULL;
759  joinlist = list_make1(jtnode);
760  }
761  else if (IsA(jtnode, FromExpr))
762  {
763  FromExpr *f = (FromExpr *) jtnode;
764  List *child_postponed_quals = NIL;
765  int remaining;
766  ListCell *l;
767 
768  /*
769  * First, recurse to handle child joins. We collapse subproblems into
770  * a single joinlist whenever the resulting joinlist wouldn't exceed
771  * from_collapse_limit members. Also, always collapse one-element
772  * subproblems, since that won't lengthen the joinlist anyway.
773  */
774  *qualscope = NULL;
775  *inner_join_rels = NULL;
776  joinlist = NIL;
777  remaining = list_length(f->fromlist);
778  foreach(l, f->fromlist)
779  {
780  Relids sub_qualscope;
781  List *sub_joinlist;
782  int sub_members;
783 
784  sub_joinlist = deconstruct_recurse(root, lfirst(l),
785  below_outer_join,
786  &sub_qualscope,
787  inner_join_rels,
788  &child_postponed_quals);
789  *qualscope = bms_add_members(*qualscope, sub_qualscope);
790  sub_members = list_length(sub_joinlist);
791  remaining--;
792  if (sub_members <= 1 ||
793  list_length(joinlist) + sub_members + remaining <= from_collapse_limit)
794  joinlist = list_concat(joinlist, sub_joinlist);
795  else
796  joinlist = lappend(joinlist, sub_joinlist);
797  }
798 
799  /*
800  * A FROM with more than one list element is an inner join subsuming
801  * all below it, so we should report inner_join_rels = qualscope. If
802  * there was exactly one element, we should (and already did) report
803  * whatever its inner_join_rels were. If there were no elements (is
804  * that still possible?) the initialization before the loop fixed it.
805  */
806  if (list_length(f->fromlist) > 1)
807  *inner_join_rels = *qualscope;
808 
809  /*
810  * Try to process any quals postponed by children. If they need
811  * further postponement, add them to my output postponed_qual_list.
812  */
813  foreach(l, child_postponed_quals)
814  {
815  PostponedQual *pq = (PostponedQual *) lfirst(l);
816 
817  if (bms_is_subset(pq->relids, *qualscope))
818  distribute_qual_to_rels(root, pq->qual,
819  below_outer_join, JOIN_INNER,
820  root->qual_security_level,
821  *qualscope, NULL, NULL,
822  NULL);
823  else
824  *postponed_qual_list = lappend(*postponed_qual_list, pq);
825  }
826 
827  /*
828  * Now process the top-level quals.
829  */
830  foreach(l, (List *) f->quals)
831  {
832  Node *qual = (Node *) lfirst(l);
833 
834  distribute_qual_to_rels(root, qual,
835  below_outer_join, JOIN_INNER,
836  root->qual_security_level,
837  *qualscope, NULL, NULL,
838  postponed_qual_list);
839  }
840  }
841  else if (IsA(jtnode, JoinExpr))
842  {
843  JoinExpr *j = (JoinExpr *) jtnode;
844  List *child_postponed_quals = NIL;
845  Relids leftids,
846  rightids,
847  left_inners,
848  right_inners,
849  nonnullable_rels,
850  nullable_rels,
851  ojscope;
852  List *leftjoinlist,
853  *rightjoinlist;
854  List *my_quals;
855  SpecialJoinInfo *sjinfo;
856  ListCell *l;
857 
858  /*
859  * Order of operations here is subtle and critical. First we recurse
860  * to handle sub-JOINs. Their join quals will be placed without
861  * regard for whether this level is an outer join, which is correct.
862  * Then we place our own join quals, which are restricted by lower
863  * outer joins in any case, and are forced to this level if this is an
864  * outer join and they mention the outer side. Finally, if this is an
865  * outer join, we create a join_info_list entry for the join. This
866  * will prevent quals above us in the join tree that use those rels
867  * from being pushed down below this level. (It's okay for upper
868  * quals to be pushed down to the outer side, however.)
869  */
870  switch (j->jointype)
871  {
872  case JOIN_INNER:
873  leftjoinlist = deconstruct_recurse(root, j->larg,
874  below_outer_join,
875  &leftids, &left_inners,
876  &child_postponed_quals);
877  rightjoinlist = deconstruct_recurse(root, j->rarg,
878  below_outer_join,
879  &rightids, &right_inners,
880  &child_postponed_quals);
881  *qualscope = bms_union(leftids, rightids);
882  *inner_join_rels = *qualscope;
883  /* Inner join adds no restrictions for quals */
884  nonnullable_rels = NULL;
885  /* and it doesn't force anything to null, either */
886  nullable_rels = NULL;
887  break;
888  case JOIN_LEFT:
889  case JOIN_ANTI:
890  leftjoinlist = deconstruct_recurse(root, j->larg,
891  below_outer_join,
892  &leftids, &left_inners,
893  &child_postponed_quals);
894  rightjoinlist = deconstruct_recurse(root, j->rarg,
895  true,
896  &rightids, &right_inners,
897  &child_postponed_quals);
898  *qualscope = bms_union(leftids, rightids);
899  *inner_join_rels = bms_union(left_inners, right_inners);
900  nonnullable_rels = leftids;
901  nullable_rels = rightids;
902  break;
903  case JOIN_SEMI:
904  leftjoinlist = deconstruct_recurse(root, j->larg,
905  below_outer_join,
906  &leftids, &left_inners,
907  &child_postponed_quals);
908  rightjoinlist = deconstruct_recurse(root, j->rarg,
909  below_outer_join,
910  &rightids, &right_inners,
911  &child_postponed_quals);
912  *qualscope = bms_union(leftids, rightids);
913  *inner_join_rels = bms_union(left_inners, right_inners);
914  /* Semi join adds no restrictions for quals */
915  nonnullable_rels = NULL;
916 
917  /*
918  * Theoretically, a semijoin would null the RHS; but since the
919  * RHS can't be accessed above the join, this is immaterial
920  * and we needn't account for it.
921  */
922  nullable_rels = NULL;
923  break;
924  case JOIN_FULL:
925  leftjoinlist = deconstruct_recurse(root, j->larg,
926  true,
927  &leftids, &left_inners,
928  &child_postponed_quals);
929  rightjoinlist = deconstruct_recurse(root, j->rarg,
930  true,
931  &rightids, &right_inners,
932  &child_postponed_quals);
933  *qualscope = bms_union(leftids, rightids);
934  *inner_join_rels = bms_union(left_inners, right_inners);
935  /* each side is both outer and inner */
936  nonnullable_rels = *qualscope;
937  nullable_rels = *qualscope;
938  break;
939  default:
940  /* JOIN_RIGHT was eliminated during reduce_outer_joins() */
941  elog(ERROR, "unrecognized join type: %d",
942  (int) j->jointype);
943  nonnullable_rels = NULL; /* keep compiler quiet */
944  nullable_rels = NULL;
945  leftjoinlist = rightjoinlist = NIL;
946  break;
947  }
948 
949  /* Report all rels that will be nulled anywhere in the jointree */
951  nullable_rels);
952 
953  /*
954  * Try to process any quals postponed by children. If they need
955  * further postponement, add them to my output postponed_qual_list.
956  * Quals that can be processed now must be included in my_quals, so
957  * that they'll be handled properly in make_outerjoininfo.
958  */
959  my_quals = NIL;
960  foreach(l, child_postponed_quals)
961  {
962  PostponedQual *pq = (PostponedQual *) lfirst(l);
963 
964  if (bms_is_subset(pq->relids, *qualscope))
965  my_quals = lappend(my_quals, pq->qual);
966  else
967  {
968  /*
969  * We should not be postponing any quals past an outer join.
970  * If this Assert fires, pull_up_subqueries() messed up.
971  */
972  Assert(j->jointype == JOIN_INNER);
973  *postponed_qual_list = lappend(*postponed_qual_list, pq);
974  }
975  }
976  my_quals = list_concat(my_quals, (List *) j->quals);
977 
978  /*
979  * For an OJ, form the SpecialJoinInfo now, because we need the OJ's
980  * semantic scope (ojscope) to pass to distribute_qual_to_rels. But
981  * we mustn't add it to join_info_list just yet, because we don't want
982  * distribute_qual_to_rels to think it is an outer join below us.
983  *
984  * Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we
985  * want ojscope = NULL for distribute_qual_to_rels.
986  */
987  if (j->jointype != JOIN_INNER)
988  {
989  sjinfo = make_outerjoininfo(root,
990  leftids, rightids,
991  *inner_join_rels,
992  j->jointype,
993  my_quals);
994  if (j->jointype == JOIN_SEMI)
995  ojscope = NULL;
996  else
997  ojscope = bms_union(sjinfo->min_lefthand,
998  sjinfo->min_righthand);
999  }
1000  else
1001  {
1002  sjinfo = NULL;
1003  ojscope = NULL;
1004  }
1005 
1006  /* Process the JOIN's qual clauses */
1007  foreach(l, my_quals)
1008  {
1009  Node *qual = (Node *) lfirst(l);
1010 
1011  distribute_qual_to_rels(root, qual,
1012  below_outer_join, j->jointype,
1013  root->qual_security_level,
1014  *qualscope,
1015  ojscope, nonnullable_rels,
1016  postponed_qual_list);
1017  }
1018 
1019  /* Now we can add the SpecialJoinInfo to join_info_list */
1020  if (sjinfo)
1021  {
1022  root->join_info_list = lappend(root->join_info_list, sjinfo);
1023  /* Each time we do that, recheck placeholder eval levels */
1024  update_placeholder_eval_levels(root, sjinfo);
1025  }
1026 
1027  /*
1028  * Finally, compute the output joinlist. We fold subproblems together
1029  * except at a FULL JOIN or where join_collapse_limit would be
1030  * exceeded.
1031  */
1032  if (j->jointype == JOIN_FULL)
1033  {
1034  /* force the join order exactly at this node */
1035  joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist));
1036  }
1037  else if (list_length(leftjoinlist) + list_length(rightjoinlist) <=
1039  {
1040  /* OK to combine subproblems */
1041  joinlist = list_concat(leftjoinlist, rightjoinlist);
1042  }
1043  else
1044  {
1045  /* can't combine, but needn't force join order above here */
1046  Node *leftpart,
1047  *rightpart;
1048 
1049  /* avoid creating useless 1-element sublists */
1050  if (list_length(leftjoinlist) == 1)
1051  leftpart = (Node *) linitial(leftjoinlist);
1052  else
1053  leftpart = (Node *) leftjoinlist;
1054  if (list_length(rightjoinlist) == 1)
1055  rightpart = (Node *) linitial(rightjoinlist);
1056  else
1057  rightpart = (Node *) rightjoinlist;
1058  joinlist = list_make2(leftpart, rightpart);
1059  }
1060  }
1061  else
1062  {
1063  elog(ERROR, "unrecognized node type: %d",
1064  (int) nodeTag(jtnode));
1065  joinlist = NIL; /* keep compiler quiet */
1066  }
1067  return joinlist;
1068 }
int remaining
Definition: informix.c:667
#define list_make2(x1, x2)
Definition: pg_list.h:208
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * join_info_list
Definition: pathnodes.h:265
Relids min_righthand
Definition: pathnodes.h:2242
static void process_security_barrier_quals(PlannerInfo *root, int rti, Relids qualscope, bool below_outer_join)
Definition: initsplan.c:1084
Definition: nodes.h:539
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
List * fromlist
Definition: primnodes.h:1553
static void distribute_qual_to_rels(PlannerInfo *root, Node *clause, bool below_outer_join, JoinType jointype, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, List **postponed_qual_list)
Definition: initsplan.c:1606
Node * quals
Definition: primnodes.h:1554
Node * qual
Definition: initsplan.c:46
Node * larg
Definition: primnodes.h:1532
#define list_make1(x1)
Definition: pg_list.h:206
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
static SpecialJoinInfo * make_outerjoininfo(PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, JoinType jointype, List *clause)
Definition: initsplan.c:1148
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
List * lappend(List *list, void *datum)
Definition: list.c:336
int from_collapse_limit
Definition: initsplan.c:39
Node * quals
Definition: primnodes.h:1536
Node * rarg
Definition: primnodes.h:1533
JoinType jointype
Definition: primnodes.h:1530
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
static int list_length(const List *l)
Definition: pg_list.h:149
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, Relids *qualscope, Relids *inner_join_rels, List **postponed_qual_list)
Definition: initsplan.c:733
int join_collapse_limit
Definition: initsplan.c:40
Index qual_security_level
Definition: pathnodes.h:342
#define nodeTag(nodeptr)
Definition: nodes.h:544
void update_placeholder_eval_levels(PlannerInfo *root, SpecialJoinInfo *new_sjinfo)
Definition: placeholder.c:265
Relids nullable_baserels
Definition: pathnodes.h:217
#define elog(elevel,...)
Definition: elog.h:232
Relids relids
Definition: initsplan.c:47
Definition: pg_list.h:50
Relids min_lefthand
Definition: pathnodes.h:2241
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ distribute_qual_to_rels()

static void distribute_qual_to_rels ( PlannerInfo root,
Node clause,
bool  below_outer_join,
JoinType  jointype,
Index  security_level,
Relids  qualscope,
Relids  ojscope,
Relids  outerjoin_nonnullable,
List **  postponed_qual_list 
)
static

Definition at line 1606 of file initsplan.c.

References add_vars_to_targetlist(), Assert, bms_copy(), bms_is_empty(), bms_is_subset(), bms_membership(), BMS_MULTIPLE, bms_overlap(), RestrictInfo::can_join, check_equivalence_delay(), check_mergejoinable(), check_outerjoin_delay(), check_redundant_nullability_qual(), contain_volatile_functions(), distribute_restrictinfo_to_rels(), elog, ERROR, PlannerInfo::full_join_clauses, get_relids_in_jointree(), PlannerInfo::hasLateralRTEs, PlannerInfo::hasPseudoConstantQuals, initialize_mergeclause_eclasses(), JOIN_FULL, JOIN_INNER, Query::jointree, lappend(), PlannerInfo::left_join_clauses, RestrictInfo::left_relids, list_free(), make_restrictinfo(), RestrictInfo::mergeopfamilies, palloc(), PlannerInfo::parse, process_equivalence(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, PostponedQual::qual, PostponedQual::relids, PlannerInfo::right_join_clauses, and RestrictInfo::right_relids.

Referenced by deconstruct_recurse(), and process_security_barrier_quals().

1614 {
1615  Relids relids;
1616  bool is_pushed_down;
1617  bool outerjoin_delayed;
1618  bool pseudoconstant = false;
1619  bool maybe_equivalence;
1620  bool maybe_outer_join;
1621  Relids nullable_relids;
1622  RestrictInfo *restrictinfo;
1623 
1624  /*
1625  * Retrieve all relids mentioned within the clause.
1626  */
1627  relids = pull_varnos(root, clause);
1628 
1629  /*
1630  * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels
1631  * that aren't within its syntactic scope; however, if we pulled up a
1632  * LATERAL subquery then we might find such references in quals that have
1633  * been pulled up. We need to treat such quals as belonging to the join
1634  * level that includes every rel they reference. Although we could make
1635  * pull_up_subqueries() place such quals correctly to begin with, it's
1636  * easier to handle it here. When we find a clause that contains Vars
1637  * outside its syntactic scope, we add it to the postponed-quals list, and
1638  * process it once we've recursed back up to the appropriate join level.
1639  */
1640  if (!bms_is_subset(relids, qualscope))
1641  {
1642  PostponedQual *pq = (PostponedQual *) palloc(sizeof(PostponedQual));
1643 
1644  Assert(root->hasLateralRTEs); /* shouldn't happen otherwise */
1645  Assert(jointype == JOIN_INNER); /* mustn't postpone past outer join */
1646  pq->qual = clause;
1647  pq->relids = relids;
1648  *postponed_qual_list = lappend(*postponed_qual_list, pq);
1649  return;
1650  }
1651 
1652  /*
1653  * If it's an outer-join clause, also check that relids is a subset of
1654  * ojscope. (This should not fail if the syntactic scope check passed.)
1655  */
1656  if (ojscope && !bms_is_subset(relids, ojscope))
1657  elog(ERROR, "JOIN qualification cannot refer to other relations");
1658 
1659  /*
1660  * If the clause is variable-free, our normal heuristic for pushing it
1661  * down to just the mentioned rels doesn't work, because there are none.
1662  *
1663  * If the clause is an outer-join clause, we must force it to the OJ's
1664  * semantic level to preserve semantics.
1665  *
1666  * Otherwise, when the clause contains volatile functions, we force it to
1667  * be evaluated at its original syntactic level. This preserves the
1668  * expected semantics.
1669  *
1670  * When the clause contains no volatile functions either, it is actually a
1671  * pseudoconstant clause that will not change value during any one
1672  * execution of the plan, and hence can be used as a one-time qual in a
1673  * gating Result plan node. We put such a clause into the regular
1674  * RestrictInfo lists for the moment, but eventually createplan.c will
1675  * pull it out and make a gating Result node immediately above whatever
1676  * plan node the pseudoconstant clause is assigned to. It's usually best
1677  * to put a gating node as high in the plan tree as possible. If we are
1678  * not below an outer join, we can actually push the pseudoconstant qual
1679  * all the way to the top of the tree. If we are below an outer join, we
1680  * leave the qual at its original syntactic level (we could push it up to
1681  * just below the outer join, but that seems more complex than it's
1682  * worth).
1683  */
1684  if (bms_is_empty(relids))
1685  {
1686  if (ojscope)
1687  {
1688  /* clause is attached to outer join, eval it there */
1689  relids = bms_copy(ojscope);
1690  /* mustn't use as gating qual, so don't mark pseudoconstant */
1691  }
1692  else
1693  {
1694  /* eval at original syntactic level */
1695  relids = bms_copy(qualscope);
1696  if (!contain_volatile_functions(clause))
1697  {
1698  /* mark as gating qual */
1699  pseudoconstant = true;
1700  /* tell createplan.c to check for gating quals */
1701  root->hasPseudoConstantQuals = true;
1702  /* if not below outer join, push it to top of tree */
1703  if (!below_outer_join)
1704  {
1705  relids =
1707  false);
1708  qualscope = bms_copy(relids);
1709  }
1710  }
1711  }
1712  }
1713 
1714  /*----------
1715  * Check to see if clause application must be delayed by outer-join
1716  * considerations.
1717  *
1718  * A word about is_pushed_down: we mark the qual as "pushed down" if
1719  * it is (potentially) applicable at a level different from its original
1720  * syntactic level. This flag is used to distinguish OUTER JOIN ON quals
1721  * from other quals pushed down to the same joinrel. The rules are:
1722  * WHERE quals and INNER JOIN quals: is_pushed_down = true.
1723  * Non-degenerate OUTER JOIN quals: is_pushed_down = false.
1724  * Degenerate OUTER JOIN quals: is_pushed_down = true.
1725  * A "degenerate" OUTER JOIN qual is one that doesn't mention the
1726  * non-nullable side, and hence can be pushed down into the nullable side
1727  * without changing the join result. It is correct to treat it as a
1728  * regular filter condition at the level where it is evaluated.
1729  *
1730  * Note: it is not immediately obvious that a simple boolean is enough
1731  * for this: if for some reason we were to attach a degenerate qual to
1732  * its original join level, it would need to be treated as an outer join
1733  * qual there. However, this cannot happen, because all the rels the
1734  * clause mentions must be in the outer join's min_righthand, therefore
1735  * the join it needs must be formed before the outer join; and we always
1736  * attach quals to the lowest level where they can be evaluated. But
1737  * if we were ever to re-introduce a mechanism for delaying evaluation
1738  * of "expensive" quals, this area would need work.
1739  *
1740  * Note: generally, use of is_pushed_down has to go through the macro
1741  * RINFO_IS_PUSHED_DOWN, because that flag alone is not always sufficient
1742  * to tell whether a clause must be treated as pushed-down in context.
1743  * This seems like another reason why it should perhaps be rethought.
1744  *----------
1745  */
1746  if (bms_overlap(relids, outerjoin_nonnullable))
1747  {
1748  /*
1749  * The qual is attached to an outer join and mentions (some of the)
1750  * rels on the nonnullable side, so it's not degenerate.
1751  *
1752  * We can't use such a clause to deduce equivalence (the left and
1753  * right sides might be unequal above the join because one of them has
1754  * gone to NULL) ... but we might be able to use it for more limited
1755  * deductions, if it is mergejoinable. So consider adding it to the
1756  * lists of set-aside outer-join clauses.
1757  */
1758  is_pushed_down = false;
1759  maybe_equivalence = false;
1760  maybe_outer_join = true;
1761 
1762  /* Check to see if must be delayed by lower outer join */
1763  outerjoin_delayed = check_outerjoin_delay(root,
1764  &relids,
1765  &nullable_relids,
1766  false);
1767 
1768  /*
1769  * Now force the qual to be evaluated exactly at the level of joining
1770  * corresponding to the outer join. We cannot let it get pushed down
1771  * into the nonnullable side, since then we'd produce no output rows,
1772  * rather than the intended single null-extended row, for any
1773  * nonnullable-side rows failing the qual.
1774  *
1775  * (Do this step after calling check_outerjoin_delay, because that
1776  * trashes relids.)
1777  */
1778  Assert(ojscope);
1779  relids = ojscope;
1780  Assert(!pseudoconstant);
1781  }
1782  else
1783  {
1784  /*
1785  * Normal qual clause or degenerate outer-join clause. Either way, we
1786  * can mark it as pushed-down.
1787  */
1788  is_pushed_down = true;
1789 
1790  /* Check to see if must be delayed by lower outer join */
1791  outerjoin_delayed = check_outerjoin_delay(root,
1792  &relids,
1793  &nullable_relids,
1794  true);
1795 
1796  if (outerjoin_delayed)
1797  {
1798  /* Should still be a subset of current scope ... */
1799  Assert(root->hasLateralRTEs || bms_is_subset(relids, qualscope));
1800  Assert(ojscope == NULL || bms_is_subset(relids, ojscope));
1801 
1802  /*
1803  * Because application of the qual will be delayed by outer join,
1804  * we mustn't assume its vars are equal everywhere.
1805  */
1806  maybe_equivalence = false;
1807 
1808  /*
1809  * It's possible that this is an IS NULL clause that's redundant
1810  * with a lower antijoin; if so we can just discard it. We need
1811  * not test in any of the other cases, because this will only be
1812  * possible for pushed-down, delayed clauses.
1813  */
1814  if (check_redundant_nullability_qual(root, clause))
1815  return;
1816  }
1817  else
1818  {
1819  /*
1820  * Qual is not delayed by any lower outer-join restriction, so we
1821  * can consider feeding it to the equivalence machinery. However,
1822  * if it's itself within an outer-join clause, treat it as though
1823  * it appeared below that outer join (note that we can only get
1824  * here when the clause references only nullable-side rels).
1825  */
1826  maybe_equivalence = true;
1827  if (outerjoin_nonnullable != NULL)
1828  below_outer_join = true;
1829  }
1830 
1831  /*
1832  * Since it doesn't mention the LHS, it's certainly not useful as a
1833  * set-aside OJ clause, even if it's in an OJ.
1834  */
1835  maybe_outer_join = false;
1836  }
1837 
1838  /*
1839  * Build the RestrictInfo node itself.
1840  */
1841  restrictinfo = make_restrictinfo(root,
1842  (Expr *) clause,
1843  is_pushed_down,
1844  outerjoin_delayed,
1845  pseudoconstant,
1846  security_level,
1847  relids,
1848  outerjoin_nonnullable,
1849  nullable_relids);
1850 
1851  /*
1852  * If it's a join clause (either naturally, or because delayed by
1853  * outer-join rules), add vars used in the clause to targetlists of their
1854  * relations, so that they will be emitted by the plan nodes that scan
1855  * those relations (else they won't be available at the join node!).
1856  *
1857  * Note: if the clause gets absorbed into an EquivalenceClass then this
1858  * may be unnecessary, but for now we have to do it to cover the case
1859  * where the EC becomes ec_broken and we end up reinserting the original
1860  * clauses into the plan.
1861  */
1862  if (bms_membership(relids) == BMS_MULTIPLE)
1863  {
1864  List *vars = pull_var_clause(clause,
1868 
1869  add_vars_to_targetlist(root, vars, relids, false);
1870  list_free(vars);
1871  }
1872 
1873  /*
1874  * We check "mergejoinability" of every clause, not only join clauses,
1875  * because we want to know about equivalences between vars of the same
1876  * relation, or between vars and consts.
1877  */
1878  check_mergejoinable(restrictinfo);
1879 
1880  /*
1881  * If it is a true equivalence clause, send it to the EquivalenceClass
1882  * machinery. We do *not* attach it directly to any restriction or join
1883  * lists. The EC code will propagate it to the appropriate places later.
1884  *
1885  * If the clause has a mergejoinable operator and is not
1886  * outerjoin-delayed, yet isn't an equivalence because it is an outer-join
1887  * clause, the EC code may yet be able to do something with it. We add it
1888  * to appropriate lists for further consideration later. Specifically:
1889  *
1890  * If it is a left or right outer-join qualification that relates the two
1891  * sides of the outer join (no funny business like leftvar1 = leftvar2 +
1892  * rightvar), we add it to root->left_join_clauses or
1893  * root->right_join_clauses according to which side the nonnullable
1894  * variable appears on.
1895  *
1896  * If it is a full outer-join qualification, we add it to
1897  * root->full_join_clauses. (Ideally we'd discard cases that aren't
1898  * leftvar = rightvar, as we do for left/right joins, but this routine
1899  * doesn't have the info needed to do that; and the current usage of the
1900  * full_join_clauses list doesn't require that, so it's not currently
1901  * worth complicating this routine's API to make it possible.)
1902  *
1903  * If none of the above hold, pass it off to
1904  * distribute_restrictinfo_to_rels().
1905  *
1906  * In all cases, it's important to initialize the left_ec and right_ec
1907  * fields of a mergejoinable clause, so that all possibly mergejoinable
1908  * expressions have representations in EquivalenceClasses. If
1909  * process_equivalence is successful, it will take care of that;
1910  * otherwise, we have to call initialize_mergeclause_eclasses to do it.
1911  */
1912  if (restrictinfo->mergeopfamilies)
1913  {
1914  if (maybe_equivalence)
1915  {
1916  if (check_equivalence_delay(root, restrictinfo) &&
1917  process_equivalence(root, &restrictinfo, below_outer_join))
1918  return;
1919  /* EC rejected it, so set left_ec/right_ec the hard way ... */
1920  if (restrictinfo->mergeopfamilies) /* EC might have changed this */
1921  initialize_mergeclause_eclasses(root, restrictinfo);
1922  /* ... and fall through to distribute_restrictinfo_to_rels */
1923  }
1924  else if (maybe_outer_join && restrictinfo->can_join)
1925  {
1926  /* we need to set up left_ec/right_ec the hard way */
1927  initialize_mergeclause_eclasses(root, restrictinfo);
1928  /* now see if it should go to any outer-join lists */
1929  if (bms_is_subset(restrictinfo->left_relids,
1930  outerjoin_nonnullable) &&
1931  !bms_overlap(restrictinfo->right_relids,
1932  outerjoin_nonnullable))
1933  {
1934  /* we have outervar = innervar */
1936  restrictinfo);
1937  return;
1938  }
1939  if (bms_is_subset(restrictinfo->right_relids,
1940  outerjoin_nonnullable) &&
1941  !bms_overlap(restrictinfo->left_relids,
1942  outerjoin_nonnullable))
1943  {
1944  /* we have innervar = outervar */
1946  restrictinfo);
1947  return;
1948  }
1949  if (jointype == JOIN_FULL)
1950  {
1951  /* FULL JOIN (above tests cannot match in this case) */
1953  restrictinfo);
1954  return;
1955  }
1956  /* nope, so fall through to distribute_restrictinfo_to_rels */
1957  }
1958  else
1959  {
1960  /* we still need to set up left_ec/right_ec */
1961  initialize_mergeclause_eclasses(root, restrictinfo);
1962  }
1963  }
1964 
1965  /* No EC special case applies, so push it into the clause lists */
1966  distribute_restrictinfo_to_rels(root, restrictinfo);
1967 }
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p, Relids *nullable_relids_p, bool is_pushed_down)
Definition: initsplan.c:2020
Query * parse
Definition: pathnodes.h:161
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
void initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:1179
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
Relids left_relids
Definition: pathnodes.h:2075
List * pull_var_clause(Node *node, int flags)
Definition: var.c:562
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
List * mergeopfamilies
Definition: pathnodes.h:2093
Node * qual
Definition: initsplan.c:46
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2177
#define ERROR
Definition: elog.h:46
bool process_equivalence(PlannerInfo *root, RestrictInfo **p_restrictinfo, bool below_outer_join)
Definition: equivclass.c:119
bool hasLateralRTEs
Definition: pathnodes.h:346
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
List * left_join_clauses
Definition: pathnodes.h:254
List * full_join_clauses
Definition: pathnodes.h:262
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:61
List * lappend(List *list, void *datum)
Definition: list.c:336
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:189
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
bool hasPseudoConstantQuals
Definition: pathnodes.h:348
Relids right_relids
Definition: pathnodes.h:2076
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
Definition: initsplan.c:2139
#define Assert(condition)
Definition: c.h:804
static bool check_equivalence_delay(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2104
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2653
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
void * palloc(Size size)
Definition: mcxt.c:1062
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:188
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:232
Relids relids
Definition: initsplan.c:47
List * right_join_clauses
Definition: pathnodes.h:258
Definition: regcomp.c:237
Definition: pg_list.h:50
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:186

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2177 of file initsplan.c.

References add_join_clause_to_rels(), RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, bms_membership(), BMS_MULTIPLE, BMS_SINGLETON, bms_singleton_member(), check_hashjoinable(), check_resultcacheable(), elog, ERROR, find_base_rel(), lappend(), Min, PostponedQual::relids, RestrictInfo::required_relids, and RestrictInfo::security_level.

Referenced by distribute_qual_to_rels(), generate_base_implied_equalities_broken(), generate_base_implied_equalities_const(), process_implied_equality(), reconsider_outer_join_clauses(), and remove_rel_from_query().

2179 {
2180  Relids relids = restrictinfo->required_relids;
2181  RelOptInfo *rel;
2182 
2183  switch (bms_membership(relids))
2184  {
2185  case BMS_SINGLETON:
2186 
2187  /*
2188  * There is only one relation participating in the clause, so it
2189  * is a restriction clause for that relation.
2190  */
2191  rel = find_base_rel(root, bms_singleton_member(relids));
2192 
2193  /* Add clause to rel's restriction list */
2195  restrictinfo);
2196  /* Update security level info */
2198  restrictinfo->security_level);
2199  break;
2200  case BMS_MULTIPLE:
2201 
2202  /*
2203  * The clause is a join clause, since there is more than one rel
2204  * in its relid set.
2205  */
2206 
2207  /*
2208  * Check for hashjoinable operators. (We don't bother setting the
2209  * hashjoin info except in true join clauses.)
2210  */
2211  check_hashjoinable(restrictinfo);
2212 
2213  /*
2214  * Likewise, check if the clause is suitable to be used with a
2215  * Result Cache node to cache inner tuples during a parameterized
2216  * nested loop.
2217  */
2218  check_resultcacheable(restrictinfo);
2219 
2220  /*
2221  * Add clause to the join lists of all the relevant relations.
2222  */
2223  add_join_clause_to_rels(root, restrictinfo, relids);
2224  break;
2225  default:
2226 
2227  /*
2228  * clause references no rels, and therefore we have no place to
2229  * attach it. Shouldn't get here if callers are working properly.
2230  */
2231  elog(ERROR, "cannot cope with variable-free clause");
2232  break;
2233  }
2234 }
Index security_level
Definition: pathnodes.h:2060
Relids required_relids
Definition: pathnodes.h:2066
static void check_resultcacheable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2718
List * baserestrictinfo
Definition: pathnodes.h:740
#define Min(x, y)
Definition: c.h:986
Index baserestrict_min_security
Definition: pathnodes.h:742
#define ERROR
Definition: elog.h:46
List * lappend(List *list, void *datum)
Definition: list.c:336
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:577
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:95
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2690
#define elog(elevel,...)
Definition: elog.h:232
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374

◆ extract_lateral_references()

static void extract_lateral_references ( PlannerInfo root,
RelOptInfo brel,
Index  rtindex 
)
static

Definition at line 352 of file initsplan.c.

References add_vars_to_targetlist(), Assert, bms_make_singleton(), copyObject, RangeTblEntry::functions, IncrementVarSublevelsUp(), IsA, lappend(), RangeTblEntry::lateral, RelOptInfo::lateral_vars, lfirst, list_free(), NIL, PlaceHolderVar::phexpr, PlaceHolderVar::phlevelsup, preprocess_phv_expression(), pull_vars_of_level(), RTE_FUNCTION, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, PlannerInfo::simple_rte_array, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, RangeTblEntry::values_lists, and Var::varlevelsup.

Referenced by find_lateral_references().

353 {
354  RangeTblEntry *rte = root->simple_rte_array[rtindex];
355  List *vars;
356  List *newvars;
357  Relids where_needed;
358  ListCell *lc;
359 
360  /* No cross-references are possible if it's not LATERAL */
361  if (!rte->lateral)
362  return;
363 
364  /* Fetch the appropriate variables */
365  if (rte->rtekind == RTE_RELATION)
366  vars = pull_vars_of_level((Node *) rte->tablesample, 0);
367  else if (rte->rtekind == RTE_SUBQUERY)
368  vars = pull_vars_of_level((Node *) rte->subquery, 1);
369  else if (rte->rtekind == RTE_FUNCTION)
370  vars = pull_vars_of_level((Node *) rte->functions, 0);
371  else if (rte->rtekind == RTE_TABLEFUNC)
372  vars = pull_vars_of_level((Node *) rte->tablefunc, 0);
373  else if (rte->rtekind == RTE_VALUES)
374  vars = pull_vars_of_level((Node *) rte->values_lists, 0);
375  else
376  {
377  Assert(false);
378  return; /* keep compiler quiet */
379  }
380 
381  if (vars == NIL)
382  return; /* nothing to do */
383 
384  /* Copy each Var (or PlaceHolderVar) and adjust it to match our level */
385  newvars = NIL;
386  foreach(lc, vars)
387  {
388  Node *node = (Node *) lfirst(lc);
389 
390  node = copyObject(node);
391  if (IsA(node, Var))
392  {
393  Var *var = (Var *) node;
394 
395  /* Adjustment is easy since it's just one node */
396  var->varlevelsup = 0;
397  }
398  else if (IsA(node, PlaceHolderVar))
399  {
400  PlaceHolderVar *phv = (PlaceHolderVar *) node;
401  int levelsup = phv->phlevelsup;
402 
403  /* Have to work harder to adjust the contained expression too */
404  if (levelsup != 0)
405  IncrementVarSublevelsUp(node, -levelsup, 0);
406 
407  /*
408  * If we pulled the PHV out of a subquery RTE, its expression
409  * needs to be preprocessed. subquery_planner() already did this
410  * for level-zero PHVs in function and values RTEs, though.
411  */
412  if (levelsup > 0)
413  phv->phexpr = preprocess_phv_expression(root, phv->phexpr);
414  }
415  else
416  Assert(false);
417  newvars = lappend(newvars, node);
418  }
419 
420  list_free(vars);
421 
422  /*
423  * We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
424  * of a cheat: a more formal approach would be to mark each one as needed
425  * at the join of the LATERAL RTE with its source RTE. But it will work,
426  * and it's much less tedious than computing a separate where_needed for
427  * each Var.
428  */
429  where_needed = bms_make_singleton(rtindex);
430 
431  /*
432  * Push Vars into their source relations' targetlists, and PHVs into
433  * root->placeholder_list.
434  */
435  add_vars_to_targetlist(root, newvars, where_needed, true);
436 
437  /* Remember the lateral references for create_lateral_join_info */
438  brel->lateral_vars = newvars;
439 }
List * pull_vars_of_level(Node *node, int levelsup)
Definition: var.c:290
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Expr * preprocess_phv_expression(PlannerInfo *root, Expr *expr)
Definition: planner.c:1198
Index varlevelsup
Definition: primnodes.h:196
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:776
Definition: nodes.h:539
Definition: primnodes.h:186
List * values_lists
Definition: parsenodes.h:1100
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
TableFunc * tablefunc
Definition: parsenodes.h:1095
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
List * lappend(List *list, void *datum)
Definition: list.c:336
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:193
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1089
List * lateral_vars
Definition: pathnodes.h:711
RTEKind rtekind
Definition: parsenodes.h:995
Query * subquery
Definition: parsenodes.h:1030
Index phlevelsup
Definition: pathnodes.h:2173
void list_free(List *list)
Definition: list.c:1391
#define copyObject(obj)
Definition: nodes.h:655
Definition: regcomp.c:237
Definition: pg_list.h:50
struct TableSampleClause * tablesample
Definition: parsenodes.h:1025

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 304 of file initsplan.c.

References Assert, extract_lateral_references(), PlannerInfo::hasLateralRTEs, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, and PlannerInfo::simple_rel_array_size.

Referenced by query_planner().

305 {
306  Index rti;
307 
308  /* We need do nothing if the query contains no LATERAL RTEs */
309  if (!root->hasLateralRTEs)
310  return;
311 
312  /*
313  * Examine all baserels (the rel array has been set up by now).
314  */
315  for (rti = 1; rti < root->simple_rel_array_size; rti++)
316  {
317  RelOptInfo *brel = root->simple_rel_array[rti];
318 
319  /* there may be empty slots corresponding to non-baserel RTEs */
320  if (brel == NULL)
321  continue;
322 
323  Assert(brel->relid == rti); /* sanity check on array */
324 
325  /*
326  * This bit is less obvious than it might look. We ignore appendrel
327  * otherrels and consider only their parent baserels. In a case where
328  * a LATERAL-containing UNION ALL subquery was pulled up, it is the
329  * otherrel that is actually going to be in the plan. However, we
330  * want to mark all its lateral references as needed by the parent,
331  * because it is the parent's relid that will be used for join
332  * planning purposes. And the parent's RTE will contain all the
333  * lateral references we need to know, since the pulled-up member is
334  * nothing but a copy of parts of the original RTE's subquery. We
335  * could visit the parent's children instead and transform their
336  * references back to the parent's relid, but it would be much more
337  * complicated for no real gain. (Important here is that the child
338  * members have not yet received any processing beyond being pulled
339  * up.) Similarly, in appendrels created by inheritance expansion,
340  * it's sufficient to look at the parent relation.
341  */
342 
343  /* ignore RTEs that are "other rels" */
344  if (brel->reloptkind != RELOPT_BASEREL)
345  continue;
346 
347  extract_lateral_references(root, brel, rti);
348  }
349 }
RelOptKind reloptkind
Definition: pathnodes.h:673
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
bool hasLateralRTEs
Definition: pathnodes.h:346
int simple_rel_array_size
Definition: pathnodes.h:186
Index relid
Definition: pathnodes.h:704
unsigned int Index
Definition: c.h:549
#define Assert(condition)
Definition: c.h:804
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:352

◆ make_outerjoininfo()

static SpecialJoinInfo * make_outerjoininfo ( PlannerInfo root,
Relids  left_rels,
Relids  right_rels,
Relids  inner_join_rels,
JoinType  jointype,
List clause 
)
static

Definition at line 1148 of file initsplan.c.

References Assert, bms_add_members(), bms_copy(), bms_int_members(), bms_intersect(), bms_is_empty(), bms_is_member(), bms_is_subset(), bms_overlap(), bms_union(), compute_semijoin_info(), SpecialJoinInfo::delay_upper_joins, ereport, errcode(), errmsg(), ERROR, find_nonnullable_rels(), JOIN_ANTI, JOIN_FULL, PlannerInfo::join_info_list, JOIN_INNER, JOIN_RIGHT, JOIN_SEMI, SpecialJoinInfo::jointype, LCS_asString(), lfirst, SpecialJoinInfo::lhs_strict, makeNode, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, PlannerInfo::parse, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_var, PlaceHolderVar::phrels, PlannerInfo::placeholder_list, pull_varnos(), Query::rowMarks, RowMarkClause::rti, RowMarkClause::strength, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.

Referenced by deconstruct_recurse().

1152 {
1154  Relids clause_relids;
1155  Relids strict_relids;
1156  Relids min_lefthand;
1157  Relids min_righthand;
1158  ListCell *l;
1159 
1160  /*
1161  * We should not see RIGHT JOIN here because left/right were switched
1162  * earlier
1163  */
1164  Assert(jointype != JOIN_INNER);
1165  Assert(jointype != JOIN_RIGHT);
1166 
1167  /*
1168  * Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of
1169  * rels appearing on the nullable side of an outer join. (It's somewhat
1170  * unclear what that would mean, anyway: what should we mark when a result
1171  * row is generated from no element of the nullable relation?) So,
1172  * complain if any nullable rel is FOR [KEY] UPDATE/SHARE.
1173  *
1174  * You might be wondering why this test isn't made far upstream in the
1175  * parser. It's because the parser hasn't got enough info --- consider
1176  * FOR UPDATE applied to a view. Only after rewriting and flattening do
1177  * we know whether the view contains an outer join.
1178  *
1179  * We use the original RowMarkClause list here; the PlanRowMark list would
1180  * list everything.
1181  */
1182  foreach(l, root->parse->rowMarks)
1183  {
1184  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
1185 
1186  if (bms_is_member(rc->rti, right_rels) ||
1187  (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels)))
1188  ereport(ERROR,
1189  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1190  /*------
1191  translator: %s is a SQL row locking clause such as FOR UPDATE */
1192  errmsg("%s cannot be applied to the nullable side of an outer join",
1193  LCS_asString(rc->strength))));
1194  }
1195 
1196  sjinfo->syn_lefthand = left_rels;
1197  sjinfo->syn_righthand = right_rels;
1198  sjinfo->jointype = jointype;
1199  /* this always starts out false */
1200  sjinfo->delay_upper_joins = false;
1201 
1202  compute_semijoin_info(root, sjinfo, clause);
1203 
1204  /* If it's a full join, no need to be very smart */
1205  if (jointype == JOIN_FULL)
1206  {
1207  sjinfo->min_lefthand = bms_copy(left_rels);
1208  sjinfo->min_righthand = bms_copy(right_rels);
1209  sjinfo->lhs_strict = false; /* don't care about this */
1210  return sjinfo;
1211  }
1212 
1213  /*
1214  * Retrieve all relids mentioned within the join clause.
1215  */
1216  clause_relids = pull_varnos(root, (Node *) clause);
1217 
1218  /*
1219  * For which relids is the clause strict, ie, it cannot succeed if the
1220  * rel's columns are all NULL?
1221  */
1222  strict_relids = find_nonnullable_rels((Node *) clause);
1223 
1224  /* Remember whether the clause is strict for any LHS relations */
1225  sjinfo->lhs_strict = bms_overlap(strict_relids, left_rels);
1226 
1227  /*
1228  * Required LHS always includes the LHS rels mentioned in the clause. We
1229  * may have to add more rels based on lower outer joins; see below.
1230  */
1231  min_lefthand = bms_intersect(clause_relids, left_rels);
1232 
1233  /*
1234  * Similarly for required RHS. But here, we must also include any lower
1235  * inner joins, to ensure we don't try to commute with any of them.
1236  */
1237  min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
1238  right_rels);
1239 
1240  /*
1241  * Now check previous outer joins for ordering restrictions.
1242  */
1243  foreach(l, root->join_info_list)
1244  {
1245  SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
1246 
1247  /*
1248  * A full join is an optimization barrier: we can't associate into or
1249  * out of it. Hence, if it overlaps either LHS or RHS of the current
1250  * rel, expand that side's min relset to cover the whole full join.
1251  */
1252  if (otherinfo->jointype == JOIN_FULL)
1253  {
1254  if (bms_overlap(left_rels, otherinfo->syn_lefthand) ||
1255  bms_overlap(left_rels, otherinfo->syn_righthand))
1256  {
1257  min_lefthand = bms_add_members(min_lefthand,
1258  otherinfo->syn_lefthand);
1259  min_lefthand = bms_add_members(min_lefthand,
1260  otherinfo->syn_righthand);
1261  }
1262  if (bms_overlap(right_rels, otherinfo->syn_lefthand) ||
1263  bms_overlap(right_rels, otherinfo->syn_righthand))
1264  {
1265  min_righthand = bms_add_members(min_righthand,
1266  otherinfo->syn_lefthand);
1267  min_righthand = bms_add_members(min_righthand,
1268  otherinfo->syn_righthand);
1269  }
1270  /* Needn't do anything else with the full join */
1271  continue;
1272  }
1273 
1274  /*
1275  * For a lower OJ in our LHS, if our join condition uses the lower
1276  * join's RHS and is not strict for that rel, we must preserve the
1277  * ordering of the two OJs, so add lower OJ's full syntactic relset to
1278  * min_lefthand. (We must use its full syntactic relset, not just its
1279  * min_lefthand + min_righthand. This is because there might be other
1280  * OJs below this one that this one can commute with, but we cannot
1281  * commute with them if we don't with this one.) Also, if the current
1282  * join is a semijoin or antijoin, we must preserve ordering
1283  * regardless of strictness.
1284  *
1285  * Note: I believe we have to insist on being strict for at least one
1286  * rel in the lower OJ's min_righthand, not its whole syn_righthand.
1287  */
1288  if (bms_overlap(left_rels, otherinfo->syn_righthand))
1289  {
1290  if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
1291  (jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
1292  !bms_overlap(strict_relids, otherinfo->min_righthand)))
1293  {
1294  min_lefthand = bms_add_members(min_lefthand,
1295  otherinfo->syn_lefthand);
1296  min_lefthand = bms_add_members(min_lefthand,
1297  otherinfo->syn_righthand);
1298  }
1299  }
1300 
1301  /*
1302  * For a lower OJ in our RHS, if our join condition does not use the
1303  * lower join's RHS and the lower OJ's join condition is strict, we
1304  * can interchange the ordering of the two OJs; otherwise we must add
1305  * the lower OJ's full syntactic relset to min_righthand.
1306  *
1307  * Also, if our join condition does not use the lower join's LHS
1308  * either, force the ordering to be preserved. Otherwise we can end
1309  * up with SpecialJoinInfos with identical min_righthands, which can
1310  * confuse join_is_legal (see discussion in backend/optimizer/README).
1311  *
1312  * Also, we must preserve ordering anyway if either the current join
1313  * or the lower OJ is either a semijoin or an antijoin.
1314  *
1315  * Here, we have to consider that "our join condition" includes any
1316  * clauses that syntactically appeared above the lower OJ and below
1317  * ours; those are equivalent to degenerate clauses in our OJ and must
1318  * be treated as such. Such clauses obviously can't reference our
1319  * LHS, and they must be non-strict for the lower OJ's RHS (else
1320  * reduce_outer_joins would have reduced the lower OJ to a plain
1321  * join). Hence the other ways in which we handle clauses within our
1322  * join condition are not affected by them. The net effect is
1323  * therefore sufficiently represented by the delay_upper_joins flag
1324  * saved for us by check_outerjoin_delay.
1325  */
1326  if (bms_overlap(right_rels, otherinfo->syn_righthand))
1327  {
1328  if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
1329  !bms_overlap(clause_relids, otherinfo->min_lefthand) ||
1330  jointype == JOIN_SEMI ||
1331  jointype == JOIN_ANTI ||
1332  otherinfo->jointype == JOIN_SEMI ||
1333  otherinfo->jointype == JOIN_ANTI ||
1334  !otherinfo->lhs_strict || otherinfo->delay_upper_joins)
1335  {
1336  min_righthand = bms_add_members(min_righthand,
1337  otherinfo->syn_lefthand);
1338  min_righthand = bms_add_members(min_righthand,
1339  otherinfo->syn_righthand);
1340  }
1341  }
1342  }
1343 
1344  /*
1345  * Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
1346  * this join's nullable side, then ensure that min_righthand contains the
1347  * full eval_at set of the PHV. This ensures that the PHV actually can be
1348  * evaluated within the RHS. Note that this works only because we should
1349  * already have determined the final eval_at level for any PHV
1350  * syntactically within this join.
1351  */
1352  foreach(l, root->placeholder_list)
1353  {
1354  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
1355  Relids ph_syn_level = phinfo->ph_var->phrels;
1356 
1357  /* Ignore placeholder if it didn't syntactically come from RHS */
1358  if (!bms_is_subset(ph_syn_level, right_rels))
1359  continue;
1360 
1361  /* Else, prevent join from being formed before we eval the PHV */
1362  min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
1363  }
1364 
1365  /*
1366  * If we found nothing to put in min_lefthand, punt and make it the full
1367  * LHS, to avoid having an empty min_lefthand which will confuse later
1368  * processing. (We don't try to be smart about such cases, just correct.)
1369  * Likewise for min_righthand.
1370  */
1371  if (bms_is_empty(min_lefthand))
1372  min_lefthand = bms_copy(left_rels);
1373  if (bms_is_empty(min_righthand))
1374  min_righthand = bms_copy(right_rels);
1375 
1376  /* Now they'd better be nonempty */
1377  Assert(!bms_is_empty(min_lefthand));
1378  Assert(!bms_is_empty(min_righthand));
1379  /* Shouldn't overlap either */
1380  Assert(!bms_overlap(min_lefthand, min_righthand));
1381 
1382  sjinfo->min_lefthand = min_lefthand;
1383  sjinfo->min_righthand = min_righthand;
1384 
1385  return sjinfo;
1386 }
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
Query * parse
Definition: pathnodes.h:161
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:2979
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Relids ph_eval_at
Definition: pathnodes.h:2402
PlaceHolderVar * ph_var
Definition: pathnodes.h:2401
List * join_info_list
Definition: pathnodes.h:265
Relids min_righthand
Definition: pathnodes.h:2242
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
List * rowMarks
Definition: parsenodes.h:175
Relids syn_lefthand
Definition: pathnodes.h:2243
LockClauseStrength strength
Definition: parsenodes.h:1409
Relids syn_righthand
Definition: pathnodes.h:2244
#define ERROR
Definition: elog.h:46
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Relids find_nonnullable_rels(Node *clause)
Definition: clauses.c:1338
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
bool delay_upper_joins
Definition: pathnodes.h:2247
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:259
#define ereport(elevel,...)
Definition: elog.h:157
#define makeNode(_type_)
Definition: nodes.h:587
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
JoinType jointype
Definition: pathnodes.h:2245
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
int errmsg(const char *fmt,...)
Definition: elog.c:909
List * placeholder_list
Definition: pathnodes.h:289
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:902
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
Relids min_lefthand
Definition: pathnodes.h:2241
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
Definition: initsplan.c:1396

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 2483 of file initsplan.c.

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, ForeignKeyOptInfo::confkey, ForeignKeyOptInfo::conkey, ForeignKeyOptInfo::conpfeqop, EquivalenceClass::ec_has_const, PlannerInfo::fkey_list, get_commutator(), get_leftop(), get_rightop(), InvalidOid, IsA, RelOptInfo::joininfo, lappend(), lfirst, list_length(), match_eclasses_to_foreign_key_col(), ForeignKeyOptInfo::nconst_ec, NIL, ForeignKeyOptInfo::nkeys, ForeignKeyOptInfo::nmatched_ec, ForeignKeyOptInfo::nmatched_rcols, ForeignKeyOptInfo::nmatched_ri, OidIsValid, OpExpr::opno, RestrictInfo::outerjoin_delayed, ForeignKeyOptInfo::ref_relid, RELOPT_BASEREL, RelOptInfo::reloptkind, ForeignKeyOptInfo::rinfos, PlannerInfo::simple_rel_array, and PlannerInfo::simple_rel_array_size.

Referenced by query_planner().

2484 {
2485  List *newlist = NIL;
2486  ListCell *lc;
2487 
2488  foreach(lc, root->fkey_list)
2489  {
2490  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
2491  RelOptInfo *con_rel;
2492  RelOptInfo *ref_rel;
2493  int colno;
2494 
2495  /*
2496  * Either relid might identify a rel that is in the query's rtable but
2497  * isn't referenced by the jointree so won't have a RelOptInfo. Hence
2498  * don't use find_base_rel() here. We can ignore such FKs.
2499  */
2500  if (fkinfo->con_relid >= root->simple_rel_array_size ||
2501  fkinfo->ref_relid >= root->simple_rel_array_size)
2502  continue; /* just paranoia */
2503  con_rel = root->simple_rel_array[fkinfo->con_relid];
2504  if (con_rel == NULL)
2505  continue;
2506  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
2507  if (ref_rel == NULL)
2508  continue;
2509 
2510  /*
2511  * Ignore FK unless both rels are baserels. This gets rid of FKs that
2512  * link to inheritance child rels (otherrels) and those that link to
2513  * rels removed by join removal (dead rels).
2514  */
2515  if (con_rel->reloptkind != RELOPT_BASEREL ||
2516  ref_rel->reloptkind != RELOPT_BASEREL)
2517  continue;
2518 
2519  /*
2520  * Scan the columns and try to match them to eclasses and quals.
2521  *
2522  * Note: for simple inner joins, any match should be in an eclass.
2523  * "Loose" quals that syntactically match an FK equality must have
2524  * been rejected for EC status because they are outer-join quals or
2525  * similar. We can still consider them to match the FK if they are
2526  * not outerjoin_delayed.
2527  */
2528  for (colno = 0; colno < fkinfo->nkeys; colno++)
2529  {
2530  EquivalenceClass *ec;
2531  AttrNumber con_attno,
2532  ref_attno;
2533  Oid fpeqop;
2534  ListCell *lc2;
2535 
2536  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
2537  /* Don't bother looking for loose quals if we got an EC match */
2538  if (ec != NULL)
2539  {
2540  fkinfo->nmatched_ec++;
2541  if (ec->ec_has_const)
2542  fkinfo->nconst_ec++;
2543  continue;
2544  }
2545 
2546  /*
2547  * Scan joininfo list for relevant clauses. Either rel's joininfo
2548  * list would do equally well; we use con_rel's.
2549  */
2550  con_attno = fkinfo->conkey[colno];
2551  ref_attno = fkinfo->confkey[colno];
2552  fpeqop = InvalidOid; /* we'll look this up only if needed */
2553 
2554  foreach(lc2, con_rel->joininfo)
2555  {
2556  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
2557  OpExpr *clause = (OpExpr *) rinfo->clause;
2558  Var *leftvar;
2559  Var *rightvar;
2560 
2561  /* Ignore outerjoin-delayed clauses */
2562  if (rinfo->outerjoin_delayed)
2563  continue;
2564 
2565  /* Only binary OpExprs are useful for consideration */
2566  if (!IsA(clause, OpExpr) ||
2567  list_length(clause->args) != 2)
2568  continue;
2569  leftvar = (Var *) get_leftop((Expr *) clause);
2570  rightvar = (Var *) get_rightop((Expr *) clause);
2571 
2572  /* Operands must be Vars, possibly with RelabelType */
2573  while (leftvar && IsA(leftvar, RelabelType))
2574  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
2575  if (!(leftvar && IsA(leftvar, Var)))
2576  continue;
2577  while (rightvar && IsA(rightvar, RelabelType))
2578  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
2579  if (!(rightvar && IsA(rightvar, Var)))
2580  continue;
2581 
2582  /* Now try to match the vars to the current foreign key cols */
2583  if (fkinfo->ref_relid == leftvar->varno &&
2584  ref_attno == leftvar->varattno &&
2585  fkinfo->con_relid == rightvar->varno &&
2586  con_attno == rightvar->varattno)
2587  {
2588  /* Vars match, but is it the right operator? */
2589  if (clause->opno == fkinfo->conpfeqop[colno])
2590  {
2591  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
2592  rinfo);
2593  fkinfo->nmatched_ri++;
2594  }
2595  }
2596  else if (fkinfo->ref_relid == rightvar->varno &&
2597  ref_attno == rightvar->varattno &&
2598  fkinfo->con_relid == leftvar->varno &&
2599  con_attno == leftvar->varattno)
2600  {
2601  /*
2602  * Reverse match, must check commutator operator. Look it
2603  * up if we didn't already. (In the worst case we might
2604  * do multiple lookups here, but that would require an FK
2605  * equality operator without commutator, which is
2606  * unlikely.)
2607  */
2608  if (!OidIsValid(fpeqop))
2609  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
2610  if (clause->opno == fpeqop)
2611  {
2612  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
2613  rinfo);
2614  fkinfo->nmatched_ri++;
2615  }
2616  }
2617  }
2618  /* If we found any matching loose quals, count col as matched */
2619  if (fkinfo->rinfos[colno])
2620  fkinfo->nmatched_rcols++;
2621  }
2622 
2623  /*
2624  * Currently, we drop multicolumn FKs that aren't fully matched to the
2625  * query. Later we might figure out how to derive some sort of
2626  * estimate from them, in which case this test should be weakened to
2627  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
2628  */
2629  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
2630  newlist = lappend(newlist, fkinfo);
2631  }
2632  /* Replace fkey_list, thereby discarding any useless entries */
2633  root->fkey_list = newlist;
2634 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1480
RelOptKind reloptkind
Definition: pathnodes.h:673
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:186
List * fkey_list
Definition: pathnodes.h:291
#define OidIsValid(objectId)
Definition: c.h:710
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: pathnodes.h:902
bool outerjoin_delayed
Definition: pathnodes.h:2049
List * joininfo
Definition: pathnodes.h:744
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:73
int simple_rel_array_size
Definition: pathnodes.h:186
List * lappend(List *list, void *datum)
Definition: list.c:336
Expr * clause
Definition: pathnodes.h:2045
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: pathnodes.h:900
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2437
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Oid opno
Definition: primnodes.h:542
List * args
Definition: primnodes.h:548
Definition: pg_list.h:50
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: pathnodes.h:901
int16 AttrNumber
Definition: attnum.h:21
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:914

◆ process_implied_equality()

RestrictInfo* process_implied_equality ( PlannerInfo root,
Oid  opno,
Oid  collation,
Expr item1,
Expr item2,
Relids  qualscope,
Relids  nullable_relids,
Index  security_level,
bool  below_outer_join,
bool  both_const 
)

Definition at line 2272 of file initsplan.c.

References add_vars_to_targetlist(), Assert, bms_copy(), bms_is_empty(), bms_is_subset(), bms_membership(), BMS_MULTIPLE, check_mergejoinable(), Const::constisnull, Const::consttype, Const::constvalue, contain_volatile_functions(), copyObject, DatumGetBool, distribute_restrictinfo_to_rels(), eval_const_expressions(), get_relids_in_jointree(), PlannerInfo::hasPseudoConstantQuals, InvalidOid, IsA, Query::jointree, list_free(), make_opclause(), make_restrictinfo(), PlannerInfo::parse, pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and PostponedQual::relids.

Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().

2282 {
2283  RestrictInfo *restrictinfo;
2284  Node *clause;
2285  Relids relids;
2286  bool pseudoconstant = false;
2287 
2288  /*
2289  * Build the new clause. Copy to ensure it shares no substructure with
2290  * original (this is necessary in case there are subselects in there...)
2291  */
2292  clause = (Node *) make_opclause(opno,
2293  BOOLOID, /* opresulttype */
2294  false, /* opretset */
2295  copyObject(item1),
2296  copyObject(item2),
2297  InvalidOid,
2298  collation);
2299 
2300  /* If both constant, try to reduce to a boolean constant. */
2301  if (both_const)
2302  {
2303  clause = eval_const_expressions(root, clause);
2304 
2305  /* If we produced const TRUE, just drop the clause */
2306  if (clause && IsA(clause, Const))
2307  {
2308  Const *cclause = (Const *) clause;
2309 
2310  Assert(cclause->consttype == BOOLOID);
2311  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
2312  return NULL;
2313  }
2314  }
2315 
2316  /*
2317  * The rest of this is a very cut-down version of distribute_qual_to_rels.
2318  * We can skip most of the work therein, but there are a couple of special
2319  * cases we still have to handle.
2320  *
2321  * Retrieve all relids mentioned within the possibly-simplified clause.
2322  */
2323  relids = pull_varnos(root, clause);
2324  Assert(bms_is_subset(relids, qualscope));
2325 
2326  /*
2327  * If the clause is variable-free, our normal heuristic for pushing it
2328  * down to just the mentioned rels doesn't work, because there are none.
2329  * Apply at the given qualscope, or at the top of tree if it's nonvolatile
2330  * (which it very likely is, but we'll check, just to be sure).
2331  */
2332  if (bms_is_empty(relids))
2333  {
2334  /* eval at original syntactic level */
2335  relids = bms_copy(qualscope);
2336  if (!contain_volatile_functions(clause))
2337  {
2338  /* mark as gating qual */
2339  pseudoconstant = true;
2340  /* tell createplan.c to check for gating quals */
2341  root->hasPseudoConstantQuals = true;
2342  /* if not below outer join, push it to top of tree */
2343  if (!below_outer_join)
2344  {
2345  relids =
2347  false);
2348  }
2349  }
2350  }
2351 
2352  /*
2353  * Build the RestrictInfo node itself.
2354  */
2355  restrictinfo = make_restrictinfo(root,
2356  (Expr *) clause,
2357  true, /* is_pushed_down */
2358  false, /* outerjoin_delayed */
2359  pseudoconstant,
2360  security_level,
2361  relids,
2362  NULL, /* outer_relids */
2363  nullable_relids);
2364 
2365  /*
2366  * If it's a join clause, add vars used in the clause to targetlists of
2367  * their relations, so that they will be emitted by the plan nodes that
2368  * scan those relations (else they won't be available at the join node!).
2369  *
2370  * Typically, we'd have already done this when the component expressions
2371  * were first seen by distribute_qual_to_rels; but it is possible that
2372  * some of the Vars could have missed having that done because they only
2373  * appeared in single-relation clauses originally. So do it here for
2374  * safety.
2375  */
2376  if (bms_membership(relids) == BMS_MULTIPLE)
2377  {
2378  List *vars = pull_var_clause(clause,
2382 
2383  add_vars_to_targetlist(root, vars, relids, false);
2384  list_free(vars);
2385  }
2386 
2387  /*
2388  * Check mergejoinability. This will usually succeed, since the op came
2389  * from an EquivalenceClass; but we could have reduced the original clause
2390  * to a constant.
2391  */
2392  check_mergejoinable(restrictinfo);
2393 
2394  /*
2395  * Note we don't do initialize_mergeclause_eclasses(); the caller can
2396  * handle that much more cheaply than we can. It's okay to call
2397  * distribute_restrictinfo_to_rels() before that happens.
2398  */
2399 
2400  /*
2401  * Push the new clause into all the appropriate restrictinfo lists.
2402  */
2403  distribute_restrictinfo_to_rels(root, restrictinfo);
2404 
2405  return restrictinfo;
2406 }
Datum constvalue
Definition: primnodes.h:219
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2090
List * pull_var_clause(Node *node, int flags)
Definition: var.c:562
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:610
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
Oid consttype
Definition: primnodes.h:215
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2177
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define DatumGetBool(X)
Definition: postgres.h:437
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:61
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:189
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
bool hasPseudoConstantQuals
Definition: pathnodes.h:348
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:804
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2653
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:188
void list_free(List *list)
Definition: list.c:1391
#define copyObject(obj)
Definition: nodes.h:655
Definition: regcomp.c:237
Definition: pg_list.h:50
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:186
bool constisnull
Definition: primnodes.h:220

◆ process_security_barrier_quals()

static void process_security_barrier_quals ( PlannerInfo root,
int  rti,
Relids  qualscope,
bool  below_outer_join 
)
static

Definition at line 1084 of file initsplan.c.

References Assert, distribute_qual_to_rels(), JOIN_INNER, lfirst, PostponedQual::qual, RangeTblEntry::securityQuals, and PlannerInfo::simple_rte_array.

Referenced by deconstruct_recurse().

1087 {
1088  RangeTblEntry *rte = root->simple_rte_array[rti];
1089  Index security_level = 0;
1090  ListCell *lc;
1091 
1092  /*
1093  * Each element of the securityQuals list has been preprocessed into an
1094  * implicitly-ANDed list of clauses. All the clauses in a given sublist
1095  * should get the same security level, but successive sublists get higher
1096  * levels.
1097  */
1098  foreach(lc, rte->securityQuals)
1099  {
1100  List *qualset = (List *) lfirst(lc);
1101  ListCell *lc2;
1102 
1103  foreach(lc2, qualset)
1104  {
1105  Node *qual = (Node *) lfirst(lc2);
1106 
1107  /*
1108  * We cheat to the extent of passing ojscope = qualscope rather
1109  * than its more logical value of NULL. The only effect this has
1110  * is to force a Var-free qual to be evaluated at the rel rather
1111  * than being pushed up to top of tree, which we don't want.
1112  */
1113  distribute_qual_to_rels(root, qual,
1114  below_outer_join,
1115  JOIN_INNER,
1116  security_level,
1117  qualscope,
1118  qualscope,
1119  NULL,
1120  NULL);
1121  }
1122  security_level++;
1123  }
1124 
1125  /* Assert that qual_security_level is higher than anything we just used */
1126  Assert(security_level <= root->qual_security_level);
1127 }
List * securityQuals
Definition: parsenodes.h:1151
Definition: nodes.h:539
static void distribute_qual_to_rels(PlannerInfo *root, Node *clause, bool below_outer_join, JoinType jointype, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, List **postponed_qual_list)
Definition: initsplan.c:1606
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:193
unsigned int Index
Definition: c.h:549
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Definition: pg_list.h:50

Variable Documentation

◆ from_collapse_limit

int from_collapse_limit

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 40 of file initsplan.c.

Referenced by deconstruct_recurse().