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 find_lateral_references (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 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 2628 of file initsplan.c.

2630 {
2631  RelOptInfo *rel = find_base_rel(root, relid);
2632 
2634 
2635  /* Don't add the clause if it is always true */
2636  if (restriction_is_always_true(root, restrictinfo))
2637  return;
2638 
2639  /*
2640  * Substitute the origin qual with constant-FALSE if it is provably always
2641  * false. Note that we keep the same rinfo_serial.
2642  */
2643  if (restriction_is_always_false(root, restrictinfo))
2644  {
2645  int save_rinfo_serial = restrictinfo->rinfo_serial;
2646 
2647  restrictinfo = make_restrictinfo(root,
2648  (Expr *) makeBoolConst(false, false),
2649  restrictinfo->is_pushed_down,
2650  restrictinfo->has_clone,
2651  restrictinfo->is_clone,
2652  restrictinfo->pseudoconstant,
2653  0, /* security_level */
2654  restrictinfo->required_relids,
2655  restrictinfo->incompatible_relids,
2656  restrictinfo->outer_relids);
2657  restrictinfo->rinfo_serial = save_rinfo_serial;
2658  }
2659 
2660  /* Add clause to rel's restriction list */
2661  rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo);
2662 
2663  /* Update security level info */
2665  restrictinfo->security_level);
2666 }
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_SINGLETON
Definition: bitmapset.h:72
#define Min(x, y)
Definition: c.h:991
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2712
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2761
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:339
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:359
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:407
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:63
List * baserestrictinfo
Definition: pathnodes.h:966
Index baserestrict_min_security
Definition: pathnodes.h:970
bool is_pushed_down
Definition: pathnodes.h:2544
Index security_level
Definition: pathnodes.h:2563
Relids required_relids
Definition: pathnodes.h:2572
int rinfo_serial
Definition: pathnodes.h:2613
Relids outer_relids
Definition: pathnodes.h:2578
Relids incompatible_relids
Definition: pathnodes.h:2575
bool has_clone
Definition: pathnodes.h:2553

References Assert(), RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, bms_membership(), BMS_SINGLETON, find_base_rel(), RestrictInfo::has_clone, RestrictInfo::incompatible_relids, 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, 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 156 of file initsplan.c.

157 {
158  if (jtnode == NULL)
159  return;
160  if (IsA(jtnode, RangeTblRef))
161  {
162  int varno = ((RangeTblRef *) jtnode)->rtindex;
163 
164  (void) build_simple_rel(root, varno, NULL);
165  }
166  else if (IsA(jtnode, FromExpr))
167  {
168  FromExpr *f = (FromExpr *) jtnode;
169  ListCell *l;
170 
171  foreach(l, f->fromlist)
172  add_base_rels_to_query(root, lfirst(l));
173  }
174  else if (IsA(jtnode, JoinExpr))
175  {
176  JoinExpr *j = (JoinExpr *) jtnode;
177 
178  add_base_rels_to_query(root, j->larg);
179  add_base_rels_to_query(root, j->rarg);
180  }
181  else
182  elog(ERROR, "unrecognized node type: %d",
183  (int) nodeTag(jtnode));
184 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:156
int j
Definition: isn.c:74
#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:2061

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

Referenced by query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 194 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_vars_to_targetlist()

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

Definition at line 278 of file initsplan.c.

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

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, 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 233 of file initsplan.c.

234 {
235  List *tlist_vars = pull_var_clause((Node *) final_tlist,
239 
240  if (tlist_vars != NIL)
241  {
242  add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0));
243  list_free(tlist_vars);
244  }
245 
246  /*
247  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
248  * that HAVING can contain Aggrefs but not WindowFuncs.
249  */
250  if (root->parse->havingQual)
251  {
252  List *having_vars = pull_var_clause(root->parse->havingQual,
255 
256  if (having_vars != NIL)
257  {
258  add_vars_to_targetlist(root, having_vars,
259  bms_make_singleton(0));
260  list_free(having_vars);
261  }
262  }
263 }
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:278
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
Query * parse
Definition: pathnodes.h:199
Node * havingQual
Definition: parsenodes.h:204
List * pull_var_clause(Node *node, int flags)
Definition: var.c:607

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

Referenced by 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 3040 of file initsplan.c.

3047 {
3048  RestrictInfo *restrictinfo;
3049  Expr *clause;
3050 
3051  /*
3052  * Build the new clause. Copy to ensure it shares no substructure with
3053  * original (this is necessary in case there are subselects in there...)
3054  */
3055  clause = make_opclause(opno,
3056  BOOLOID, /* opresulttype */
3057  false, /* opretset */
3058  copyObject(item1),
3059  copyObject(item2),
3060  InvalidOid,
3061  collation);
3062 
3063  /*
3064  * Build the RestrictInfo node itself.
3065  */
3066  restrictinfo = make_restrictinfo(root,
3067  clause,
3068  true, /* is_pushed_down */
3069  false, /* !has_clone */
3070  false, /* !is_clone */
3071  false, /* pseudoconstant */
3072  security_level, /* security_level */
3073  qualscope, /* required_relids */
3074  NULL, /* incompatible_relids */
3075  NULL); /* outer_relids */
3076 
3077  /* Set mergejoinability/hashjoinability flags */
3078  check_mergejoinable(restrictinfo);
3079  check_hashjoinable(restrictinfo);
3080  check_memoizable(restrictinfo);
3081 
3082  return restrictinfo;
3083 }
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3351
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3314
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3379
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:612
#define InvalidOid
Definition: postgres_ext.h:36

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

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 3351 of file initsplan.c.

3352 {
3353  Expr *clause = restrictinfo->clause;
3354  Oid opno;
3355  Node *leftarg;
3356 
3357  if (restrictinfo->pseudoconstant)
3358  return;
3359  if (!is_opclause(clause))
3360  return;
3361  if (list_length(((OpExpr *) clause)->args) != 2)
3362  return;
3363 
3364  opno = ((OpExpr *) clause)->opno;
3365  leftarg = linitial(((OpExpr *) clause)->args);
3366 
3367  if (op_hashjoinable(opno, exprType(leftarg)) &&
3368  !contain_volatile_functions((Node *) restrictinfo))
3369  restrictinfo->hashjoinoperator = opno;
3370 }
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:518
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1415
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:74
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:2541

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 3379 of file initsplan.c.

3380 {
3381  TypeCacheEntry *typentry;
3382  Expr *clause = restrictinfo->clause;
3383  Oid lefttype;
3384  Oid righttype;
3385 
3386  if (restrictinfo->pseudoconstant)
3387  return;
3388  if (!is_opclause(clause))
3389  return;
3390  if (list_length(((OpExpr *) clause)->args) != 2)
3391  return;
3392 
3393  lefttype = exprType(linitial(((OpExpr *) clause)->args));
3394 
3395  typentry = lookup_type_cache(lefttype, TYPECACHE_HASH_PROC |
3397 
3398  if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3399  restrictinfo->left_hasheqoperator = typentry->eq_opr;
3400 
3401  righttype = exprType(lsecond(((OpExpr *) clause)->args));
3402 
3403  /*
3404  * Lookup the right type, unless it's the same as the left type, in which
3405  * case typentry is already pointing to the required TypeCacheEntry.
3406  */
3407  if (lefttype != righttype)
3408  typentry = lookup_type_cache(righttype, TYPECACHE_HASH_PROC |
3410 
3411  if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3412  restrictinfo->right_hasheqoperator = typentry->eq_opr;
3413 }
#define OidIsValid(objectId)
Definition: c.h:762
#define lsecond(l)
Definition: pg_list.h:183
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:346
#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 3314 of file initsplan.c.

3315 {
3316  Expr *clause = restrictinfo->clause;
3317  Oid opno;
3318  Node *leftarg;
3319 
3320  if (restrictinfo->pseudoconstant)
3321  return;
3322  if (!is_opclause(clause))
3323  return;
3324  if (list_length(((OpExpr *) clause)->args) != 2)
3325  return;
3326 
3327  opno = ((OpExpr *) clause)->opno;
3328  leftarg = linitial(((OpExpr *) clause)->args);
3329 
3330  if (op_mergejoinable(opno, exprType(leftarg)) &&
3331  !contain_volatile_functions((Node *) restrictinfo))
3332  restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
3333 
3334  /*
3335  * Note: op_mergejoinable is just a hint; if we fail to find the operator
3336  * in any btree opfamilies, mergeopfamilies remains NIL and so the clause
3337  * is not treated as mergejoinable.
3338  */
3339 }
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:366
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1364

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 2583 of file initsplan.c.

2584 {
2585  Var *forced_null_var;
2586  ListCell *lc;
2587 
2588  /* Check for IS NULL, and identify the Var forced to NULL */
2589  forced_null_var = find_forced_null_var(clause);
2590  if (forced_null_var == NULL)
2591  return false;
2592 
2593  /*
2594  * If the Var comes from the nullable side of a lower antijoin, the IS
2595  * NULL condition is necessarily true. If it's not nulled by anything,
2596  * there is no point in searching the join_info_list. Otherwise, we need
2597  * to find out whether the nulling rel is an antijoin.
2598  */
2599  if (forced_null_var->varnullingrels == NULL)
2600  return false;
2601 
2602  foreach(lc, root->join_info_list)
2603  {
2604  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
2605 
2606  /*
2607  * This test will not succeed if sjinfo->ojrelid is zero, which is
2608  * possible for an antijoin that was converted from a semijoin; but in
2609  * such a case the Var couldn't have come from its nullable side.
2610  */
2611  if (sjinfo->jointype == JOIN_ANTI && sjinfo->ojrelid != 0 &&
2612  bms_is_member(sjinfo->ojrelid, forced_null_var->varnullingrels))
2613  return true;
2614  }
2615 
2616  return false;
2617 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Var * find_forced_null_var(Node *node)
Definition: clauses.c:1957
@ JOIN_ANTI
Definition: nodes.h:298
List * join_info_list
Definition: pathnodes.h:337
JoinType jointype
Definition: pathnodes.h:2872

References bms_is_member(), find_forced_null_var(), JOIN_ANTI, PlannerInfo::join_info_list, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::ojrelid, 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 1699 of file initsplan.c.

1700 {
1701  List *semi_operators;
1702  List *semi_rhs_exprs;
1703  bool all_btree;
1704  bool all_hash;
1705  ListCell *lc;
1706 
1707  /* Initialize semijoin-related fields in case we can't unique-ify */
1708  sjinfo->semi_can_btree = false;
1709  sjinfo->semi_can_hash = false;
1710  sjinfo->semi_operators = NIL;
1711  sjinfo->semi_rhs_exprs = NIL;
1712 
1713  /* Nothing more to do if it's not a semijoin */
1714  if (sjinfo->jointype != JOIN_SEMI)
1715  return;
1716 
1717  /*
1718  * Look to see whether the semijoin's join quals consist of AND'ed
1719  * equality operators, with (only) RHS variables on only one side of each
1720  * one. If so, we can figure out how to enforce uniqueness for the RHS.
1721  *
1722  * Note that the input clause list is the list of quals that are
1723  * *syntactically* associated with the semijoin, which in practice means
1724  * the synthesized comparison list for an IN or the WHERE of an EXISTS.
1725  * Particularly in the latter case, it might contain clauses that aren't
1726  * *semantically* associated with the join, but refer to just one side or
1727  * the other. We can ignore such clauses here, as they will just drop
1728  * down to be processed within one side or the other. (It is okay to
1729  * consider only the syntactically-associated clauses here because for a
1730  * semijoin, no higher-level quals could refer to the RHS, and so there
1731  * can be no other quals that are semantically associated with this join.
1732  * We do things this way because it is useful to have the set of potential
1733  * unique-ification expressions before we can extract the list of quals
1734  * that are actually semantically associated with the particular join.)
1735  *
1736  * Note that the semi_operators list consists of the joinqual operators
1737  * themselves (but commuted if needed to put the RHS value on the right).
1738  * These could be cross-type operators, in which case the operator
1739  * actually needed for uniqueness is a related single-type operator. We
1740  * assume here that that operator will be available from the btree or hash
1741  * opclass when the time comes ... if not, create_unique_plan() will fail.
1742  */
1743  semi_operators = NIL;
1744  semi_rhs_exprs = NIL;
1745  all_btree = true;
1746  all_hash = enable_hashagg; /* don't consider hash if not enabled */
1747  foreach(lc, clause)
1748  {
1749  OpExpr *op = (OpExpr *) lfirst(lc);
1750  Oid opno;
1751  Node *left_expr;
1752  Node *right_expr;
1753  Relids left_varnos;
1754  Relids right_varnos;
1755  Relids all_varnos;
1756  Oid opinputtype;
1757 
1758  /* Is it a binary opclause? */
1759  if (!IsA(op, OpExpr) ||
1760  list_length(op->args) != 2)
1761  {
1762  /* No, but does it reference both sides? */
1763  all_varnos = pull_varnos(root, (Node *) op);
1764  if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
1765  bms_is_subset(all_varnos, sjinfo->syn_righthand))
1766  {
1767  /*
1768  * Clause refers to only one rel, so ignore it --- unless it
1769  * contains volatile functions, in which case we'd better
1770  * punt.
1771  */
1772  if (contain_volatile_functions((Node *) op))
1773  return;
1774  continue;
1775  }
1776  /* Non-operator clause referencing both sides, must punt */
1777  return;
1778  }
1779 
1780  /* Extract data from binary opclause */
1781  opno = op->opno;
1782  left_expr = linitial(op->args);
1783  right_expr = lsecond(op->args);
1784  left_varnos = pull_varnos(root, left_expr);
1785  right_varnos = pull_varnos(root, right_expr);
1786  all_varnos = bms_union(left_varnos, right_varnos);
1787  opinputtype = exprType(left_expr);
1788 
1789  /* Does it reference both sides? */
1790  if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
1791  bms_is_subset(all_varnos, sjinfo->syn_righthand))
1792  {
1793  /*
1794  * Clause refers to only one rel, so ignore it --- unless it
1795  * contains volatile functions, in which case we'd better punt.
1796  */
1797  if (contain_volatile_functions((Node *) op))
1798  return;
1799  continue;
1800  }
1801 
1802  /* check rel membership of arguments */
1803  if (!bms_is_empty(right_varnos) &&
1804  bms_is_subset(right_varnos, sjinfo->syn_righthand) &&
1805  !bms_overlap(left_varnos, sjinfo->syn_righthand))
1806  {
1807  /* typical case, right_expr is RHS variable */
1808  }
1809  else if (!bms_is_empty(left_varnos) &&
1810  bms_is_subset(left_varnos, sjinfo->syn_righthand) &&
1811  !bms_overlap(right_varnos, sjinfo->syn_righthand))
1812  {
1813  /* flipped case, left_expr is RHS variable */
1814  opno = get_commutator(opno);
1815  if (!OidIsValid(opno))
1816  return;
1817  right_expr = left_expr;
1818  }
1819  else
1820  {
1821  /* mixed membership of args, punt */
1822  return;
1823  }
1824 
1825  /* all operators must be btree equality or hash equality */
1826  if (all_btree)
1827  {
1828  /* oprcanmerge is considered a hint... */
1829  if (!op_mergejoinable(opno, opinputtype) ||
1830  get_mergejoin_opfamilies(opno) == NIL)
1831  all_btree = false;
1832  }
1833  if (all_hash)
1834  {
1835  /* ... but oprcanhash had better be correct */
1836  if (!op_hashjoinable(opno, opinputtype))
1837  all_hash = false;
1838  }
1839  if (!(all_btree || all_hash))
1840  return;
1841 
1842  /* so far so good, keep building lists */
1843  semi_operators = lappend_oid(semi_operators, opno);
1844  semi_rhs_exprs = lappend(semi_rhs_exprs, copyObject(right_expr));
1845  }
1846 
1847  /* Punt if we didn't find at least one column to unique-ify */
1848  if (semi_rhs_exprs == NIL)
1849  return;
1850 
1851  /*
1852  * The expressions we'd need to unique-ify mustn't be volatile.
1853  */
1854  if (contain_volatile_functions((Node *) semi_rhs_exprs))
1855  return;
1856 
1857  /*
1858  * If we get here, we can unique-ify the semijoin's RHS using at least one
1859  * of sorting and hashing. Save the information about how to do that.
1860  */
1861  sjinfo->semi_can_btree = all_btree;
1862  sjinfo->semi_can_hash = all_hash;
1863  sjinfo->semi_operators = semi_operators;
1864  sjinfo->semi_rhs_exprs = semi_rhs_exprs;
1865 }
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:141
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1487
@ JOIN_SEMI
Definition: nodes.h:297
Oid opno
Definition: primnodes.h:774
List * args
Definition: primnodes.h:792
List * semi_rhs_exprs
Definition: pathnodes.h:2883
Relids syn_righthand
Definition: pathnodes.h:2871
List * semi_operators
Definition: pathnodes.h:2882
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108

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

Referenced by make_outerjoininfo().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 500 of file initsplan.c.

501 {
502  bool found_laterals = false;
503  Index rti;
504  ListCell *lc;
505 
506  /* We need do nothing if the query contains no LATERAL RTEs */
507  if (!root->hasLateralRTEs)
508  return;
509 
510  /* We'll need to have the ph_eval_at values for PlaceHolderVars */
511  Assert(root->placeholdersFrozen);
512 
513  /*
514  * Examine all baserels (the rel array has been set up by now).
515  */
516  for (rti = 1; rti < root->simple_rel_array_size; rti++)
517  {
518  RelOptInfo *brel = root->simple_rel_array[rti];
519  Relids lateral_relids;
520 
521  /* there may be empty slots corresponding to non-baserel RTEs */
522  if (brel == NULL)
523  continue;
524 
525  Assert(brel->relid == rti); /* sanity check on array */
526 
527  /* ignore RTEs that are "other rels" */
528  if (brel->reloptkind != RELOPT_BASEREL)
529  continue;
530 
531  lateral_relids = NULL;
532 
533  /* consider each laterally-referenced Var or PHV */
534  foreach(lc, brel->lateral_vars)
535  {
536  Node *node = (Node *) lfirst(lc);
537 
538  if (IsA(node, Var))
539  {
540  Var *var = (Var *) node;
541 
542  found_laterals = true;
543  lateral_relids = bms_add_member(lateral_relids,
544  var->varno);
545  }
546  else if (IsA(node, PlaceHolderVar))
547  {
548  PlaceHolderVar *phv = (PlaceHolderVar *) node;
549  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
550 
551  found_laterals = true;
552  lateral_relids = bms_add_members(lateral_relids,
553  phinfo->ph_eval_at);
554  }
555  else
556  Assert(false);
557  }
558 
559  /* We now have all the simple lateral refs from this rel */
560  brel->direct_lateral_relids = lateral_relids;
561  brel->lateral_relids = bms_copy(lateral_relids);
562  }
563 
564  /*
565  * Now check for lateral references within PlaceHolderVars, and mark their
566  * eval_at rels as having lateral references to the source rels.
567  *
568  * For a PHV that is due to be evaluated at a baserel, mark its source(s)
569  * as direct lateral dependencies of the baserel (adding onto the ones
570  * recorded above). If it's due to be evaluated at a join, mark its
571  * source(s) as indirect lateral dependencies of each baserel in the join,
572  * ie put them into lateral_relids but not direct_lateral_relids. This is
573  * appropriate because we can't put any such baserel on the outside of a
574  * join to one of the PHV's lateral dependencies, but on the other hand we
575  * also can't yet join it directly to the dependency.
576  */
577  foreach(lc, root->placeholder_list)
578  {
579  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
580  Relids eval_at = phinfo->ph_eval_at;
581  Relids lateral_refs;
582  int varno;
583 
584  if (phinfo->ph_lateral == NULL)
585  continue; /* PHV is uninteresting if no lateral refs */
586 
587  found_laterals = true;
588 
589  /*
590  * Include only baserels not outer joins in the evaluation sites'
591  * lateral relids. This avoids problems when outer join order gets
592  * rearranged, and it should still ensure that the lateral values are
593  * available when needed.
594  */
595  lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels);
596  Assert(!bms_is_empty(lateral_refs));
597 
598  if (bms_get_singleton_member(eval_at, &varno))
599  {
600  /* Evaluation site is a baserel */
601  RelOptInfo *brel = find_base_rel(root, varno);
602 
603  brel->direct_lateral_relids =
605  lateral_refs);
606  brel->lateral_relids =
608  lateral_refs);
609  }
610  else
611  {
612  /* Evaluation site is a join */
613  varno = -1;
614  while ((varno = bms_next_member(eval_at, varno)) >= 0)
615  {
616  RelOptInfo *brel = find_base_rel_ignore_join(root, varno);
617 
618  if (brel == NULL)
619  continue; /* ignore outer joins in eval_at */
621  lateral_refs);
622  }
623  }
624  }
625 
626  /*
627  * If we found no actual lateral references, we're done; but reset the
628  * hasLateralRTEs flag to avoid useless work later.
629  */
630  if (!found_laterals)
631  {
632  root->hasLateralRTEs = false;
633  return;
634  }
635 
636  /*
637  * Calculate the transitive closure of the lateral_relids sets, so that
638  * they describe both direct and indirect lateral references. If relation
639  * X references Y laterally, and Y references Z laterally, then we will
640  * have to scan X on the inside of a nestloop with Z, so for all intents
641  * and purposes X is laterally dependent on Z too.
642  *
643  * This code is essentially Warshall's algorithm for transitive closure.
644  * The outer loop considers each baserel, and propagates its lateral
645  * dependencies to those baserels that have a lateral dependency on it.
646  */
647  for (rti = 1; rti < root->simple_rel_array_size; rti++)
648  {
649  RelOptInfo *brel = root->simple_rel_array[rti];
650  Relids outer_lateral_relids;
651  Index rti2;
652 
653  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
654  continue;
655 
656  /* need not consider baserel further if it has no lateral refs */
657  outer_lateral_relids = brel->lateral_relids;
658  if (outer_lateral_relids == NULL)
659  continue;
660 
661  /* else scan all baserels */
662  for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
663  {
664  RelOptInfo *brel2 = root->simple_rel_array[rti2];
665 
666  if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
667  continue;
668 
669  /* if brel2 has lateral ref to brel, propagate brel's refs */
670  if (bms_is_member(rti, brel2->lateral_relids))
672  outer_lateral_relids);
673  }
674  }
675 
676  /*
677  * Now that we've identified all lateral references, mark each baserel
678  * with the set of relids of rels that reference it laterally (possibly
679  * indirectly) --- that is, the inverse mapping of lateral_relids.
680  */
681  for (rti = 1; rti < root->simple_rel_array_size; rti++)
682  {
683  RelOptInfo *brel = root->simple_rel_array[rti];
684  Relids lateral_relids;
685  int rti2;
686 
687  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
688  continue;
689 
690  /* Nothing to do at rels with no lateral refs */
691  lateral_relids = brel->lateral_relids;
692  if (bms_is_empty(lateral_relids))
693  continue;
694 
695  /* No rel should have a lateral dependency on itself */
696  Assert(!bms_is_member(rti, lateral_relids));
697 
698  /* Mark this rel's referencees */
699  rti2 = -1;
700  while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
701  {
702  RelOptInfo *brel2 = root->simple_rel_array[rti2];
703 
704  if (brel2 == NULL)
705  continue; /* must be an OJ */
706 
707  Assert(brel2->reloptkind == RELOPT_BASEREL);
708  brel2->lateral_referencers =
709  bms_add_member(brel2->lateral_referencers, rti);
710  }
711  }
712 }
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:601
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:447
Relids ph_lateral
Definition: pathnodes.h:3065
Relids ph_eval_at
Definition: pathnodes.h:3062
bool hasLateralRTEs
Definition: pathnodes.h:491
List * placeholder_list
Definition: pathnodes.h:371
bool placeholdersFrozen
Definition: pathnodes.h:499
Relids all_baserels
Definition: pathnodes.h:252
Index relid
Definition: pathnodes.h:903
List * lateral_vars
Definition: pathnodes.h:921
Relids lateral_relids
Definition: pathnodes.h:898
Relids lateral_referencers
Definition: pathnodes.h:923
Relids direct_lateral_relids
Definition: pathnodes.h:896

