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  JoinTreeItem
 

Typedefs

typedef struct JoinTreeItem JoinTreeItem
 

Functions

static void extract_lateral_references (PlannerInfo *root, RelOptInfo *brel, Index rtindex)
 
static Listdeconstruct_recurse (PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, JoinTreeItem *parent_jtitem, List **item_list)
 
static void deconstruct_distribute (PlannerInfo *root, JoinTreeItem *jtitem)
 
static void process_security_barrier_quals (PlannerInfo *root, int rti, JoinTreeItem *jtitem)
 
static void mark_rels_nulled_by_join (PlannerInfo *root, Index ojrelid, Relids lower_rels)
 
static SpecialJoinInfomake_outerjoininfo (PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, JoinType jointype, Index ojrelid, List *clause)
 
static void compute_semijoin_info (PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
 
static void deconstruct_distribute_oj_quals (PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
 
static void distribute_quals_to_rels (PlannerInfo *root, List *clauses, JoinTreeItem *jtitem, SpecialJoinInfo *sjinfo, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, Relids incompatible_relids, bool allow_equivalence, bool has_clone, bool is_clone, List **postponed_oj_qual_list)
 
static void distribute_qual_to_rels (PlannerInfo *root, Node *clause, JoinTreeItem *jtitem, SpecialJoinInfo *sjinfo, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, Relids incompatible_relids, bool allow_equivalence, bool has_clone, bool is_clone, List **postponed_oj_qual_list)
 
static bool check_redundant_nullability_qual (PlannerInfo *root, Node *clause)
 
static Relids get_join_domain_min_rels (PlannerInfo *root, Relids domain_relids)
 
static void check_mergejoinable (RestrictInfo *restrictinfo)
 
static void check_hashjoinable (RestrictInfo *restrictinfo)
 
static void check_memoizable (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)
 
void add_vars_to_attr_needed (PlannerInfo *root, List *vars, Relids where_needed)
 
void find_lateral_references (PlannerInfo *root)
 
void rebuild_lateral_attr_needed (PlannerInfo *root)
 
void create_lateral_join_info (PlannerInfo *root)
 
Listdeconstruct_jointree (PlannerInfo *root)
 
static void add_base_clause_to_rel (PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
 
static bool expr_is_nonnullable (PlannerInfo *root, Expr *expr)
 
bool restriction_is_always_true (PlannerInfo *root, RestrictInfo *restrictinfo)
 
bool restriction_is_always_false (PlannerInfo *root, RestrictInfo *restrictinfo)
 
void distribute_restrictinfo_to_rels (PlannerInfo *root, RestrictInfo *restrictinfo)
 
RestrictInfoprocess_implied_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Index security_level, bool both_const)
 
RestrictInfobuild_implied_join_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Index security_level)
 
void rebuild_joinclause_attr_needed (PlannerInfo *root)
 
void match_foreign_keys_to_quals (PlannerInfo *root)
 

Variables

int from_collapse_limit
 
int join_collapse_limit
 

Typedef Documentation

◆ JoinTreeItem

typedef struct JoinTreeItem JoinTreeItem

Function Documentation

◆ add_base_clause_to_rel()

static void add_base_clause_to_rel ( PlannerInfo root,
Index  relid,
RestrictInfo restrictinfo 
)
static

Definition at line 2739 of file initsplan.c.

2741 {
2742  RelOptInfo *rel = find_base_rel(root, relid);
2743  RangeTblEntry *rte = root->simple_rte_array[relid];
2744 
2746 
2747  /*
2748  * For inheritance parent tables, we must always record the RestrictInfo
2749  * in baserestrictinfo as is. If we were to transform or skip adding it,
2750  * then the original wouldn't be available in apply_child_basequals. Since
2751  * there are two RangeTblEntries for inheritance parents, one with
2752  * inh==true and the other with inh==false, we're still able to apply this
2753  * optimization to the inh==false one. The inh==true one is what
2754  * apply_child_basequals() sees, whereas the inh==false one is what's used
2755  * for the scan node in the final plan.
2756  *
2757  * We make an exception to this for partitioned tables. For these, we
2758  * always apply the constant-TRUE and constant-FALSE transformations. A
2759  * qual which is either of these for a partitioned table must also be that
2760  * for all of its child partitions.
2761  */
2762  if (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE)
2763  {
2764  /* Don't add the clause if it is always true */
2765  if (restriction_is_always_true(root, restrictinfo))
2766  return;
2767 
2768  /*
2769  * Substitute the origin qual with constant-FALSE if it is provably
2770  * always false.
2771  *
2772  * Note that we need to keep the same rinfo_serial, since it is in
2773  * practice the same condition. We also need to reset the
2774  * last_rinfo_serial counter, which is essential to ensure that the
2775  * RestrictInfos for the "same" qual condition get identical serial
2776  * numbers (see deconstruct_distribute_oj_quals).
2777  */
2778  if (restriction_is_always_false(root, restrictinfo))
2779  {
2780  int save_rinfo_serial = restrictinfo->rinfo_serial;
2781  int save_last_rinfo_serial = root->last_rinfo_serial;
2782 
2783  restrictinfo = make_restrictinfo(root,
2784  (Expr *) makeBoolConst(false, false),
2785  restrictinfo->is_pushed_down,
2786  restrictinfo->has_clone,
2787  restrictinfo->is_clone,
2788  restrictinfo->pseudoconstant,
2789  0, /* security_level */
2790  restrictinfo->required_relids,
2791  restrictinfo->incompatible_relids,
2792  restrictinfo->outer_relids);
2793  restrictinfo->rinfo_serial = save_rinfo_serial;
2794  root->last_rinfo_serial = save_last_rinfo_serial;
2795  }
2796  }
2797 
2798  /* Add clause to rel's restriction list */
2799  rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo);
2800 
2801  /* Update security level info */
2803  restrictinfo->security_level);
2804 }
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_SINGLETON
Definition: bitmapset.h:72
#define Min(x, y)
Definition: c.h:958
#define Assert(condition)
Definition: c.h:812
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2850
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2899
List * lappend(List *list, void *datum)
Definition: list.c:339
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:359
tree ctl root
Definition: radixtree.h:1886
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:52
List * baserestrictinfo
Definition: pathnodes.h:985
Index baserestrict_min_security
Definition: pathnodes.h:989
bool is_pushed_down
Definition: pathnodes.h:2577
Index security_level
Definition: pathnodes.h:2596
Relids required_relids
Definition: pathnodes.h:2605
int rinfo_serial
Definition: pathnodes.h:2646
Relids outer_relids
Definition: pathnodes.h:2611
Relids incompatible_relids
Definition: pathnodes.h:2608
bool has_clone
Definition: pathnodes.h:2586

References Assert, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, bms_membership(), BMS_SINGLETON, find_base_rel(), RestrictInfo::has_clone, RestrictInfo::incompatible_relids, RangeTblEntry::inh, RestrictInfo::is_clone, RestrictInfo::is_pushed_down, lappend(), make_restrictinfo(), makeBoolConst(), Min, RestrictInfo::outer_relids, RestrictInfo::required_relids, restriction_is_always_false(), restriction_is_always_true(), RestrictInfo::rinfo_serial, root, and RestrictInfo::security_level.

Referenced by distribute_restrictinfo_to_rels().

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 157 of file initsplan.c.

158 {
159  if (jtnode == NULL)
160  return;
161  if (IsA(jtnode, RangeTblRef))
162  {
163  int varno = ((RangeTblRef *) jtnode)->rtindex;
164 
165  (void) build_simple_rel(root, varno, NULL);
166  }
167  else if (IsA(jtnode, FromExpr))
168  {
169  FromExpr *f = (FromExpr *) jtnode;
170  ListCell *l;
171 
172  foreach(l, f->fromlist)
174  }
175  else if (IsA(jtnode, JoinExpr))
176  {
177  JoinExpr *j = (JoinExpr *) jtnode;
178 
179  add_base_rels_to_query(root, j->larg);
180  add_base_rels_to_query(root, j->rarg);
181  }
182  else
183  elog(ERROR, "unrecognized node type: %d",
184  (int) nodeTag(jtnode));
185 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:157
int j
Definition: isn.c:73
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define lfirst(lc)
Definition: pg_list.h:172
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:192
List * fromlist
Definition: primnodes.h:2308

References build_simple_rel(), elog, ERROR, FromExpr::fromlist, IsA, j, JoinTreeItem::jtnode, lfirst, nodeTag, and root.

Referenced by query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 195 of file initsplan.c.

196 {
197  int rti;
198 
199  for (rti = 1; rti < root->simple_rel_array_size; rti++)
200  {
201  RelOptInfo *rel = root->simple_rel_array[rti];
202  RangeTblEntry *rte = root->simple_rte_array[rti];
203 
204  /* there may be empty slots corresponding to non-baserel RTEs */
205  if (rel == NULL)
206  continue;
207 
208  /* Ignore any "otherrels" that were already added. */
209  if (rel->reloptkind != RELOPT_BASEREL)
210  continue;
211 
212  /* If it's marked as inheritable, look for children. */
213  if (rte->inh)
214  expand_inherited_rtentry(root, rel, rte, rti);
215  }
216 }
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:86
@ RELOPT_BASEREL
Definition: pathnodes.h:827
RelOptKind reloptkind
Definition: pathnodes.h:865

References expand_inherited_rtentry(), RangeTblEntry::inh, RELOPT_BASEREL, RelOptInfo::reloptkind, and root.

Referenced by query_planner().

◆ add_vars_to_attr_needed()

void add_vars_to_attr_needed ( PlannerInfo root,
List vars,
Relids  where_needed 
)

Definition at line 352 of file initsplan.c.

354 {
355  ListCell *temp;
356 
357  Assert(!bms_is_empty(where_needed));
358 
359  foreach(temp, vars)
360  {
361  Node *node = (Node *) lfirst(temp);
362 
363  if (IsA(node, Var))
364  {
365  Var *var = (Var *) node;
366  RelOptInfo *rel = find_base_rel(root, var->varno);
367  int attno = var->varattno;
368 
369  if (bms_is_subset(where_needed, rel->relids))
370  continue;
371  Assert(attno >= rel->min_attr && attno <= rel->max_attr);
372  attno -= rel->min_attr;
373  rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
374  where_needed);
375  }
376  else if (IsA(node, PlaceHolderVar))
377  {
378  PlaceHolderVar *phv = (PlaceHolderVar *) node;
380 
381  phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
382  where_needed);
383  }
384  else
385  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
386  }
387 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
#define bms_is_empty(a)
Definition: bitmapset.h:118
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
Definition: placeholder.c:83
Definition: nodes.h:129
Relids ph_needed
Definition: pathnodes.h:3104
Relids relids
Definition: pathnodes.h:871
AttrNumber min_attr
Definition: pathnodes.h:924
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Definition: regcomp.c:282

References Assert, bms_add_members(), bms_is_empty, bms_is_subset(), elog, ERROR, find_base_rel(), find_placeholder_info(), IsA, lfirst, RelOptInfo::min_attr, nodeTag, PlaceHolderInfo::ph_needed, RelOptInfo::relids, root, Var::varattno, and Var::varno.

Referenced by rebuild_eclass_attr_needed(), rebuild_joinclause_attr_needed(), rebuild_lateral_attr_needed(), and rebuild_placeholder_attr_needed().

◆ add_vars_to_targetlist()

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

Definition at line 281 of file initsplan.c.

283 {
284  ListCell *temp;
285 
286  Assert(!bms_is_empty(where_needed));
287 
288  foreach(temp, vars)
289  {
290  Node *node = (Node *) lfirst(temp);
291 
292  if (IsA(node, Var))
293  {
294  Var *var = (Var *) node;
295  RelOptInfo *rel = find_base_rel(root, var->varno);
296  int attno = var->varattno;
297 
298  if (bms_is_subset(where_needed, rel->relids))
299  continue;
300  Assert(attno >= rel->min_attr && attno <= rel->max_attr);
301  attno -= rel->min_attr;
302  if (rel->attr_needed[attno] == NULL)
303  {
304  /*
305  * Variable not yet requested, so add to rel's targetlist.
306  *
307  * The value available at the rel's scan level has not been
308  * nulled by any outer join, so drop its varnullingrels.
309  * (We'll put those back as we climb up the join tree.)
310  */
311  var = copyObject(var);
312  var->varnullingrels = NULL;
313  rel->reltarget->exprs = lappend(rel->reltarget->exprs, var);
314  /* reltarget cost and width will be computed later */
315  }
316  rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
317  where_needed);
318  }
319  else if (IsA(node, PlaceHolderVar))
320  {
321  PlaceHolderVar *phv = (PlaceHolderVar *) node;
323 
324  phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
325  where_needed);
326  }
327  else
328  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
329  }
330 }
#define copyObject(obj)
Definition: nodes.h:224
List * exprs
Definition: pathnodes.h:1542
struct PathTarget * reltarget
Definition: pathnodes.h:893

References Assert, 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, root, 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().

◆ build_base_rel_tlists()

void build_base_rel_tlists ( PlannerInfo root,
List final_tlist 
)

Definition at line 234 of file initsplan.c.

