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

2631 {
2632  RelOptInfo *rel = find_base_rel(root, relid);
2633  RangeTblEntry *rte = root->simple_rte_array[relid];
2634 
2636 
2637  /*
2638  * For inheritance parent tables, we must always record the RestrictInfo
2639  * in baserestrictinfo as is. If we were to transform or skip adding it,
2640  * then the original wouldn't be available in apply_child_basequals. Since
2641  * there are two RangeTblEntries for inheritance parents, one with
2642  * inh==true and the other with inh==false, we're still able to apply this
2643  * optimization to the inh==false one. The inh==true one is what
2644  * apply_child_basequals() sees, whereas the inh==false one is what's used
2645  * for the scan node in the final plan.
2646  *
2647  * We make an exception to this for partitioned tables. For these, we
2648  * always apply the constant-TRUE and constant-FALSE transformations. A
2649  * qual which is either of these for a partitioned table must also be that
2650  * for all of its child partitions.
2651  */
2652  if (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE)
2653  {
2654  /* Don't add the clause if it is always true */
2655  if (restriction_is_always_true(root, restrictinfo))
2656  return;
2657 
2658  /*
2659  * Substitute the origin qual with constant-FALSE if it is provably
2660  * always false. Note that we keep the same rinfo_serial.
2661  */
2662  if (restriction_is_always_false(root, restrictinfo))
2663  {
2664  int save_rinfo_serial = restrictinfo->rinfo_serial;
2665 
2666  restrictinfo = make_restrictinfo(root,
2667  (Expr *) makeBoolConst(false, false),
2668  restrictinfo->is_pushed_down,
2669  restrictinfo->has_clone,
2670  restrictinfo->is_clone,
2671  restrictinfo->pseudoconstant,
2672  0, /* security_level */
2673  restrictinfo->required_relids,
2674  restrictinfo->incompatible_relids,
2675  restrictinfo->outer_relids);
2676  restrictinfo->rinfo_serial = save_rinfo_serial;
2677  }
2678  }
2679 
2680  /* Add clause to rel's restriction list */
2681  rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo);
2682 
2683  /* Update security level info */
2685  restrictinfo->security_level);
2686 }
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_SINGLETON
Definition: bitmapset.h:72
#define Min(x, y)
Definition: c.h:1004
#define Assert(condition)
Definition: c.h:858
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2732
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2781
List * lappend(List *list, void *datum)
Definition: list.c:339
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:359
tree ctl root
Definition: radixtree.h:1880
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:63
List * baserestrictinfo
Definition: pathnodes.h:975
Index baserestrict_min_security
Definition: pathnodes.h:979
bool is_pushed_down
Definition: pathnodes.h:2555
Index security_level
Definition: pathnodes.h:2574
Relids required_relids
Definition: pathnodes.h:2583
int rinfo_serial
Definition: pathnodes.h:2624
Relids outer_relids
Definition: pathnodes.h:2589
Relids incompatible_relids
Definition: pathnodes.h:2586
bool has_clone
Definition: pathnodes.h:2564

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

Referenced by distribute_restrictinfo_to_rels().

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 157 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 195 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_vars_to_targetlist()

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

Definition at line 279 of file initsplan.c.

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

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

◆ build_base_rel_tlists()

void build_base_rel_tlists ( PlannerInfo root,
List final_tlist 
)

Definition at line 234 of file initsplan.c.