References PlannerInfo::all_baserels, 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(), PlannerInfo::hasLateralRTEs, IsA, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, lfirst, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_lateral, PlannerInfo::placeholder_list, PlannerInfo::placeholdersFrozen, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array_size, and Var::varno.

Referenced by query_planner().

◆ deconstruct_distribute()

static void deconstruct_distribute ( PlannerInfo root,
JoinTreeItem jtitem 
)
static

Definition at line 1119 of file initsplan.c.

1120 {
1121  Node *jtnode = jtitem->jtnode;
1122 
1123  if (IsA(jtnode, RangeTblRef))
1124  {
1125  int varno = ((RangeTblRef *) jtnode)->rtindex;
1126 
1127  /* Deal with any securityQuals attached to the RTE */
1128  if (root->qual_security_level > 0)
1130  varno,
1131  jtitem);
1132  }
1133  else if (IsA(jtnode, FromExpr))
1134  {
1135  FromExpr *f = (FromExpr *) jtnode;
1136 
1137  /*
1138  * Process any lateral-referencing quals that were postponed to this
1139  * level by children.
1140  */
1142  jtitem,
1143  NULL,
1144  root->qual_security_level,
1145  jtitem->qualscope,
1146  NULL, NULL, NULL,
1147  true, false, false,
1148  NULL);
1149 
1150  /*
1151  * Now process the top-level quals.
1152  */
1153  distribute_quals_to_rels(root, (List *) f->quals,
1154  jtitem,
1155  NULL,
1156  root->qual_security_level,
1157  jtitem->qualscope,
1158  NULL, NULL, NULL,
1159  true, false, false,
1160  NULL);
1161  }
1162  else if (IsA(jtnode, JoinExpr))
1163  {
1164  JoinExpr *j = (JoinExpr *) jtnode;
1165  Relids ojscope;
1166  List *my_quals;
1167  SpecialJoinInfo *sjinfo;
1168  List **postponed_oj_qual_list;
1169 
1170  /*
1171  * Include lateral-referencing quals postponed from children in
1172  * my_quals, so that they'll be handled properly in
1173  * make_outerjoininfo. (This is destructive to
1174  * jtitem->lateral_clauses, but we won't use that again.)
1175  */
1176  my_quals = list_concat(jtitem->lateral_clauses,
1177  (List *) j->quals);
1178 
1179  /*
1180  * For an OJ, form the SpecialJoinInfo now, so that we can pass it to
1181  * distribute_qual_to_rels. We must compute its ojscope too.
1182  *
1183  * Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we
1184  * want ojscope = NULL for distribute_qual_to_rels.
1185  */
1186  if (j->jointype != JOIN_INNER)
1187  {
1188  sjinfo = make_outerjoininfo(root,
1189  jtitem->left_rels,
1190  jtitem->right_rels,
1191  jtitem->inner_join_rels,
1192  j->jointype,
1193  j->rtindex,
1194  my_quals);
1195  jtitem->sjinfo = sjinfo;
1196  if (j->jointype == JOIN_SEMI)
1197  ojscope = NULL;
1198  else
1199  ojscope = bms_union(sjinfo->min_lefthand,
1200  sjinfo->min_righthand);
1201  }
1202  else
1203  {
1204  sjinfo = NULL;
1205  ojscope = NULL;
1206  }
1207 
1208  /*
1209  * If it's a left join with a join clause that is strict for the LHS,
1210  * then we need to postpone handling of any non-degenerate join
1211  * clauses, in case the join is able to commute with another left join
1212  * per identity 3. (Degenerate clauses need not be postponed, since
1213  * they will drop down below this join anyway.)
1214  */
1215  if (j->jointype == JOIN_LEFT && sjinfo->lhs_strict)
1216  {
1217  postponed_oj_qual_list = &jtitem->oj_joinclauses;
1218 
1219  /*
1220  * Add back any commutable lower OJ relids that were removed from
1221  * min_lefthand or min_righthand, else the ojscope cross-check in
1222  * distribute_qual_to_rels will complain. Since we are postponing
1223  * processing of non-degenerate clauses, this addition doesn't
1224  * affect anything except that cross-check. Real clause
1225  * positioning decisions will be made later, when we revisit the
1226  * postponed clauses.
1227  */
1228  ojscope = bms_add_members(ojscope, sjinfo->commute_below_l);
1229  ojscope = bms_add_members(ojscope, sjinfo->commute_below_r);
1230  }
1231  else
1232  postponed_oj_qual_list = NULL;
1233 
1234  /* Process the JOIN's qual clauses */
1235  distribute_quals_to_rels(root, my_quals,
1236  jtitem,
1237  sjinfo,
1238  root->qual_security_level,
1239  jtitem->qualscope,
1240  ojscope, jtitem->nonnullable_rels,
1241  NULL, /* incompatible_relids */
1242  true, /* allow_equivalence */
1243  false, false, /* not clones */
1244  postponed_oj_qual_list);
1245 
1246  /* And add the SpecialJoinInfo to join_info_list */
1247  if (sjinfo)
1248  root->join_info_list = lappend(root->join_info_list, sjinfo);
1249  }
1250  else
1251  {
1252  elog(ERROR, "unrecognized node type: %d",
1253  (int) nodeTag(jtnode));
1254  }
1255 }
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:2118
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:1359
static void process_security_barrier_quals(PlannerInfo *root, int rti, JoinTreeItem *jtitem)
Definition: initsplan.c:1271
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
@ JOIN_INNER
Definition: nodes.h:283
@ JOIN_LEFT
Definition: nodes.h:284
Node * quals
Definition: primnodes.h:2062
SpecialJoinInfo * sjinfo
Definition: initsplan.c:75
Relids inner_join_rels
Definition: initsplan.c:67
Relids left_rels
Definition: initsplan.c:70
Relids right_rels
Definition: initsplan.c:71
Relids nonnullable_rels
Definition: initsplan.c:72
Node * jtnode
Definition: initsplan.c:61
List * oj_joinclauses
Definition: initsplan.c:76
Relids qualscope
Definition: initsplan.c:65
List * lateral_clauses
Definition: initsplan.c:77
Index qual_security_level
Definition: pathnodes.h:486
Relids min_righthand
Definition: pathnodes.h:2869
Relids commute_below_l
Definition: pathnodes.h:2876
Relids min_lefthand
Definition: pathnodes.h:2868
Relids commute_below_r
Definition: pathnodes.h:2877

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, PlannerInfo::join_info_list, 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(), PlannerInfo::qual_security_level, FromExpr::quals, JoinTreeItem::qualscope, JoinTreeItem::right_rels, 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 1877 of file initsplan.c.