235 {
236  List *tlist_vars = pull_var_clause((Node *) final_tlist,
240 
241  if (tlist_vars != NIL)
242  {
244  list_free(tlist_vars);
245  }
246 
247  /*
248  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
249  * that HAVING can contain Aggrefs but not WindowFuncs.
250  */
251  if (root->parse->havingQual)
252  {
253  List *having_vars = pull_var_clause(root->parse->havingQual,
256 
257  if (having_vars != NIL)
258  {
259  add_vars_to_targetlist(root, having_vars,
260  bms_make_singleton(0));
261  list_free(having_vars);
262  }
263  }
264 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:281
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:188
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:190
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:191
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
List * pull_var_clause(Node *node, int flags)
Definition: var.c:609

References add_vars_to_targetlist(), bms_make_singleton(), list_free(), NIL, pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and root.

Referenced by distribute_row_identity_vars(), and query_planner().

◆ build_implied_join_equality()

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

Definition at line 3183 of file initsplan.c.

3190 {
3191  RestrictInfo *restrictinfo;
3192  Expr *clause;
3193 
3194  /*
3195  * Build the new clause. Copy to ensure it shares no substructure with
3196  * original (this is necessary in case there are subselects in there...)
3197  */
3198  clause = make_opclause(opno,
3199  BOOLOID, /* opresulttype */
3200  false, /* opretset */
3201  copyObject(item1),
3202  copyObject(item2),
3203  InvalidOid,
3204  collation);
3205 
3206  /*
3207  * Build the RestrictInfo node itself.
3208  */
3209  restrictinfo = make_restrictinfo(root,
3210  clause,
3211  true, /* is_pushed_down */
3212  false, /* !has_clone */
3213  false, /* !is_clone */
3214  false, /* pseudoconstant */
3215  security_level, /* security_level */
3216  qualscope, /* required_relids */
3217  NULL, /* incompatible_relids */
3218  NULL); /* outer_relids */
3219 
3220  /* Set mergejoinability/hashjoinability flags */
3221  check_mergejoinable(restrictinfo);
3222  check_hashjoinable(restrictinfo);
3223  check_memoizable(restrictinfo);
3224 
3225  return restrictinfo;
3226 }
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3560
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3523
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3588
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:651
#define InvalidOid
Definition: postgres_ext.h:36

References check_hashjoinable(), check_memoizable(), check_mergejoinable(), copyObject, InvalidOid, make_opclause(), make_restrictinfo(), JoinTreeItem::qualscope, and root.

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

◆ check_hashjoinable()

static void check_hashjoinable ( RestrictInfo restrictinfo)
static

Definition at line 3560 of file initsplan.c.

3561 {
3562  Expr *clause = restrictinfo->clause;
3563  Oid opno;
3564  Node *leftarg;
3565 
3566  if (restrictinfo->pseudoconstant)
3567  return;
3568  if (!is_opclause(clause))
3569  return;
3570  if (list_length(((OpExpr *) clause)->args) != 2)
3571  return;
3572 
3573  opno = ((OpExpr *) clause)->opno;
3574  leftarg = linitial(((OpExpr *) clause)->args);
3575 
3576  if (op_hashjoinable(opno, exprType(leftarg)) &&
3577  !contain_volatile_functions((Node *) restrictinfo))
3578  restrictinfo->hashjoinoperator = opno;
3579 }
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:537
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1437
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:76
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
unsigned int Oid
Definition: postgres_ext.h:31
Expr * clause
Definition: pathnodes.h:2574

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

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

◆ check_memoizable()

static void check_memoizable ( RestrictInfo restrictinfo)
static

Definition at line 3588 of file initsplan.c.

3589 {
3590  TypeCacheEntry *typentry;
3591  Expr *clause = restrictinfo->clause;
3592  Oid lefttype;
3593  Oid righttype;
3594 
3595  if (restrictinfo->pseudoconstant)
3596  return;
3597  if (!is_opclause(clause))
3598  return;
3599  if (list_length(((OpExpr *) clause)->args) != 2)
3600  return;
3601 
3602  lefttype = exprType(linitial(((OpExpr *) clause)->args));
3603 
3604  typentry = lookup_type_cache(lefttype, TYPECACHE_HASH_PROC |
3606 
3607  if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3608  restrictinfo->left_hasheqoperator = typentry->eq_opr;
3609 
3610  righttype = exprType(lsecond(((OpExpr *) clause)->args));
3611 
3612  /*
3613  * Lookup the right type, unless it's the same as the left type, in which
3614  * case typentry is already pointing to the required TypeCacheEntry.
3615  */
3616  if (lefttype != righttype)
3617  typentry = lookup_type_cache(righttype, TYPECACHE_HASH_PROC |
3619 
3620  if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3621  restrictinfo->right_hasheqoperator = typentry->eq_opr;
3622 }
#define OidIsValid(objectId)
Definition: c.h:729
#define lsecond(l)
Definition: pg_list.h:183
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_EQ_OPR
Definition: typcache.h:137
#define TYPECACHE_HASH_PROC
Definition: typcache.h:141

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

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

◆ check_mergejoinable()

static void check_mergejoinable ( RestrictInfo restrictinfo)
static

Definition at line 3523 of file initsplan.c.

3524 {
3525  Expr *clause = restrictinfo->clause;
3526  Oid opno;
3527  Node *leftarg;
3528 
3529  if (restrictinfo->pseudoconstant)
3530  return;
3531  if (!is_opclause(clause))
3532  return;
3533  if (list_length(((OpExpr *) clause)->args) != 2)
3534  return;
3535 
3536  opno = ((OpExpr *) clause)->opno;
3537  leftarg = linitial(((OpExpr *) clause)->args);
3538 
3539  if (op_mergejoinable(opno, exprType(leftarg)) &&
3540  !contain_volatile_functions((Node *) restrictinfo))
3541  restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
3542 
3543  /*
3544  * Note: op_mergejoinable is just a hint; if we fail to find the operator
3545  * in any btree opfamilies, mergeopfamilies remains NIL and so the clause
3546  * is not treated as mergejoinable.
3547  */
3548 }
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:366
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1386

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

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

◆ check_redundant_nullability_qual()

static bool check_redundant_nullability_qual ( PlannerInfo root,
Node clause 
)
static

Definition at line 2694 of file initsplan.c.

2695 {
2696  Var *forced_null_var;
2697  ListCell *lc;
2698 
2699  /* Check for IS NULL, and identify the Var forced to NULL */
2700  forced_null_var = find_forced_null_var(clause);
2701  if (forced_null_var == NULL)
2702  return false;
2703 
2704  /*
2705  * If the Var comes from the nullable side of a lower antijoin, the IS
2706  * NULL condition is necessarily true. If it's not nulled by anything,
2707  * there is no point in searching the join_info_list. Otherwise, we need
2708  * to find out whether the nulling rel is an antijoin.
2709  */
2710  if (forced_null_var->varnullingrels == NULL)
2711  return false;
2712 
2713  foreach(lc, root->join_info_list)
2714  {
2715  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
2716 
2717  /*
2718  * This test will not succeed if sjinfo->ojrelid is zero, which is
2719  * possible for an antijoin that was converted from a semijoin; but in
2720  * such a case the Var couldn't have come from its nullable side.
2721  */
2722  if (sjinfo->jointype == JOIN_ANTI && sjinfo->ojrelid != 0 &&
2723  bms_is_member(sjinfo->ojrelid, forced_null_var->varnullingrels))
2724  return true;
2725  }
2726 
2727  return false;
2728 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Var * find_forced_null_var(Node *node)
Definition: clauses.c:1976
@ JOIN_ANTI
Definition: nodes.h:308
JoinType jointype
Definition: pathnodes.h:2908

References bms_is_member(), find_forced_null_var(), JOIN_ANTI, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::ojrelid, root, and JoinTreeItem::sjinfo.

Referenced by distribute_qual_to_rels().

◆ compute_semijoin_info()

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

Definition at line 1807 of file initsplan.c.

1808 {
1809  List *semi_operators;
1810  List *semi_rhs_exprs;
1811  bool all_btree;
1812  bool all_hash;
1813  ListCell *lc;
1814 
1815  /* Initialize semijoin-related fields in case we can't unique-ify */
1816  sjinfo->semi_can_btree = false;
1817  sjinfo->semi_can_hash = false;
1818  sjinfo->semi_operators = NIL;
1819  sjinfo->semi_rhs_exprs = NIL;
1820 
1821  /* Nothing more to do if it's not a semijoin */
1822  if (sjinfo->jointype != JOIN_SEMI)
1823  return;
1824 
1825  /*
1826  * Look to see whether the semijoin's join quals consist of AND'ed
1827  * equality operators, with (only) RHS variables on only one side of each
1828  * one. If so, we can figure out how to enforce uniqueness for the RHS.
1829  *
1830  * Note that the input clause list is the list of quals that are
1831  * *syntactically* associated with the semijoin, which in practice means
1832  * the synthesized comparison list for an IN or the WHERE of an EXISTS.
1833  * Particularly in the latter case, it might contain clauses that aren't
1834  * *semantically* associated with the join, but refer to just one side or
1835  * the other. We can ignore such clauses here, as they will just drop
1836  * down to be processed within one side or the other. (It is okay to
1837  * consider only the syntactically-associated clauses here because for a
1838  * semijoin, no higher-level quals could refer to the RHS, and so there
1839  * can be no other quals that are semantically associated with this join.
1840  * We do things this way because it is useful to have the set of potential
1841  * unique-ification expressions before we can extract the list of quals
1842  * that are actually semantically associated with the particular join.)
1843  *
1844  * Note that the semi_operators list consists of the joinqual operators
1845  * themselves (but commuted if needed to put the RHS value on the right).
1846  * These could be cross-type operators, in which case the operator
1847  * actually needed for uniqueness is a related single-type operator. We
1848  * assume here that that operator will be available from the btree or hash
1849  * opclass when the time comes ... if not, create_unique_plan() will fail.
1850  */
1851  semi_operators = NIL;
1852  semi_rhs_exprs = NIL;
1853  all_btree = true;
1854  all_hash = enable_hashagg; /* don't consider hash if not enabled */
1855  foreach(lc, clause)
1856  {
1857  OpExpr *op = (OpExpr *) lfirst(lc);
1858  Oid opno;
1859  Node *left_expr;
1860  Node *right_expr;
1861  Relids left_varnos;
1862  Relids right_varnos;
1863  Relids all_varnos;
1864  Oid opinputtype;
1865 
1866  /* Is it a binary opclause? */
1867  if (!IsA(op, OpExpr) ||
1868  list_length(op->args) != 2)
1869  {
1870  /* No, but does it reference both sides? */
1871  all_varnos = pull_varnos(root, (Node *) op);
1872  if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
1873  bms_is_subset(all_varnos, sjinfo->syn_righthand))
1874  {
1875  /*
1876  * Clause refers to only one rel, so ignore it --- unless it
1877  * contains volatile functions, in which case we'd better
1878  * punt.
1879  */
1880  if (contain_volatile_functions((Node *) op))
1881  return;
1882  continue;
1883  }
1884  /* Non-operator clause referencing both sides, must punt */
1885  return;
1886  }
1887 
1888  /* Extract data from binary opclause */
1889  opno = op->opno;
1890  left_expr = linitial(op->args);
1891  right_expr = lsecond(op->args);
1892  left_varnos = pull_varnos(root, left_expr);
1893  right_varnos = pull_varnos(root, right_expr);
1894  all_varnos = bms_union(left_varnos, right_varnos);
1895  opinputtype = exprType(left_expr);
1896 
1897  /* Does it reference both sides? */
1898  if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
1899  bms_is_subset(all_varnos, sjinfo->syn_righthand))
1900  {
1901  /*
1902  * Clause refers to only one rel, so ignore it --- unless it
1903  * contains volatile functions, in which case we'd better punt.
1904  */
1905  if (contain_volatile_functions((Node *) op))
1906  return;
1907  continue;
1908  }
1909 
1910  /* check rel membership of arguments */
1911  if (!bms_is_empty(right_varnos) &&
1912  bms_is_subset(right_varnos, sjinfo->syn_righthand) &&
1913  !bms_overlap(left_varnos, sjinfo->syn_righthand))
1914  {
1915  /* typical case, right_expr is RHS variable */
1916  }
1917  else if (!bms_is_empty(left_varnos) &&
1918  bms_is_subset(left_varnos, sjinfo->syn_righthand) &&
1919  !bms_overlap(right_varnos, sjinfo->syn_righthand))
1920  {
1921  /* flipped case, left_expr is RHS variable */
1922  opno = get_commutator(opno);
1923  if (!OidIsValid(opno))
1924  return;
1925  right_expr = left_expr;
1926  }
1927  else
1928  {
1929  /* mixed membership of args, punt */
1930  return;
1931  }
1932 
1933  /* all operators must be btree equality or hash equality */
1934  if (all_btree)
1935  {
1936  /* oprcanmerge is considered a hint... */
1937  if (!op_mergejoinable(opno, opinputtype) ||
1938  get_mergejoin_opfamilies(opno) == NIL)
1939  all_btree = false;
1940  }
1941  if (all_hash)
1942  {
1943  /* ... but oprcanhash had better be correct */
1944  if (!op_hashjoinable(opno, opinputtype))
1945  all_hash = false;
1946  }
1947  if (!(all_btree || all_hash))
1948  return;
1949 
1950  /* so far so good, keep building lists */
1951  semi_operators = lappend_oid(semi_operators, opno);
1952  semi_rhs_exprs = lappend(semi_rhs_exprs, copyObject(right_expr));
1953  }
1954 
1955  /* Punt if we didn't find at least one column to unique-ify */
1956  if (semi_rhs_exprs == NIL)
1957  return;
1958 
1959  /*
1960  * The expressions we'd need to unique-ify mustn't be volatile.
1961  */
1962  if (contain_volatile_functions((Node *) semi_rhs_exprs))
1963  return;
1964 
1965  /*
1966  * If we get here, we can unique-ify the semijoin's RHS using at least one
1967  * of sorting and hashing. Save the information about how to do that.
1968  */
1969  sjinfo->semi_can_btree = all_btree;
1970  sjinfo->semi_can_hash = all_hash;
1971  sjinfo->semi_operators = semi_operators;
1972  sjinfo->semi_rhs_exprs = semi_rhs_exprs;
1973 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
bool enable_hashagg
Definition: costsize.c:152
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1509
@ JOIN_SEMI
Definition: nodes.h:307
Oid opno
Definition: primnodes.h:818
List * args
Definition: primnodes.h:836
List * semi_rhs_exprs
Definition: pathnodes.h:2919
Relids syn_righthand
Definition: pathnodes.h:2907
List * semi_operators
Definition: pathnodes.h:2918
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:113

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(), root, SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, SpecialJoinInfo::semi_operators, SpecialJoinInfo::semi_rhs_exprs, JoinTreeItem::sjinfo, and SpecialJoinInfo::syn_righthand.

Referenced by make_outerjoininfo().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 604 of file initsplan.c.

605 {
606  bool found_laterals = false;
607  Index rti;
608  ListCell *lc;
609 
610  /* We need do nothing if the query contains no LATERAL RTEs */
611  if (!root->hasLateralRTEs)
612  return;
613 
614  /* We'll need to have the ph_eval_at values for PlaceHolderVars */
615  Assert(root->placeholdersFrozen);
616 
617  /*
618  * Examine all baserels (the rel array has been set up by now).
619  */
620  for (rti = 1; rti < root->simple_rel_array_size; rti++)
621  {
622  RelOptInfo *brel = root->simple_rel_array[rti];
623  Relids lateral_relids;
624 
625  /* there may be empty slots corresponding to non-baserel RTEs */
626  if (brel == NULL)
627  continue;
628 
629  Assert(brel->relid == rti); /* sanity check on array */
630 
631  /* ignore RTEs that are "other rels" */
632  if (brel->reloptkind != RELOPT_BASEREL)
633  continue;
634 
635  lateral_relids = NULL;
636 
637  /* consider each laterally-referenced Var or PHV */
638  foreach(lc, brel->lateral_vars)
639  {
640  Node *node = (Node *) lfirst(lc);
641 
642  if (IsA(node, Var))
643  {
644  Var *var = (Var *) node;
645 
646  found_laterals = true;
647  lateral_relids = bms_add_member(lateral_relids,
648  var->varno);
649  }
650  else if (IsA(node, PlaceHolderVar))
651  {
652  PlaceHolderVar *phv = (PlaceHolderVar *) node;
654 
655  found_laterals = true;
656  lateral_relids = bms_add_members(lateral_relids,
657  phinfo->ph_eval_at);
658  }
659  else
660  Assert(false);
661  }
662 
663  /* We now have all the simple lateral refs from this rel */
664  brel->direct_lateral_relids = lateral_relids;
665  brel->lateral_relids = bms_copy(lateral_relids);
666  }
667 
668  /*
669  * Now check for lateral references within PlaceHolderVars, and mark their
670  * eval_at rels as having lateral references to the source rels.
671  *
672  * For a PHV that is due to be evaluated at a baserel, mark its source(s)
673  * as direct lateral dependencies of the baserel (adding onto the ones
674  * recorded above). If it's due to be evaluated at a join, mark its
675  * source(s) as indirect lateral dependencies of each baserel in the join,
676  * ie put them into lateral_relids but not direct_lateral_relids. This is
677  * appropriate because we can't put any such baserel on the outside of a
678  * join to one of the PHV's lateral dependencies, but on the other hand we
679  * also can't yet join it directly to the dependency.
680  */
681  foreach(lc, root->placeholder_list)
682  {
683  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
684  Relids eval_at = phinfo->ph_eval_at;
685  Relids lateral_refs;
686  int varno;
687 
688  if (phinfo->ph_lateral == NULL)
689  continue; /* PHV is uninteresting if no lateral refs */
690 
691  found_laterals = true;
692 
693  /*
694  * Include only baserels not outer joins in the evaluation sites'
695  * lateral relids. This avoids problems when outer join order gets
696  * rearranged, and it should still ensure that the lateral values are
697  * available when needed.
698  */
699  lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels);
700  Assert(!bms_is_empty(lateral_refs));
701 
702  if (bms_get_singleton_member(eval_at, &varno))
703  {
704  /* Evaluation site is a baserel */
705  RelOptInfo *brel = find_base_rel(root, varno);
706 
707  brel->direct_lateral_relids =
709  lateral_refs);
710  brel->lateral_relids =
712  lateral_refs);
713  }
714  else
715  {
716  /* Evaluation site is a join */
717  varno = -1;
718  while ((varno = bms_next_member(eval_at, varno)) >= 0)
719  {
720  RelOptInfo *brel = find_base_rel_ignore_join(root, varno);
721 
722  if (brel == NULL)
723  continue; /* ignore outer joins in eval_at */
725  lateral_refs);
726  }
727  }
728  }
729 
730  /*
731  * If we found no actual lateral references, we're done; but reset the
732  * hasLateralRTEs flag to avoid useless work later.
733  */
734  if (!found_laterals)
735  {
736  root->hasLateralRTEs = false;
737  return;
738  }
739 
740  /*
741  * Calculate the transitive closure of the lateral_relids sets, so that
742  * they describe both direct and indirect lateral references. If relation
743  * X references Y laterally, and Y references Z laterally, then we will
744  * have to scan X on the inside of a nestloop with Z, so for all intents
745  * and purposes X is laterally dependent on Z too.
746  *
747  * This code is essentially Warshall's algorithm for transitive closure.
748  * The outer loop considers each baserel, and propagates its lateral
749  * dependencies to those baserels that have a lateral dependency on it.
750  */
751  for (rti = 1; rti < root->simple_rel_array_size; rti++)
752  {
753  RelOptInfo *brel = root->simple_rel_array[rti];
754  Relids outer_lateral_relids;
755  Index rti2;
756 
757  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
758  continue;
759 
760  /* need not consider baserel further if it has no lateral refs */
761  outer_lateral_relids = brel->lateral_relids;
762  if (outer_lateral_relids == NULL)
763  continue;
764 
765  /* else scan all baserels */
766  for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
767  {
768  RelOptInfo *brel2 = root->simple_rel_array[rti2];
769 
770  if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
771  continue;
772 
773  /* if brel2 has lateral ref to brel, propagate brel's refs */
774  if (bms_is_member(rti, brel2->lateral_relids))
776  outer_lateral_relids);
777  }
778  }
779 
780  /*
781  * Now that we've identified all lateral references, mark each baserel
782  * with the set of relids of rels that reference it laterally (possibly
783  * indirectly) --- that is, the inverse mapping of lateral_relids.
784  */
785  for (rti = 1; rti < root->simple_rel_array_size; rti++)
786  {
787  RelOptInfo *brel = root->simple_rel_array[rti];
788  Relids lateral_relids;
789  int rti2;
790 
791  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
792  continue;
793 
794  /* Nothing to do at rels with no lateral refs */
795  lateral_relids = brel->lateral_relids;
796  if (bms_is_empty(lateral_relids))
797  continue;
798 
799  /* No rel should have a lateral dependency on itself */
800  Assert(!bms_is_member(rti, lateral_relids));
801 
802  /* Mark this rel's referencees */
803  rti2 = -1;
804  while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
805  {
806  RelOptInfo *brel2 = root->simple_rel_array[rti2];
807 
808  if (brel2 == NULL)
809  continue; /* must be an OJ */
810 
811  Assert(brel2->reloptkind == RELOPT_BASEREL);
812  brel2->lateral_referencers =
813  bms_add_member(brel2->lateral_referencers, rti);
814  }
815  }
816 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:292
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:715
unsigned int Index
Definition: c.h:568
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:454
Relids ph_lateral
Definition: pathnodes.h:3101
Relids ph_eval_at
Definition: pathnodes.h:3098
Index relid
Definition: pathnodes.h:918
List * lateral_vars
Definition: pathnodes.h:940
Relids lateral_relids
Definition: pathnodes.h:913
Relids lateral_referencers
Definition: pathnodes.h:942
Relids direct_lateral_relids
Definition: pathnodes.h:911

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

Referenced by query_planner().

◆ deconstruct_distribute()

static void deconstruct_distribute ( PlannerInfo root,
JoinTreeItem jtitem 
)
static

Definition at line 1223 of file initsplan.c.

1224 {
1225  Node *jtnode = jtitem->jtnode;
1226 
1227  if (IsA(jtnode, RangeTblRef))
1228  {
1229  int varno = ((RangeTblRef *) jtnode)->rtindex;
1230 
1231  /* Deal with any securityQuals attached to the RTE */
1232  if (root->qual_security_level > 0)
1234  varno,
1235  jtitem);
1236  }
1237  else if (IsA(jtnode, FromExpr))
1238  {
1239  FromExpr *f = (FromExpr *) jtnode;
1240 
1241  /*
1242  * Process any lateral-referencing quals that were postponed to this
1243  * level by children.
1244  */
1246  jtitem,
1247  NULL,
1248  root->qual_security_level,
1249  jtitem->qualscope,
1250  NULL, NULL, NULL,
1251  true, false, false,
1252  NULL);
1253 
1254  /*
1255  * Now process the top-level quals.
1256  */
1258  jtitem,
1259  NULL,
1260  root->qual_security_level,
1261  jtitem->qualscope,
1262  NULL, NULL, NULL,
1263  true, false, false,
1264  NULL);
1265  }
1266  else if (IsA(jtnode, JoinExpr))
1267  {
1268  JoinExpr *j = (JoinExpr *) jtnode;
1269  Relids ojscope;
1270  List *my_quals;
1271  SpecialJoinInfo *sjinfo;
1272  List **postponed_oj_qual_list;
1273 
1274  /*
1275  * Include lateral-referencing quals postponed from children in
1276  * my_quals, so that they'll be handled properly in
1277  * make_outerjoininfo. (This is destructive to
1278  * jtitem->lateral_clauses, but we won't use that again.)
1279  */
1280  my_quals = list_concat(jtitem->lateral_clauses,
1281  (List *) j->quals);
1282 
1283  /*
1284  * For an OJ, form the SpecialJoinInfo now, so that we can pass it to
1285  * distribute_qual_to_rels. We must compute its ojscope too.
1286  *
1287  * Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we
1288  * want ojscope = NULL for distribute_qual_to_rels.
1289  */
1290  if (j->jointype != JOIN_INNER)
1291  {
1292  sjinfo = make_outerjoininfo(root,
1293  jtitem->left_rels,
1294  jtitem->right_rels,
1295  jtitem->inner_join_rels,
1296  j->jointype,
1297  j->rtindex,
1298  my_quals);
1299  jtitem->sjinfo = sjinfo;
1300  if (j->jointype == JOIN_SEMI)
1301  ojscope = NULL;
1302  else
1303  ojscope = bms_union(sjinfo->min_lefthand,
1304  sjinfo->min_righthand);
1305  }
1306  else
1307  {
1308  sjinfo = NULL;
1309  ojscope = NULL;
1310  }
1311 
1312  /*
1313  * If it's a left join with a join clause that is strict for the LHS,
1314  * then we need to postpone handling of any non-degenerate join
1315  * clauses, in case the join is able to commute with another left join
1316  * per identity 3. (Degenerate clauses need not be postponed, since
1317  * they will drop down below this join anyway.)
1318  */
1319  if (j->jointype == JOIN_LEFT && sjinfo->lhs_strict)
1320  {
1321  postponed_oj_qual_list = &jtitem->oj_joinclauses;
1322 
1323  /*
1324  * Add back any commutable lower OJ relids that were removed from
1325  * min_lefthand or min_righthand, else the ojscope cross-check in
1326  * distribute_qual_to_rels will complain. Since we are postponing
1327  * processing of non-degenerate clauses, this addition doesn't
1328  * affect anything except that cross-check. Real clause
1329  * positioning decisions will be made later, when we revisit the
1330  * postponed clauses.
1331  */
1332  ojscope = bms_add_members(ojscope, sjinfo->commute_below_l);
1333  ojscope = bms_add_members(ojscope, sjinfo->commute_below_r);
1334  }
1335  else
1336  postponed_oj_qual_list = NULL;
1337 
1338  /* Process the JOIN's qual clauses */
1339  distribute_quals_to_rels(root, my_quals,
1340  jtitem,
1341  sjinfo,
1342  root->qual_security_level,
1343  jtitem->qualscope,
1344  ojscope, jtitem->nonnullable_rels,
1345  NULL, /* incompatible_relids */
1346  true, /* allow_equivalence */
1347  false, false, /* not clones */
1348  postponed_oj_qual_list);
1349 
1350  /* And add the SpecialJoinInfo to join_info_list */
1351  if (sjinfo)
1352  root->join_info_list = lappend(root->join_info_list, sjinfo);
1353  }
1354  else
1355  {
1356  elog(ERROR, "unrecognized node type: %d",
1357  (int) nodeTag(jtnode));
1358  }
1359 }
static void distribute_quals_to_rels(PlannerInfo *root, List *clauses, JoinTreeItem *jtitem, SpecialJoinInfo *sjinfo, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, Relids incompatible_relids, bool allow_equivalence, bool has_clone, bool is_clone, List **postponed_oj_qual_list)
Definition: initsplan.c:2226
static SpecialJoinInfo * make_outerjoininfo(PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, JoinType jointype, Index ojrelid, List *clause)
Definition: initsplan.c:1467
static void process_security_barrier_quals(PlannerInfo *root, int rti, JoinTreeItem *jtitem)
Definition: initsplan.c:1375
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
@ JOIN_INNER
Definition: nodes.h:293
@ JOIN_LEFT
Definition: nodes.h:294
Node * quals
Definition: primnodes.h:2309
SpecialJoinInfo * sjinfo
Definition: initsplan.c:76
Relids inner_join_rels
Definition: initsplan.c:68
Relids left_rels
Definition: initsplan.c:71
Relids right_rels
Definition: initsplan.c:72
Relids nonnullable_rels
Definition: initsplan.c:73
Node * jtnode
Definition: initsplan.c:62
List * oj_joinclauses
Definition: initsplan.c:77
Relids qualscope
Definition: initsplan.c:66
List * lateral_clauses
Definition: initsplan.c:78
Relids min_righthand
Definition: pathnodes.h:2905
Relids commute_below_l
Definition: pathnodes.h:2912
Relids min_lefthand
Definition: pathnodes.h:2904
Relids commute_below_r
Definition: pathnodes.h:2913