235 {
236  List *tlist_vars = pull_var_clause((Node *) final_tlist,
240 
241  if (tlist_vars != NIL)
242  {
244  list_free(tlist_vars);
245  }
246 
247  /*
248  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
249  * that HAVING can contain Aggrefs but not WindowFuncs.
250  */
251  if (root->parse->havingQual)
252  {
253  List *having_vars = pull_var_clause(root->parse->havingQual,
256 
257  if (having_vars != NIL)
258  {
259  add_vars_to_targetlist(root, having_vars,
260  bms_make_singleton(0));
261  list_free(having_vars);
262  }
263  }
264 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:279
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
List * pull_var_clause(Node *node, int flags)
Definition: var.c:607

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

Referenced by distribute_row_identity_vars(), and query_planner().

◆ build_implied_join_equality()

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

Definition at line 3060 of file initsplan.c.

3067 {
3068  RestrictInfo *restrictinfo;
3069  Expr *clause;
3070 
3071  /*
3072  * Build the new clause. Copy to ensure it shares no substructure with
3073  * original (this is necessary in case there are subselects in there...)
3074  */
3075  clause = make_opclause(opno,
3076  BOOLOID, /* opresulttype */
3077  false, /* opretset */
3078  copyObject(item1),
3079  copyObject(item2),
3080  InvalidOid,
3081  collation);
3082 
3083  /*
3084  * Build the RestrictInfo node itself.
3085  */
3086  restrictinfo = make_restrictinfo(root,
3087  clause,
3088  true, /* is_pushed_down */
3089  false, /* !has_clone */
3090  false, /* !is_clone */
3091  false, /* pseudoconstant */
3092  security_level, /* security_level */
3093  qualscope, /* required_relids */
3094  NULL, /* incompatible_relids */
3095  NULL); /* outer_relids */
3096 
3097  /* Set mergejoinability/hashjoinability flags */
3098  check_mergejoinable(restrictinfo);
3099  check_hashjoinable(restrictinfo);
3100  check_memoizable(restrictinfo);
3101 
3102  return restrictinfo;
3103 }
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3371
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3334
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3399
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:628
#define InvalidOid
Definition: postgres_ext.h:36

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

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

◆ check_hashjoinable()

static void check_hashjoinable ( RestrictInfo restrictinfo)
static

Definition at line 3371 of file initsplan.c.

3372 {
3373  Expr *clause = restrictinfo->clause;
3374  Oid opno;
3375  Node *leftarg;
3376 
3377  if (restrictinfo->pseudoconstant)
3378  return;
3379  if (!is_opclause(clause))
3380  return;
3381  if (list_length(((OpExpr *) clause)->args) != 2)
3382  return;
3383 
3384  opno = ((OpExpr *) clause)->opno;
3385  leftarg = linitial(((OpExpr *) clause)->args);
3386 
3387  if (op_hashjoinable(opno, exprType(leftarg)) &&
3388  !contain_volatile_functions((Node *) restrictinfo))
3389  restrictinfo->hashjoinoperator = opno;
3390 }
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1437
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h: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:2552

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

3400 {
3401  TypeCacheEntry *typentry;
3402  Expr *clause = restrictinfo->clause;
3403  Oid lefttype;
3404  Oid righttype;
3405 
3406  if (restrictinfo->pseudoconstant)
3407  return;
3408  if (!is_opclause(clause))
3409  return;
3410  if (list_length(((OpExpr *) clause)->args) != 2)
3411  return;
3412 
3413  lefttype = exprType(linitial(((OpExpr *) clause)->args));
3414 
3415  typentry = lookup_type_cache(lefttype, TYPECACHE_HASH_PROC |
3417 
3418  if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3419  restrictinfo->left_hasheqoperator = typentry->eq_opr;
3420 
3421  righttype = exprType(lsecond(((OpExpr *) clause)->args));
3422 
3423  /*
3424  * Lookup the right type, unless it's the same as the left type, in which
3425  * case typentry is already pointing to the required TypeCacheEntry.
3426  */
3427  if (lefttype != righttype)
3428  typentry = lookup_type_cache(righttype, TYPECACHE_HASH_PROC |
3430 
3431  if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3432  restrictinfo->right_hasheqoperator = typentry->eq_opr;
3433 }
#define OidIsValid(objectId)
Definition: c.h:775
#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 3334 of file initsplan.c.

3335 {
3336  Expr *clause = restrictinfo->clause;
3337  Oid opno;
3338  Node *leftarg;
3339 
3340  if (restrictinfo->pseudoconstant)
3341  return;
3342  if (!is_opclause(clause))
3343  return;
3344  if (list_length(((OpExpr *) clause)->args) != 2)
3345  return;
3346 
3347  opno = ((OpExpr *) clause)->opno;
3348  leftarg = linitial(((OpExpr *) clause)->args);
3349 
3350  if (op_mergejoinable(opno, exprType(leftarg)) &&
3351  !contain_volatile_functions((Node *) restrictinfo))
3352  restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
3353 
3354  /*
3355  * Note: op_mergejoinable is just a hint; if we fail to find the operator
3356  * in any btree opfamilies, mergeopfamilies remains NIL and so the clause
3357  * is not treated as mergejoinable.
3358  */
3359 }
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:366
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1386

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

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

◆ check_redundant_nullability_qual()

static bool check_redundant_nullability_qual ( PlannerInfo root,
Node clause 
)
static

Definition at line 2584 of file initsplan.c.

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

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

Referenced by distribute_qual_to_rels().

◆ compute_semijoin_info()

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

Definition at line 1700 of file initsplan.c.

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

Referenced by make_outerjoininfo().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 501 of file initsplan.c.

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

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

Referenced by query_planner().

◆ deconstruct_distribute()

static void deconstruct_distribute ( PlannerInfo root,
JoinTreeItem jtitem 
)
static

Definition at line 1120 of file initsplan.c.

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

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

Referenced by deconstruct_jointree().

◆ deconstruct_distribute_oj_quals()

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

Definition at line 1878 of file initsplan.c.

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

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

Referenced by deconstruct_jointree().

◆ deconstruct_jointree()

List* deconstruct_jointree ( PlannerInfo root)

Definition at line 740 of file initsplan.c.

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

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

Referenced by query_planner().

◆ deconstruct_recurse()

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

Definition at line 822 of file initsplan.c.

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

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

Referenced by deconstruct_jointree().

◆ distribute_qual_to_rels()

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

Definition at line 2197 of file initsplan.c.

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

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

Referenced by distribute_quals_to_rels().

◆ distribute_quals_to_rels()

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

Definition at line 2119 of file initsplan.c.

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

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

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

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2836 of file initsplan.c.

2838 {
2839  Relids relids = restrictinfo->required_relids;
2840 
2841  if (!bms_is_empty(relids))
2842  {
2843  int relid;
2844 
2845  if (bms_get_singleton_member(relids, &relid))
2846  {
2847  /*
2848  * There is only one relation participating in the clause, so it
2849  * is a restriction clause for that relation.
2850  */
2851  add_base_clause_to_rel(root, relid, restrictinfo);
2852  }
2853  else
2854  {
2855  /*
2856  * The clause is a join clause, since there is more than one rel
2857  * in its relid set.
2858  */
2859 
2860  /*
2861  * Check for hashjoinable operators. (We don't bother setting the
2862  * hashjoin info except in true join clauses.)
2863  */
2864  check_hashjoinable(restrictinfo);
2865 
2866  /*
2867  * Likewise, check if the clause is suitable to be used with a
2868  * Memoize node to cache inner tuples during a parameterized
2869  * nested loop.
2870  */
2871  check_memoizable(restrictinfo);
2872 
2873  /*
2874  * Add clause to the join lists of all the relevant relations.
2875  */
2876  add_join_clause_to_rels(root, restrictinfo, relids);
2877  }
2878  }
2879  else
2880  {
2881  /*
2882  * clause references no rels, and therefore we have no place to attach
2883  * it. Shouldn't get here if callers are working properly.
2884  */
2885  elog(ERROR, "cannot cope with variable-free clause");
2886  }
2887 }
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:2629
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:98

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

Referenced by distribute_qual_to_rels(), generate_base_implied_equalities_broken(), generate_base_implied_equalities_const(), process_implied_equality(), reconsider_outer_join_clauses(), 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 2696 of file initsplan.c.

2697 {
2698  RelOptInfo *rel;
2699  Var *var;
2700 
2701  /* For now only check simple Vars */
2702  if (!IsA(expr, Var))
2703  return false;
2704 
2705  var = (Var *) expr;
2706 
2707  /* could the Var be nulled by any outer joins? */
2708  if (!bms_is_empty(var->varnullingrels))
2709  return false;
2710 
2711  /* system columns cannot be NULL */
2712  if (var->varattno < 0)
2713  return true;
2714 
2715  /* is the column defined NOT NULL? */
2716  rel = find_base_rel(root, var->varno);
2717  if (var->varattno > 0 &&
2719  return true;
2720 
2721  return false;
2722 }
Bitmapset * notnullattnums
Definition: pathnodes.h:926

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

Referenced by restriction_is_always_false(), and restriction_is_always_true().

◆ extract_lateral_references()

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

Definition at line 406 of file initsplan.c.

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

Referenced by find_lateral_references().

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 358 of file initsplan.c.

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

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

Referenced by query_planner().

◆ get_join_domain_min_rels()

static Relids get_join_domain_min_rels ( PlannerInfo root,
Relids  domain_relids 
)
static

Definition at line 3129 of file initsplan.c.

3130 {
3131  Relids result = bms_copy(domain_relids);
3132  ListCell *lc;
3133 
3134  /* Top-level join domain? */
3135  if (bms_equal(result, root->all_query_rels))
3136  return result;
3137 
3138  /* Nope, look for lower outer joins that could potentially commute out */
3139  foreach(lc, root->join_info_list)
3140  {
3141  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
3142 
3143  if (sjinfo->jointype == JOIN_LEFT &&
3144  bms_is_member(sjinfo->ojrelid, result))
3145  {
3146  result = bms_del_member(result, sjinfo->ojrelid);
3147  result = bms_del_members(result, sjinfo->syn_righthand);
3148  }
3149  }
3150  return result;
3151 }
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161

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

Referenced by process_implied_equality().

◆ make_outerjoininfo()

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

Definition at line 1360 of file initsplan.c.

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

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

Referenced by deconstruct_distribute().

◆ mark_rels_nulled_by_join()

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

Definition at line 1322 of file initsplan.c.

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

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

Referenced by deconstruct_recurse().

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 3169 of file initsplan.c.

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

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, EquivalenceClass::ec_has_const, get_commutator(), get_leftop(), get_rightop(), if(), InvalidOid, IsA, RelOptInfo::joininfo, lappend(), lfirst, list_length(), match_eclasses_to_foreign_key_col(), ForeignKeyOptInfo::nconst_ec, NIL, ForeignKeyOptInfo::nkeys, ForeignKeyOptInfo::nmatched_ec, ForeignKeyOptInfo::nmatched_rcols, ForeignKeyOptInfo::nmatched_ri, OidIsValid, OpExpr::opno, ForeignKeyOptInfo::ref_relid, RELOPT_BASEREL, RelOptInfo::reloptkind, ForeignKeyOptInfo::rinfos, and root.

Referenced by query_planner().

◆ process_implied_equality()

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

Definition at line 2921 of file initsplan.c.

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

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

Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().

◆ process_security_barrier_quals()

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

Definition at line 1272 of file initsplan.c.

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

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

Referenced by deconstruct_distribute().

◆ restriction_is_always_false()

bool restriction_is_always_false ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2781 of file initsplan.c.

2783 {
2784  /* Check for NullTest qual */
2785  if (IsA(restrictinfo->clause, NullTest))
2786  {
2787  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2788 
2789  /* is this NullTest an IS_NULL qual? */
2790  if (nulltest->nulltesttype != IS_NULL)
2791  return false;
2792 
2793  return expr_is_nonnullable(root, nulltest->arg);
2794  }
2795 
2796  /* If it's an OR, check its sub-clauses */
2797  if (restriction_is_or_clause(restrictinfo))
2798  {
2799  ListCell *lc;
2800 
2801  Assert(is_orclause(restrictinfo->orclause));
2802 
2803  /*
2804  * Currently, when processing OR expressions, we only return true when
2805  * all of the OR branches are always false. This could perhaps be
2806  * expanded to remove OR branches that are provably false. This may
2807  * be a useful thing to do as it could result in the OR being left
2808  * with a single arg. That's useful as it would allow the OR
2809  * condition to be replaced with its single argument which may allow
2810  * use of an index for faster filtering on the remaining condition.
2811  */
2812  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2813  {
2814  Node *orarg = (Node *) lfirst(lc);
2815 
2816  if (!IsA(orarg, RestrictInfo) ||
2818  return false;
2819  }
2820  return true;
2821  }
2822 
2823  return false;
2824 }
static bool expr_is_nonnullable(PlannerInfo *root, Expr *expr)
Definition: initsplan.c:2696
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:114
@ IS_NULL
Definition: primnodes.h:1924
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:416
NullTestType nulltesttype
Definition: primnodes.h:1931
Expr * arg
Definition: primnodes.h:1930

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

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

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2732 of file initsplan.c.

2734 {
2735  /* Check for NullTest qual */
2736  if (IsA(restrictinfo->clause, NullTest))
2737  {
2738  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2739 
2740  /* is this NullTest an IS_NOT_NULL qual? */
2741  if (nulltest->nulltesttype != IS_NOT_NULL)
2742  return false;
2743 
2744  return expr_is_nonnullable(root, nulltest->arg);
2745  }
2746 
2747  /* If it's an OR, check its sub-clauses */
2748  if (restriction_is_or_clause(restrictinfo))
2749  {
2750  ListCell *lc;
2751 
2752  Assert(is_orclause(restrictinfo->orclause));
2753 
2754  /*
2755  * if any of the given OR branches is provably always true then the
2756  * entire condition is true.
2757  */
2758  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2759  {
2760  Node *orarg = (Node *) lfirst(lc);
2761 
2762  if (!IsA(orarg, RestrictInfo))
2763  continue;
2764 
2766  return true;
2767  }
2768  }
2769 
2770  return false;
2771 }
@ IS_NOT_NULL
Definition: primnodes.h:1924

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

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

Variable Documentation

◆ from_collapse_limit

int from_collapse_limit

Definition at line 38 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().