1880 {
1881  SpecialJoinInfo *sjinfo = jtitem->sjinfo;
1882  Relids qualscope,
1883  ojscope,
1884  nonnullable_rels;
1885 
1886  /* Recompute syntactic and semantic scopes of this left join */
1887  qualscope = bms_union(sjinfo->syn_lefthand, sjinfo->syn_righthand);
1888  qualscope = bms_add_member(qualscope, sjinfo->ojrelid);
1889  ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
1890  nonnullable_rels = sjinfo->syn_lefthand;
1891 
1892  /*
1893  * If this join can commute with any other ones per outer-join identity 3,
1894  * and it is the one providing the join clause with flexible semantics,
1895  * then we have to generate variants of the join clause with different
1896  * nullingrels labeling. Otherwise, just push out the postponed clause
1897  * as-is.
1898  */
1899  Assert(sjinfo->lhs_strict); /* else we shouldn't be here */
1900  if (sjinfo->commute_above_r || sjinfo->commute_below_l)
1901  {
1902  Relids joins_above;
1903  Relids joins_below;
1904  Relids incompatible_joins;
1905  Relids joins_so_far;
1906  List *quals;
1907  int save_last_rinfo_serial;
1908  ListCell *lc;
1909 
1910  /* Identify the outer joins this one commutes with */
1911  joins_above = sjinfo->commute_above_r;
1912  joins_below = sjinfo->commute_below_l;
1913 
1914  /*
1915  * Generate qual variants with different sets of nullingrels bits.
1916  *
1917  * We only need bit-sets that correspond to the successively less
1918  * deeply syntactically-nested subsets of this join and its
1919  * commutators. That's true first because obviously only those forms
1920  * of the Vars and PHVs could appear elsewhere in the query, and
1921  * second because the outer join identities do not provide a way to
1922  * re-order such joins in a way that would require different marking.
1923  * (That is, while the current join may commute with several others,
1924  * none of those others can commute with each other.) To visit the
1925  * interesting joins in syntactic nesting order, we rely on the
1926  * jtitems list to be ordered that way.
1927  *
1928  * We first strip out all the nullingrels bits corresponding to
1929  * commuting joins below this one, and then successively put them back
1930  * as we crawl up the join stack.
1931  */
1932  quals = jtitem->oj_joinclauses;
1933  if (!bms_is_empty(joins_below))
1934  quals = (List *) remove_nulling_relids((Node *) quals,
1935  joins_below,
1936  NULL);
1937 
1938  /*
1939  * We'll need to mark the lower versions of the quals as not safe to
1940  * apply above not-yet-processed joins of the stack. This prevents
1941  * possibly applying a cloned qual at the wrong join level.
1942  */
1943  incompatible_joins = bms_union(joins_below, joins_above);
1944  incompatible_joins = bms_add_member(incompatible_joins,
1945  sjinfo->ojrelid);
1946 
1947  /*
1948  * Each time we produce RestrictInfo(s) from these quals, reset the
1949  * last_rinfo_serial counter, so that the RestrictInfos for the "same"
1950  * qual condition get identical serial numbers. (This relies on the
1951  * fact that we're not changing the qual list in any way that'd affect
1952  * the number of RestrictInfos built from it.) This'll allow us to
1953  * detect duplicative qual usage later.
1954  */
1955  save_last_rinfo_serial = root->last_rinfo_serial;
1956 
1957  joins_so_far = NULL;
1958  foreach(lc, jtitems)
1959  {
1960  JoinTreeItem *otherjtitem = (JoinTreeItem *) lfirst(lc);
1961  SpecialJoinInfo *othersj = otherjtitem->sjinfo;
1962  bool below_sjinfo = false;
1963  bool above_sjinfo = false;
1964  Relids this_qualscope;
1965  Relids this_ojscope;
1966  bool allow_equivalence,
1967  has_clone,
1968  is_clone;
1969 
1970  if (othersj == NULL)
1971  continue; /* not an outer-join item, ignore */
1972 
1973  if (bms_is_member(othersj->ojrelid, joins_below))
1974  {
1975  /* othersj commutes with sjinfo from below left */
1976  below_sjinfo = true;
1977  }
1978  else if (othersj == sjinfo)
1979  {
1980  /* found our join in syntactic order */
1981  Assert(bms_equal(joins_so_far, joins_below));
1982  }
1983  else if (bms_is_member(othersj->ojrelid, joins_above))
1984  {
1985  /* othersj commutes with sjinfo from above */
1986  above_sjinfo = true;
1987  }
1988  else
1989  {
1990  /* othersj is not relevant, ignore */
1991  continue;
1992  }
1993 
1994  /* Reset serial counter for this version of the quals */
1995  root->last_rinfo_serial = save_last_rinfo_serial;
1996 
1997  /*
1998  * When we are looking at joins above sjinfo, we are envisioning
1999  * pushing sjinfo to above othersj, so add othersj's nulling bit
2000  * before distributing the quals. We should add it to Vars coming
2001  * from the current join's LHS: we want to transform the second
2002  * form of OJ identity 3 to the first form, in which Vars of
2003  * relation B will appear nulled by the syntactically-upper OJ
2004  * within the Pbc clause, but those of relation C will not. (In
2005  * the notation used by optimizer/README, we're converting a qual
2006  * of the form Pbc to Pb*c.) Of course, we must also remove that
2007  * bit from the incompatible_joins value, else we'll make a qual
2008  * that can't be placed anywhere.
2009  */
2010  if (above_sjinfo)
2011  {
2012  quals = (List *)
2013  add_nulling_relids((Node *) quals,
2014  sjinfo->syn_lefthand,
2015  bms_make_singleton(othersj->ojrelid));
2016  incompatible_joins = bms_del_member(incompatible_joins,
2017  othersj->ojrelid);
2018  }
2019 
2020  /* Compute qualscope and ojscope for this join level */
2021  this_qualscope = bms_union(qualscope, joins_so_far);
2022  this_ojscope = bms_union(ojscope, joins_so_far);
2023  if (above_sjinfo)
2024  {
2025  /* othersj is not yet in joins_so_far, but we need it */
2026  this_qualscope = bms_add_member(this_qualscope,
2027  othersj->ojrelid);
2028  this_ojscope = bms_add_member(this_ojscope,
2029  othersj->ojrelid);
2030  /* sjinfo is in joins_so_far, and we don't want it */
2031  this_ojscope = bms_del_member(this_ojscope,
2032  sjinfo->ojrelid);
2033  }
2034 
2035  /*
2036  * We generate EquivalenceClasses only from the first form of the
2037  * quals, with the fewest nullingrels bits set. An EC made from
2038  * this version of the quals can be useful below the outer-join
2039  * nest, whereas versions with some nullingrels bits set would not
2040  * be. We cannot generate ECs from more than one version, or
2041  * we'll make nonsensical conclusions that Vars with nullingrels
2042  * bits set are equal to their versions without. Fortunately,
2043  * such ECs wouldn't be very useful anyway, because they'd equate
2044  * values not observable outside the join nest. (See
2045  * optimizer/README.)
2046  *
2047  * The first form of the quals is also the only one marked as
2048  * has_clone rather than is_clone.
2049  */
2050  allow_equivalence = (joins_so_far == NULL);
2051  has_clone = allow_equivalence;
2052  is_clone = !has_clone;
2053 
2054  distribute_quals_to_rels(root, quals,
2055  otherjtitem,
2056  sjinfo,
2057  root->qual_security_level,
2058  this_qualscope,
2059  this_ojscope, nonnullable_rels,
2060  bms_copy(incompatible_joins),
2061  allow_equivalence,
2062  has_clone,
2063  is_clone,
2064  NULL); /* no more postponement */
2065 
2066  /*
2067  * Adjust qual nulling bits for next level up, if needed. We
2068  * don't want to put sjinfo's own bit in at all, and if we're
2069  * above sjinfo then we did it already. Here, we should mark all
2070  * Vars coming from the lower join's RHS. (Again, we are
2071  * converting a qual of the form Pbc to Pb*c, but now we are
2072  * putting back bits that were there in the parser output and were
2073  * temporarily stripped above.) Update incompatible_joins too.
2074  */
2075  if (below_sjinfo)
2076  {
2077  quals = (List *)
2078  add_nulling_relids((Node *) quals,
2079  othersj->syn_righthand,
2080  bms_make_singleton(othersj->ojrelid));
2081  incompatible_joins = bms_del_member(incompatible_joins,
2082  othersj->ojrelid);
2083  }
2084 
2085  /* ... and track joins processed so far */
2086  joins_so_far = bms_add_member(joins_so_far, othersj->ojrelid);
2087  }
2088  }
2089  else
2090  {
2091  /* No commutation possible, just process the postponed clauses */
2093  jtitem,
2094  sjinfo,
2095  root->qual_security_level,
2096  qualscope,
2097  ojscope, nonnullable_rels,
2098  NULL, /* incompatible_relids */
2099  true, /* allow_equivalence */
2100  false, false, /* not clones */
2101  NULL); /* no more postponement */
2102  }
2103 }
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)
int last_rinfo_serial
Definition: pathnodes.h:340
Relids commute_above_r
Definition: pathnodes.h:2875
Relids syn_lefthand
Definition: pathnodes.h:2870

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(), PlannerInfo::last_rinfo_serial, lfirst, SpecialJoinInfo::lhs_strict, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, JoinTreeItem::nonnullable_rels, JoinTreeItem::oj_joinclauses, SpecialJoinInfo::ojrelid, PlannerInfo::qual_security_level, JoinTreeItem::qualscope, remove_nulling_relids(), JoinTreeItem::sjinfo, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.

Referenced by deconstruct_jointree().

◆ deconstruct_jointree()

List* deconstruct_jointree ( PlannerInfo root)

Definition at line 739 of file initsplan.c.