References bms_add_members(), bms_union(), SpecialJoinInfo::commute_below_l, SpecialJoinInfo::commute_below_r, distribute_quals_to_rels(), elog, ERROR, JoinTreeItem::inner_join_rels, IsA, j, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, JoinTreeItem::jtnode, lappend(), JoinTreeItem::lateral_clauses, JoinTreeItem::left_rels, SpecialJoinInfo::lhs_strict, list_concat(), make_outerjoininfo(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, nodeTag, JoinTreeItem::nonnullable_rels, JoinTreeItem::oj_joinclauses, process_security_barrier_quals(), FromExpr::quals, JoinTreeItem::qualscope, JoinTreeItem::right_rels, root, and JoinTreeItem::sjinfo.

Referenced by deconstruct_jointree().

◆ deconstruct_distribute_oj_quals()

static void deconstruct_distribute_oj_quals ( PlannerInfo root,
List jtitems,
JoinTreeItem jtitem 
)
static

Definition at line 1985 of file initsplan.c.

1988 {
1989  SpecialJoinInfo *sjinfo = jtitem->sjinfo;
1990  Relids qualscope,
1991  ojscope,
1992  nonnullable_rels;
1993 
1994  /* Recompute syntactic and semantic scopes of this left join */
1995  qualscope = bms_union(sjinfo->syn_lefthand, sjinfo->syn_righthand);
1996  qualscope = bms_add_member(qualscope, sjinfo->ojrelid);
1997  ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
1998  nonnullable_rels = sjinfo->syn_lefthand;
1999 
2000  /*
2001  * If this join can commute with any other ones per outer-join identity 3,
2002  * and it is the one providing the join clause with flexible semantics,
2003  * then we have to generate variants of the join clause with different
2004  * nullingrels labeling. Otherwise, just push out the postponed clause
2005  * as-is.
2006  */
2007  Assert(sjinfo->lhs_strict); /* else we shouldn't be here */
2008  if (sjinfo->commute_above_r || sjinfo->commute_below_l)
2009  {
2010  Relids joins_above;
2011  Relids joins_below;
2012  Relids incompatible_joins;
2013  Relids joins_so_far;
2014  List *quals;
2015  int save_last_rinfo_serial;
2016  ListCell *lc;
2017 
2018  /* Identify the outer joins this one commutes with */
2019  joins_above = sjinfo->commute_above_r;
2020  joins_below = sjinfo->commute_below_l;
2021 
2022  /*
2023  * Generate qual variants with different sets of nullingrels bits.
2024  *
2025  * We only need bit-sets that correspond to the successively less
2026  * deeply syntactically-nested subsets of this join and its
2027  * commutators. That's true first because obviously only those forms
2028  * of the Vars and PHVs could appear elsewhere in the query, and
2029  * second because the outer join identities do not provide a way to
2030  * re-order such joins in a way that would require different marking.
2031  * (That is, while the current join may commute with several others,
2032  * none of those others can commute with each other.) To visit the
2033  * interesting joins in syntactic nesting order, we rely on the
2034  * jtitems list to be ordered that way.
2035  *
2036  * We first strip out all the nullingrels bits corresponding to
2037  * commuting joins below this one, and then successively put them back
2038  * as we crawl up the join stack.
2039  */
2040  quals = jtitem->oj_joinclauses;
2041  if (!bms_is_empty(joins_below))
2042  quals = (List *) remove_nulling_relids((Node *) quals,
2043  joins_below,
2044  NULL);
2045 
2046  /*
2047  * We'll need to mark the lower versions of the quals as not safe to
2048  * apply above not-yet-processed joins of the stack. This prevents
2049  * possibly applying a cloned qual at the wrong join level.
2050  */
2051  incompatible_joins = bms_union(joins_below, joins_above);
2052  incompatible_joins = bms_add_member(incompatible_joins,
2053  sjinfo->ojrelid);
2054 
2055  /*
2056  * Each time we produce RestrictInfo(s) from these quals, reset the
2057  * last_rinfo_serial counter, so that the RestrictInfos for the "same"
2058  * qual condition get identical serial numbers. (This relies on the
2059  * fact that we're not changing the qual list in any way that'd affect
2060  * the number of RestrictInfos built from it.) This'll allow us to
2061  * detect duplicative qual usage later.
2062  */
2063  save_last_rinfo_serial = root->last_rinfo_serial;
2064 
2065  joins_so_far = NULL;
2066  foreach(lc, jtitems)
2067  {
2068  JoinTreeItem *otherjtitem = (JoinTreeItem *) lfirst(lc);
2069  SpecialJoinInfo *othersj = otherjtitem->sjinfo;
2070  bool below_sjinfo = false;
2071  bool above_sjinfo = false;
2072  Relids this_qualscope;
2073  Relids this_ojscope;
2074  bool allow_equivalence,
2075  has_clone,
2076  is_clone;
2077 
2078  if (othersj == NULL)
2079  continue; /* not an outer-join item, ignore */
2080 
2081  if (bms_is_member(othersj->ojrelid, joins_below))
2082  {
2083  /* othersj commutes with sjinfo from below left */
2084  below_sjinfo = true;
2085  }
2086  else if (othersj == sjinfo)
2087  {
2088  /* found our join in syntactic order */
2089  Assert(bms_equal(joins_so_far, joins_below));
2090  }
2091  else if (bms_is_member(othersj->ojrelid, joins_above))
2092  {
2093  /* othersj commutes with sjinfo from above */
2094  above_sjinfo = true;
2095  }
2096  else
2097  {
2098  /* othersj is not relevant, ignore */
2099  continue;
2100  }
2101 
2102  /* Reset serial counter for this version of the quals */
2103  root->last_rinfo_serial = save_last_rinfo_serial;
2104 
2105  /*
2106  * When we are looking at joins above sjinfo, we are envisioning
2107  * pushing sjinfo to above othersj, so add othersj's nulling bit
2108  * before distributing the quals. We should add it to Vars coming
2109  * from the current join's LHS: we want to transform the second
2110  * form of OJ identity 3 to the first form, in which Vars of
2111  * relation B will appear nulled by the syntactically-upper OJ
2112  * within the Pbc clause, but those of relation C will not. (In
2113  * the notation used by optimizer/README, we're converting a qual
2114  * of the form Pbc to Pb*c.) Of course, we must also remove that
2115  * bit from the incompatible_joins value, else we'll make a qual
2116  * that can't be placed anywhere.
2117  */
2118  if (above_sjinfo)
2119  {
2120  quals = (List *)
2121  add_nulling_relids((Node *) quals,
2122  sjinfo->syn_lefthand,
2123  bms_make_singleton(othersj->ojrelid));
2124  incompatible_joins = bms_del_member(incompatible_joins,
2125  othersj->ojrelid);
2126  }
2127 
2128  /* Compute qualscope and ojscope for this join level */
2129  this_qualscope = bms_union(qualscope, joins_so_far);
2130  this_ojscope = bms_union(ojscope, joins_so_far);
2131  if (above_sjinfo)
2132  {
2133  /* othersj is not yet in joins_so_far, but we need it */
2134  this_qualscope = bms_add_member(this_qualscope,
2135  othersj->ojrelid);
2136  this_ojscope = bms_add_member(this_ojscope,
2137  othersj->ojrelid);
2138  /* sjinfo is in joins_so_far, and we don't want it */
2139  this_ojscope = bms_del_member(this_ojscope,
2140  sjinfo->ojrelid);
2141  }
2142 
2143  /*
2144  * We generate EquivalenceClasses only from the first form of the
2145  * quals, with the fewest nullingrels bits set. An EC made from
2146  * this version of the quals can be useful below the outer-join
2147  * nest, whereas versions with some nullingrels bits set would not
2148  * be. We cannot generate ECs from more than one version, or
2149  * we'll make nonsensical conclusions that Vars with nullingrels
2150  * bits set are equal to their versions without. Fortunately,
2151  * such ECs wouldn't be very useful anyway, because they'd equate
2152  * values not observable outside the join nest. (See
2153  * optimizer/README.)
2154  *
2155  * The first form of the quals is also the only one marked as
2156  * has_clone rather than is_clone.
2157  */
2158  allow_equivalence = (joins_so_far == NULL);
2159  has_clone = allow_equivalence;
2160  is_clone = !has_clone;
2161 
2163  otherjtitem,
2164  sjinfo,
2165  root->qual_security_level,
2166  this_qualscope,
2167  this_ojscope, nonnullable_rels,
2168  bms_copy(incompatible_joins),
2169  allow_equivalence,
2170  has_clone,
2171  is_clone,
2172  NULL); /* no more postponement */
2173 
2174  /*
2175  * Adjust qual nulling bits for next level up, if needed. We
2176  * don't want to put sjinfo's own bit in at all, and if we're
2177  * above sjinfo then we did it already. Here, we should mark all
2178  * Vars coming from the lower join's RHS. (Again, we are
2179  * converting a qual of the form Pbc to Pb*c, but now we are
2180  * putting back bits that were there in the parser output and were
2181  * temporarily stripped above.) Update incompatible_joins too.
2182  */
2183  if (below_sjinfo)
2184  {
2185  quals = (List *)
2186  add_nulling_relids((Node *) quals,
2187  othersj->syn_righthand,
2188  bms_make_singleton(othersj->ojrelid));
2189  incompatible_joins = bms_del_member(incompatible_joins,
2190  othersj->ojrelid);
2191  }
2192 
2193  /* ... and track joins processed so far */
2194  joins_so_far = bms_add_member(joins_so_far, othersj->ojrelid);
2195  }
2196  }
2197  else
2198  {
2199  /* No commutation possible, just process the postponed clauses */
2201  jtitem,
2202  sjinfo,
2203  root->qual_security_level,
2204  qualscope,
2205  ojscope, nonnullable_rels,
2206  NULL, /* incompatible_relids */
2207  true, /* allow_equivalence */
2208  false, false, /* not clones */
2209  NULL); /* no more postponement */
2210  }
2211 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)
Node * add_nulling_relids(Node *node, const Bitmapset *target_relids, const Bitmapset *added_relids)
Relids commute_above_r
Definition: pathnodes.h:2911
Relids syn_lefthand
Definition: pathnodes.h:2906

References add_nulling_relids(), Assert, bms_add_member(), bms_copy(), bms_del_member(), bms_equal(), bms_is_empty, bms_is_member(), bms_make_singleton(), bms_union(), SpecialJoinInfo::commute_above_r, SpecialJoinInfo::commute_below_l, distribute_quals_to_rels(), lfirst, SpecialJoinInfo::lhs_strict, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, JoinTreeItem::nonnullable_rels, JoinTreeItem::oj_joinclauses, SpecialJoinInfo::ojrelid, JoinTreeItem::qualscope, remove_nulling_relids(), root, JoinTreeItem::sjinfo, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.

Referenced by deconstruct_jointree().

◆ deconstruct_jointree()

List* deconstruct_jointree ( PlannerInfo root)

Definition at line 843 of file initsplan.c.

844 {
845  List *result;
846  JoinDomain *top_jdomain;
847  List *item_list = NIL;
848  ListCell *lc;
849 
850  /*
851  * After this point, no more PlaceHolderInfos may be made, because
852  * make_outerjoininfo requires all active placeholders to be present in
853  * root->placeholder_list while we crawl up the join tree.
854  */
855  root->placeholdersFrozen = true;
856 
857  /* Fetch the already-created top-level join domain for the query */
858  top_jdomain = linitial_node(JoinDomain, root->join_domains);
859  top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
860 
861  /* Start recursion at top of jointree */
862  Assert(root->parse->jointree != NULL &&
863  IsA(root->parse->jointree, FromExpr));
864 
865  /* These are filled as we scan the jointree */
866  root->all_baserels = NULL;
867  root->outer_join_rels = NULL;
868 
869  /* Perform the initial scan of the jointree */
870  result = deconstruct_recurse(root, (Node *) root->parse->jointree,
871  top_jdomain, NULL,
872  &item_list);
873 
874  /* Now we can form the value of all_query_rels, too */
875  root->all_query_rels = bms_union(root->all_baserels, root->outer_join_rels);
876 
877  /* ... which should match what we computed for the top join domain */
878  Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
879 
880  /* Now scan all the jointree nodes again, and distribute quals */
881  foreach(lc, item_list)
882  {
883  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
884 
885  deconstruct_distribute(root, jtitem);
886  }
887 
888  /*
889  * If there were any special joins then we may have some postponed LEFT
890  * JOIN clauses to deal with.
891  */
892  if (root->join_info_list)
893  {
894  foreach(lc, item_list)
895  {
896  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
897 
898  if (jtitem->oj_joinclauses != NIL)
899  deconstruct_distribute_oj_quals(root, item_list, jtitem);
900  }
901  }
902 
903  /* Don't need the JoinTreeItems any more */
904  list_free_deep(item_list);
905 
906  return result;
907 }
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, JoinTreeItem *parent_jtitem, List **item_list)
Definition: initsplan.c:925
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:1985
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition: initsplan.c:1223
void list_free_deep(List *list)
Definition: list.c:1560
#define linitial_node(type, l)
Definition: pg_list.h:181
Relids jd_relids
Definition: pathnodes.h:1330

References Assert, bms_equal(), bms_union(), deconstruct_distribute(), deconstruct_distribute_oj_quals(), deconstruct_recurse(), IsA, JoinDomain::jd_relids, lfirst, linitial_node, list_free_deep(), NIL, JoinTreeItem::oj_joinclauses, and root.

Referenced by query_planner().

◆ deconstruct_recurse()

static List * deconstruct_recurse ( PlannerInfo root,
Node jtnode,
JoinDomain parent_domain,
JoinTreeItem parent_jtitem,
List **  item_list 
)
static

Definition at line 925 of file initsplan.c.

929 {
930  List *joinlist;
931  JoinTreeItem *jtitem;
932 
933  Assert(jtnode != NULL);
934 
935  /* Make the new JoinTreeItem, but don't add it to item_list yet */
936  jtitem = palloc0_object(JoinTreeItem);
937  jtitem->jtnode = jtnode;
938  jtitem->jti_parent = parent_jtitem;
939 
940  if (IsA(jtnode, RangeTblRef))
941  {
942  int varno = ((RangeTblRef *) jtnode)->rtindex;
943 
944  /* Fill all_baserels as we encounter baserel jointree nodes */
945  root->all_baserels = bms_add_member(root->all_baserels, varno);
946  /* This node belongs to parent_domain */
947  jtitem->jdomain = parent_domain;
948  parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
949  varno);
950  /* qualscope is just the one RTE */
951  jtitem->qualscope = bms_make_singleton(varno);
952  /* A single baserel does not create an inner join */
953  jtitem->inner_join_rels = NULL;
954  joinlist = list_make1(jtnode);
955  }
956  else if (IsA(jtnode, FromExpr))
957  {
958  FromExpr *f = (FromExpr *) jtnode;
959  int remaining;
960  ListCell *l;
961 
962  /* This node belongs to parent_domain, as do its children */
963  jtitem->jdomain = parent_domain;
964 
965  /*
966  * Recurse to handle child nodes, and compute output joinlist. We
967  * collapse subproblems into a single joinlist whenever the resulting
968  * joinlist wouldn't exceed from_collapse_limit members. Also, always
969  * collapse one-element subproblems, since that won't lengthen the
970  * joinlist anyway.
971  */
972  jtitem->qualscope = NULL;
973  jtitem->inner_join_rels = NULL;
974  joinlist = NIL;
976  foreach(l, f->fromlist)
977  {
978  JoinTreeItem *sub_item;
979  List *sub_joinlist;
980  int sub_members;
981 
982  sub_joinlist = deconstruct_recurse(root, lfirst(l),
983  parent_domain,
984  jtitem,
985  item_list);
986  sub_item = (JoinTreeItem *) llast(*item_list);
987  jtitem->qualscope = bms_add_members(jtitem->qualscope,
988  sub_item->qualscope);
989  jtitem->inner_join_rels = sub_item->inner_join_rels;
990  sub_members = list_length(sub_joinlist);
991  remaining--;
992  if (sub_members <= 1 ||
993  list_length(joinlist) + sub_members + remaining <= from_collapse_limit)
994  joinlist = list_concat(joinlist, sub_joinlist);
995  else
996  joinlist = lappend(joinlist, sub_joinlist);
997  }
998 
999  /*
1000  * A FROM with more than one list element is an inner join subsuming
1001  * all below it, so we should report inner_join_rels = qualscope. If
1002  * there was exactly one element, we should (and already did) report
1003  * whatever its inner_join_rels were. If there were no elements (is
1004  * that still possible?) the initialization before the loop fixed it.
1005  */
1006  if (list_length(f->fromlist) > 1)
1007  jtitem->inner_join_rels = jtitem->qualscope;
1008  }
1009  else if (IsA(jtnode, JoinExpr))
1010  {
1011  JoinExpr *j = (JoinExpr *) jtnode;
1012  JoinDomain *child_domain,
1013  *fj_domain;
1014  JoinTreeItem *left_item,
1015  *right_item;
1016  List *leftjoinlist,
1017  *rightjoinlist;
1018 
1019  switch (j->jointype)
1020  {
1021  case JOIN_INNER:
1022  /* This node belongs to parent_domain, as do its children */
1023  jtitem->jdomain = parent_domain;
1024  /* Recurse */
1025  leftjoinlist = deconstruct_recurse(root, j->larg,
1026  parent_domain,
1027  jtitem,
1028  item_list);
1029  left_item = (JoinTreeItem *) llast(*item_list);
1030  rightjoinlist = deconstruct_recurse(root, j->rarg,
1031  parent_domain,
1032  jtitem,
1033  item_list);
1034  right_item = (JoinTreeItem *) llast(*item_list);
1035  /* Compute qualscope etc */
1036  jtitem->qualscope = bms_union(left_item->qualscope,
1037  right_item->qualscope);
1038  jtitem->inner_join_rels = jtitem->qualscope;
1039  jtitem->left_rels = left_item->qualscope;
1040  jtitem->right_rels = right_item->qualscope;
1041  /* Inner join adds no restrictions for quals */
1042  jtitem->nonnullable_rels = NULL;
1043  break;
1044  case JOIN_LEFT:
1045  case JOIN_ANTI:
1046  /* Make new join domain for my quals and the RHS */
1047  child_domain = makeNode(JoinDomain);
1048  child_domain->jd_relids = NULL; /* filled by recursion */
1049  root->join_domains = lappend(root->join_domains, child_domain);
1050  jtitem->jdomain = child_domain;
1051  /* Recurse */
1052  leftjoinlist = deconstruct_recurse(root, j->larg,
1053  parent_domain,
1054  jtitem,
1055  item_list);
1056  left_item = (JoinTreeItem *) llast(*item_list);
1057  rightjoinlist = deconstruct_recurse(root, j->rarg,
1058  child_domain,
1059  jtitem,
1060  item_list);
1061  right_item = (JoinTreeItem *) llast(*item_list);
1062  /* Compute join domain contents, qualscope etc */
1063  parent_domain->jd_relids =
1064  bms_add_members(parent_domain->jd_relids,
1065  child_domain->jd_relids);
1066  jtitem->qualscope = bms_union(left_item->qualscope,
1067  right_item->qualscope);
1068  /* caution: ANTI join derived from SEMI will lack rtindex */
1069  if (j->rtindex != 0)
1070  {
1071  parent_domain->jd_relids =
1072  bms_add_member(parent_domain->jd_relids,
1073  j->rtindex);
1074  jtitem->qualscope = bms_add_member(jtitem->qualscope,
1075  j->rtindex);
1076  root->outer_join_rels = bms_add_member(root->outer_join_rels,
1077  j->rtindex);
1078  mark_rels_nulled_by_join(root, j->rtindex,
1079  right_item->qualscope);
1080  }
1081  jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1082  right_item->inner_join_rels);
1083  jtitem->left_rels = left_item->qualscope;
1084  jtitem->right_rels = right_item->qualscope;
1085  jtitem->nonnullable_rels = left_item->qualscope;
1086  break;
1087  case JOIN_SEMI:
1088  /* This node belongs to parent_domain, as do its children */
1089  jtitem->jdomain = parent_domain;
1090  /* Recurse */
1091  leftjoinlist = deconstruct_recurse(root, j->larg,
1092  parent_domain,
1093  jtitem,
1094  item_list);
1095  left_item = (JoinTreeItem *) llast(*item_list);
1096  rightjoinlist = deconstruct_recurse(root, j->rarg,
1097  parent_domain,
1098  jtitem,
1099  item_list);
1100  right_item = (JoinTreeItem *) llast(*item_list);
1101  /* Compute qualscope etc */
1102  jtitem->qualscope = bms_union(left_item->qualscope,
1103  right_item->qualscope);
1104  /* SEMI join never has rtindex, so don't add to anything */
1105  Assert(j->rtindex == 0);
1106  jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1107  right_item->inner_join_rels);
1108  jtitem->left_rels = left_item->qualscope;
1109  jtitem->right_rels = right_item->qualscope;
1110  /* Semi join adds no restrictions for quals */
1111  jtitem->nonnullable_rels = NULL;
1112  break;
1113  case JOIN_FULL:
1114  /* The FULL JOIN's quals need their very own domain */
1115  fj_domain = makeNode(JoinDomain);
1116  root->join_domains = lappend(root->join_domains, fj_domain);
1117  jtitem->jdomain = fj_domain;
1118  /* Recurse, giving each side its own join domain */
1119  child_domain = makeNode(JoinDomain);
1120  child_domain->jd_relids = NULL; /* filled by recursion */
1121  root->join_domains = lappend(root->join_domains, child_domain);
1122  leftjoinlist = deconstruct_recurse(root, j->larg,
1123  child_domain,
1124  jtitem,
1125  item_list);
1126  left_item = (JoinTreeItem *) llast(*item_list);
1127  fj_domain->jd_relids = bms_copy(child_domain->jd_relids);
1128  child_domain = makeNode(JoinDomain);
1129  child_domain->jd_relids = NULL; /* filled by recursion */
1130  root->join_domains = lappend(root->join_domains, child_domain);
1131  rightjoinlist = deconstruct_recurse(root, j->rarg,
1132  child_domain,
1133  jtitem,
1134  item_list);
1135  right_item = (JoinTreeItem *) llast(*item_list);
1136  /* Compute qualscope etc */
1137  fj_domain->jd_relids = bms_add_members(fj_domain->jd_relids,
1138  child_domain->jd_relids);
1139  parent_domain->jd_relids = bms_add_members(parent_domain->jd_relids,
1140  fj_domain->jd_relids);
1141  jtitem->qualscope = bms_union(left_item->qualscope,
1142  right_item->qualscope);
1143  Assert(j->rtindex != 0);
1144  parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
1145  j->rtindex);
1146  jtitem->qualscope = bms_add_member(jtitem->qualscope,
1147  j->rtindex);
1148  root->outer_join_rels = bms_add_member(root->outer_join_rels,
1149  j->rtindex);
1150  mark_rels_nulled_by_join(root, j->rtindex,
1151  left_item->qualscope);
1152  mark_rels_nulled_by_join(root, j->rtindex,
1153  right_item->qualscope);
1154  jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1155  right_item->inner_join_rels);
1156  jtitem->left_rels = left_item->qualscope;
1157  jtitem->right_rels = right_item->qualscope;
1158  /* each side is both outer and inner */
1159  jtitem->nonnullable_rels = jtitem->qualscope;
1160  break;
1161  default:
1162  /* JOIN_RIGHT was eliminated during reduce_outer_joins() */
1163  elog(ERROR, "unrecognized join type: %d",
1164  (int) j->jointype);
1165  leftjoinlist = rightjoinlist = NIL; /* keep compiler quiet */
1166  break;
1167  }
1168 
1169  /*
1170  * Compute the output joinlist. We fold subproblems together except
1171  * at a FULL JOIN or where join_collapse_limit would be exceeded.
1172  */
1173  if (j->jointype == JOIN_FULL)
1174  {
1175  /* force the join order exactly at this node */
1176  joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist));
1177  }
1178  else if (list_length(leftjoinlist) + list_length(rightjoinlist) <=
1180  {
1181  /* OK to combine subproblems */
1182  joinlist = list_concat(leftjoinlist, rightjoinlist);
1183  }
1184  else
1185  {
1186  /* can't combine, but needn't force join order above here */
1187  Node *leftpart,
1188  *rightpart;
1189 
1190  /* avoid creating useless 1-element sublists */
1191  if (list_length(leftjoinlist) == 1)
1192  leftpart = (Node *) linitial(leftjoinlist);
1193  else
1194  leftpart = (Node *) leftjoinlist;
1195  if (list_length(rightjoinlist) == 1)
1196  rightpart = (Node *) linitial(rightjoinlist);
1197  else
1198  rightpart = (Node *) rightjoinlist;
1199  joinlist = list_make2(leftpart, rightpart);
1200  }
1201  }
1202  else
1203  {
1204  elog(ERROR, "unrecognized node type: %d",
1205  (int) nodeTag(jtnode));
1206  joinlist = NIL; /* keep compiler quiet */
1207  }
1208 
1209  /* Finally, we can add the new JoinTreeItem to item_list */
1210  *item_list = lappend(*item_list, jtitem);
1211 
1212  return joinlist;
1213 }
#define palloc0_object(type)
Definition: fe_memutils.h:75
int remaining
Definition: informix.c:692
int join_collapse_limit
Definition: initsplan.c:39
int from_collapse_limit
Definition: initsplan.c:38
static void mark_rels_nulled_by_join(PlannerInfo *root, Index ojrelid, Relids lower_rels)
Definition: initsplan.c:1425
#define makeNode(_type_)
Definition: nodes.h:155
@ JOIN_FULL
Definition: nodes.h:295
#define llast(l)
Definition: pg_list.h:198
#define list_make1(x1)
Definition: pg_list.h:212
#define list_make2(x1, x2)
Definition: pg_list.h:214
struct JoinTreeItem * jti_parent
Definition: initsplan.c:64
JoinDomain * jdomain
Definition: initsplan.c:63

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_make_singleton(), bms_union(), elog, ERROR, from_collapse_limit, FromExpr::fromlist, JoinTreeItem::inner_join_rels, IsA, j, JoinDomain::jd_relids, JoinTreeItem::jdomain, JOIN_ANTI, join_collapse_limit, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, JoinTreeItem::jti_parent, JoinTreeItem::jtnode, lappend(), JoinTreeItem::left_rels, lfirst, linitial, list_concat(), list_length(), list_make1, list_make2, llast, makeNode, mark_rels_nulled_by_join(), NIL, nodeTag, JoinTreeItem::nonnullable_rels, palloc0_object, JoinTreeItem::qualscope, remaining, JoinTreeItem::right_rels, and root.