740 {
741  List *result;
742  JoinDomain *top_jdomain;
743  List *item_list = NIL;
744  ListCell *lc;
745 
746  /*
747  * After this point, no more PlaceHolderInfos may be made, because
748  * make_outerjoininfo requires all active placeholders to be present in
749  * root->placeholder_list while we crawl up the join tree.
750  */
751  root->placeholdersFrozen = true;
752 
753  /* Fetch the already-created top-level join domain for the query */
754  top_jdomain = linitial_node(JoinDomain, root->join_domains);
755  top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
756 
757  /* Start recursion at top of jointree */
758  Assert(root->parse->jointree != NULL &&
759  IsA(root->parse->jointree, FromExpr));
760 
761  /* These are filled as we scan the jointree */
762  root->all_baserels = NULL;
763  root->outer_join_rels = NULL;
764 
765  /* Perform the initial scan of the jointree */
766  result = deconstruct_recurse(root, (Node *) root->parse->jointree,
767  top_jdomain, NULL,
768  &item_list);
769 
770  /* Now we can form the value of all_query_rels, too */
772 
773  /* ... which should match what we computed for the top join domain */
774  Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
775 
776  /* Now scan all the jointree nodes again, and distribute quals */
777  foreach(lc, item_list)
778  {
779  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
780 
781  deconstruct_distribute(root, jtitem);
782  }
783 
784  /*
785  * If there were any special joins then we may have some postponed LEFT
786  * JOIN clauses to deal with.
787  */
788  if (root->join_info_list)
789  {
790  foreach(lc, item_list)
791  {
792  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
793 
794  if (jtitem->oj_joinclauses != NIL)
795  deconstruct_distribute_oj_quals(root, item_list, jtitem);
796  }
797  }
798 
799  /* Don't need the JoinTreeItems any more */
800  list_free_deep(item_list);
801 
802  return result;
803 }
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, JoinTreeItem *parent_jtitem, List **item_list)
Definition: initsplan.c:821
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:1877
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition: initsplan.c:1119
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:1308
Relids all_query_rels
Definition: pathnodes.h:266
Relids outer_join_rels
Definition: pathnodes.h:258
List * join_domains
Definition: pathnodes.h:308
FromExpr * jointree
Definition: parsenodes.h:175

References PlannerInfo::all_baserels, PlannerInfo::all_query_rels, Assert(), bms_equal(), bms_union(), deconstruct_distribute(), deconstruct_distribute_oj_quals(), deconstruct_recurse(), IsA, JoinDomain::jd_relids, PlannerInfo::join_domains, PlannerInfo::join_info_list, Query::jointree, lfirst, linitial_node, list_free_deep(), NIL, JoinTreeItem::oj_joinclauses, PlannerInfo::outer_join_rels, PlannerInfo::parse, and PlannerInfo::placeholdersFrozen.

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 821 of file initsplan.c.

825 {
826  List *joinlist;
827  JoinTreeItem *jtitem;
828 
829  Assert(jtnode != NULL);
830 
831  /* Make the new JoinTreeItem, but don't add it to item_list yet */
832  jtitem = palloc0_object(JoinTreeItem);
833  jtitem->jtnode = jtnode;
834  jtitem->jti_parent = parent_jtitem;
835 
836  if (IsA(jtnode, RangeTblRef))
837  {
838  int varno = ((RangeTblRef *) jtnode)->rtindex;
839 
840  /* Fill all_baserels as we encounter baserel jointree nodes */
841  root->all_baserels = bms_add_member(root->all_baserels, varno);
842  /* This node belongs to parent_domain */
843  jtitem->jdomain = parent_domain;
844  parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
845  varno);
846  /* qualscope is just the one RTE */
847  jtitem->qualscope = bms_make_singleton(varno);
848  /* A single baserel does not create an inner join */
849  jtitem->inner_join_rels = NULL;
850  joinlist = list_make1(jtnode);
851  }
852  else if (IsA(jtnode, FromExpr))
853  {
854  FromExpr *f = (FromExpr *) jtnode;
855  int remaining;
856  ListCell *l;
857 
858  /* This node belongs to parent_domain, as do its children */
859  jtitem->jdomain = parent_domain;
860 
861  /*
862  * Recurse to handle child nodes, and compute output joinlist. We
863  * collapse subproblems into a single joinlist whenever the resulting
864  * joinlist wouldn't exceed from_collapse_limit members. Also, always
865  * collapse one-element subproblems, since that won't lengthen the
866  * joinlist anyway.
867  */
868  jtitem->qualscope = NULL;
869  jtitem->inner_join_rels = NULL;
870  joinlist = NIL;
872  foreach(l, f->fromlist)
873  {
874  JoinTreeItem *sub_item;
875  List *sub_joinlist;
876  int sub_members;
877 
878  sub_joinlist = deconstruct_recurse(root, lfirst(l),
879  parent_domain,
880  jtitem,
881  item_list);
882  sub_item = (JoinTreeItem *) llast(*item_list);
883  jtitem->qualscope = bms_add_members(jtitem->qualscope,
884  sub_item->qualscope);
885  jtitem->inner_join_rels = sub_item->inner_join_rels;
886  sub_members = list_length(sub_joinlist);
887  remaining--;
888  if (sub_members <= 1 ||
889  list_length(joinlist) + sub_members + remaining <= from_collapse_limit)
890  joinlist = list_concat(joinlist, sub_joinlist);
891  else
892  joinlist = lappend(joinlist, sub_joinlist);
893  }
894 
895  /*
896  * A FROM with more than one list element is an inner join subsuming
897  * all below it, so we should report inner_join_rels = qualscope. If
898  * there was exactly one element, we should (and already did) report
899  * whatever its inner_join_rels were. If there were no elements (is
900  * that still possible?) the initialization before the loop fixed it.
901  */
902  if (list_length(f->fromlist) > 1)
903  jtitem->inner_join_rels = jtitem->qualscope;
904  }
905  else if (IsA(jtnode, JoinExpr))
906  {
907  JoinExpr *j = (JoinExpr *) jtnode;
908  JoinDomain *child_domain,
909  *fj_domain;
910  JoinTreeItem *left_item,
911  *right_item;
912  List *leftjoinlist,
913  *rightjoinlist;
914 
915  switch (j->jointype)
916  {
917  case JOIN_INNER:
918  /* This node belongs to parent_domain, as do its children */
919  jtitem->jdomain = parent_domain;
920  /* Recurse */
921  leftjoinlist = deconstruct_recurse(root, j->larg,
922  parent_domain,
923  jtitem,
924  item_list);
925  left_item = (JoinTreeItem *) llast(*item_list);
926  rightjoinlist = deconstruct_recurse(root, j->rarg,
927  parent_domain,
928  jtitem,
929  item_list);
930  right_item = (JoinTreeItem *) llast(*item_list);
931  /* Compute qualscope etc */
932  jtitem->qualscope = bms_union(left_item->qualscope,
933  right_item->qualscope);
934  jtitem->inner_join_rels = jtitem->qualscope;
935  jtitem->left_rels = left_item->qualscope;
936  jtitem->right_rels = right_item->qualscope;
937  /* Inner join adds no restrictions for quals */
938  jtitem->nonnullable_rels = NULL;
939  break;
940  case JOIN_LEFT:
941  case JOIN_ANTI:
942  /* Make new join domain for my quals and the RHS */
943  child_domain = makeNode(JoinDomain);
944  child_domain->jd_relids = NULL; /* filled by recursion */
945  root->join_domains = lappend(root->join_domains, child_domain);
946  jtitem->jdomain = child_domain;
947  /* Recurse */
948  leftjoinlist = deconstruct_recurse(root, j->larg,
949  parent_domain,
950  jtitem,
951  item_list);
952  left_item = (JoinTreeItem *) llast(*item_list);
953  rightjoinlist = deconstruct_recurse(root, j->rarg,
954  child_domain,
955  jtitem,
956  item_list);
957  right_item = (JoinTreeItem *) llast(*item_list);
958  /* Compute join domain contents, qualscope etc */
959  parent_domain->jd_relids =
960  bms_add_members(parent_domain->jd_relids,
961  child_domain->jd_relids);
962  jtitem->qualscope = bms_union(left_item->qualscope,
963  right_item->qualscope);
964  /* caution: ANTI join derived from SEMI will lack rtindex */
965  if (j->rtindex != 0)
966  {
967  parent_domain->jd_relids =
968  bms_add_member(parent_domain->jd_relids,
969  j->rtindex);
970  jtitem->qualscope = bms_add_member(jtitem->qualscope,
971  j->rtindex);
973  j->rtindex);
974  mark_rels_nulled_by_join(root, j->rtindex,
975  right_item->qualscope);
976  }
977  jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
978  right_item->inner_join_rels);
979  jtitem->left_rels = left_item->qualscope;
980  jtitem->right_rels = right_item->qualscope;
981  jtitem->nonnullable_rels = left_item->qualscope;
982  break;
983  case JOIN_SEMI:
984  /* This node belongs to parent_domain, as do its children */
985  jtitem->jdomain = parent_domain;
986  /* Recurse */
987  leftjoinlist = deconstruct_recurse(root, j->larg,
988  parent_domain,
989  jtitem,
990  item_list);
991  left_item = (JoinTreeItem *) llast(*item_list);
992  rightjoinlist = deconstruct_recurse(root, j->rarg,
993  parent_domain,
994  jtitem,
995  item_list);
996  right_item = (JoinTreeItem *) llast(*item_list);
997  /* Compute qualscope etc */
998  jtitem->qualscope = bms_union(left_item->qualscope,
999  right_item->qualscope);
1000  /* SEMI join never has rtindex, so don't add to anything */
1001  Assert(j->rtindex == 0);
1002  jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1003  right_item->inner_join_rels);
1004  jtitem->left_rels = left_item->qualscope;
1005  jtitem->right_rels = right_item->qualscope;
1006  /* Semi join adds no restrictions for quals */
1007  jtitem->nonnullable_rels = NULL;
1008  break;
1009  case JOIN_FULL:
1010  /* The FULL JOIN's quals need their very own domain */
1011  fj_domain = makeNode(JoinDomain);
1012  root->join_domains = lappend(root->join_domains, fj_domain);
1013  jtitem->jdomain = fj_domain;
1014  /* Recurse, giving each side its own join domain */
1015  child_domain = makeNode(JoinDomain);
1016  child_domain->jd_relids = NULL; /* filled by recursion */
1017  root->join_domains = lappend(root->join_domains, child_domain);
1018  leftjoinlist = deconstruct_recurse(root, j->larg,
1019  child_domain,
1020  jtitem,
1021  item_list);
1022  left_item = (JoinTreeItem *) llast(*item_list);
1023  fj_domain->jd_relids = bms_copy(child_domain->jd_relids);
1024  child_domain = makeNode(JoinDomain);
1025  child_domain->jd_relids = NULL; /* filled by recursion */
1026  root->join_domains = lappend(root->join_domains, child_domain);
1027  rightjoinlist = deconstruct_recurse(root, j->rarg,
1028  child_domain,
1029  jtitem,
1030  item_list);
1031  right_item = (JoinTreeItem *) llast(*item_list);
1032  /* Compute qualscope etc */
1033  fj_domain->jd_relids = bms_add_members(fj_domain->jd_relids,
1034  child_domain->jd_relids);
1035  parent_domain->jd_relids = bms_add_members(parent_domain->jd_relids,
1036  fj_domain->jd_relids);
1037  jtitem->qualscope = bms_union(left_item->qualscope,
1038  right_item->qualscope);
1039  Assert(j->rtindex != 0);
1040  parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
1041  j->rtindex);
1042  jtitem->qualscope = bms_add_member(jtitem->qualscope,
1043  j->rtindex);
1045  j->rtindex);
1046  mark_rels_nulled_by_join(root, j->rtindex,
1047  left_item->qualscope);
1048  mark_rels_nulled_by_join(root, j->rtindex,
1049  right_item->qualscope);
1050  jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1051  right_item->inner_join_rels);
1052  jtitem->left_rels = left_item->qualscope;
1053  jtitem->right_rels = right_item->qualscope;
1054  /* each side is both outer and inner */
1055  jtitem->nonnullable_rels = jtitem->qualscope;
1056  break;
1057  default:
1058  /* JOIN_RIGHT was eliminated during reduce_outer_joins() */
1059  elog(ERROR, "unrecognized join type: %d",
1060  (int) j->jointype);
1061  leftjoinlist = rightjoinlist = NIL; /* keep compiler quiet */
1062  break;
1063  }
1064 
1065  /*
1066  * Compute the output joinlist. We fold subproblems together except
1067  * at a FULL JOIN or where join_collapse_limit would be exceeded.
1068  */
1069  if (j->jointype == JOIN_FULL)
1070  {
1071  /* force the join order exactly at this node */
1072  joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist));
1073  }
1074  else if (list_length(leftjoinlist) + list_length(rightjoinlist) <=
1076  {
1077  /* OK to combine subproblems */
1078  joinlist = list_concat(leftjoinlist, rightjoinlist);
1079  }
1080  else
1081  {
1082  /* can't combine, but needn't force join order above here */
1083  Node *leftpart,
1084  *rightpart;
1085 
1086  /* avoid creating useless 1-element sublists */
1087  if (list_length(leftjoinlist) == 1)
1088  leftpart = (Node *) linitial(leftjoinlist);
1089  else
1090  leftpart = (Node *) leftjoinlist;
1091  if (list_length(rightjoinlist) == 1)
1092  rightpart = (Node *) linitial(rightjoinlist);
1093  else
1094  rightpart = (Node *) rightjoinlist;
1095  joinlist = list_make2(leftpart, rightpart);
1096  }
1097  }
1098  else
1099  {
1100  elog(ERROR, "unrecognized node type: %d",
1101  (int) nodeTag(jtnode));
1102  joinlist = NIL; /* keep compiler quiet */
1103  }
1104 
1105  /* Finally, we can add the new JoinTreeItem to item_list */
1106  *item_list = lappend(*item_list, jtitem);
1107 
1108  return joinlist;
1109 }
#define palloc0_object(type)
Definition: fe_memutils.h:63
int remaining
Definition: informix.c:667
int join_collapse_limit
Definition: initsplan.c:38
int from_collapse_limit
Definition: initsplan.c:37
static void mark_rels_nulled_by_join(PlannerInfo *root, Index ojrelid, Relids lower_rels)
Definition: initsplan.c:1321
#define makeNode(_type_)
Definition: nodes.h:155
@ JOIN_FULL
Definition: nodes.h:285
#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:63
JoinDomain * jdomain
Definition: initsplan.c:62

References PlannerInfo::all_baserels, 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, PlannerInfo::join_domains, 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, PlannerInfo::outer_join_rels, palloc0_object, JoinTreeItem::qualscope, remaining, and JoinTreeItem::right_rels.

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 2196 of file initsplan.c.