Referenced by deconstruct_jointree().

◆ distribute_qual_to_rels()

static void distribute_qual_to_rels ( PlannerInfo root,
Node clause,
JoinTreeItem jtitem,
SpecialJoinInfo sjinfo,
Index  security_level,
Relids  qualscope,
Relids  ojscope,
Relids  outerjoin_nonnullable,
Relids  incompatible_relids,
bool  allow_equivalence,
bool  has_clone,
bool  is_clone,
List **  postponed_oj_qual_list 
)
static

Definition at line 2304 of file initsplan.c.

2316 {
2317  Relids relids;
2318  bool is_pushed_down;
2319  bool pseudoconstant = false;
2320  bool maybe_equivalence;
2321  bool maybe_outer_join;
2322  RestrictInfo *restrictinfo;
2323 
2324  /*
2325  * Retrieve all relids mentioned within the clause.
2326  */
2327  relids = pull_varnos(root, clause);
2328 
2329  /*
2330  * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels
2331  * that aren't within its syntactic scope; however, if we pulled up a
2332  * LATERAL subquery then we might find such references in quals that have
2333  * been pulled up. We need to treat such quals as belonging to the join
2334  * level that includes every rel they reference. Although we could make
2335  * pull_up_subqueries() place such quals correctly to begin with, it's
2336  * easier to handle it here. When we find a clause that contains Vars
2337  * outside its syntactic scope, locate the nearest parent join level that
2338  * includes all the required rels and add the clause to that level's
2339  * lateral_clauses list. We'll process it when we reach that join level.
2340  */
2341  if (!bms_is_subset(relids, qualscope))
2342  {
2343  JoinTreeItem *pitem;
2344 
2345  Assert(root->hasLateralRTEs); /* shouldn't happen otherwise */
2346  Assert(sjinfo == NULL); /* mustn't postpone past outer join */
2347  for (pitem = jtitem->jti_parent; pitem; pitem = pitem->jti_parent)
2348  {
2349  if (bms_is_subset(relids, pitem->qualscope))
2350  {
2351  pitem->lateral_clauses = lappend(pitem->lateral_clauses,
2352  clause);
2353  return;
2354  }
2355 
2356  /*
2357  * We should not be postponing any quals past an outer join. If
2358  * this Assert fires, pull_up_subqueries() messed up.
2359  */
2360  Assert(pitem->sjinfo == NULL);
2361  }
2362  elog(ERROR, "failed to postpone qual containing lateral reference");
2363  }
2364 
2365  /*
2366  * If it's an outer-join clause, also check that relids is a subset of
2367  * ojscope. (This should not fail if the syntactic scope check passed.)
2368  */
2369  if (ojscope && !bms_is_subset(relids, ojscope))
2370  elog(ERROR, "JOIN qualification cannot refer to other relations");
2371 
2372  /*
2373  * If the clause is variable-free, our normal heuristic for pushing it
2374  * down to just the mentioned rels doesn't work, because there are none.
2375  *
2376  * If the clause is an outer-join clause, we must force it to the OJ's
2377  * semantic level to preserve semantics.
2378  *
2379  * Otherwise, when the clause contains volatile functions, we force it to
2380  * be evaluated at its original syntactic level. This preserves the
2381  * expected semantics.
2382  *
2383  * When the clause contains no volatile functions either, it is actually a
2384  * pseudoconstant clause that will not change value during any one
2385  * execution of the plan, and hence can be used as a one-time qual in a
2386  * gating Result plan node. We put such a clause into the regular
2387  * RestrictInfo lists for the moment, but eventually createplan.c will
2388  * pull it out and make a gating Result node immediately above whatever
2389  * plan node the pseudoconstant clause is assigned to. It's usually best
2390  * to put a gating node as high in the plan tree as possible.
2391  */
2392  if (bms_is_empty(relids))
2393  {
2394  if (ojscope)
2395  {
2396  /* clause is attached to outer join, eval it there */
2397  relids = bms_copy(ojscope);
2398  /* mustn't use as gating qual, so don't mark pseudoconstant */
2399  }
2400  else if (contain_volatile_functions(clause))
2401  {
2402  /* eval at original syntactic level */
2403  relids = bms_copy(qualscope);
2404  /* again, can't mark pseudoconstant */
2405  }
2406  else
2407  {
2408  /*
2409  * If we are in the top-level join domain, we can push the qual to
2410  * the top of the plan tree. Otherwise, be conservative and eval
2411  * it at original syntactic level. (Ideally we'd push it to the
2412  * top of the current join domain in all cases, but that causes
2413  * problems if we later rearrange outer-join evaluation order.
2414  * Pseudoconstant quals below the top level are a pretty odd case,
2415  * so it's not clear that it's worth working hard on.)
2416  */
2417  if (jtitem->jdomain == (JoinDomain *) linitial(root->join_domains))
2418  relids = bms_copy(jtitem->jdomain->jd_relids);
2419  else
2420  relids = bms_copy(qualscope);
2421  /* mark as gating qual */
2422  pseudoconstant = true;
2423  /* tell createplan.c to check for gating quals */
2424  root->hasPseudoConstantQuals = true;
2425  }
2426  }
2427 
2428  /*----------
2429  * Check to see if clause application must be delayed by outer-join
2430  * considerations.
2431  *
2432  * A word about is_pushed_down: we mark the qual as "pushed down" if
2433  * it is (potentially) applicable at a level different from its original
2434  * syntactic level. This flag is used to distinguish OUTER JOIN ON quals
2435  * from other quals pushed down to the same joinrel. The rules are:
2436  * WHERE quals and INNER JOIN quals: is_pushed_down = true.
2437  * Non-degenerate OUTER JOIN quals: is_pushed_down = false.
2438  * Degenerate OUTER JOIN quals: is_pushed_down = true.
2439  * A "degenerate" OUTER JOIN qual is one that doesn't mention the
2440  * non-nullable side, and hence can be pushed down into the nullable side
2441  * without changing the join result. It is correct to treat it as a
2442  * regular filter condition at the level where it is evaluated.
2443  *
2444  * Note: it is not immediately obvious that a simple boolean is enough
2445  * for this: if for some reason we were to attach a degenerate qual to
2446  * its original join level, it would need to be treated as an outer join
2447  * qual there. However, this cannot happen, because all the rels the
2448  * clause mentions must be in the outer join's min_righthand, therefore
2449  * the join it needs must be formed before the outer join; and we always
2450  * attach quals to the lowest level where they can be evaluated. But
2451  * if we were ever to re-introduce a mechanism for delaying evaluation
2452  * of "expensive" quals, this area would need work.
2453  *
2454  * Note: generally, use of is_pushed_down has to go through the macro
2455  * RINFO_IS_PUSHED_DOWN, because that flag alone is not always sufficient
2456  * to tell whether a clause must be treated as pushed-down in context.
2457  * This seems like another reason why it should perhaps be rethought.
2458  *----------
2459  */
2460  if (bms_overlap(relids, outerjoin_nonnullable))
2461  {
2462  /*
2463  * The qual is attached to an outer join and mentions (some of the)
2464  * rels on the nonnullable side, so it's not degenerate. If the
2465  * caller wants to postpone handling such clauses, just add it to
2466  * postponed_oj_qual_list and return. (The work we've done up to here
2467  * will have to be redone later, but there's not much of it.)
2468  */
2469  if (postponed_oj_qual_list != NULL)
2470  {
2471  *postponed_oj_qual_list = lappend(*postponed_oj_qual_list, clause);
2472  return;
2473  }
2474 
2475  /*
2476  * We can't use such a clause to deduce equivalence (the left and
2477  * right sides might be unequal above the join because one of them has
2478  * gone to NULL) ... but we might be able to use it for more limited
2479  * deductions, if it is mergejoinable. So consider adding it to the
2480  * lists of set-aside outer-join clauses.
2481  */
2482  is_pushed_down = false;
2483  maybe_equivalence = false;
2484  maybe_outer_join = true;
2485 
2486  /*
2487  * Now force the qual to be evaluated exactly at the level of joining
2488  * corresponding to the outer join. We cannot let it get pushed down
2489  * into the nonnullable side, since then we'd produce no output rows,
2490  * rather than the intended single null-extended row, for any
2491  * nonnullable-side rows failing the qual.
2492  */
2493  Assert(ojscope);
2494  relids = ojscope;
2495  Assert(!pseudoconstant);
2496  }
2497  else
2498  {
2499  /*
2500  * Normal qual clause or degenerate outer-join clause. Either way, we
2501  * can mark it as pushed-down.
2502  */
2503  is_pushed_down = true;
2504 
2505  /*
2506  * It's possible that this is an IS NULL clause that's redundant with
2507  * a lower antijoin; if so we can just discard it. We need not test
2508  * in any of the other cases, because this will only be possible for
2509  * pushed-down clauses.
2510  */
2512  return;
2513 
2514  /* Feed qual to the equivalence machinery, if allowed by caller */
2515  maybe_equivalence = allow_equivalence;
2516 
2517  /*
2518  * Since it doesn't mention the LHS, it's certainly not useful as a
2519  * set-aside OJ clause, even if it's in an OJ.
2520  */
2521  maybe_outer_join = false;
2522  }
2523 
2524  /*
2525  * Build the RestrictInfo node itself.
2526  */
2527  restrictinfo = make_restrictinfo(root,
2528  (Expr *) clause,
2529  is_pushed_down,
2530  has_clone,
2531  is_clone,
2532  pseudoconstant,
2533  security_level,
2534  relids,
2535  incompatible_relids,
2536  outerjoin_nonnullable);
2537 
2538  /*
2539  * If it's a join clause, add vars used in the clause to targetlists of
2540  * their relations, so that they will be emitted by the plan nodes that
2541  * scan those relations (else they won't be available at the join node!).
2542  *
2543  * Normally we mark the vars as needed at the join identified by "relids".
2544  * However, if this is a clone clause then ignore the outer-join relids in
2545  * that set. Otherwise, vars appearing in a cloned clause would end up
2546  * marked as having to propagate to the highest one of the commuting
2547  * joins, which would often be an overestimate. For such clauses, correct
2548  * var propagation is ensured by making ojscope include input rels from
2549  * both sides of the join.
2550  *
2551  * See also rebuild_joinclause_attr_needed, which has to partially repeat
2552  * this work after removal of an outer join.
2553  *
2554  * Note: if the clause gets absorbed into an EquivalenceClass then this
2555  * may be unnecessary, but for now we have to do it to cover the case
2556  * where the EC becomes ec_broken and we end up reinserting the original
2557  * clauses into the plan.
2558  */
2559  if (bms_membership(relids) == BMS_MULTIPLE)
2560  {
2561  List *vars = pull_var_clause(clause,
2565  Relids where_needed;
2566 
2567  if (is_clone)
2568  where_needed = bms_intersect(relids, root->all_baserels);
2569  else
2570  where_needed = relids;
2571  add_vars_to_targetlist(root, vars, where_needed);
2572  list_free(vars);
2573  }
2574 
2575  /*
2576  * We check "mergejoinability" of every clause, not only join clauses,
2577  * because we want to know about equivalences between vars of the same
2578  * relation, or between vars and consts.
2579  */
2580  check_mergejoinable(restrictinfo);
2581 
2582  /*
2583  * If it is a true equivalence clause, send it to the EquivalenceClass
2584  * machinery. We do *not* attach it directly to any restriction or join
2585  * lists. The EC code will propagate it to the appropriate places later.
2586  *
2587  * If the clause has a mergejoinable operator, yet isn't an equivalence
2588  * because it is an outer-join clause, the EC code may still be able to do
2589  * something with it. We add it to appropriate lists for further
2590  * consideration later. Specifically:
2591  *
2592  * If it is a left or right outer-join qualification that relates the two
2593  * sides of the outer join (no funny business like leftvar1 = leftvar2 +
2594  * rightvar), we add it to root->left_join_clauses or
2595  * root->right_join_clauses according to which side the nonnullable
2596  * variable appears on.
2597  *
2598  * If it is a full outer-join qualification, we add it to
2599  * root->full_join_clauses. (Ideally we'd discard cases that aren't
2600  * leftvar = rightvar, as we do for left/right joins, but this routine
2601  * doesn't have the info needed to do that; and the current usage of the
2602  * full_join_clauses list doesn't require that, so it's not currently
2603  * worth complicating this routine's API to make it possible.)
2604  *
2605  * If none of the above hold, pass it off to
2606  * distribute_restrictinfo_to_rels().
2607  *
2608  * In all cases, it's important to initialize the left_ec and right_ec
2609  * fields of a mergejoinable clause, so that all possibly mergejoinable
2610  * expressions have representations in EquivalenceClasses. If
2611  * process_equivalence is successful, it will take care of that;
2612  * otherwise, we have to call initialize_mergeclause_eclasses to do it.
2613  */
2614  if (restrictinfo->mergeopfamilies)
2615  {
2616  if (maybe_equivalence)
2617  {
2618  if (process_equivalence(root, &restrictinfo, jtitem->jdomain))
2619  return;
2620  /* EC rejected it, so set left_ec/right_ec the hard way ... */
2621  if (restrictinfo->mergeopfamilies) /* EC might have changed this */
2622  initialize_mergeclause_eclasses(root, restrictinfo);
2623  /* ... and fall through to distribute_restrictinfo_to_rels */
2624  }
2625  else if (maybe_outer_join && restrictinfo->can_join)
2626  {
2627  /* we need to set up left_ec/right_ec the hard way */
2628  initialize_mergeclause_eclasses(root, restrictinfo);
2629  /* now see if it should go to any outer-join lists */
2630  Assert(sjinfo != NULL);
2631  if (bms_is_subset(restrictinfo->left_relids,
2632  outerjoin_nonnullable) &&
2633  !bms_overlap(restrictinfo->right_relids,
2634  outerjoin_nonnullable))
2635  {
2636  /* we have outervar = innervar */
2638 
2639  ojcinfo->rinfo = restrictinfo;
2640  ojcinfo->sjinfo = sjinfo;
2641  root->left_join_clauses = lappend(root->left_join_clauses,
2642  ojcinfo);
2643  return;
2644  }
2645  if (bms_is_subset(restrictinfo->right_relids,
2646  outerjoin_nonnullable) &&
2647  !bms_overlap(restrictinfo->left_relids,
2648  outerjoin_nonnullable))
2649  {
2650  /* we have innervar = outervar */
2652 
2653  ojcinfo->rinfo = restrictinfo;
2654  ojcinfo->sjinfo = sjinfo;
2655  root->right_join_clauses = lappend(root->right_join_clauses,
2656  ojcinfo);
2657  return;
2658  }
2659  if (sjinfo->jointype == JOIN_FULL)
2660  {
2661  /* FULL JOIN (above tests cannot match in this case) */
2663 
2664  ojcinfo->rinfo = restrictinfo;
2665  ojcinfo->sjinfo = sjinfo;
2666  root->full_join_clauses = lappend(root->full_join_clauses,
2667  ojcinfo);
2668  return;
2669  }
2670  /* nope, so fall through to distribute_restrictinfo_to_rels */
2671  }
2672  else
2673  {
2674  /* we still need to set up left_ec/right_ec */
2675  initialize_mergeclause_eclasses(root, restrictinfo);
2676  }
2677  }
2678 
2679  /* No EC special case applies, so push it into the clause lists */
2680  distribute_restrictinfo_to_rels(root, restrictinfo);
2681 }
@ BMS_MULTIPLE
Definition: bitmapset.h:73
bool process_equivalence(PlannerInfo *root, RestrictInfo **p_restrictinfo, JoinDomain *jdomain)
Definition: equivclass.c:117
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2954
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
Definition: initsplan.c:2694
void initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:1462
RestrictInfo * rinfo
Definition: pathnodes.h:2933
SpecialJoinInfo * sjinfo
Definition: pathnodes.h:2934

References add_vars_to_targetlist(), Assert, bms_copy(), bms_intersect(), bms_is_empty, bms_is_subset(), bms_membership(), BMS_MULTIPLE, bms_overlap(), check_mergejoinable(), check_redundant_nullability_qual(), contain_volatile_functions(), distribute_restrictinfo_to_rels(), elog, ERROR, initialize_mergeclause_eclasses(), JoinDomain::jd_relids, JoinTreeItem::jdomain, JOIN_FULL, SpecialJoinInfo::jointype, JoinTreeItem::jti_parent, lappend(), JoinTreeItem::lateral_clauses, linitial, list_free(), make_restrictinfo(), makeNode, process_equivalence(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, JoinTreeItem::qualscope, OuterJoinClauseInfo::rinfo, root, JoinTreeItem::sjinfo, and OuterJoinClauseInfo::sjinfo.

Referenced by distribute_quals_to_rels().

◆ distribute_quals_to_rels()

static void distribute_quals_to_rels ( PlannerInfo root,
List clauses,
JoinTreeItem jtitem,
SpecialJoinInfo sjinfo,
Index  security_level,
Relids  qualscope,
Relids  ojscope,
Relids  outerjoin_nonnullable,
Relids  incompatible_relids,
bool  allow_equivalence,
bool  has_clone,
bool  is_clone,
List **  postponed_oj_qual_list 
)
static

Definition at line 2226 of file initsplan.c.

2238 {
2239  ListCell *lc;
2240 
2241  foreach(lc, clauses)
2242  {
2243  Node *clause = (Node *) lfirst(lc);
2244 
2245  distribute_qual_to_rels(root, clause,
2246  jtitem,
2247  sjinfo,
2248  security_level,
2249  qualscope,
2250  ojscope,
2251  outerjoin_nonnullable,
2252  incompatible_relids,
2253  allow_equivalence,
2254  has_clone,
2255  is_clone,
2256  postponed_oj_qual_list);
2257  }
2258 }
static void distribute_qual_to_rels(PlannerInfo *root, Node *clause, JoinTreeItem *jtitem, SpecialJoinInfo *sjinfo, Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, Relids incompatible_relids, bool allow_equivalence, bool has_clone, bool is_clone, List **postponed_oj_qual_list)
Definition: initsplan.c:2304

References distribute_qual_to_rels(), lfirst, JoinTreeItem::qualscope, root, and JoinTreeItem::sjinfo.

Referenced by deconstruct_distribute(), deconstruct_distribute_oj_quals(), and process_security_barrier_quals().

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2954 of file initsplan.c.

2956 {
2957  Relids relids = restrictinfo->required_relids;
2958 
2959  if (!bms_is_empty(relids))
2960  {
2961  int relid;
2962 
2963  if (bms_get_singleton_member(relids, &relid))
2964  {
2965  /*
2966  * There is only one relation participating in the clause, so it
2967  * is a restriction clause for that relation.
2968  */
2969  add_base_clause_to_rel(root, relid, restrictinfo);
2970  }
2971  else
2972  {
2973  /*
2974  * The clause is a join clause, since there is more than one rel
2975  * in its relid set.
2976  */
2977 
2978  /*
2979  * Check for hashjoinable operators. (We don't bother setting the
2980  * hashjoin info except in true join clauses.)
2981  */
2982  check_hashjoinable(restrictinfo);
2983 
2984  /*
2985  * Likewise, check if the clause is suitable to be used with a
2986  * Memoize node to cache inner tuples during a parameterized
2987  * nested loop.
2988  */
2989  check_memoizable(restrictinfo);
2990 
2991  /*
2992  * Add clause to the join lists of all the relevant relations.
2993  */
2994  add_join_clause_to_rels(root, restrictinfo, relids);
2995  }
2996  }
2997  else
2998  {
2999  /*
3000  * clause references no rels, and therefore we have no place to attach
3001  * it. Shouldn't get here if callers are working properly.
3002  */
3003  elog(ERROR, "cannot cope with variable-free clause");
3004  }
3005 }
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:2739
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:98

References add_base_clause_to_rel(), add_join_clause_to_rels(), bms_get_singleton_member(), bms_is_empty, check_hashjoinable(), check_memoizable(), elog, ERROR, RestrictInfo::required_relids, and root.

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

◆ expr_is_nonnullable()

static bool expr_is_nonnullable ( PlannerInfo root,
Expr expr 
)
static

Definition at line 2814 of file initsplan.c.

2815 {
2816  RelOptInfo *rel;
2817  Var *var;
2818 
2819  /* For now only check simple Vars */
2820  if (!IsA(expr, Var))
2821  return false;
2822 
2823  var = (Var *) expr;
2824 
2825  /* could the Var be nulled by any outer joins? */
2826  if (!bms_is_empty(var->varnullingrels))
2827  return false;
2828 
2829  /* system columns cannot be NULL */
2830  if (var->varattno < 0)
2831  return true;
2832 
2833  /* is the column defined NOT NULL? */
2834  rel = find_base_rel(root, var->varno);
2835  if (var->varattno > 0 &&
2837  return true;
2838 
2839  return false;
2840 }
Bitmapset * notnullattnums
Definition: pathnodes.h:936

References bms_is_empty, bms_is_member(), find_base_rel(), IsA, RelOptInfo::notnullattnums, root, Var::varattno, and Var::varno.

Referenced by restriction_is_always_false(), and restriction_is_always_true().

◆ extract_lateral_references()

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

Definition at line 465 of file initsplan.c.

466 {
467  RangeTblEntry *rte = root->simple_rte_array[rtindex];
468  List *vars;
469  List *newvars;
470  Relids where_needed;
471  ListCell *lc;
472 
473  /* No cross-references are possible if it's not LATERAL */
474  if (!rte->lateral)
475  return;
476 
477  /* Fetch the appropriate variables */
478  if (rte->rtekind == RTE_RELATION)
479  vars = pull_vars_of_level((Node *) rte->tablesample, 0);
480  else if (rte->rtekind == RTE_SUBQUERY)
481  vars = pull_vars_of_level((Node *) rte->subquery, 1);
482  else if (rte->rtekind == RTE_FUNCTION)
483  vars = pull_vars_of_level((Node *) rte->functions, 0);
484  else if (rte->rtekind == RTE_TABLEFUNC)
485  vars = pull_vars_of_level((Node *) rte->tablefunc, 0);
486  else if (rte->rtekind == RTE_VALUES)
487  vars = pull_vars_of_level((Node *) rte->values_lists, 0);
488  else
489  {
490  Assert(false);
491  return; /* keep compiler quiet */
492  }
493 
494  if (vars == NIL)
495  return; /* nothing to do */
496 
497  /* Copy each Var (or PlaceHolderVar) and adjust it to match our level */
498  newvars = NIL;
499  foreach(lc, vars)
500  {
501  Node *node = (Node *) lfirst(lc);
502 
503  node = copyObject(node);
504  if (IsA(node, Var))
505  {
506  Var *var = (Var *) node;
507 
508  /* Adjustment is easy since it's just one node */
509  var->varlevelsup = 0;
510  }
511  else if (IsA(node, PlaceHolderVar))
512  {
513  PlaceHolderVar *phv = (PlaceHolderVar *) node;
514  int levelsup = phv->phlevelsup;
515 
516  /* Have to work harder to adjust the contained expression too */
517  if (levelsup != 0)
518  IncrementVarSublevelsUp(node, -levelsup, 0);
519 
520  /*
521  * If we pulled the PHV out of a subquery RTE, its expression
522  * needs to be preprocessed. subquery_planner() already did this
523  * for level-zero PHVs in function and values RTEs, though.
524  */
525  if (levelsup > 0)
526  phv->phexpr = preprocess_phv_expression(root, phv->phexpr);
527  }
528  else
529  Assert(false);
530  newvars = lappend(newvars, node);
531  }
532 
533  list_free(vars);
534 
535  /*
536  * We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
537  * of a cheat: a more formal approach would be to mark each one as needed
538  * at the join of the LATERAL RTE with its source RTE. But it will work,
539  * and it's much less tedious than computing a separate where_needed for
540  * each Var.
541  */
542  where_needed = bms_make_singleton(rtindex);
543 
544  /*
545  * Push Vars into their source relations' targetlists, and PHVs into
546  * root->placeholder_list.
547  */
548  add_vars_to_targetlist(root, newvars, where_needed);
549 
550  /*
551  * Remember the lateral references for rebuild_lateral_attr_needed and
552  * create_lateral_join_info.
553  */
554  brel->lateral_vars = newvars;
555 }
@ RTE_VALUES
Definition: parsenodes.h:1022
@ RTE_SUBQUERY
Definition: parsenodes.h:1018
@ RTE_FUNCTION
Definition: parsenodes.h:1020
@ RTE_TABLEFUNC
Definition: parsenodes.h:1021
@ RTE_RELATION
Definition: parsenodes.h:1017
Expr * preprocess_phv_expression(PlannerInfo *root, Expr *expr)
Definition: planner.c:1333
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:841
Index phlevelsup
Definition: pathnodes.h:2807
TableFunc * tablefunc
Definition: parsenodes.h:1184
struct TableSampleClause * tablesample
Definition: parsenodes.h:1098
Query * subquery
Definition: parsenodes.h:1104
List * values_lists
Definition: parsenodes.h:1190
List * functions
Definition: parsenodes.h:1177
RTEKind rtekind
Definition: parsenodes.h:1047
Index varlevelsup
Definition: primnodes.h:280
List * pull_vars_of_level(Node *node, int levelsup)
Definition: var.c:338

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

Referenced by find_lateral_references().

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 417 of file initsplan.c.

418 {
419  Index rti;
420 
421  /* We need do nothing if the query contains no LATERAL RTEs */
422  if (!root->hasLateralRTEs)
423  return;
424 
425  /*
426  * Examine all baserels (the rel array has been set up by now).
427  */
428  for (rti = 1; rti < root->simple_rel_array_size; rti++)
429  {
430  RelOptInfo *brel = root->simple_rel_array[rti];
431 
432  /* there may be empty slots corresponding to non-baserel RTEs */
433  if (brel == NULL)
434  continue;
435 
436  Assert(brel->relid == rti); /* sanity check on array */
437 
438  /*
439  * This bit is less obvious than it might look. We ignore appendrel
440  * otherrels and consider only their parent baserels. In a case where
441  * a LATERAL-containing UNION ALL subquery was pulled up, it is the
442  * otherrel that is actually going to be in the plan. However, we
443  * want to mark all its lateral references as needed by the parent,
444  * because it is the parent's relid that will be used for join
445  * planning purposes. And the parent's RTE will contain all the
446  * lateral references we need to know, since the pulled-up member is
447  * nothing but a copy of parts of the original RTE's subquery. We
448  * could visit the parent's children instead and transform their
449  * references back to the parent's relid, but it would be much more
450  * complicated for no real gain. (Important here is that the child
451  * members have not yet received any processing beyond being pulled
452  * up.) Similarly, in appendrels created by inheritance expansion,
453  * it's sufficient to look at the parent relation.
454  */
455 
456  /* ignore RTEs that are "other rels" */
457  if (brel->reloptkind != RELOPT_BASEREL)
458  continue;
459 
460  extract_lateral_references(root, brel, rti);
461  }
462 }
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:465

References Assert, extract_lateral_references(), RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, and root.

Referenced by query_planner().

◆ get_join_domain_min_rels()

static Relids get_join_domain_min_rels ( PlannerInfo root,
Relids  domain_relids 
)
static

Definition at line 3252 of file initsplan.c.

3253 {
3254  Relids result = bms_copy(domain_relids);
3255  ListCell *lc;
3256 
3257  /* Top-level join domain? */
3258  if (bms_equal(result, root->all_query_rels))
3259  return result;
3260 
3261  /* Nope, look for lower outer joins that could potentially commute out */
3262  foreach(lc, root->join_info_list)
3263  {
3264  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
3265 
3266  if (sjinfo->jointype == JOIN_LEFT &&
3267  bms_is_member(sjinfo->ojrelid, result))
3268  {
3269  result = bms_del_member(result, sjinfo->ojrelid);
3270  result = bms_del_members(result, sjinfo->syn_righthand);
3271  }
3272  }
3273  return result;
3274 }
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161

References bms_copy(), bms_del_member(), bms_del_members(), bms_equal(), bms_is_member(), JOIN_LEFT, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::ojrelid, root, JoinTreeItem::sjinfo, and SpecialJoinInfo::syn_righthand.

Referenced by process_implied_equality().

◆ make_outerjoininfo()

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

Definition at line 1467 of file initsplan.c.

1472 {
1474  Relids clause_relids;
1475  Relids strict_relids;
1476  Relids min_lefthand;
1477  Relids min_righthand;
1478  Relids commute_below_l;
1479  Relids commute_below_r;
1480  ListCell *l;
1481 
1482  /*
1483  * We should not see RIGHT JOIN here because left/right were switched
1484  * earlier
1485  */
1486  Assert(jointype != JOIN_INNER);
1487  Assert(jointype != JOIN_RIGHT);
1488 
1489  /*
1490  * Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of
1491  * rels appearing on the nullable side of an outer join. (It's somewhat
1492  * unclear what that would mean, anyway: what should we mark when a result
1493  * row is generated from no element of the nullable relation?) So,
1494  * complain if any nullable rel is FOR [KEY] UPDATE/SHARE.
1495  *
1496  * You might be wondering why this test isn't made far upstream in the
1497  * parser. It's because the parser hasn't got enough info --- consider
1498  * FOR UPDATE applied to a view. Only after rewriting and flattening do
1499  * we know whether the view contains an outer join.
1500  *
1501  * We use the original RowMarkClause list here; the PlanRowMark list would
1502  * list everything.
1503  */
1504  foreach(l, root->parse->rowMarks)
1505  {
1506  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
1507 
1508  if (bms_is_member(rc->rti, right_rels) ||
1509  (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels)))
1510  ereport(ERROR,
1511  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1512  /*------
1513  translator: %s is a SQL row locking clause such as FOR UPDATE */
1514  errmsg("%s cannot be applied to the nullable side of an outer join",
1515  LCS_asString(rc->strength))));
1516  }
1517 
1518  sjinfo->syn_lefthand = left_rels;
1519  sjinfo->syn_righthand = right_rels;
1520  sjinfo->jointype = jointype;
1521  sjinfo->ojrelid = ojrelid;
1522  /* these fields may get added to later: */
1523  sjinfo->commute_above_l = NULL;
1524  sjinfo->commute_above_r = NULL;
1525  sjinfo->commute_below_l = NULL;
1526  sjinfo->commute_below_r = NULL;
1527 
1528  compute_semijoin_info(root, sjinfo, clause);
1529 
1530  /* If it's a full join, no need to be very smart */
1531  if (jointype == JOIN_FULL)
1532  {
1533  sjinfo->min_lefthand = bms_copy(left_rels);
1534  sjinfo->min_righthand = bms_copy(right_rels);
1535  sjinfo->lhs_strict = false; /* don't care about this */
1536  return sjinfo;
1537  }
1538 
1539  /*
1540  * Retrieve all relids mentioned within the join clause.
1541  */
1542  clause_relids = pull_varnos(root, (Node *) clause);
1543 
1544  /*
1545  * For which relids is the clause strict, ie, it cannot succeed if the
1546  * rel's columns are all NULL?
1547  */
1548  strict_relids = find_nonnullable_rels((Node *) clause);
1549 
1550  /* Remember whether the clause is strict for any LHS relations */
1551  sjinfo->lhs_strict = bms_overlap(strict_relids, left_rels);
1552 
1553  /*
1554  * Required LHS always includes the LHS rels mentioned in the clause. We
1555  * may have to add more rels based on lower outer joins; see below.
1556  */
1557  min_lefthand = bms_intersect(clause_relids, left_rels);
1558 
1559  /*
1560  * Similarly for required RHS. But here, we must also include any lower
1561  * inner joins, to ensure we don't try to commute with any of them.
1562  */
1563  min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
1564  right_rels);
1565 
1566  /*
1567  * Now check previous outer joins for ordering restrictions.
1568  *
1569  * commute_below_l and commute_below_r accumulate the relids of lower
1570  * outer joins that we think this one can commute with. These decisions
1571  * are just tentative within this loop, since we might find an
1572  * intermediate outer join that prevents commutation. Surviving relids
1573  * will get merged into the SpecialJoinInfo structs afterwards.
1574  */
1575  commute_below_l = commute_below_r = NULL;
1576  foreach(l, root->join_info_list)
1577  {
1578  SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
1579  bool have_unsafe_phvs;
1580 
1581  /*
1582  * A full join is an optimization barrier: we can't associate into or
1583  * out of it. Hence, if it overlaps either LHS or RHS of the current
1584  * rel, expand that side's min relset to cover the whole full join.
1585  */
1586  if (otherinfo->jointype == JOIN_FULL)
1587  {
1588  Assert(otherinfo->ojrelid != 0);
1589  if (bms_overlap(left_rels, otherinfo->syn_lefthand) ||
1590  bms_overlap(left_rels, otherinfo->syn_righthand))
1591  {
1592  min_lefthand = bms_add_members(min_lefthand,
1593  otherinfo->syn_lefthand);
1594  min_lefthand = bms_add_members(min_lefthand,
1595  otherinfo->syn_righthand);
1596  min_lefthand = bms_add_member(min_lefthand,
1597  otherinfo->ojrelid);
1598  }
1599  if (bms_overlap(right_rels, otherinfo->syn_lefthand) ||
1600  bms_overlap(right_rels, otherinfo->syn_righthand))
1601  {
1602  min_righthand = bms_add_members(min_righthand,
1603  otherinfo->syn_lefthand);
1604  min_righthand = bms_add_members(min_righthand,
1605  otherinfo->syn_righthand);
1606  min_righthand = bms_add_member(min_righthand,
1607  otherinfo->ojrelid);
1608  }
1609  /* Needn't do anything else with the full join */
1610  continue;
1611  }
1612 
1613  /*
1614  * If our join condition contains any PlaceHolderVars that need to be
1615  * evaluated above the lower OJ, then we can't commute with it.
1616  */
1617  if (otherinfo->ojrelid != 0)
1618  have_unsafe_phvs =
1620  (Node *) clause,
1621  otherinfo->ojrelid);
1622  else
1623  have_unsafe_phvs = false;
1624 
1625  /*
1626  * For a lower OJ in our LHS, if our join condition uses the lower
1627  * join's RHS and is not strict for that rel, we must preserve the
1628  * ordering of the two OJs, so add lower OJ's full syntactic relset to
1629  * min_lefthand. (We must use its full syntactic relset, not just its
1630  * min_lefthand + min_righthand. This is because there might be other
1631  * OJs below this one that this one can commute with, but we cannot
1632  * commute with them if we don't with this one.) Also, if we have
1633  * unsafe PHVs or the current join is a semijoin or antijoin, we must
1634  * preserve ordering regardless of strictness.
1635  *
1636  * Note: I believe we have to insist on being strict for at least one
1637  * rel in the lower OJ's min_righthand, not its whole syn_righthand.
1638  *
1639  * When we don't need to preserve ordering, check to see if outer join
1640  * identity 3 applies, and if so, remove the lower OJ's ojrelid from
1641  * our min_lefthand so that commutation is allowed.
1642  */
1643  if (bms_overlap(left_rels, otherinfo->syn_righthand))
1644  {
1645  if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
1646  (have_unsafe_phvs ||
1647  jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
1648  !bms_overlap(strict_relids, otherinfo->min_righthand)))
1649  {
1650  /* Preserve ordering */
1651  min_lefthand = bms_add_members(min_lefthand,
1652  otherinfo->syn_lefthand);
1653  min_lefthand = bms_add_members(min_lefthand,
1654  otherinfo->syn_righthand);
1655  if (otherinfo->ojrelid != 0)
1656  min_lefthand = bms_add_member(min_lefthand,
1657  otherinfo->ojrelid);
1658  }
1659  else if (jointype == JOIN_LEFT &&
1660  otherinfo->jointype == JOIN_LEFT &&
1661  bms_overlap(strict_relids, otherinfo->min_righthand) &&
1662  !bms_overlap(clause_relids, otherinfo->syn_lefthand))
1663  {
1664  /* Identity 3 applies, so remove the ordering restriction */
1665  min_lefthand = bms_del_member(min_lefthand, otherinfo->ojrelid);
1666  /* Record the (still tentative) commutability relationship */
1667  commute_below_l =
1668  bms_add_member(commute_below_l, otherinfo->ojrelid);
1669  }
1670  }
1671 
1672  /*
1673  * For a lower OJ in our RHS, if our join condition does not use the
1674  * lower join's RHS and the lower OJ's join condition is strict, we
1675  * can interchange the ordering of the two OJs; otherwise we must add
1676  * the lower OJ's full syntactic relset to min_righthand.
1677  *
1678  * Also, if our join condition does not use the lower join's LHS
1679  * either, force the ordering to be preserved. Otherwise we can end
1680  * up with SpecialJoinInfos with identical min_righthands, which can
1681  * confuse join_is_legal (see discussion in backend/optimizer/README).
1682  *
1683  * Also, we must preserve ordering anyway if we have unsafe PHVs, or
1684  * if either this join or the lower OJ is a semijoin or antijoin.
1685  *
1686  * When we don't need to preserve ordering, check to see if outer join
1687  * identity 3 applies, and if so, remove the lower OJ's ojrelid from
1688  * our min_righthand so that commutation is allowed.
1689  */
1690  if (bms_overlap(right_rels, otherinfo->syn_righthand))
1691  {
1692  if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
1693  !bms_overlap(clause_relids, otherinfo->min_lefthand) ||
1694  have_unsafe_phvs ||
1695  jointype == JOIN_SEMI ||
1696  jointype == JOIN_ANTI ||
1697  otherinfo->jointype == JOIN_SEMI ||
1698  otherinfo->jointype == JOIN_ANTI ||
1699  !otherinfo->lhs_strict)
1700  {
1701  /* Preserve ordering */
1702  min_righthand = bms_add_members(min_righthand,
1703  otherinfo->syn_lefthand);
1704  min_righthand = bms_add_members(min_righthand,
1705  otherinfo->syn_righthand);
1706  if (otherinfo->ojrelid != 0)
1707  min_righthand = bms_add_member(min_righthand,
1708  otherinfo->ojrelid);
1709  }
1710  else if (jointype == JOIN_LEFT &&
1711  otherinfo->jointype == JOIN_LEFT &&
1712  otherinfo->lhs_strict)
1713  {
1714  /* Identity 3 applies, so remove the ordering restriction */
1715  min_righthand = bms_del_member(min_righthand,
1716  otherinfo->ojrelid);
1717  /* Record the (still tentative) commutability relationship */
1718  commute_below_r =
1719  bms_add_member(commute_below_r, otherinfo->ojrelid);
1720  }
1721  }
1722  }
1723 
1724  /*
1725  * Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
1726  * this join's nullable side, then ensure that min_righthand contains the
1727  * full eval_at set of the PHV. This ensures that the PHV actually can be
1728  * evaluated within the RHS. Note that this works only because we should
1729  * already have determined the final eval_at level for any PHV
1730  * syntactically within this join.
1731  */
1732  foreach(l, root->placeholder_list)
1733  {
1734  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
1735  Relids ph_syn_level = phinfo->ph_var->phrels;
1736 
1737  /* Ignore placeholder if it didn't syntactically come from RHS */
1738  if (!bms_is_subset(ph_syn_level, right_rels))
1739  continue;
1740 
1741  /* Else, prevent join from being formed before we eval the PHV */
1742  min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
1743  }
1744 
1745  /*
1746  * If we found nothing to put in min_lefthand, punt and make it the full
1747  * LHS, to avoid having an empty min_lefthand which will confuse later
1748  * processing. (We don't try to be smart about such cases, just correct.)
1749  * Likewise for min_righthand.
1750  */
1751  if (bms_is_empty(min_lefthand))
1752  min_lefthand = bms_copy(left_rels);
1753  if (bms_is_empty(min_righthand))
1754  min_righthand = bms_copy(right_rels);
1755 
1756  /* Now they'd better be nonempty */
1757  Assert(!bms_is_empty(min_lefthand));
1758  Assert(!bms_is_empty(min_righthand));
1759  /* Shouldn't overlap either */
1760  Assert(!bms_overlap(min_lefthand, min_righthand));
1761 
1762  sjinfo->min_lefthand = min_lefthand;
1763  sjinfo->min_righthand = min_righthand;
1764 
1765  /*
1766  * Now that we've identified the correct min_lefthand and min_righthand,
1767  * any commute_below_l or commute_below_r relids that have not gotten
1768  * added back into those sets (due to intervening outer joins) are indeed
1769  * commutable with this one.
1770  *
1771  * First, delete any subsequently-added-back relids (this is easier than
1772  * maintaining commute_below_l/r precisely through all the above).
1773  */
1774  commute_below_l = bms_del_members(commute_below_l, min_lefthand);
1775  commute_below_r = bms_del_members(commute_below_r, min_righthand);
1776 
1777  /* Anything left? */
1778  if (commute_below_l || commute_below_r)
1779  {
1780  /* Yup, so we must update the derived data in the SpecialJoinInfos */
1781  sjinfo->commute_below_l = commute_below_l;
1782  sjinfo->commute_below_r = commute_below_r;
1783  foreach(l, root->join_info_list)
1784  {
1785  SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
1786 
1787  if (bms_is_member(otherinfo->ojrelid, commute_below_l))
1788  otherinfo->commute_above_l =
1789  bms_add_member(otherinfo->commute_above_l, ojrelid);
1790  else if (bms_is_member(otherinfo->ojrelid, commute_below_r))
1791  otherinfo->commute_above_r =
1792  bms_add_member(otherinfo->commute_above_r, ojrelid);
1793  }
1794  }
1795 
1796  return sjinfo;
1797 }
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1109
Relids find_nonnullable_rels(Node *clause)
Definition: clauses.c:1455
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
Definition: initsplan.c:1807
@ JOIN_RIGHT
Definition: nodes.h:296
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3305
bool contain_placeholder_references_to(PlannerInfo *root, Node *clause, int relid)
Definition: placeholder.c:491
PlaceHolderVar * ph_var
Definition: pathnodes.h:3095
LockClauseStrength strength
Definition: parsenodes.h:1580
Relids commute_above_l
Definition: pathnodes.h:2910

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_del_member(), bms_del_members(), bms_int_members(), bms_intersect(), bms_is_empty, bms_is_member(), bms_is_subset(), bms_overlap(), bms_union(), SpecialJoinInfo::commute_above_l, SpecialJoinInfo::commute_above_r, SpecialJoinInfo::commute_below_l, SpecialJoinInfo::commute_below_r, compute_semijoin_info(), contain_placeholder_references_to(), ereport, errcode(), errmsg(), ERROR, find_nonnullable_rels(), JoinTreeItem::inner_join_rels, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, SpecialJoinInfo::jointype, LCS_asString(), JoinTreeItem::left_rels, lfirst, SpecialJoinInfo::lhs_strict, makeNode, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, SpecialJoinInfo::ojrelid, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_var, pull_varnos(), JoinTreeItem::right_rels, root, RowMarkClause::rti, JoinTreeItem::sjinfo, RowMarkClause::strength, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.

Referenced by deconstruct_distribute().

◆ mark_rels_nulled_by_join()

static void mark_rels_nulled_by_join ( PlannerInfo root,
Index  ojrelid,
Relids  lower_rels 
)
static

Definition at line 1425 of file initsplan.c.

1427 {
1428  int relid = -1;
1429 
1430  while ((relid = bms_next_member(lower_rels, relid)) > 0)
1431  {
1432  RelOptInfo *rel = root->simple_rel_array[relid];
1433 
1434  /* ignore the RTE_GROUP RTE */
1435  if (relid == root->group_rtindex)
1436  continue;
1437 
1438  if (rel == NULL) /* must be an outer join */
1439  {
1440  Assert(bms_is_member(relid, root->outer_join_rels));
1441  continue;
1442  }
1443  rel->nulling_relids = bms_add_member(rel->nulling_relids, ojrelid);
1444  }
1445 }
Relids nulling_relids
Definition: pathnodes.h:938

References Assert, bms_add_member(), bms_is_member(), bms_next_member(), RelOptInfo::nulling_relids, and root.

Referenced by deconstruct_recurse().

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 3358 of file initsplan.c.

3359 {
3360  List *newlist = NIL;
3361  ListCell *lc;
3362 
3363  foreach(lc, root->fkey_list)
3364  {
3365  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
3366  RelOptInfo *con_rel;
3367  RelOptInfo *ref_rel;
3368  int colno;
3369 
3370  /*
3371  * Either relid might identify a rel that is in the query's rtable but
3372  * isn't referenced by the jointree, or has been removed by join
3373  * removal, so that it won't have a RelOptInfo. Hence don't use
3374  * find_base_rel() here. We can ignore such FKs.
3375  */
3376  if (fkinfo->con_relid >= root->simple_rel_array_size ||
3377  fkinfo->ref_relid >= root->simple_rel_array_size)
3378  continue; /* just paranoia */
3379  con_rel = root->simple_rel_array[fkinfo->con_relid];
3380  if (con_rel == NULL)
3381  continue;
3382  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3383  if (ref_rel == NULL)
3384  continue;
3385 
3386  /*
3387  * Ignore FK unless both rels are baserels. This gets rid of FKs that
3388  * link to inheritance child rels (otherrels).
3389  */
3390  if (con_rel->reloptkind != RELOPT_BASEREL ||
3391  ref_rel->reloptkind != RELOPT_BASEREL)
3392  continue;
3393 
3394  /*
3395  * Scan the columns and try to match them to eclasses and quals.
3396  *
3397  * Note: for simple inner joins, any match should be in an eclass.
3398  * "Loose" quals that syntactically match an FK equality must have
3399  * been rejected for EC status because they are outer-join quals or
3400  * similar. We can still consider them to match the FK.
3401  */
3402  for (colno = 0; colno < fkinfo->nkeys; colno++)
3403  {
3404  EquivalenceClass *ec;
3405  AttrNumber con_attno,
3406  ref_attno;
3407  Oid fpeqop;
3408  ListCell *lc2;
3409 
3410  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
3411  /* Don't bother looking for loose quals if we got an EC match */
3412  if (ec != NULL)
3413  {
3414  fkinfo->nmatched_ec++;
3415  if (ec->ec_has_const)
3416  fkinfo->nconst_ec++;
3417  continue;
3418  }
3419 
3420  /*
3421  * Scan joininfo list for relevant clauses. Either rel's joininfo
3422  * list would do equally well; we use con_rel's.
3423  */
3424  con_attno = fkinfo->conkey[colno];
3425  ref_attno = fkinfo->confkey[colno];
3426  fpeqop = InvalidOid; /* we'll look this up only if needed */
3427 
3428  foreach(lc2, con_rel->joininfo)
3429  {
3430  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
3431  OpExpr *clause = (OpExpr *) rinfo->clause;
3432  Var *leftvar;
3433  Var *rightvar;
3434 
3435  /* Only binary OpExprs are useful for consideration */
3436  if (!IsA(clause, OpExpr) ||
3437  list_length(clause->args) != 2)
3438  continue;
3439  leftvar = (Var *) get_leftop((Expr *) clause);
3440  rightvar = (Var *) get_rightop((Expr *) clause);
3441 
3442  /* Operands must be Vars, possibly with RelabelType */
3443  while (leftvar && IsA(leftvar, RelabelType))
3444  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
3445  if (!(leftvar && IsA(leftvar, Var)))
3446  continue;
3447  while (rightvar && IsA(rightvar, RelabelType))
3448  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
3449  if (!(rightvar && IsA(rightvar, Var)))
3450  continue;
3451 
3452  /* Now try to match the vars to the current foreign key cols */
3453  if (fkinfo->ref_relid == leftvar->varno &&
3454  ref_attno == leftvar->varattno &&
3455  fkinfo->con_relid == rightvar->varno &&
3456  con_attno == rightvar->varattno)
3457  {
3458  /* Vars match, but is it the right operator? */
3459  if (clause->opno == fkinfo->conpfeqop[colno])
3460  {
3461  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3462  rinfo);
3463  fkinfo->nmatched_ri++;
3464  }
3465  }
3466  else if (fkinfo->ref_relid == rightvar->varno &&
3467  ref_attno == rightvar->varattno &&
3468  fkinfo->con_relid == leftvar->varno &&
3469  con_attno == leftvar->varattno)
3470  {
3471  /*
3472  * Reverse match, must check commutator operator. Look it
3473  * up if we didn't already. (In the worst case we might
3474  * do multiple lookups here, but that would require an FK
3475  * equality operator without commutator, which is
3476  * unlikely.)
3477  */
3478  if (!OidIsValid(fpeqop))
3479  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
3480  if (clause->opno == fpeqop)
3481  {
3482  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3483  rinfo);
3484  fkinfo->nmatched_ri++;
3485  }
3486  }
3487  }
3488  /* If we found any matching loose quals, count col as matched */
3489  if (fkinfo->rinfos[colno])
3490  fkinfo->nmatched_rcols++;
3491  }
3492 
3493  /*
3494  * Currently, we drop multicolumn FKs that aren't fully matched to the
3495  * query. Later we might figure out how to derive some sort of
3496  * estimate from them, in which case this test should be weakened to
3497  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3498  */
3499  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3500  newlist = lappend(newlist, fkinfo);
3501  }
3502  /* Replace fkey_list, thereby discarding any useless entries */
3503  root->fkey_list = newlist;
3504 }
int16 AttrNumber
Definition: attnum.h:21
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2559
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:95
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:83
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:1263
List * joininfo
Definition: pathnodes.h:991

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, EquivalenceClass::ec_has_const, get_commutator(), get_leftop(), get_rightop(), if(), 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, ForeignKeyOptInfo::ref_relid, RELOPT_BASEREL, RelOptInfo::reloptkind, ForeignKeyOptInfo::rinfos, and root.