2208 {
2209  Relids relids;
2210  bool is_pushed_down;
2211  bool pseudoconstant = false;
2212  bool maybe_equivalence;
2213  bool maybe_outer_join;
2214  RestrictInfo *restrictinfo;
2215 
2216  /*
2217  * Retrieve all relids mentioned within the clause.
2218  */
2219  relids = pull_varnos(root, clause);
2220 
2221  /*
2222  * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels
2223  * that aren't within its syntactic scope; however, if we pulled up a
2224  * LATERAL subquery then we might find such references in quals that have
2225  * been pulled up. We need to treat such quals as belonging to the join
2226  * level that includes every rel they reference. Although we could make
2227  * pull_up_subqueries() place such quals correctly to begin with, it's
2228  * easier to handle it here. When we find a clause that contains Vars
2229  * outside its syntactic scope, locate the nearest parent join level that
2230  * includes all the required rels and add the clause to that level's
2231  * lateral_clauses list. We'll process it when we reach that join level.
2232  */
2233  if (!bms_is_subset(relids, qualscope))
2234  {
2235  JoinTreeItem *pitem;
2236 
2237  Assert(root->hasLateralRTEs); /* shouldn't happen otherwise */
2238  Assert(sjinfo == NULL); /* mustn't postpone past outer join */
2239  for (pitem = jtitem->jti_parent; pitem; pitem = pitem->jti_parent)
2240  {
2241  if (bms_is_subset(relids, pitem->qualscope))
2242  {
2243  pitem->lateral_clauses = lappend(pitem->lateral_clauses,
2244  clause);
2245  return;
2246  }
2247 
2248  /*
2249  * We should not be postponing any quals past an outer join. If
2250  * this Assert fires, pull_up_subqueries() messed up.
2251  */
2252  Assert(pitem->sjinfo == NULL);
2253  }
2254  elog(ERROR, "failed to postpone qual containing lateral reference");
2255  }
2256 
2257  /*
2258  * If it's an outer-join clause, also check that relids is a subset of
2259  * ojscope. (This should not fail if the syntactic scope check passed.)
2260  */
2261  if (ojscope && !bms_is_subset(relids, ojscope))
2262  elog(ERROR, "JOIN qualification cannot refer to other relations");
2263 
2264  /*
2265  * If the clause is variable-free, our normal heuristic for pushing it
2266  * down to just the mentioned rels doesn't work, because there are none.
2267  *
2268  * If the clause is an outer-join clause, we must force it to the OJ's
2269  * semantic level to preserve semantics.
2270  *
2271  * Otherwise, when the clause contains volatile functions, we force it to
2272  * be evaluated at its original syntactic level. This preserves the
2273  * expected semantics.
2274  *
2275  * When the clause contains no volatile functions either, it is actually a
2276  * pseudoconstant clause that will not change value during any one
2277  * execution of the plan, and hence can be used as a one-time qual in a
2278  * gating Result plan node. We put such a clause into the regular
2279  * RestrictInfo lists for the moment, but eventually createplan.c will
2280  * pull it out and make a gating Result node immediately above whatever
2281  * plan node the pseudoconstant clause is assigned to. It's usually best
2282  * to put a gating node as high in the plan tree as possible.
2283  */
2284  if (bms_is_empty(relids))
2285  {
2286  if (ojscope)
2287  {
2288  /* clause is attached to outer join, eval it there */
2289  relids = bms_copy(ojscope);
2290  /* mustn't use as gating qual, so don't mark pseudoconstant */
2291  }
2292  else if (contain_volatile_functions(clause))
2293  {
2294  /* eval at original syntactic level */
2295  relids = bms_copy(qualscope);
2296  /* again, can't mark pseudoconstant */
2297  }
2298  else
2299  {
2300  /*
2301  * If we are in the top-level join domain, we can push the qual to
2302  * the top of the plan tree. Otherwise, be conservative and eval
2303  * it at original syntactic level. (Ideally we'd push it to the
2304  * top of the current join domain in all cases, but that causes
2305  * problems if we later rearrange outer-join evaluation order.
2306  * Pseudoconstant quals below the top level are a pretty odd case,
2307  * so it's not clear that it's worth working hard on.)
2308  */
2309  if (jtitem->jdomain == (JoinDomain *) linitial(root->join_domains))
2310  relids = bms_copy(jtitem->jdomain->jd_relids);
2311  else
2312  relids = bms_copy(qualscope);
2313  /* mark as gating qual */
2314  pseudoconstant = true;
2315  /* tell createplan.c to check for gating quals */
2316  root->hasPseudoConstantQuals = true;
2317  }
2318  }
2319 
2320  /*----------
2321  * Check to see if clause application must be delayed by outer-join
2322  * considerations.
2323  *
2324  * A word about is_pushed_down: we mark the qual as "pushed down" if
2325  * it is (potentially) applicable at a level different from its original
2326  * syntactic level. This flag is used to distinguish OUTER JOIN ON quals
2327  * from other quals pushed down to the same joinrel. The rules are:
2328  * WHERE quals and INNER JOIN quals: is_pushed_down = true.
2329  * Non-degenerate OUTER JOIN quals: is_pushed_down = false.
2330  * Degenerate OUTER JOIN quals: is_pushed_down = true.
2331  * A "degenerate" OUTER JOIN qual is one that doesn't mention the
2332  * non-nullable side, and hence can be pushed down into the nullable side
2333  * without changing the join result. It is correct to treat it as a
2334  * regular filter condition at the level where it is evaluated.
2335  *
2336  * Note: it is not immediately obvious that a simple boolean is enough
2337  * for this: if for some reason we were to attach a degenerate qual to
2338  * its original join level, it would need to be treated as an outer join
2339  * qual there. However, this cannot happen, because all the rels the
2340  * clause mentions must be in the outer join's min_righthand, therefore
2341  * the join it needs must be formed before the outer join; and we always
2342  * attach quals to the lowest level where they can be evaluated. But
2343  * if we were ever to re-introduce a mechanism for delaying evaluation
2344  * of "expensive" quals, this area would need work.
2345  *
2346  * Note: generally, use of is_pushed_down has to go through the macro
2347  * RINFO_IS_PUSHED_DOWN, because that flag alone is not always sufficient
2348  * to tell whether a clause must be treated as pushed-down in context.
2349  * This seems like another reason why it should perhaps be rethought.
2350  *----------
2351  */
2352  if (bms_overlap(relids, outerjoin_nonnullable))
2353  {
2354  /*
2355  * The qual is attached to an outer join and mentions (some of the)
2356  * rels on the nonnullable side, so it's not degenerate. If the
2357  * caller wants to postpone handling such clauses, just add it to
2358  * postponed_oj_qual_list and return. (The work we've done up to here
2359  * will have to be redone later, but there's not much of it.)
2360  */
2361  if (postponed_oj_qual_list != NULL)
2362  {
2363  *postponed_oj_qual_list = lappend(*postponed_oj_qual_list, clause);
2364  return;
2365  }
2366 
2367  /*
2368  * We can't use such a clause to deduce equivalence (the left and
2369  * right sides might be unequal above the join because one of them has
2370  * gone to NULL) ... but we might be able to use it for more limited
2371  * deductions, if it is mergejoinable. So consider adding it to the
2372  * lists of set-aside outer-join clauses.
2373  */
2374  is_pushed_down = false;
2375  maybe_equivalence = false;
2376  maybe_outer_join = true;
2377 
2378  /*
2379  * Now force the qual to be evaluated exactly at the level of joining
2380  * corresponding to the outer join. We cannot let it get pushed down
2381  * into the nonnullable side, since then we'd produce no output rows,
2382  * rather than the intended single null-extended row, for any
2383  * nonnullable-side rows failing the qual.
2384  */
2385  Assert(ojscope);
2386  relids = ojscope;
2387  Assert(!pseudoconstant);
2388  }
2389  else
2390  {
2391  /*
2392  * Normal qual clause or degenerate outer-join clause. Either way, we
2393  * can mark it as pushed-down.
2394  */
2395  is_pushed_down = true;
2396 
2397  /*
2398  * It's possible that this is an IS NULL clause that's redundant with
2399  * a lower antijoin; if so we can just discard it. We need not test
2400  * in any of the other cases, because this will only be possible for
2401  * pushed-down clauses.
2402  */
2403  if (check_redundant_nullability_qual(root, clause))
2404  return;
2405 
2406  /* Feed qual to the equivalence machinery, if allowed by caller */
2407  maybe_equivalence = allow_equivalence;
2408 
2409  /*
2410  * Since it doesn't mention the LHS, it's certainly not useful as a
2411  * set-aside OJ clause, even if it's in an OJ.
2412  */
2413  maybe_outer_join = false;
2414  }
2415 
2416  /*
2417  * Build the RestrictInfo node itself.
2418  */
2419  restrictinfo = make_restrictinfo(root,
2420  (Expr *) clause,
2421  is_pushed_down,
2422  has_clone,
2423  is_clone,
2424  pseudoconstant,
2425  security_level,
2426  relids,
2427  incompatible_relids,
2428  outerjoin_nonnullable);
2429 
2430  /*
2431  * If it's a join clause, add vars used in the clause to targetlists of
2432  * their relations, so that they will be emitted by the plan nodes that
2433  * scan those relations (else they won't be available at the join node!).
2434  *
2435  * Normally we mark the vars as needed at the join identified by "relids".
2436  * However, if this is a clone clause then ignore the outer-join relids in
2437  * that set. Otherwise, vars appearing in a cloned clause would end up
2438  * marked as having to propagate to the highest one of the commuting
2439  * joins, which would often be an overestimate. For such clauses, correct
2440  * var propagation is ensured by making ojscope include input rels from
2441  * both sides of the join.
2442  *
2443  * Note: if the clause gets absorbed into an EquivalenceClass then this
2444  * may be unnecessary, but for now we have to do it to cover the case
2445  * where the EC becomes ec_broken and we end up reinserting the original
2446  * clauses into the plan.
2447  */
2448  if (bms_membership(relids) == BMS_MULTIPLE)
2449  {
2450  List *vars = pull_var_clause(clause,
2454  Relids where_needed;
2455 
2456  if (is_clone)
2457  where_needed = bms_intersect(relids, root->all_baserels);
2458  else
2459  where_needed = relids;
2460  add_vars_to_targetlist(root, vars, where_needed);
2461  list_free(vars);
2462  }
2463 
2464  /*
2465  * We check "mergejoinability" of every clause, not only join clauses,
2466  * because we want to know about equivalences between vars of the same
2467  * relation, or between vars and consts.
2468  */
2469  check_mergejoinable(restrictinfo);
2470 
2471  /*
2472  * If it is a true equivalence clause, send it to the EquivalenceClass
2473  * machinery. We do *not* attach it directly to any restriction or join
2474  * lists. The EC code will propagate it to the appropriate places later.
2475  *
2476  * If the clause has a mergejoinable operator, yet isn't an equivalence
2477  * because it is an outer-join clause, the EC code may still be able to do
2478  * something with it. We add it to appropriate lists for further
2479  * consideration later. Specifically:
2480  *
2481  * If it is a left or right outer-join qualification that relates the two
2482  * sides of the outer join (no funny business like leftvar1 = leftvar2 +
2483  * rightvar), we add it to root->left_join_clauses or
2484  * root->right_join_clauses according to which side the nonnullable
2485  * variable appears on.
2486  *
2487  * If it is a full outer-join qualification, we add it to
2488  * root->full_join_clauses. (Ideally we'd discard cases that aren't
2489  * leftvar = rightvar, as we do for left/right joins, but this routine
2490  * doesn't have the info needed to do that; and the current usage of the
2491  * full_join_clauses list doesn't require that, so it's not currently
2492  * worth complicating this routine's API to make it possible.)
2493  *
2494  * If none of the above hold, pass it off to
2495  * distribute_restrictinfo_to_rels().
2496  *
2497  * In all cases, it's important to initialize the left_ec and right_ec
2498  * fields of a mergejoinable clause, so that all possibly mergejoinable
2499  * expressions have representations in EquivalenceClasses. If
2500  * process_equivalence is successful, it will take care of that;
2501  * otherwise, we have to call initialize_mergeclause_eclasses to do it.
2502  */
2503  if (restrictinfo->mergeopfamilies)
2504  {
2505  if (maybe_equivalence)
2506  {
2507  if (process_equivalence(root, &restrictinfo, jtitem->jdomain))
2508  return;
2509  /* EC rejected it, so set left_ec/right_ec the hard way ... */
2510  if (restrictinfo->mergeopfamilies) /* EC might have changed this */
2511  initialize_mergeclause_eclasses(root, restrictinfo);
2512  /* ... and fall through to distribute_restrictinfo_to_rels */
2513  }
2514  else if (maybe_outer_join && restrictinfo->can_join)
2515  {
2516  /* we need to set up left_ec/right_ec the hard way */
2517  initialize_mergeclause_eclasses(root, restrictinfo);
2518  /* now see if it should go to any outer-join lists */
2519  Assert(sjinfo != NULL);
2520  if (bms_is_subset(restrictinfo->left_relids,
2521  outerjoin_nonnullable) &&
2522  !bms_overlap(restrictinfo->right_relids,
2523  outerjoin_nonnullable))
2524  {
2525  /* we have outervar = innervar */
2527 
2528  ojcinfo->rinfo = restrictinfo;
2529  ojcinfo->sjinfo = sjinfo;
2531  ojcinfo);
2532  return;
2533  }
2534  if (bms_is_subset(restrictinfo->right_relids,
2535  outerjoin_nonnullable) &&
2536  !bms_overlap(restrictinfo->left_relids,
2537  outerjoin_nonnullable))
2538  {
2539  /* we have innervar = outervar */
2541 
2542  ojcinfo->rinfo = restrictinfo;
2543  ojcinfo->sjinfo = sjinfo;
2545  ojcinfo);
2546  return;
2547  }
2548  if (sjinfo->jointype == JOIN_FULL)
2549  {
2550  /* FULL JOIN (above tests cannot match in this case) */
2552 
2553  ojcinfo->rinfo = restrictinfo;
2554  ojcinfo->sjinfo = sjinfo;
2556  ojcinfo);
2557  return;
2558  }
2559  /* nope, so fall through to distribute_restrictinfo_to_rels */
2560  }
2561  else
2562  {
2563  /* we still need to set up left_ec/right_ec */
2564  initialize_mergeclause_eclasses(root, restrictinfo);
2565  }
2566  }
2567 
2568  /* No EC special case applies, so push it into the clause lists */
2569  distribute_restrictinfo_to_rels(root, restrictinfo);
2570 }
@ BMS_MULTIPLE
Definition: bitmapset.h:73
bool process_equivalence(PlannerInfo *root, RestrictInfo **p_restrictinfo, JoinDomain *jdomain)
Definition: equivclass.c:118
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2816
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
Definition: initsplan.c:2583
void initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:1446
RestrictInfo * rinfo
Definition: pathnodes.h:2897
SpecialJoinInfo * sjinfo
Definition: pathnodes.h:2898
List * left_join_clauses
Definition: pathnodes.h:323
List * full_join_clauses
Definition: pathnodes.h:334
List * right_join_clauses
Definition: pathnodes.h:329
bool hasPseudoConstantQuals
Definition: pathnodes.h:495