Referenced by query_planner().

◆ process_implied_equality()

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

Definition at line 3039 of file initsplan.c.

3047 {
3048  RestrictInfo *restrictinfo;
3049  Node *clause;
3050  Relids relids;
3051  bool pseudoconstant = false;
3052 
3053  /*
3054  * Build the new clause. Copy to ensure it shares no substructure with
3055  * original (this is necessary in case there are subselects in there...)
3056  */
3057  clause = (Node *) make_opclause(opno,
3058  BOOLOID, /* opresulttype */
3059  false, /* opretset */
3060  copyObject(item1),
3061  copyObject(item2),
3062  InvalidOid,
3063  collation);
3064 
3065  /* If both constant, try to reduce to a boolean constant. */
3066  if (both_const)
3067  {
3068  clause = eval_const_expressions(root, clause);
3069 
3070  /* If we produced const TRUE, just drop the clause */
3071  if (clause && IsA(clause, Const))
3072  {
3073  Const *cclause = (Const *) clause;
3074 
3075  Assert(cclause->consttype == BOOLOID);
3076  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
3077  return NULL;
3078  }
3079  }
3080 
3081  /*
3082  * The rest of this is a very cut-down version of distribute_qual_to_rels.
3083  * We can skip most of the work therein, but there are a couple of special
3084  * cases we still have to handle.
3085  *
3086  * Retrieve all relids mentioned within the possibly-simplified clause.
3087  */
3088  relids = pull_varnos(root, clause);
3089  Assert(bms_is_subset(relids, qualscope));
3090 
3091  /*
3092  * If the clause is variable-free, our normal heuristic for pushing it
3093  * down to just the mentioned rels doesn't work, because there are none.
3094  * Apply it as a gating qual at the appropriate level (see comments for
3095  * get_join_domain_min_rels).
3096  */
3097  if (bms_is_empty(relids))
3098  {
3099  /* eval at join domain's safe level */
3100  relids = get_join_domain_min_rels(root, qualscope);
3101  /* mark as gating qual */
3102  pseudoconstant = true;
3103  /* tell createplan.c to check for gating quals */
3104  root->hasPseudoConstantQuals = true;
3105  }
3106 
3107  /*
3108  * Build the RestrictInfo node itself.
3109  */
3110  restrictinfo = make_restrictinfo(root,
3111  (Expr *) clause,
3112  true, /* is_pushed_down */
3113  false, /* !has_clone */
3114  false, /* !is_clone */
3115  pseudoconstant,
3116  security_level,
3117  relids,
3118  NULL, /* incompatible_relids */
3119  NULL); /* outer_relids */
3120 
3121  /*
3122  * If it's a join clause, add vars used in the clause to targetlists of
3123  * their relations, so that they will be emitted by the plan nodes that
3124  * scan those relations (else they won't be available at the join node!).
3125  *
3126  * Typically, we'd have already done this when the component expressions
3127  * were first seen by distribute_qual_to_rels; but it is possible that
3128  * some of the Vars could have missed having that done because they only
3129  * appeared in single-relation clauses originally. So do it here for
3130  * safety.
3131  *
3132  * See also rebuild_joinclause_attr_needed, which has to partially repeat
3133  * this work after removal of an outer join. (Since we will put this
3134  * clause into the joininfo lists, that function needn't do any extra work
3135  * to find it.)
3136  */
3137  if (bms_membership(relids) == BMS_MULTIPLE)
3138  {
3139  List *vars = pull_var_clause(clause,
3143 
3144  add_vars_to_targetlist(root, vars, relids);
3145  list_free(vars);
3146  }
3147 
3148  /*
3149  * Check mergejoinability. This will usually succeed, since the op came
3150  * from an EquivalenceClass; but we could have reduced the original clause
3151  * to a constant.
3152  */
3153  check_mergejoinable(restrictinfo);
3154 
3155  /*
3156  * Note we don't do initialize_mergeclause_eclasses(); the caller can
3157  * handle that much more cheaply than we can. It's okay to call
3158  * distribute_restrictinfo_to_rels() before that happens.
3159  */
3160 
3161  /*
3162  * Push the new clause into all the appropriate restrictinfo lists.
3163  */
3164  distribute_restrictinfo_to_rels(root, restrictinfo);
3165 
3166  return restrictinfo;
3167 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2253
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition: initsplan.c:3252
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Oid consttype
Definition: primnodes.h:312

References add_vars_to_targetlist(), Assert, bms_is_empty, bms_is_subset(), bms_membership(), BMS_MULTIPLE, check_mergejoinable(), Const::consttype, copyObject, DatumGetBool(), distribute_restrictinfo_to_rels(), eval_const_expressions(), get_join_domain_min_rels(), InvalidOid, IsA, list_free(), make_opclause(), make_restrictinfo(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, JoinTreeItem::qualscope, and root.

Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().

◆ process_security_barrier_quals()

static void process_security_barrier_quals ( PlannerInfo root,
int  rti,
JoinTreeItem jtitem 
)
static

Definition at line 1375 of file initsplan.c.

1377 {
1378  RangeTblEntry *rte = root->simple_rte_array[rti];
1379  Index security_level = 0;
1380  ListCell *lc;
1381 
1382  /*
1383  * Each element of the securityQuals list has been preprocessed into an
1384  * implicitly-ANDed list of clauses. All the clauses in a given sublist
1385  * should get the same security level, but successive sublists get higher
1386  * levels.
1387  */
1388  foreach(lc, rte->securityQuals)
1389  {
1390  List *qualset = (List *) lfirst(lc);
1391 
1392  /*
1393  * We cheat to the extent of passing ojscope = qualscope rather than
1394  * its more logical value of NULL. The only effect this has is to
1395  * force a Var-free qual to be evaluated at the rel rather than being
1396  * pushed up to top of tree, which we don't want.
1397  */
1398  distribute_quals_to_rels(root, qualset,
1399  jtitem,
1400  NULL,
1401  security_level,
1402  jtitem->qualscope,
1403  jtitem->qualscope,
1404  NULL,
1405  NULL,
1406  true,
1407  false, false, /* not clones */
1408  NULL);
1409  security_level++;
1410  }
1411 
1412  /* Assert that qual_security_level is higher than anything we just used */
1413  Assert(security_level <= root->qual_security_level);
1414 }

References Assert, distribute_quals_to_rels(), lfirst, JoinTreeItem::qualscope, and root.

Referenced by deconstruct_distribute().

◆ rebuild_joinclause_attr_needed()

void rebuild_joinclause_attr_needed ( PlannerInfo root)

Definition at line 3286 of file initsplan.c.

3287 {
3288  /*
3289  * We must examine all join clauses, but there's no value in processing
3290  * any join clause more than once. So it's slightly annoying that we have
3291  * to find them via the per-base-relation joininfo lists. Avoid duplicate
3292  * processing by tracking the rinfo_serial numbers of join clauses we've
3293  * already seen. (This doesn't work for is_clone clauses, so we must
3294  * waste effort on them.)
3295  */
3296  Bitmapset *seen_serials = NULL;
3297  Index rti;
3298 
3299  /* Scan all baserels for join clauses */
3300  for (rti = 1; rti < root->simple_rel_array_size; rti++)
3301  {
3302  RelOptInfo *brel = root->simple_rel_array[rti];
3303  ListCell *lc;
3304 
3305  if (brel == NULL)
3306  continue;
3307  if (brel->reloptkind != RELOPT_BASEREL)
3308  continue;
3309 
3310  foreach(lc, brel->joininfo)
3311  {
3312  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
3313  Relids relids = rinfo->required_relids;
3314 
3315  if (!rinfo->is_clone) /* else serial number is not unique */
3316  {
3317  if (bms_is_member(rinfo->rinfo_serial, seen_serials))
3318  continue; /* saw it already */
3319  seen_serials = bms_add_member(seen_serials,
3320  rinfo->rinfo_serial);
3321  }
3322 
3323  if (bms_membership(relids) == BMS_MULTIPLE)
3324  {
3325  List *vars = pull_var_clause((Node *) rinfo->clause,
3329  Relids where_needed;
3330 
3331  if (rinfo->is_clone)
3332  where_needed = bms_intersect(relids, root->all_baserels);
3333  else
3334  where_needed = relids;
3335  add_vars_to_attr_needed(root, vars, where_needed);
3336  list_free(vars);
3337  }
3338  }
3339  }
3340 }
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:352

References add_vars_to_attr_needed(), bms_add_member(), bms_intersect(), bms_is_member(), bms_membership(), BMS_MULTIPLE, RestrictInfo::clause, RestrictInfo::is_clone, RelOptInfo::joininfo, lfirst, list_free(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RELOPT_BASEREL, RelOptInfo::reloptkind, RestrictInfo::required_relids, RestrictInfo::rinfo_serial, and root.

Referenced by remove_rel_from_query().

◆ rebuild_lateral_attr_needed()

void rebuild_lateral_attr_needed ( PlannerInfo root)

Definition at line 566 of file initsplan.c.

567 {
568  Index rti;
569 
570  /* We need do nothing if the query contains no LATERAL RTEs */
571  if (!root->hasLateralRTEs)
572  return;
573 
574  /* Examine the same baserels that find_lateral_references did */
575  for (rti = 1; rti < root->simple_rel_array_size; rti++)
576  {
577  RelOptInfo *brel = root->simple_rel_array[rti];
578  Relids where_needed;
579 
580  if (brel == NULL)
581  continue;
582  if (brel->reloptkind != RELOPT_BASEREL)
583  continue;
584 
585  /*
586  * We don't need to repeat all of extract_lateral_references, since it
587  * kindly saved the extracted Vars/PHVs in lateral_vars.
588  */
589  if (brel->lateral_vars == NIL)
590  continue;
591 
592  where_needed = bms_make_singleton(rti);
593 
594  add_vars_to_attr_needed(root, brel->lateral_vars, where_needed);
595  }
596 }

References add_vars_to_attr_needed(), bms_make_singleton(), RelOptInfo::lateral_vars, NIL, RELOPT_BASEREL, RelOptInfo::reloptkind, and root.

Referenced by remove_rel_from_query().

◆ restriction_is_always_false()

bool restriction_is_always_false ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2899 of file initsplan.c.

2901 {
2902  /* Check for NullTest qual */
2903  if (IsA(restrictinfo->clause, NullTest))
2904  {
2905  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2906 
2907  /* is this NullTest an IS_NULL qual? */
2908  if (nulltest->nulltesttype != IS_NULL)
2909  return false;
2910 
2911  return expr_is_nonnullable(root, nulltest->arg);
2912  }
2913 
2914  /* If it's an OR, check its sub-clauses */
2915  if (restriction_is_or_clause(restrictinfo))
2916  {
2917  ListCell *lc;
2918 
2919  Assert(is_orclause(restrictinfo->orclause));
2920 
2921  /*
2922  * Currently, when processing OR expressions, we only return true when
2923  * all of the OR branches are always false. This could perhaps be
2924  * expanded to remove OR branches that are provably false. This may
2925  * be a useful thing to do as it could result in the OR being left
2926  * with a single arg. That's useful as it would allow the OR
2927  * condition to be replaced with its single argument which may allow
2928  * use of an index for faster filtering on the remaining condition.
2929  */
2930  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2931  {
2932  Node *orarg = (Node *) lfirst(lc);
2933 
2934  if (!IsA(orarg, RestrictInfo) ||
2936  return false;
2937  }
2938  return true;
2939  }
2940 
2941  return false;
2942 }
static bool expr_is_nonnullable(PlannerInfo *root, Expr *expr)
Definition: initsplan.c:2814
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:116
@ IS_NULL
Definition: primnodes.h:1952
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:407
NullTestType nulltesttype
Definition: primnodes.h:1959
Expr * arg
Definition: primnodes.h:1958

References NullTest::arg, Assert, RestrictInfo::clause, expr_is_nonnullable(), if(), IS_NULL, is_orclause(), IsA, lfirst, NullTest::nulltesttype, restriction_is_or_clause(), and root.

Referenced by add_base_clause_to_rel(), add_join_clause_to_rels(), and apply_child_basequals().

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2850 of file initsplan.c.

2852 {
2853  /* Check for NullTest qual */
2854  if (IsA(restrictinfo->clause, NullTest))
2855  {
2856  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2857 
2858  /* is this NullTest an IS_NOT_NULL qual? */
2859  if (nulltest->nulltesttype != IS_NOT_NULL)
2860  return false;
2861 
2862  return expr_is_nonnullable(root, nulltest->arg);
2863  }
2864 
2865  /* If it's an OR, check its sub-clauses */
2866  if (restriction_is_or_clause(restrictinfo))
2867  {
2868  ListCell *lc;
2869 
2870  Assert(is_orclause(restrictinfo->orclause));
2871 
2872  /*
2873  * if any of the given OR branches is provably always true then the
2874  * entire condition is true.
2875  */
2876  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2877  {
2878  Node *orarg = (Node *) lfirst(lc);
2879 
2880  if (!IsA(orarg, RestrictInfo))
2881  continue;
2882 
2884  return true;
2885  }
2886  }
2887 
2888  return false;
2889 }
@ IS_NOT_NULL
Definition: primnodes.h:1952

References NullTest::arg, Assert, RestrictInfo::clause, expr_is_nonnullable(), if(), IS_NOT_NULL, is_orclause(), IsA, lfirst, NullTest::nulltesttype, restriction_is_or_clause(), and root.

Referenced by add_base_clause_to_rel(), add_join_clause_to_rels(), and apply_child_basequals().

Variable Documentation

◆ from_collapse_limit

int from_collapse_limit

Definition at line 38 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().