References add_vars_to_targetlist(), PlannerInfo::all_baserels, 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, PlannerInfo::full_join_clauses, PlannerInfo::hasLateralRTEs, PlannerInfo::hasPseudoConstantQuals, initialize_mergeclause_eclasses(), JoinDomain::jd_relids, JoinTreeItem::jdomain, PlannerInfo::join_domains, JOIN_FULL, SpecialJoinInfo::jointype, JoinTreeItem::jti_parent, lappend(), JoinTreeItem::lateral_clauses, PlannerInfo::left_join_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, PlannerInfo::right_join_clauses, OuterJoinClauseInfo::rinfo, 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 2118 of file initsplan.c.

2130 {
2131  ListCell *lc;
2132 
2133  foreach(lc, clauses)
2134  {
2135  Node *clause = (Node *) lfirst(lc);
2136 
2137  distribute_qual_to_rels(root, clause,
2138  jtitem,
2139  sjinfo,
2140  security_level,
2141  qualscope,
2142  ojscope,
2143  outerjoin_nonnullable,
2144  incompatible_relids,
2145  allow_equivalence,
2146  has_clone,
2147  is_clone,
2148  postponed_oj_qual_list);
2149  }
2150 }
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:2196

References distribute_qual_to_rels(), lfirst, JoinTreeItem::qualscope, 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 2816 of file initsplan.c.

2818 {
2819  Relids relids = restrictinfo->required_relids;
2820 
2821  if (!bms_is_empty(relids))
2822  {
2823  int relid;
2824 
2825  if (bms_get_singleton_member(relids, &relid))
2826  {
2827  /*
2828  * There is only one relation participating in the clause, so it
2829  * is a restriction clause for that relation.
2830  */
2831  add_base_clause_to_rel(root, relid, restrictinfo);
2832  }
2833  else
2834  {
2835  /*
2836  * The clause is a join clause, since there is more than one rel
2837  * in its relid set.
2838  */
2839 
2840  /*
2841  * Check for hashjoinable operators. (We don't bother setting the
2842  * hashjoin info except in true join clauses.)
2843  */
2844  check_hashjoinable(restrictinfo);
2845 
2846  /*
2847  * Likewise, check if the clause is suitable to be used with a
2848  * Memoize node to cache inner tuples during a parameterized
2849  * nested loop.
2850  */
2851  check_memoizable(restrictinfo);
2852 
2853  /*
2854  * Add clause to the join lists of all the relevant relations.
2855  */
2856  add_join_clause_to_rels(root, restrictinfo, relids);
2857  }
2858  }
2859  else
2860  {
2861  /*
2862  * clause references no rels, and therefore we have no place to attach
2863  * it. Shouldn't get here if callers are working properly.
2864  */
2865  elog(ERROR, "cannot cope with variable-free clause");
2866  }
2867 }
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:2628
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, and RestrictInfo::required_relids.

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

◆ expr_is_nonnullable()

static bool expr_is_nonnullable ( PlannerInfo root,
Expr expr 
)
static

Definition at line 2676 of file initsplan.c.

2677 {
2678  RelOptInfo *rel;
2679  Var *var;
2680 
2681  /* For now only check simple Vars */
2682  if (!IsA(expr, Var))
2683  return false;
2684 
2685  var = (Var *) expr;
2686 
2687  /* could the Var be nulled by any outer joins? */
2688  if (!bms_is_empty(var->varnullingrels))
2689  return false;
2690 
2691  /* system columns cannot be NULL */
2692  if (var->varattno < 0)
2693  return true;
2694 
2695  /* is the column defined NOT NULL? */
2696  rel = find_base_rel(root, var->varno);
2697  if (var->varattno > 0 &&
2699  return true;
2700 
2701  return false;
2702 }
Bitmapset * notnullattnums
Definition: pathnodes.h:917

References bms_is_empty, bms_is_member(), find_base_rel(), IsA, RelOptInfo::notnullattnums, 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 405 of file initsplan.c.

406 {
407  RangeTblEntry *rte = root->simple_rte_array[rtindex];
408  List *vars;
409  List *newvars;
410  Relids where_needed;
411  ListCell *lc;
412 
413  /* No cross-references are possible if it's not LATERAL */
414  if (!rte->lateral)
415  return;
416 
417  /* Fetch the appropriate variables */
418  if (rte->rtekind == RTE_RELATION)
419  vars = pull_vars_of_level((Node *) rte->tablesample, 0);
420  else if (rte->rtekind == RTE_SUBQUERY)
421  vars = pull_vars_of_level((Node *) rte->subquery, 1);
422  else if (rte->rtekind == RTE_FUNCTION)
423  vars = pull_vars_of_level((Node *) rte->functions, 0);
424  else if (rte->rtekind == RTE_TABLEFUNC)
425  vars = pull_vars_of_level((Node *) rte->tablefunc, 0);
426  else if (rte->rtekind == RTE_VALUES)
427  vars = pull_vars_of_level((Node *) rte->values_lists, 0);
428  else
429  {
430  Assert(false);
431  return; /* keep compiler quiet */
432  }
433 
434  if (vars == NIL)
435  return; /* nothing to do */
436 
437  /* Copy each Var (or PlaceHolderVar) and adjust it to match our level */
438  newvars = NIL;
439  foreach(lc, vars)
440  {
441  Node *node = (Node *) lfirst(lc);
442 
443  node = copyObject(node);
444  if (IsA(node, Var))
445  {
446  Var *var = (Var *) node;
447 
448  /* Adjustment is easy since it's just one node */
449  var->varlevelsup = 0;
450  }
451  else if (IsA(node, PlaceHolderVar))
452  {
453  PlaceHolderVar *phv = (PlaceHolderVar *) node;
454  int levelsup = phv->phlevelsup;
455 
456  /* Have to work harder to adjust the contained expression too */
457  if (levelsup != 0)
458  IncrementVarSublevelsUp(node, -levelsup, 0);
459 
460  /*
461  * If we pulled the PHV out of a subquery RTE, its expression
462  * needs to be preprocessed. subquery_planner() already did this
463  * for level-zero PHVs in function and values RTEs, though.
464  */
465  if (levelsup > 0)
466  phv->phexpr = preprocess_phv_expression(root, phv->phexpr);
467  }
468  else
469  Assert(false);
470  newvars = lappend(newvars, node);
471  }
472 
473  list_free(vars);
474 
475  /*
476  * We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
477  * of a cheat: a more formal approach would be to mark each one as needed
478  * at the join of the LATERAL RTE with its source RTE. But it will work,
479  * and it's much less tedious than computing a separate where_needed for
480  * each Var.
481  */
482  where_needed = bms_make_singleton(rtindex);
483 
484  /*
485  * Push Vars into their source relations' targetlists, and PHVs into
486  * root->placeholder_list.
487  */
488  add_vars_to_targetlist(root, newvars, where_needed);
489 
490  /* Remember the lateral references for create_lateral_join_info */
491  brel->lateral_vars = newvars;
492 }
@ RTE_VALUES
Definition: parsenodes.h:1016
@ RTE_SUBQUERY
Definition: parsenodes.h:1012
@ RTE_FUNCTION
Definition: parsenodes.h:1014
@ RTE_TABLEFUNC
Definition: parsenodes.h:1015
@ RTE_RELATION
Definition: parsenodes.h:1011
Expr * preprocess_phv_expression(PlannerInfo *root, Expr *expr)
Definition: planner.c:1259
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:849
Index phlevelsup
Definition: pathnodes.h:2774
TableFunc * tablefunc
Definition: parsenodes.h:1159
struct TableSampleClause * tablesample
Definition: parsenodes.h:1081
Query * subquery
Definition: parsenodes.h:1086
List * values_lists
Definition: parsenodes.h:1164
List * functions
Definition: parsenodes.h:1153
RTEKind rtekind
Definition: parsenodes.h:1030
Index varlevelsup
Definition: primnodes.h:266
List * pull_vars_of_level(Node *node, int levelsup)
Definition: var.c:335

References add_vars_to_targetlist(), Assert(), bms_make_singleton(), copyObject, RangeTblEntry::functions, IncrementVarSublevelsUp(), IsA, lappend(), RangeTblEntry::lateral, RelOptInfo::lateral_vars, lfirst, list_free(), NIL, PlaceHolderVar::phlevelsup, preprocess_phv_expression(), pull_vars_of_level(), 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 357 of file initsplan.c.

358 {
359  Index rti;
360 
361  /* We need do nothing if the query contains no LATERAL RTEs */
362  if (!root->hasLateralRTEs)
363  return;
364 
365  /*
366  * Examine all baserels (the rel array has been set up by now).
367  */
368  for (rti = 1; rti < root->simple_rel_array_size; rti++)
369  {
370  RelOptInfo *brel = root->simple_rel_array[rti];
371 
372  /* there may be empty slots corresponding to non-baserel RTEs */
373  if (brel == NULL)
374  continue;
375 
376  Assert(brel->relid == rti); /* sanity check on array */
377 
378  /*
379  * This bit is less obvious than it might look. We ignore appendrel
380  * otherrels and consider only their parent baserels. In a case where
381  * a LATERAL-containing UNION ALL subquery was pulled up, it is the
382  * otherrel that is actually going to be in the plan. However, we
383  * want to mark all its lateral references as needed by the parent,
384  * because it is the parent's relid that will be used for join
385  * planning purposes. And the parent's RTE will contain all the
386  * lateral references we need to know, since the pulled-up member is
387  * nothing but a copy of parts of the original RTE's subquery. We
388  * could visit the parent's children instead and transform their
389  * references back to the parent's relid, but it would be much more
390  * complicated for no real gain. (Important here is that the child
391  * members have not yet received any processing beyond being pulled
392  * up.) Similarly, in appendrels created by inheritance expansion,
393  * it's sufficient to look at the parent relation.
394  */
395 
396  /* ignore RTEs that are "other rels" */
397  if (brel->reloptkind != RELOPT_BASEREL)
398  continue;
399 
400  extract_lateral_references(root, brel, rti);
401  }
402 }
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:405

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

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 3109 of file initsplan.c.

3110 {
3111  Relids result = bms_copy(domain_relids);
3112  ListCell *lc;
3113 
3114  /* Top-level join domain? */
3115  if (bms_equal(result, root->all_query_rels))
3116  return result;
3117 
3118  /* Nope, look for lower outer joins that could potentially commute out */
3119  foreach(lc, root->join_info_list)
3120  {
3121  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
3122 
3123  if (sjinfo->jointype == JOIN_LEFT &&
3124  bms_is_member(sjinfo->ojrelid, result))
3125  {
3126  result = bms_del_member(result, sjinfo->ojrelid);
3127  result = bms_del_members(result, sjinfo->syn_righthand);
3128  }
3129  }
3130  return result;
3131 }
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161

References PlannerInfo::all_query_rels, bms_copy(), bms_del_member(), bms_del_members(), bms_equal(), bms_is_member(), PlannerInfo::join_info_list, JOIN_LEFT, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::ojrelid, 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 1359 of file initsplan.c.

1364 {
1366  Relids clause_relids;
1367  Relids strict_relids;
1368  Relids min_lefthand;
1369  Relids min_righthand;
1370  Relids commute_below_l;
1371  Relids commute_below_r;
1372  ListCell *l;
1373 
1374  /*
1375  * We should not see RIGHT JOIN here because left/right were switched
1376  * earlier
1377  */
1378  Assert(jointype != JOIN_INNER);
1379  Assert(jointype != JOIN_RIGHT);
1380 
1381  /*
1382  * Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of
1383  * rels appearing on the nullable side of an outer join. (It's somewhat
1384  * unclear what that would mean, anyway: what should we mark when a result
1385  * row is generated from no element of the nullable relation?) So,
1386  * complain if any nullable rel is FOR [KEY] UPDATE/SHARE.
1387  *
1388  * You might be wondering why this test isn't made far upstream in the
1389  * parser. It's because the parser hasn't got enough info --- consider
1390  * FOR UPDATE applied to a view. Only after rewriting and flattening do
1391  * we know whether the view contains an outer join.
1392  *
1393  * We use the original RowMarkClause list here; the PlanRowMark list would
1394  * list everything.
1395  */
1396  foreach(l, root->parse->rowMarks)
1397  {
1398  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
1399 
1400  if (bms_is_member(rc->rti, right_rels) ||
1401  (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels)))
1402  ereport(ERROR,
1403  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1404  /*------
1405  translator: %s is a SQL row locking clause such as FOR UPDATE */
1406  errmsg("%s cannot be applied to the nullable side of an outer join",
1407  LCS_asString(rc->strength))));
1408  }
1409 
1410  sjinfo->syn_lefthand = left_rels;
1411  sjinfo->syn_righthand = right_rels;
1412  sjinfo->jointype = jointype;
1413  sjinfo->ojrelid = ojrelid;
1414  /* these fields may get added to later: */
1415  sjinfo->commute_above_l = NULL;
1416  sjinfo->commute_above_r = NULL;
1417  sjinfo->commute_below_l = NULL;
1418  sjinfo->commute_below_r = NULL;
1419 
1420  compute_semijoin_info(root, sjinfo, clause);
1421 
1422  /* If it's a full join, no need to be very smart */
1423  if (jointype == JOIN_FULL)
1424  {
1425  sjinfo->min_lefthand = bms_copy(left_rels);
1426  sjinfo->min_righthand = bms_copy(right_rels);
1427  sjinfo->lhs_strict = false; /* don't care about this */
1428  return sjinfo;
1429  }
1430 
1431  /*
1432  * Retrieve all relids mentioned within the join clause.
1433  */
1434  clause_relids = pull_varnos(root, (Node *) clause);
1435 
1436  /*
1437  * For which relids is the clause strict, ie, it cannot succeed if the
1438  * rel's columns are all NULL?
1439  */
1440  strict_relids = find_nonnullable_rels((Node *) clause);
1441 
1442  /* Remember whether the clause is strict for any LHS relations */
1443  sjinfo->lhs_strict = bms_overlap(strict_relids, left_rels);
1444 
1445  /*
1446  * Required LHS always includes the LHS rels mentioned in the clause. We
1447  * may have to add more rels based on lower outer joins; see below.
1448  */
1449  min_lefthand = bms_intersect(clause_relids, left_rels);
1450 
1451  /*
1452  * Similarly for required RHS. But here, we must also include any lower
1453  * inner joins, to ensure we don't try to commute with any of them.
1454  */
1455  min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
1456  right_rels);
1457 
1458  /*
1459  * Now check previous outer joins for ordering restrictions.
1460  *
1461  * commute_below_l and commute_below_r accumulate the relids of lower
1462  * outer joins that we think this one can commute with. These decisions
1463  * are just tentative within this loop, since we might find an
1464  * intermediate outer join that prevents commutation. Surviving relids
1465  * will get merged into the SpecialJoinInfo structs afterwards.
1466  */
1467  commute_below_l = commute_below_r = NULL;
1468  foreach(l, root->join_info_list)
1469  {
1470  SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
1471  bool have_unsafe_phvs;
1472 
1473  /*
1474  * A full join is an optimization barrier: we can't associate into or
1475  * out of it. Hence, if it overlaps either LHS or RHS of the current
1476  * rel, expand that side's min relset to cover the whole full join.
1477  */
1478  if (otherinfo->jointype == JOIN_FULL)
1479  {
1480  Assert(otherinfo->ojrelid != 0);
1481  if (bms_overlap(left_rels, otherinfo->syn_lefthand) ||
1482  bms_overlap(left_rels, otherinfo->syn_righthand))
1483  {
1484  min_lefthand = bms_add_members(min_lefthand,
1485  otherinfo->syn_lefthand);
1486  min_lefthand = bms_add_members(min_lefthand,
1487  otherinfo->syn_righthand);
1488  min_lefthand = bms_add_member(min_lefthand,
1489  otherinfo->ojrelid);
1490  }
1491  if (bms_overlap(right_rels, otherinfo->syn_lefthand) ||
1492  bms_overlap(right_rels, otherinfo->syn_righthand))
1493  {
1494  min_righthand = bms_add_members(min_righthand,
1495  otherinfo->syn_lefthand);
1496  min_righthand = bms_add_members(min_righthand,
1497  otherinfo->syn_righthand);
1498  min_righthand = bms_add_member(min_righthand,
1499  otherinfo->ojrelid);
1500  }
1501  /* Needn't do anything else with the full join */
1502  continue;
1503  }
1504 
1505  /*
1506  * If our join condition contains any PlaceHolderVars that need to be
1507  * evaluated above the lower OJ, then we can't commute with it.
1508  */
1509  if (otherinfo->ojrelid != 0)
1510  have_unsafe_phvs =
1512  (Node *) clause,
1513  otherinfo->ojrelid);
1514  else
1515  have_unsafe_phvs = false;
1516 
1517  /*
1518  * For a lower OJ in our LHS, if our join condition uses the lower
1519  * join's RHS and is not strict for that rel, we must preserve the
1520  * ordering of the two OJs, so add lower OJ's full syntactic relset to
1521  * min_lefthand. (We must use its full syntactic relset, not just its
1522  * min_lefthand + min_righthand. This is because there might be other
1523  * OJs below this one that this one can commute with, but we cannot
1524  * commute with them if we don't with this one.) Also, if we have
1525  * unsafe PHVs or the current join is a semijoin or antijoin, we must
1526  * preserve ordering regardless of strictness.
1527  *
1528  * Note: I believe we have to insist on being strict for at least one
1529  * rel in the lower OJ's min_righthand, not its whole syn_righthand.
1530  *
1531  * When we don't need to preserve ordering, check to see if outer join
1532  * identity 3 applies, and if so, remove the lower OJ's ojrelid from
1533  * our min_lefthand so that commutation is allowed.
1534  */
1535  if (bms_overlap(left_rels, otherinfo->syn_righthand))
1536  {
1537  if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
1538  (have_unsafe_phvs ||
1539  jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
1540  !bms_overlap(strict_relids, otherinfo->min_righthand)))
1541  {
1542  /* Preserve ordering */
1543  min_lefthand = bms_add_members(min_lefthand,
1544  otherinfo->syn_lefthand);
1545  min_lefthand = bms_add_members(min_lefthand,
1546  otherinfo->syn_righthand);
1547  if (otherinfo->ojrelid != 0)
1548  min_lefthand = bms_add_member(min_lefthand,
1549  otherinfo->ojrelid);
1550  }
1551  else if (jointype == JOIN_LEFT &&
1552  otherinfo->jointype == JOIN_LEFT &&
1553  bms_overlap(strict_relids, otherinfo->min_righthand) &&
1554  !bms_overlap(clause_relids, otherinfo->syn_lefthand))
1555  {
1556  /* Identity 3 applies, so remove the ordering restriction */
1557  min_lefthand = bms_del_member(min_lefthand, otherinfo->ojrelid);
1558  /* Record the (still tentative) commutability relationship */
1559  commute_below_l =
1560  bms_add_member(commute_below_l, otherinfo->ojrelid);
1561  }
1562  }
1563 
1564  /*
1565  * For a lower OJ in our RHS, if our join condition does not use the
1566  * lower join's RHS and the lower OJ's join condition is strict, we
1567  * can interchange the ordering of the two OJs; otherwise we must add
1568  * the lower OJ's full syntactic relset to min_righthand.
1569  *
1570  * Also, if our join condition does not use the lower join's LHS
1571  * either, force the ordering to be preserved. Otherwise we can end
1572  * up with SpecialJoinInfos with identical min_righthands, which can
1573  * confuse join_is_legal (see discussion in backend/optimizer/README).
1574  *
1575  * Also, we must preserve ordering anyway if we have unsafe PHVs, or
1576  * if either this join or the lower OJ is a semijoin or antijoin.
1577  *
1578  * When we don't need to preserve ordering, check to see if outer join
1579  * identity 3 applies, and if so, remove the lower OJ's ojrelid from
1580  * our min_righthand so that commutation is allowed.
1581  */
1582  if (bms_overlap(right_rels, otherinfo->syn_righthand))
1583  {
1584  if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
1585  !bms_overlap(clause_relids, otherinfo->min_lefthand) ||
1586  have_unsafe_phvs ||
1587  jointype == JOIN_SEMI ||
1588  jointype == JOIN_ANTI ||
1589  otherinfo->jointype == JOIN_SEMI ||
1590  otherinfo->jointype == JOIN_ANTI ||
1591  !otherinfo->lhs_strict)
1592  {
1593  /* Preserve ordering */
1594  min_righthand = bms_add_members(min_righthand,
1595  otherinfo->syn_lefthand);
1596  min_righthand = bms_add_members(min_righthand,
1597  otherinfo->syn_righthand);
1598  if (otherinfo->ojrelid != 0)
1599  min_righthand = bms_add_member(min_righthand,
1600  otherinfo->ojrelid);
1601  }
1602  else if (jointype == JOIN_LEFT &&
1603  otherinfo->jointype == JOIN_LEFT &&
1604  otherinfo->lhs_strict)
1605  {
1606  /* Identity 3 applies, so remove the ordering restriction */
1607  min_righthand = bms_del_member(min_righthand,
1608  otherinfo->ojrelid);
1609  /* Record the (still tentative) commutability relationship */
1610  commute_below_r =
1611  bms_add_member(commute_below_r, otherinfo->ojrelid);
1612  }
1613  }
1614  }
1615 
1616  /*
1617  * Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
1618  * this join's nullable side, then ensure that min_righthand contains the
1619  * full eval_at set of the PHV. This ensures that the PHV actually can be
1620  * evaluated within the RHS. Note that this works only because we should
1621  * already have determined the final eval_at level for any PHV
1622  * syntactically within this join.
1623  */
1624  foreach(l, root->placeholder_list)
1625  {
1626  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
1627  Relids ph_syn_level = phinfo->ph_var->phrels;
1628 
1629  /* Ignore placeholder if it didn't syntactically come from RHS */
1630  if (!bms_is_subset(ph_syn_level, right_rels))
1631  continue;
1632 
1633  /* Else, prevent join from being formed before we eval the PHV */
1634  min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
1635  }
1636 
1637  /*
1638  * If we found nothing to put in min_lefthand, punt and make it the full
1639  * LHS, to avoid having an empty min_lefthand which will confuse later
1640  * processing. (We don't try to be smart about such cases, just correct.)
1641  * Likewise for min_righthand.
1642  */
1643  if (bms_is_empty(min_lefthand))
1644  min_lefthand = bms_copy(left_rels);
1645  if (bms_is_empty(min_righthand))
1646  min_righthand = bms_copy(right_rels);
1647 
1648  /* Now they'd better be nonempty */
1649  Assert(!bms_is_empty(min_lefthand));
1650  Assert(!bms_is_empty(min_righthand));
1651  /* Shouldn't overlap either */
1652  Assert(!bms_overlap(min_lefthand, min_righthand));
1653 
1654  sjinfo->min_lefthand = min_lefthand;
1655  sjinfo->min_righthand = min_righthand;
1656 
1657  /*
1658  * Now that we've identified the correct min_lefthand and min_righthand,
1659  * any commute_below_l or commute_below_r relids that have not gotten
1660  * added back into those sets (due to intervening outer joins) are indeed
1661  * commutable with this one.
1662  *
1663  * First, delete any subsequently-added-back relids (this is easier than
1664  * maintaining commute_below_l/r precisely through all the above).
1665  */
1666  commute_below_l = bms_del_members(commute_below_l, min_lefthand);
1667  commute_below_r = bms_del_members(commute_below_r, min_righthand);
1668 
1669  /* Anything left? */
1670  if (commute_below_l || commute_below_r)
1671  {
1672  /* Yup, so we must update the derived data in the SpecialJoinInfos */
1673  sjinfo->commute_below_l = commute_below_l;
1674  sjinfo->commute_below_r = commute_below_r;
1675  foreach(l, root->join_info_list)
1676  {
1677  SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
1678 
1679  if (bms_is_member(otherinfo->ojrelid, commute_below_l))
1680  otherinfo->commute_above_l =
1681  bms_add_member(otherinfo->commute_above_l, ojrelid);
1682  else if (bms_is_member(otherinfo->ojrelid, commute_below_r))
1683  otherinfo->commute_above_r =
1684  bms_add_member(otherinfo->commute_above_r, ojrelid);
1685  }
1686  }
1687 
1688  return sjinfo;
1689 }
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1109
Relids find_nonnullable_rels(Node *clause)
Definition: clauses.c:1436
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereport(elevel,...)
Definition: elog.h:149
static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
Definition: initsplan.c:1699
@ JOIN_RIGHT
Definition: nodes.h:286
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3212
bool contain_placeholder_references_to(PlannerInfo *root, Node *clause, int relid)
Definition: placeholder.c:464
PlaceHolderVar * ph_var
Definition: pathnodes.h:3059
List * rowMarks
Definition: parsenodes.h:216
LockClauseStrength strength
Definition: parsenodes.h:1540
Relids commute_above_l
Definition: pathnodes.h:2874

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, PlannerInfo::join_info_list, 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, PlannerInfo::parse, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_var, PlannerInfo::placeholder_list, pull_varnos(), JoinTreeItem::right_rels, Query::rowMarks, 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 1321 of file initsplan.c.

1323 {
1324  int relid = -1;
1325 
1326  while ((relid = bms_next_member(lower_rels, relid)) > 0)
1327  {
1328  RelOptInfo *rel = root->simple_rel_array[relid];
1329 
1330  if (rel == NULL) /* must be an outer join */
1331  {
1332  Assert(bms_is_member(relid, root->outer_join_rels));
1333  continue;
1334  }
1335  rel->nulling_relids = bms_add_member(rel->nulling_relids, ojrelid);
1336  }
1337 }
Relids nulling_relids
Definition: pathnodes.h:919

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

Referenced by deconstruct_recurse().

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 3149 of file initsplan.c.

3150 {
3151  List *newlist = NIL;
3152  ListCell *lc;
3153 
3154  foreach(lc, root->fkey_list)
3155  {
3156  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
3157  RelOptInfo *con_rel;
3158  RelOptInfo *ref_rel;
3159  int colno;
3160 
3161  /*
3162  * Either relid might identify a rel that is in the query's rtable but
3163  * isn't referenced by the jointree, or has been removed by join
3164  * removal, so that it won't have a RelOptInfo. Hence don't use
3165  * find_base_rel() here. We can ignore such FKs.
3166  */
3167  if (fkinfo->con_relid >= root->simple_rel_array_size ||
3168  fkinfo->ref_relid >= root->simple_rel_array_size)
3169  continue; /* just paranoia */
3170  con_rel = root->simple_rel_array[fkinfo->con_relid];
3171  if (con_rel == NULL)
3172  continue;
3173  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3174  if (ref_rel == NULL)
3175  continue;
3176 
3177  /*
3178  * Ignore FK unless both rels are baserels. This gets rid of FKs that
3179  * link to inheritance child rels (otherrels).
3180  */
3181  if (con_rel->reloptkind != RELOPT_BASEREL ||
3182  ref_rel->reloptkind != RELOPT_BASEREL)
3183  continue;
3184 
3185  /*
3186  * Scan the columns and try to match them to eclasses and quals.
3187  *
3188  * Note: for simple inner joins, any match should be in an eclass.
3189  * "Loose" quals that syntactically match an FK equality must have
3190  * been rejected for EC status because they are outer-join quals or
3191  * similar. We can still consider them to match the FK.
3192  */
3193  for (colno = 0; colno < fkinfo->nkeys; colno++)
3194  {
3195  EquivalenceClass *ec;
3196  AttrNumber con_attno,
3197  ref_attno;
3198  Oid fpeqop;
3199  ListCell *lc2;
3200 
3201  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
3202  /* Don't bother looking for loose quals if we got an EC match */
3203  if (ec != NULL)
3204  {
3205  fkinfo->nmatched_ec++;
3206  if (ec->ec_has_const)
3207  fkinfo->nconst_ec++;
3208  continue;
3209  }
3210 
3211  /*
3212  * Scan joininfo list for relevant clauses. Either rel's joininfo
3213  * list would do equally well; we use con_rel's.
3214  */
3215  con_attno = fkinfo->conkey[colno];
3216  ref_attno = fkinfo->confkey[colno];
3217  fpeqop = InvalidOid; /* we'll look this up only if needed */
3218 
3219  foreach(lc2, con_rel->joininfo)
3220  {
3221  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
3222  OpExpr *clause = (OpExpr *) rinfo->clause;
3223  Var *leftvar;
3224  Var *rightvar;
3225 
3226  /* Only binary OpExprs are useful for consideration */
3227  if (!IsA(clause, OpExpr) ||
3228  list_length(clause->args) != 2)
3229  continue;
3230  leftvar = (Var *) get_leftop((Expr *) clause);
3231  rightvar = (Var *) get_rightop((Expr *) clause);
3232 
3233  /* Operands must be Vars, possibly with RelabelType */
3234  while (leftvar && IsA(leftvar, RelabelType))
3235  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
3236  if (!(leftvar && IsA(leftvar, Var)))
3237  continue;
3238  while (rightvar && IsA(rightvar, RelabelType))
3239  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
3240  if (!(rightvar && IsA(rightvar, Var)))
3241  continue;
3242 
3243  /* Now try to match the vars to the current foreign key cols */
3244  if (fkinfo->ref_relid == leftvar->varno &&
3245  ref_attno == leftvar->varattno &&
3246  fkinfo->con_relid == rightvar->varno &&
3247  con_attno == rightvar->varattno)
3248  {
3249  /* Vars match, but is it the right operator? */
3250  if (clause->opno == fkinfo->conpfeqop[colno])
3251  {
3252  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3253  rinfo);
3254  fkinfo->nmatched_ri++;
3255  }
3256  }
3257  else if (fkinfo->ref_relid == rightvar->varno &&
3258  ref_attno == rightvar->varattno &&
3259  fkinfo->con_relid == leftvar->varno &&
3260  con_attno == leftvar->varattno)
3261  {
3262  /*
3263  * Reverse match, must check commutator operator. Look it
3264  * up if we didn't already. (In the worst case we might
3265  * do multiple lookups here, but that would require an FK
3266  * equality operator without commutator, which is
3267  * unlikely.)
3268  */
3269  if (!OidIsValid(fpeqop))
3270  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
3271  if (clause->opno == fpeqop)
3272  {
3273  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3274  rinfo);
3275  fkinfo->nmatched_ri++;
3276  }
3277  }
3278  }
3279  /* If we found any matching loose quals, count col as matched */
3280  if (fkinfo->rinfos[colno])
3281  fkinfo->nmatched_rcols++;
3282  }
3283 
3284  /*
3285  * Currently, we drop multicolumn FKs that aren't fully matched to the
3286  * query. Later we might figure out how to derive some sort of
3287  * estimate from them, in which case this test should be weakened to
3288  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3289  */
3290  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3291  newlist = lappend(newlist, fkinfo);
3292  }
3293  /* Replace fkey_list, thereby discarding any useless entries */
3294  root->fkey_list = newlist;
3295 }
int16 AttrNumber
Definition: attnum.h:21
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2501
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:93
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:81
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:1241
List * fkey_list
Definition: pathnodes.h:379
List * joininfo
Definition: pathnodes.h:972

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, EquivalenceClass::ec_has_const, PlannerInfo::fkey_list, 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 PlannerInfo::simple_rel_array_size.

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 2901 of file initsplan.c.

2909 {
2910  RestrictInfo *restrictinfo;
2911  Node *clause;
2912  Relids relids;
2913  bool pseudoconstant = false;
2914 
2915  /*
2916  * Build the new clause. Copy to ensure it shares no substructure with
2917  * original (this is necessary in case there are subselects in there...)
2918  */
2919  clause = (Node *) make_opclause(opno,
2920  BOOLOID, /* opresulttype */
2921  false, /* opretset */
2922  copyObject(item1),
2923  copyObject(item2),
2924  InvalidOid,
2925  collation);
2926 
2927  /* If both constant, try to reduce to a boolean constant. */
2928  if (both_const)
2929  {
2930  clause = eval_const_expressions(root, clause);
2931 
2932  /* If we produced const TRUE, just drop the clause */
2933  if (clause && IsA(clause, Const))
2934  {
2935  Const *cclause = (Const *) clause;
2936 
2937  Assert(cclause->consttype == BOOLOID);
2938  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
2939  return NULL;
2940  }
2941  }
2942 
2943  /*
2944  * The rest of this is a very cut-down version of distribute_qual_to_rels.
2945  * We can skip most of the work therein, but there are a couple of special
2946  * cases we still have to handle.
2947  *
2948  * Retrieve all relids mentioned within the possibly-simplified clause.
2949  */
2950  relids = pull_varnos(root, clause);
2951  Assert(bms_is_subset(relids, qualscope));
2952 
2953  /*
2954  * If the clause is variable-free, our normal heuristic for pushing it
2955  * down to just the mentioned rels doesn't work, because there are none.
2956  * Apply it as a gating qual at the appropriate level (see comments for
2957  * get_join_domain_min_rels).
2958  */
2959  if (bms_is_empty(relids))
2960  {
2961  /* eval at join domain's safe level */
2962  relids = get_join_domain_min_rels(root, qualscope);
2963  /* mark as gating qual */
2964  pseudoconstant = true;
2965  /* tell createplan.c to check for gating quals */
2966  root->hasPseudoConstantQuals = true;
2967  }
2968 
2969  /*
2970  * Build the RestrictInfo node itself.
2971  */
2972  restrictinfo = make_restrictinfo(root,
2973  (Expr *) clause,
2974  true, /* is_pushed_down */
2975  false, /* !has_clone */
2976  false, /* !is_clone */
2977  pseudoconstant,
2978  security_level,
2979  relids,
2980  NULL, /* incompatible_relids */
2981  NULL); /* outer_relids */
2982 
2983  /*
2984  * If it's a join clause, add vars used in the clause to targetlists of
2985  * their relations, so that they will be emitted by the plan nodes that
2986  * scan those relations (else they won't be available at the join node!).
2987  *
2988  * Typically, we'd have already done this when the component expressions
2989  * were first seen by distribute_qual_to_rels; but it is possible that
2990  * some of the Vars could have missed having that done because they only
2991  * appeared in single-relation clauses originally. So do it here for
2992  * safety.
2993  */
2994  if (bms_membership(relids) == BMS_MULTIPLE)
2995  {
2996  List *vars = pull_var_clause(clause,
3000 
3001  add_vars_to_targetlist(root, vars, relids);
3002  list_free(vars);
3003  }
3004 
3005  /*
3006  * Check mergejoinability. This will usually succeed, since the op came
3007  * from an EquivalenceClass; but we could have reduced the original clause
3008  * to a constant.
3009  */
3010  check_mergejoinable(restrictinfo);
3011 
3012  /*
3013  * Note we don't do initialize_mergeclause_eclasses(); the caller can
3014  * handle that much more cheaply than we can. It's okay to call
3015  * distribute_restrictinfo_to_rels() before that happens.
3016  */
3017 
3018  /*
3019  * Push the new clause into all the appropriate restrictinfo lists.
3020  */
3021  distribute_restrictinfo_to_rels(root, restrictinfo);
3022 
3023  return restrictinfo;
3024 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2234
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition: initsplan.c:3109
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Oid consttype
Definition: primnodes.h:298

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(), PlannerInfo::hasPseudoConstantQuals, InvalidOid, IsA, list_free(), make_opclause(), make_restrictinfo(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and JoinTreeItem::qualscope.

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 1271 of file initsplan.c.

1273 {
1274  RangeTblEntry *rte = root->simple_rte_array[rti];
1275  Index security_level = 0;
1276  ListCell *lc;
1277 
1278  /*
1279  * Each element of the securityQuals list has been preprocessed into an
1280  * implicitly-ANDed list of clauses. All the clauses in a given sublist
1281  * should get the same security level, but successive sublists get higher
1282  * levels.
1283  */
1284  foreach(lc, rte->securityQuals)
1285  {
1286  List *qualset = (List *) lfirst(lc);
1287 
1288  /*
1289  * We cheat to the extent of passing ojscope = qualscope rather than
1290  * its more logical value of NULL. The only effect this has is to
1291  * force a Var-free qual to be evaluated at the rel rather than being
1292  * pushed up to top of tree, which we don't want.
1293  */
1294  distribute_quals_to_rels(root, qualset,
1295  jtitem,
1296  NULL,
1297  security_level,
1298  jtitem->qualscope,
1299  jtitem->qualscope,
1300  NULL,
1301  NULL,
1302  true,
1303  false, false, /* not clones */
1304  NULL);
1305  security_level++;
1306  }
1307 
1308  /* Assert that qual_security_level is higher than anything we just used */
1309  Assert(security_level <= root->qual_security_level);
1310 }
List * securityQuals
Definition: parsenodes.h:1208

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

Referenced by deconstruct_distribute().

◆ restriction_is_always_false()

bool restriction_is_always_false ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2761 of file initsplan.c.

2763 {
2764  /* Check for NullTest qual */
2765  if (IsA(restrictinfo->clause, NullTest))
2766  {
2767  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2768 
2769  /* is this NullTest an IS_NULL qual? */
2770  if (nulltest->nulltesttype != IS_NULL)
2771  return false;
2772 
2773  return expr_is_nonnullable(root, nulltest->arg);
2774  }
2775 
2776  /* If it's an OR, check its sub-clauses */
2777  if (restriction_is_or_clause(restrictinfo))
2778  {
2779  ListCell *lc;
2780 
2781  Assert(is_orclause(restrictinfo->orclause));
2782 
2783  /*
2784  * Currently, when processing OR expressions, we only return true when
2785  * all of the OR branches are always false. This could perhaps be
2786  * expanded to remove OR branches that are provably false. This may
2787  * be a useful thing to do as it could result in the OR being left
2788  * with a single arg. That's useful as it would allow the OR
2789  * condition to be replaced with its single argument which may allow
2790  * use of an index for faster filtering on the remaining condition.
2791  */
2792  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2793  {
2794  Node *orarg = (Node *) lfirst(lc);
2795 
2796  if (!IsA(orarg, RestrictInfo) ||
2797  !restriction_is_always_false(root, (RestrictInfo *) orarg))
2798  return false;
2799  }
2800  return true;
2801  }
2802 
2803  return false;
2804 }
static bool expr_is_nonnullable(PlannerInfo *root, Expr *expr)
Definition: initsplan.c:2676
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:114
@ IS_NULL
Definition: primnodes.h:1715
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:416
NullTestType nulltesttype
Definition: primnodes.h:1722
Expr * arg
Definition: primnodes.h:1721

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

Referenced by add_base_clause_to_rel(), and add_join_clause_to_rels().

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2712 of file initsplan.c.

2714 {
2715  /* Check for NullTest qual */
2716  if (IsA(restrictinfo->clause, NullTest))
2717  {
2718  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2719 
2720  /* is this NullTest an IS_NOT_NULL qual? */
2721  if (nulltest->nulltesttype != IS_NOT_NULL)
2722  return false;
2723 
2724  return expr_is_nonnullable(root, nulltest->arg);
2725  }
2726 
2727  /* If it's an OR, check its sub-clauses */
2728  if (restriction_is_or_clause(restrictinfo))
2729  {
2730  ListCell *lc;
2731 
2732  Assert(is_orclause(restrictinfo->orclause));
2733 
2734  /*
2735  * if any of the given OR branches is provably always true then the
2736  * entire condition is true.
2737  */
2738  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2739  {
2740  Node *orarg = (Node *) lfirst(lc);
2741 
2742  if (!IsA(orarg, RestrictInfo))
2743  continue;
2744 
2745  if (restriction_is_always_true(root, (RestrictInfo *) orarg))
2746  return true;
2747  }
2748  }
2749 
2750  return false;
2751 }
@ IS_NOT_NULL
Definition: primnodes.h:1715

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

Referenced by add_base_clause_to_rel(), and add_join_clause_to_rels().

Variable Documentation

◆ from_collapse_limit

int from_collapse_limit

Definition at line 37 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 38 of file initsplan.c.

Referenced by deconstruct_recurse().