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

Go to the source code of this file.

Data Structures

struct  JoinTreeItem
 

Typedefs

typedef struct JoinTreeItem JoinTreeItem
 

Functions

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

Variables

int from_collapse_limit
 
int join_collapse_limit
 

Typedef Documentation

◆ JoinTreeItem

typedef struct JoinTreeItem JoinTreeItem

Function Documentation

◆ add_base_clause_to_rel()

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

Definition at line 2980 of file initsplan.c.

2982{
2983 RelOptInfo *rel = find_base_rel(root, relid);
2984 RangeTblEntry *rte = root->simple_rte_array[relid];
2985
2987
2988 /*
2989 * For inheritance parent tables, we must always record the RestrictInfo
2990 * in baserestrictinfo as is. If we were to transform or skip adding it,
2991 * then the original wouldn't be available in apply_child_basequals. Since
2992 * there are two RangeTblEntries for inheritance parents, one with
2993 * inh==true and the other with inh==false, we're still able to apply this
2994 * optimization to the inh==false one. The inh==true one is what
2995 * apply_child_basequals() sees, whereas the inh==false one is what's used
2996 * for the scan node in the final plan.
2997 *
2998 * We make an exception to this for partitioned tables. For these, we
2999 * always apply the constant-TRUE and constant-FALSE transformations. A
3000 * qual which is either of these for a partitioned table must also be that
3001 * for all of its child partitions.
3002 */
3003 if (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE)
3004 {
3005 /* Don't add the clause if it is always true */
3006 if (restriction_is_always_true(root, restrictinfo))
3007 return;
3008
3009 /*
3010 * Substitute the origin qual with constant-FALSE if it is provably
3011 * always false.
3012 *
3013 * Note that we need to keep the same rinfo_serial, since it is in
3014 * practice the same condition. We also need to reset the
3015 * last_rinfo_serial counter, which is essential to ensure that the
3016 * RestrictInfos for the "same" qual condition get identical serial
3017 * numbers (see deconstruct_distribute_oj_quals).
3018 */
3019 if (restriction_is_always_false(root, restrictinfo))
3020 {
3021 int save_rinfo_serial = restrictinfo->rinfo_serial;
3022 int save_last_rinfo_serial = root->last_rinfo_serial;
3023
3024 restrictinfo = make_restrictinfo(root,
3025 (Expr *) makeBoolConst(false, false),
3026 restrictinfo->is_pushed_down,
3027 restrictinfo->has_clone,
3028 restrictinfo->is_clone,
3029 restrictinfo->pseudoconstant,
3030 0, /* security_level */
3031 restrictinfo->required_relids,
3032 restrictinfo->incompatible_relids,
3033 restrictinfo->outer_relids);
3034 restrictinfo->rinfo_serial = save_rinfo_serial;
3035 root->last_rinfo_serial = save_last_rinfo_serial;
3036 }
3037 }
3038
3039 /* Add clause to rel's restriction list */
3040 rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo);
3041
3042 /* Update security level info */
3044 restrictinfo->security_level);
3045}
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_SINGLETON
Definition: bitmapset.h:72
#define Min(x, y)
Definition: c.h:975
Assert(PointerIsAligned(start, uint64))
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3091
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3149
List * lappend(List *list, void *datum)
Definition: list.c:339
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:408
tree ctl root
Definition: radixtree.h:1857
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:52
List * baserestrictinfo
Definition: pathnodes.h:1012
Index baserestrict_min_security
Definition: pathnodes.h:1016
bool is_pushed_down
Definition: pathnodes.h:2605
Index security_level
Definition: pathnodes.h:2624
Relids required_relids
Definition: pathnodes.h:2633
int rinfo_serial
Definition: pathnodes.h:2674
Relids outer_relids
Definition: pathnodes.h:2639
Relids incompatible_relids
Definition: pathnodes.h:2636
bool has_clone
Definition: pathnodes.h:2614

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

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

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

Referenced by add_base_rels_to_query(), and query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 196 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_vars_to_attr_needed()

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

Definition at line 353 of file initsplan.c.

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

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

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

◆ add_vars_to_targetlist()

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

Definition at line 282 of file initsplan.c.

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

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

236{
237 List *tlist_vars = pull_var_clause((Node *) final_tlist,
241
242 if (tlist_vars != NIL)
243 {
245 list_free(tlist_vars);
246 }
247
248 /*
249 * If there's a HAVING clause, we'll need the Vars it uses, too. Note
250 * that HAVING can contain Aggrefs but not WindowFuncs.
251 */
252 if (root->parse->havingQual)
253 {
254 List *having_vars = pull_var_clause(root->parse->havingQual,
257
258 if (having_vars != NIL)
259 {
260 add_vars_to_targetlist(root, having_vars,
262 list_free(having_vars);
263 }
264 }
265}
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:282
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:188
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:190
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:191
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
List * pull_var_clause(Node *node, int flags)
Definition: var.c:653

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

3449{
3450 RestrictInfo *restrictinfo;
3451 Expr *clause;
3452
3453 /*
3454 * Build the new clause. Copy to ensure it shares no substructure with
3455 * original (this is necessary in case there are subselects in there...)
3456 */
3457 clause = make_opclause(opno,
3458 BOOLOID, /* opresulttype */
3459 false, /* opretset */
3460 copyObject(item1),
3461 copyObject(item2),
3462 InvalidOid,
3463 collation);
3464
3465 /*
3466 * Build the RestrictInfo node itself.
3467 */
3468 restrictinfo = make_restrictinfo(root,
3469 clause,
3470 true, /* is_pushed_down */
3471 false, /* !has_clone */
3472 false, /* !is_clone */
3473 false, /* pseudoconstant */
3474 security_level, /* security_level */
3475 qualscope, /* required_relids */
3476 NULL, /* incompatible_relids */
3477 NULL); /* outer_relids */
3478
3479 /* Set mergejoinability/hashjoinability flags */
3480 check_mergejoinable(restrictinfo);
3481 check_hashjoinable(restrictinfo);
3482 check_memoizable(restrictinfo);
3483
3484 return restrictinfo;
3485}
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3819
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3782
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3847
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:701
#define InvalidOid
Definition: postgres_ext.h:37

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

3820{
3821 Expr *clause = restrictinfo->clause;
3822 Oid opno;
3823 Node *leftarg;
3824
3825 if (restrictinfo->pseudoconstant)
3826 return;
3827 if (!is_opclause(clause))
3828 return;
3829 if (list_length(((OpExpr *) clause)->args) != 2)
3830 return;
3831
3832 opno = ((OpExpr *) clause)->opno;
3833 leftarg = linitial(((OpExpr *) clause)->args);
3834
3835 if (op_hashjoinable(opno, exprType(leftarg)) &&
3836 !contain_volatile_functions((Node *) restrictinfo))
3837 restrictinfo->hashjoinoperator = opno;
3838}
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:537
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1520
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:76
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
unsigned int Oid
Definition: postgres_ext.h:32
Expr * clause
Definition: pathnodes.h:2602

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

3848{
3849 TypeCacheEntry *typentry;
3850 Expr *clause = restrictinfo->clause;
3851 Oid lefttype;
3852 Oid righttype;
3853
3854 if (restrictinfo->pseudoconstant)
3855 return;
3856 if (!is_opclause(clause))
3857 return;
3858 if (list_length(((OpExpr *) clause)->args) != 2)
3859 return;
3860
3861 lefttype = exprType(linitial(((OpExpr *) clause)->args));
3862
3863 typentry = lookup_type_cache(lefttype, TYPECACHE_HASH_PROC |
3865
3866 if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3867 restrictinfo->left_hasheqoperator = typentry->eq_opr;
3868
3869 righttype = exprType(lsecond(((OpExpr *) clause)->args));
3870
3871 /*
3872 * Lookup the right type, unless it's the same as the left type, in which
3873 * case typentry is already pointing to the required TypeCacheEntry.
3874 */
3875 if (lefttype != righttype)
3876 typentry = lookup_type_cache(righttype, TYPECACHE_HASH_PROC |
3878
3879 if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
3880 restrictinfo->right_hasheqoperator = typentry->eq_opr;
3881}
#define OidIsValid(objectId)
Definition: c.h:746
#define lsecond(l)
Definition: pg_list.h:183
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_EQ_OPR
Definition: typcache.h:137
#define TYPECACHE_HASH_PROC
Definition: typcache.h:141

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

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

◆ check_mergejoinable()

static void check_mergejoinable ( RestrictInfo restrictinfo)
static

Definition at line 3782 of file initsplan.c.

3783{
3784 Expr *clause = restrictinfo->clause;
3785 Oid opno;
3786 Node *leftarg;
3787
3788 if (restrictinfo->pseudoconstant)
3789 return;
3790 if (!is_opclause(clause))
3791 return;
3792 if (list_length(((OpExpr *) clause)->args) != 2)
3793 return;
3794
3795 opno = ((OpExpr *) clause)->opno;
3796 leftarg = linitial(((OpExpr *) clause)->args);
3797
3798 if (op_mergejoinable(opno, exprType(leftarg)) &&
3799 !contain_volatile_functions((Node *) restrictinfo))
3800 restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
3801
3802 /*
3803 * Note: op_mergejoinable is just a hint; if we fail to find the operator
3804 * in any btree opfamilies, mergeopfamilies remains NIL and so the clause
3805 * is not treated as mergejoinable.
3806 */
3807}
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1469
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:389

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

2936{
2937 Var *forced_null_var;
2938 ListCell *lc;
2939
2940 /* Check for IS NULL, and identify the Var forced to NULL */
2941 forced_null_var = find_forced_null_var(clause);
2942 if (forced_null_var == NULL)
2943 return false;
2944
2945 /*
2946 * If the Var comes from the nullable side of a lower antijoin, the IS
2947 * NULL condition is necessarily true. If it's not nulled by anything,
2948 * there is no point in searching the join_info_list. Otherwise, we need
2949 * to find out whether the nulling rel is an antijoin.
2950 */
2951 if (forced_null_var->varnullingrels == NULL)
2952 return false;
2953
2954 foreach(lc, root->join_info_list)
2955 {
2956 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
2957
2958 /*
2959 * This test will not succeed if sjinfo->ojrelid is zero, which is
2960 * possible for an antijoin that was converted from a semijoin; but in
2961 * such a case the Var couldn't have come from its nullable side.
2962 */
2963 if (sjinfo->jointype == JOIN_ANTI && sjinfo->ojrelid != 0 &&
2964 bms_is_member(sjinfo->ojrelid, forced_null_var->varnullingrels))
2965 return true;
2966 }
2967
2968 return false;
2969}
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:310
JoinType jointype
Definition: pathnodes.h:2936

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

2049{
2050 List *semi_operators;
2051 List *semi_rhs_exprs;
2052 bool all_btree;
2053 bool all_hash;
2054 ListCell *lc;
2055
2056 /* Initialize semijoin-related fields in case we can't unique-ify */
2057 sjinfo->semi_can_btree = false;
2058 sjinfo->semi_can_hash = false;
2059 sjinfo->semi_operators = NIL;
2060 sjinfo->semi_rhs_exprs = NIL;
2061
2062 /* Nothing more to do if it's not a semijoin */
2063 if (sjinfo->jointype != JOIN_SEMI)
2064 return;
2065
2066 /*
2067 * Look to see whether the semijoin's join quals consist of AND'ed
2068 * equality operators, with (only) RHS variables on only one side of each
2069 * one. If so, we can figure out how to enforce uniqueness for the RHS.
2070 *
2071 * Note that the input clause list is the list of quals that are
2072 * *syntactically* associated with the semijoin, which in practice means
2073 * the synthesized comparison list for an IN or the WHERE of an EXISTS.
2074 * Particularly in the latter case, it might contain clauses that aren't
2075 * *semantically* associated with the join, but refer to just one side or
2076 * the other. We can ignore such clauses here, as they will just drop
2077 * down to be processed within one side or the other. (It is okay to
2078 * consider only the syntactically-associated clauses here because for a
2079 * semijoin, no higher-level quals could refer to the RHS, and so there
2080 * can be no other quals that are semantically associated with this join.
2081 * We do things this way because it is useful to have the set of potential
2082 * unique-ification expressions before we can extract the list of quals
2083 * that are actually semantically associated with the particular join.)
2084 *
2085 * Note that the semi_operators list consists of the joinqual operators
2086 * themselves (but commuted if needed to put the RHS value on the right).
2087 * These could be cross-type operators, in which case the operator
2088 * actually needed for uniqueness is a related single-type operator. We
2089 * assume here that that operator will be available from the btree or hash
2090 * opclass when the time comes ... if not, create_unique_plan() will fail.
2091 */
2092 semi_operators = NIL;
2093 semi_rhs_exprs = NIL;
2094 all_btree = true;
2095 all_hash = enable_hashagg; /* don't consider hash if not enabled */
2096 foreach(lc, clause)
2097 {
2098 OpExpr *op = (OpExpr *) lfirst(lc);
2099 Oid opno;
2100 Node *left_expr;
2101 Node *right_expr;
2102 Relids left_varnos;
2103 Relids right_varnos;
2104 Relids all_varnos;
2105 Oid opinputtype;
2106
2107 /* Is it a binary opclause? */
2108 if (!IsA(op, OpExpr) ||
2109 list_length(op->args) != 2)
2110 {
2111 /* No, but does it reference both sides? */
2112 all_varnos = pull_varnos(root, (Node *) op);
2113 if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
2114 bms_is_subset(all_varnos, sjinfo->syn_righthand))
2115 {
2116 /*
2117 * Clause refers to only one rel, so ignore it --- unless it
2118 * contains volatile functions, in which case we'd better
2119 * punt.
2120 */
2121 if (contain_volatile_functions((Node *) op))
2122 return;
2123 continue;
2124 }
2125 /* Non-operator clause referencing both sides, must punt */
2126 return;
2127 }
2128
2129 /* Extract data from binary opclause */
2130 opno = op->opno;
2131 left_expr = linitial(op->args);
2132 right_expr = lsecond(op->args);
2133 left_varnos = pull_varnos(root, left_expr);
2134 right_varnos = pull_varnos(root, right_expr);
2135 all_varnos = bms_union(left_varnos, right_varnos);
2136 opinputtype = exprType(left_expr);
2137
2138 /* Does it reference both sides? */
2139 if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
2140 bms_is_subset(all_varnos, sjinfo->syn_righthand))
2141 {
2142 /*
2143 * Clause refers to only one rel, so ignore it --- unless it
2144 * contains volatile functions, in which case we'd better punt.
2145 */
2146 if (contain_volatile_functions((Node *) op))
2147 return;
2148 continue;
2149 }
2150
2151 /* check rel membership of arguments */
2152 if (!bms_is_empty(right_varnos) &&
2153 bms_is_subset(right_varnos, sjinfo->syn_righthand) &&
2154 !bms_overlap(left_varnos, sjinfo->syn_righthand))
2155 {
2156 /* typical case, right_expr is RHS variable */
2157 }
2158 else if (!bms_is_empty(left_varnos) &&
2159 bms_is_subset(left_varnos, sjinfo->syn_righthand) &&
2160 !bms_overlap(right_varnos, sjinfo->syn_righthand))
2161 {
2162 /* flipped case, left_expr is RHS variable */
2163 opno = get_commutator(opno);
2164 if (!OidIsValid(opno))
2165 return;
2166 right_expr = left_expr;
2167 }
2168 else
2169 {
2170 /* mixed membership of args, punt */
2171 return;
2172 }
2173
2174 /* all operators must be btree equality or hash equality */
2175 if (all_btree)
2176 {
2177 /* oprcanmerge is considered a hint... */
2178 if (!op_mergejoinable(opno, opinputtype) ||
2180 all_btree = false;
2181 }
2182 if (all_hash)
2183 {
2184 /* ... but oprcanhash had better be correct */
2185 if (!op_hashjoinable(opno, opinputtype))
2186 all_hash = false;
2187 }
2188 if (!(all_btree || all_hash))
2189 return;
2190
2191 /* so far so good, keep building lists */
2192 semi_operators = lappend_oid(semi_operators, opno);
2193 semi_rhs_exprs = lappend(semi_rhs_exprs, copyObject(right_expr));
2194 }
2195
2196 /* Punt if we didn't find at least one column to unique-ify */
2197 if (semi_rhs_exprs == NIL)
2198 return;
2199
2200 /*
2201 * The expressions we'd need to unique-ify mustn't be volatile.
2202 */
2203 if (contain_volatile_functions((Node *) semi_rhs_exprs))
2204 return;
2205
2206 /*
2207 * If we get here, we can unique-ify the semijoin's RHS using at least one
2208 * of sorting and hashing. Save the information about how to do that.
2209 */
2210 sjinfo->semi_can_btree = all_btree;
2211 sjinfo->semi_can_hash = all_hash;
2212 sjinfo->semi_operators = semi_operators;
2213 sjinfo->semi_rhs_exprs = semi_rhs_exprs;
2214}
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
bool enable_hashagg
Definition: costsize.c:152
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1592
@ JOIN_SEMI
Definition: nodes.h:309
Oid opno
Definition: primnodes.h:835
List * args
Definition: primnodes.h:853
List * semi_rhs_exprs
Definition: pathnodes.h:2947
Relids syn_righthand
Definition: pathnodes.h:2935
List * semi_operators
Definition: pathnodes.h:2946
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:114

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

846{
847 bool found_laterals = false;
848 Index rti;
849 ListCell *lc;
850
851 /* We need do nothing if the query contains no LATERAL RTEs */
852 if (!root->hasLateralRTEs)
853 return;
854
855 /* We'll need to have the ph_eval_at values for PlaceHolderVars */
856 Assert(root->placeholdersFrozen);
857
858 /*
859 * Examine all baserels (the rel array has been set up by now).
860 */
861 for (rti = 1; rti < root->simple_rel_array_size; rti++)
862 {
863 RelOptInfo *brel = root->simple_rel_array[rti];
864 Relids lateral_relids;
865
866 /* there may be empty slots corresponding to non-baserel RTEs */
867 if (brel == NULL)
868 continue;
869
870 Assert(brel->relid == rti); /* sanity check on array */
871
872 /* ignore RTEs that are "other rels" */
873 if (brel->reloptkind != RELOPT_BASEREL)
874 continue;
875
876 lateral_relids = NULL;
877
878 /* consider each laterally-referenced Var or PHV */
879 foreach(lc, brel->lateral_vars)
880 {
881 Node *node = (Node *) lfirst(lc);
882
883 if (IsA(node, Var))
884 {
885 Var *var = (Var *) node;
886
887 found_laterals = true;
888 lateral_relids = bms_add_member(lateral_relids,
889 var->varno);
890 }
891 else if (IsA(node, PlaceHolderVar))
892 {
893 PlaceHolderVar *phv = (PlaceHolderVar *) node;
895
896 found_laterals = true;
897 lateral_relids = bms_add_members(lateral_relids,
898 phinfo->ph_eval_at);
899 }
900 else
901 Assert(false);
902 }
903
904 /* We now have all the simple lateral refs from this rel */
905 brel->direct_lateral_relids = lateral_relids;
906 brel->lateral_relids = bms_copy(lateral_relids);
907 }
908
909 /*
910 * Now check for lateral references within PlaceHolderVars, and mark their
911 * eval_at rels as having lateral references to the source rels.
912 *
913 * For a PHV that is due to be evaluated at a baserel, mark its source(s)
914 * as direct lateral dependencies of the baserel (adding onto the ones
915 * recorded above). If it's due to be evaluated at a join, mark its
916 * source(s) as indirect lateral dependencies of each baserel in the join,
917 * ie put them into lateral_relids but not direct_lateral_relids. This is
918 * appropriate because we can't put any such baserel on the outside of a
919 * join to one of the PHV's lateral dependencies, but on the other hand we
920 * also can't yet join it directly to the dependency.
921 */
922 foreach(lc, root->placeholder_list)
923 {
924 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
925 Relids eval_at = phinfo->ph_eval_at;
926 Relids lateral_refs;
927 int varno;
928
929 if (phinfo->ph_lateral == NULL)
930 continue; /* PHV is uninteresting if no lateral refs */
931
932 found_laterals = true;
933
934 /*
935 * Include only baserels not outer joins in the evaluation sites'
936 * lateral relids. This avoids problems when outer join order gets
937 * rearranged, and it should still ensure that the lateral values are
938 * available when needed.
939 */
940 lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels);
941 Assert(!bms_is_empty(lateral_refs));
942
943 if (bms_get_singleton_member(eval_at, &varno))
944 {
945 /* Evaluation site is a baserel */
946 RelOptInfo *brel = find_base_rel(root, varno);
947
950 lateral_refs);
951 brel->lateral_relids =
953 lateral_refs);
954 }
955 else
956 {
957 /* Evaluation site is a join */
958 varno = -1;
959 while ((varno = bms_next_member(eval_at, varno)) >= 0)
960 {
962
963 if (brel == NULL)
964 continue; /* ignore outer joins in eval_at */
966 lateral_refs);
967 }
968 }
969 }
970
971 /*
972 * If we found no actual lateral references, we're done; but reset the
973 * hasLateralRTEs flag to avoid useless work later.
974 */
975 if (!found_laterals)
976 {
977 root->hasLateralRTEs = false;
978 return;
979 }
980
981 /*
982 * Calculate the transitive closure of the lateral_relids sets, so that
983 * they describe both direct and indirect lateral references. If relation
984 * X references Y laterally, and Y references Z laterally, then we will
985 * have to scan X on the inside of a nestloop with Z, so for all intents
986 * and purposes X is laterally dependent on Z too.
987 *
988 * This code is essentially Warshall's algorithm for transitive closure.
989 * The outer loop considers each baserel, and propagates its lateral
990 * dependencies to those baserels that have a lateral dependency on it.
991 */
992 for (rti = 1; rti < root->simple_rel_array_size; rti++)
993 {
994 RelOptInfo *brel = root->simple_rel_array[rti];
995 Relids outer_lateral_relids;
996 Index rti2;
997
998 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
999 continue;
1000
1001 /* need not consider baserel further if it has no lateral refs */
1002 outer_lateral_relids = brel->lateral_relids;
1003 if (outer_lateral_relids == NULL)
1004 continue;
1005
1006 /* else scan all baserels */
1007 for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
1008 {
1009 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1010
1011 if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
1012 continue;
1013
1014 /* if brel2 has lateral ref to brel, propagate brel's refs */
1015 if (bms_is_member(rti, brel2->lateral_relids))
1017 outer_lateral_relids);
1018 }
1019 }
1020
1021 /*
1022 * Now that we've identified all lateral references, mark each baserel
1023 * with the set of relids of rels that reference it laterally (possibly
1024 * indirectly) --- that is, the inverse mapping of lateral_relids.
1025 */
1026 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1027 {
1028 RelOptInfo *brel = root->simple_rel_array[rti];
1029 Relids lateral_relids;
1030 int rti2;
1031
1032 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
1033 continue;
1034
1035 /* Nothing to do at rels with no lateral refs */
1036 lateral_relids = brel->lateral_relids;
1037 if (bms_is_empty(lateral_relids))
1038 continue;
1039
1040 /* No rel should have a lateral dependency on itself */
1041 Assert(!bms_is_member(rti, lateral_relids));
1042
1043 /* Mark this rel's referencees */
1044 rti2 = -1;
1045 while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
1046 {
1047 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1048
1049 if (brel2 == NULL)
1050 continue; /* must be an OJ */
1051
1052 Assert(brel2->reloptkind == RELOPT_BASEREL);
1053 brel2->lateral_referencers =
1055 }
1056 }
1057}
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:292
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
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:715
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
unsigned int Index
Definition: c.h:585
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:454
Relids ph_lateral
Definition: pathnodes.h:3129
Relids ph_eval_at
Definition: pathnodes.h:3126
Index relid
Definition: pathnodes.h:945
List * lateral_vars
Definition: pathnodes.h:967
Relids lateral_relids
Definition: pathnodes.h:940
Relids lateral_referencers
Definition: pathnodes.h:969
Relids direct_lateral_relids
Definition: pathnodes.h:938

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

1465{
1466 Node *jtnode = jtitem->jtnode;
1467
1468 if (IsA(jtnode, RangeTblRef))
1469 {
1470 int varno = ((RangeTblRef *) jtnode)->rtindex;
1471
1472 /* Deal with any securityQuals attached to the RTE */
1473 if (root->qual_security_level > 0)
1475 varno,
1476 jtitem);
1477 }
1478 else if (IsA(jtnode, FromExpr))
1479 {
1480 FromExpr *f = (FromExpr *) jtnode;
1481
1482 /*
1483 * Process any lateral-referencing quals that were postponed to this
1484 * level by children.
1485 */
1487 jtitem,
1488 NULL,
1489 root->qual_security_level,
1490 jtitem->qualscope,
1491 NULL, NULL, NULL,
1492 true, false, false,
1493 NULL);
1494
1495 /*
1496 * Now process the top-level quals.
1497 */
1499 jtitem,
1500 NULL,
1501 root->qual_security_level,
1502 jtitem->qualscope,
1503 NULL, NULL, NULL,
1504 true, false, false,
1505 NULL);
1506 }
1507 else if (IsA(jtnode, JoinExpr))
1508 {
1509 JoinExpr *j = (JoinExpr *) jtnode;
1510 Relids ojscope;
1511 List *my_quals;
1512 SpecialJoinInfo *sjinfo;
1513 List **postponed_oj_qual_list;
1514
1515 /*
1516 * Include lateral-referencing quals postponed from children in
1517 * my_quals, so that they'll be handled properly in
1518 * make_outerjoininfo. (This is destructive to
1519 * jtitem->lateral_clauses, but we won't use that again.)
1520 */
1521 my_quals = list_concat(jtitem->lateral_clauses,
1522 (List *) j->quals);
1523
1524 /*
1525 * For an OJ, form the SpecialJoinInfo now, so that we can pass it to
1526 * distribute_qual_to_rels. We must compute its ojscope too.
1527 *
1528 * Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we
1529 * want ojscope = NULL for distribute_qual_to_rels.
1530 */
1531 if (j->jointype != JOIN_INNER)
1532 {
1533 sjinfo = make_outerjoininfo(root,
1534 jtitem->left_rels,
1535 jtitem->right_rels,
1536 jtitem->inner_join_rels,
1537 j->jointype,
1538 j->rtindex,
1539 my_quals);
1540 jtitem->sjinfo = sjinfo;
1541 if (j->jointype == JOIN_SEMI)
1542 ojscope = NULL;
1543 else
1544 ojscope = bms_union(sjinfo->min_lefthand,
1545 sjinfo->min_righthand);
1546 }
1547 else
1548 {
1549 sjinfo = NULL;
1550 ojscope = NULL;
1551 }
1552
1553 /*
1554 * If it's a left join with a join clause that is strict for the LHS,
1555 * then we need to postpone handling of any non-degenerate join
1556 * clauses, in case the join is able to commute with another left join
1557 * per identity 3. (Degenerate clauses need not be postponed, since
1558 * they will drop down below this join anyway.)
1559 */
1560 if (j->jointype == JOIN_LEFT && sjinfo->lhs_strict)
1561 {
1562 postponed_oj_qual_list = &jtitem->oj_joinclauses;
1563
1564 /*
1565 * Add back any commutable lower OJ relids that were removed from
1566 * min_lefthand or min_righthand, else the ojscope cross-check in
1567 * distribute_qual_to_rels will complain. Since we are postponing
1568 * processing of non-degenerate clauses, this addition doesn't
1569 * affect anything except that cross-check. Real clause
1570 * positioning decisions will be made later, when we revisit the
1571 * postponed clauses.
1572 */
1573 ojscope = bms_add_members(ojscope, sjinfo->commute_below_l);
1574 ojscope = bms_add_members(ojscope, sjinfo->commute_below_r);
1575 }
1576 else
1577 postponed_oj_qual_list = NULL;
1578
1579 /* Process the JOIN's qual clauses */
1581 jtitem,
1582 sjinfo,
1583 root->qual_security_level,
1584 jtitem->qualscope,
1585 ojscope, jtitem->nonnullable_rels,
1586 NULL, /* incompatible_relids */
1587 true, /* allow_equivalence */
1588 false, false, /* not clones */
1589 postponed_oj_qual_list);
1590
1591 /* And add the SpecialJoinInfo to join_info_list */
1592 if (sjinfo)
1593 root->join_info_list = lappend(root->join_info_list, sjinfo);
1594 }
1595 else
1596 {
1597 elog(ERROR, "unrecognized node type: %d",
1598 (int) nodeTag(jtnode));
1599 }
1600}
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:2467
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:1708
static void process_security_barrier_quals(PlannerInfo *root, int rti, JoinTreeItem *jtitem)
Definition: initsplan.c:1616
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
@ JOIN_INNER
Definition: nodes.h:295
@ JOIN_LEFT
Definition: nodes.h:296
Node * quals
Definition: primnodes.h:2338
SpecialJoinInfo * sjinfo
Definition: initsplan.c:77
Relids inner_join_rels
Definition: initsplan.c:69
Relids left_rels
Definition: initsplan.c:72
Relids right_rels
Definition: initsplan.c:73
Relids nonnullable_rels
Definition: initsplan.c:74
Node * jtnode
Definition: initsplan.c:63
List * oj_joinclauses
Definition: initsplan.c:78
Relids qualscope
Definition: initsplan.c:67
List * lateral_clauses
Definition: initsplan.c:79
Relids min_righthand
Definition: pathnodes.h:2933
Relids commute_below_l
Definition: pathnodes.h:2940
Relids min_lefthand
Definition: pathnodes.h:2932
Relids commute_below_r
Definition: pathnodes.h:2941

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

2229{
2230 SpecialJoinInfo *sjinfo = jtitem->sjinfo;
2231 Relids qualscope,
2232 ojscope,
2233 nonnullable_rels;
2234
2235 /* Recompute syntactic and semantic scopes of this left join */
2236 qualscope = bms_union(sjinfo->syn_lefthand, sjinfo->syn_righthand);
2237 qualscope = bms_add_member(qualscope, sjinfo->ojrelid);
2238 ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
2239 nonnullable_rels = sjinfo->syn_lefthand;
2240
2241 /*
2242 * If this join can commute with any other ones per outer-join identity 3,
2243 * and it is the one providing the join clause with flexible semantics,
2244 * then we have to generate variants of the join clause with different
2245 * nullingrels labeling. Otherwise, just push out the postponed clause
2246 * as-is.
2247 */
2248 Assert(sjinfo->lhs_strict); /* else we shouldn't be here */
2249 if (sjinfo->commute_above_r || sjinfo->commute_below_l)
2250 {
2251 Relids joins_above;
2252 Relids joins_below;
2253 Relids incompatible_joins;
2254 Relids joins_so_far;
2255 List *quals;
2256 int save_last_rinfo_serial;
2257 ListCell *lc;
2258
2259 /* Identify the outer joins this one commutes with */
2260 joins_above = sjinfo->commute_above_r;
2261 joins_below = sjinfo->commute_below_l;
2262
2263 /*
2264 * Generate qual variants with different sets of nullingrels bits.
2265 *
2266 * We only need bit-sets that correspond to the successively less
2267 * deeply syntactically-nested subsets of this join and its
2268 * commutators. That's true first because obviously only those forms
2269 * of the Vars and PHVs could appear elsewhere in the query, and
2270 * second because the outer join identities do not provide a way to
2271 * re-order such joins in a way that would require different marking.
2272 * (That is, while the current join may commute with several others,
2273 * none of those others can commute with each other.) To visit the
2274 * interesting joins in syntactic nesting order, we rely on the
2275 * jtitems list to be ordered that way.
2276 *
2277 * We first strip out all the nullingrels bits corresponding to
2278 * commuting joins below this one, and then successively put them back
2279 * as we crawl up the join stack.
2280 */
2281 quals = jtitem->oj_joinclauses;
2282 if (!bms_is_empty(joins_below))
2283 quals = (List *) remove_nulling_relids((Node *) quals,
2284 joins_below,
2285 NULL);
2286
2287 /*
2288 * We'll need to mark the lower versions of the quals as not safe to
2289 * apply above not-yet-processed joins of the stack. This prevents
2290 * possibly applying a cloned qual at the wrong join level.
2291 */
2292 incompatible_joins = bms_union(joins_below, joins_above);
2293 incompatible_joins = bms_add_member(incompatible_joins,
2294 sjinfo->ojrelid);
2295
2296 /*
2297 * Each time we produce RestrictInfo(s) from these quals, reset the
2298 * last_rinfo_serial counter, so that the RestrictInfos for the "same"
2299 * qual condition get identical serial numbers. (This relies on the
2300 * fact that we're not changing the qual list in any way that'd affect
2301 * the number of RestrictInfos built from it.) This'll allow us to
2302 * detect duplicative qual usage later.
2303 */
2304 save_last_rinfo_serial = root->last_rinfo_serial;
2305
2306 joins_so_far = NULL;
2307 foreach(lc, jtitems)
2308 {
2309 JoinTreeItem *otherjtitem = (JoinTreeItem *) lfirst(lc);
2310 SpecialJoinInfo *othersj = otherjtitem->sjinfo;
2311 bool below_sjinfo = false;
2312 bool above_sjinfo = false;
2313 Relids this_qualscope;
2314 Relids this_ojscope;
2315 bool allow_equivalence,
2316 has_clone,
2317 is_clone;
2318
2319 if (othersj == NULL)
2320 continue; /* not an outer-join item, ignore */
2321
2322 if (bms_is_member(othersj->ojrelid, joins_below))
2323 {
2324 /* othersj commutes with sjinfo from below left */
2325 below_sjinfo = true;
2326 }
2327 else if (othersj == sjinfo)
2328 {
2329 /* found our join in syntactic order */
2330 Assert(bms_equal(joins_so_far, joins_below));
2331 }
2332 else if (bms_is_member(othersj->ojrelid, joins_above))
2333 {
2334 /* othersj commutes with sjinfo from above */
2335 above_sjinfo = true;
2336 }
2337 else
2338 {
2339 /* othersj is not relevant, ignore */
2340 continue;
2341 }
2342
2343 /* Reset serial counter for this version of the quals */
2344 root->last_rinfo_serial = save_last_rinfo_serial;
2345
2346 /*
2347 * When we are looking at joins above sjinfo, we are envisioning
2348 * pushing sjinfo to above othersj, so add othersj's nulling bit
2349 * before distributing the quals. We should add it to Vars coming
2350 * from the current join's LHS: we want to transform the second
2351 * form of OJ identity 3 to the first form, in which Vars of
2352 * relation B will appear nulled by the syntactically-upper OJ
2353 * within the Pbc clause, but those of relation C will not. (In
2354 * the notation used by optimizer/README, we're converting a qual
2355 * of the form Pbc to Pb*c.) Of course, we must also remove that
2356 * bit from the incompatible_joins value, else we'll make a qual
2357 * that can't be placed anywhere.
2358 */
2359 if (above_sjinfo)
2360 {
2361 quals = (List *)
2362 add_nulling_relids((Node *) quals,
2363 sjinfo->syn_lefthand,
2364 bms_make_singleton(othersj->ojrelid));
2365 incompatible_joins = bms_del_member(incompatible_joins,
2366 othersj->ojrelid);
2367 }
2368
2369 /* Compute qualscope and ojscope for this join level */
2370 this_qualscope = bms_union(qualscope, joins_so_far);
2371 this_ojscope = bms_union(ojscope, joins_so_far);
2372 if (above_sjinfo)
2373 {
2374 /* othersj is not yet in joins_so_far, but we need it */
2375 this_qualscope = bms_add_member(this_qualscope,
2376 othersj->ojrelid);
2377 this_ojscope = bms_add_member(this_ojscope,
2378 othersj->ojrelid);
2379 /* sjinfo is in joins_so_far, and we don't want it */
2380 this_ojscope = bms_del_member(this_ojscope,
2381 sjinfo->ojrelid);
2382 }
2383
2384 /*
2385 * We generate EquivalenceClasses only from the first form of the
2386 * quals, with the fewest nullingrels bits set. An EC made from
2387 * this version of the quals can be useful below the outer-join
2388 * nest, whereas versions with some nullingrels bits set would not
2389 * be. We cannot generate ECs from more than one version, or
2390 * we'll make nonsensical conclusions that Vars with nullingrels
2391 * bits set are equal to their versions without. Fortunately,
2392 * such ECs wouldn't be very useful anyway, because they'd equate
2393 * values not observable outside the join nest. (See
2394 * optimizer/README.)
2395 *
2396 * The first form of the quals is also the only one marked as
2397 * has_clone rather than is_clone.
2398 */
2399 allow_equivalence = (joins_so_far == NULL);
2400 has_clone = allow_equivalence;
2401 is_clone = !has_clone;
2402
2404 otherjtitem,
2405 sjinfo,
2406 root->qual_security_level,
2407 this_qualscope,
2408 this_ojscope, nonnullable_rels,
2409 bms_copy(incompatible_joins),
2410 allow_equivalence,
2411 has_clone,
2412 is_clone,
2413 NULL); /* no more postponement */
2414
2415 /*
2416 * Adjust qual nulling bits for next level up, if needed. We
2417 * don't want to put sjinfo's own bit in at all, and if we're
2418 * above sjinfo then we did it already. Here, we should mark all
2419 * Vars coming from the lower join's RHS. (Again, we are
2420 * converting a qual of the form Pbc to Pb*c, but now we are
2421 * putting back bits that were there in the parser output and were
2422 * temporarily stripped above.) Update incompatible_joins too.
2423 */
2424 if (below_sjinfo)
2425 {
2426 quals = (List *)
2427 add_nulling_relids((Node *) quals,
2428 othersj->syn_righthand,
2429 bms_make_singleton(othersj->ojrelid));
2430 incompatible_joins = bms_del_member(incompatible_joins,
2431 othersj->ojrelid);
2432 }
2433
2434 /* ... and track joins processed so far */
2435 joins_so_far = bms_add_member(joins_so_far, othersj->ojrelid);
2436 }
2437 }
2438 else
2439 {
2440 /* No commutation possible, just process the postponed clauses */
2442 jtitem,
2443 sjinfo,
2444 root->qual_security_level,
2445 qualscope,
2446 ojscope, nonnullable_rels,
2447 NULL, /* incompatible_relids */
2448 true, /* allow_equivalence */
2449 false, false, /* not clones */
2450 NULL); /* no more postponement */
2451 }
2452}
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 * add_nulling_relids(Node *node, const Bitmapset *target_relids, const Bitmapset *added_relids)
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)
Relids commute_above_r
Definition: pathnodes.h:2939
Relids syn_lefthand
Definition: pathnodes.h:2934

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

1085{
1086 List *result;
1087 JoinDomain *top_jdomain;
1088 List *item_list = NIL;
1089 ListCell *lc;
1090
1091 /*
1092 * After this point, no more PlaceHolderInfos may be made, because
1093 * make_outerjoininfo requires all active placeholders to be present in
1094 * root->placeholder_list while we crawl up the join tree.
1095 */
1096 root->placeholdersFrozen = true;
1097
1098 /* Fetch the already-created top-level join domain for the query */
1099 top_jdomain = linitial_node(JoinDomain, root->join_domains);
1100 top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
1101
1102 /* Start recursion at top of jointree */
1103 Assert(root->parse->jointree != NULL &&
1104 IsA(root->parse->jointree, FromExpr));
1105
1106 /* These are filled as we scan the jointree */
1107 root->all_baserels = NULL;
1108 root->outer_join_rels = NULL;
1109
1110 /* Perform the initial scan of the jointree */
1111 result = deconstruct_recurse(root, (Node *) root->parse->jointree,
1112 top_jdomain, NULL,
1113 &item_list);
1114
1115 /* Now we can form the value of all_query_rels, too */
1116 root->all_query_rels = bms_union(root->all_baserels, root->outer_join_rels);
1117
1118 /* ... which should match what we computed for the top join domain */
1119 Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
1120
1121 /* Now scan all the jointree nodes again, and distribute quals */
1122 foreach(lc, item_list)
1123 {
1124 JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
1125
1127 }
1128
1129 /*
1130 * If there were any special joins then we may have some postponed LEFT
1131 * JOIN clauses to deal with.
1132 */
1133 if (root->join_info_list)
1134 {
1135 foreach(lc, item_list)
1136 {
1137 JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
1138
1139 if (jtitem->oj_joinclauses != NIL)
1140 deconstruct_distribute_oj_quals(root, item_list, jtitem);
1141 }
1142 }
1143
1144 /* Don't need the JoinTreeItems any more */
1145 list_free_deep(item_list);
1146
1147 return result;
1148}
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, JoinTreeItem *parent_jtitem, List **item_list)
Definition: initsplan.c:1166
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:2226
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition: initsplan.c:1464
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:1359

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

1170{
1171 List *joinlist;
1172 JoinTreeItem *jtitem;
1173
1174 Assert(jtnode != NULL);
1175
1176 /* Make the new JoinTreeItem, but don't add it to item_list yet */
1177 jtitem = palloc0_object(JoinTreeItem);
1178 jtitem->jtnode = jtnode;
1179 jtitem->jti_parent = parent_jtitem;
1180
1181 if (IsA(jtnode, RangeTblRef))
1182 {
1183 int varno = ((RangeTblRef *) jtnode)->rtindex;
1184
1185 /* Fill all_baserels as we encounter baserel jointree nodes */
1186 root->all_baserels = bms_add_member(root->all_baserels, varno);
1187 /* This node belongs to parent_domain */
1188 jtitem->jdomain = parent_domain;
1189 parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
1190 varno);
1191 /* qualscope is just the one RTE */
1192 jtitem->qualscope = bms_make_singleton(varno);
1193 /* A single baserel does not create an inner join */
1194 jtitem->inner_join_rels = NULL;
1195 joinlist = list_make1(jtnode);
1196 }
1197 else if (IsA(jtnode, FromExpr))
1198 {
1199 FromExpr *f = (FromExpr *) jtnode;
1200 int remaining;
1201 ListCell *l;
1202
1203 /* This node belongs to parent_domain, as do its children */
1204 jtitem->jdomain = parent_domain;
1205
1206 /*
1207 * Recurse to handle child nodes, and compute output joinlist. We
1208 * collapse subproblems into a single joinlist whenever the resulting
1209 * joinlist wouldn't exceed from_collapse_limit members. Also, always
1210 * collapse one-element subproblems, since that won't lengthen the
1211 * joinlist anyway.
1212 */
1213 jtitem->qualscope = NULL;
1214 jtitem->inner_join_rels = NULL;
1215 joinlist = NIL;
1217 foreach(l, f->fromlist)
1218 {
1219 JoinTreeItem *sub_item;
1220 List *sub_joinlist;
1221 int sub_members;
1222
1223 sub_joinlist = deconstruct_recurse(root, lfirst(l),
1224 parent_domain,
1225 jtitem,
1226 item_list);
1227 sub_item = (JoinTreeItem *) llast(*item_list);
1228 jtitem->qualscope = bms_add_members(jtitem->qualscope,
1229 sub_item->qualscope);
1230 jtitem->inner_join_rels = sub_item->inner_join_rels;
1231 sub_members = list_length(sub_joinlist);
1232 remaining--;
1233 if (sub_members <= 1 ||
1234 list_length(joinlist) + sub_members + remaining <= from_collapse_limit)
1235 joinlist = list_concat(joinlist, sub_joinlist);
1236 else
1237 joinlist = lappend(joinlist, sub_joinlist);
1238 }
1239
1240 /*
1241 * A FROM with more than one list element is an inner join subsuming
1242 * all below it, so we should report inner_join_rels = qualscope. If
1243 * there was exactly one element, we should (and already did) report
1244 * whatever its inner_join_rels were. If there were no elements (is
1245 * that still possible?) the initialization before the loop fixed it.
1246 */
1247 if (list_length(f->fromlist) > 1)
1248 jtitem->inner_join_rels = jtitem->qualscope;
1249 }
1250 else if (IsA(jtnode, JoinExpr))
1251 {
1252 JoinExpr *j = (JoinExpr *) jtnode;
1253 JoinDomain *child_domain,
1254 *fj_domain;
1255 JoinTreeItem *left_item,
1256 *right_item;
1257 List *leftjoinlist,
1258 *rightjoinlist;
1259
1260 switch (j->jointype)
1261 {
1262 case JOIN_INNER:
1263 /* This node belongs to parent_domain, as do its children */
1264 jtitem->jdomain = parent_domain;
1265 /* Recurse */
1266 leftjoinlist = deconstruct_recurse(root, j->larg,
1267 parent_domain,
1268 jtitem,
1269 item_list);
1270 left_item = (JoinTreeItem *) llast(*item_list);
1271 rightjoinlist = deconstruct_recurse(root, j->rarg,
1272 parent_domain,
1273 jtitem,
1274 item_list);
1275 right_item = (JoinTreeItem *) llast(*item_list);
1276 /* Compute qualscope etc */
1277 jtitem->qualscope = bms_union(left_item->qualscope,
1278 right_item->qualscope);
1279 jtitem->inner_join_rels = jtitem->qualscope;
1280 jtitem->left_rels = left_item->qualscope;
1281 jtitem->right_rels = right_item->qualscope;
1282 /* Inner join adds no restrictions for quals */
1283 jtitem->nonnullable_rels = NULL;
1284 break;
1285 case JOIN_LEFT:
1286 case JOIN_ANTI:
1287 /* Make new join domain for my quals and the RHS */
1288 child_domain = makeNode(JoinDomain);
1289 child_domain->jd_relids = NULL; /* filled by recursion */
1290 root->join_domains = lappend(root->join_domains, child_domain);
1291 jtitem->jdomain = child_domain;
1292 /* Recurse */
1293 leftjoinlist = deconstruct_recurse(root, j->larg,
1294 parent_domain,
1295 jtitem,
1296 item_list);
1297 left_item = (JoinTreeItem *) llast(*item_list);
1298 rightjoinlist = deconstruct_recurse(root, j->rarg,
1299 child_domain,
1300 jtitem,
1301 item_list);
1302 right_item = (JoinTreeItem *) llast(*item_list);
1303 /* Compute join domain contents, qualscope etc */
1304 parent_domain->jd_relids =
1305 bms_add_members(parent_domain->jd_relids,
1306 child_domain->jd_relids);
1307 jtitem->qualscope = bms_union(left_item->qualscope,
1308 right_item->qualscope);
1309 /* caution: ANTI join derived from SEMI will lack rtindex */
1310 if (j->rtindex != 0)
1311 {
1312 parent_domain->jd_relids =
1313 bms_add_member(parent_domain->jd_relids,
1314 j->rtindex);
1315 jtitem->qualscope = bms_add_member(jtitem->qualscope,
1316 j->rtindex);
1317 root->outer_join_rels = bms_add_member(root->outer_join_rels,
1318 j->rtindex);
1320 right_item->qualscope);
1321 }
1322 jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1323 right_item->inner_join_rels);
1324 jtitem->left_rels = left_item->qualscope;
1325 jtitem->right_rels = right_item->qualscope;
1326 jtitem->nonnullable_rels = left_item->qualscope;
1327 break;
1328 case JOIN_SEMI:
1329 /* This node belongs to parent_domain, as do its children */
1330 jtitem->jdomain = parent_domain;
1331 /* Recurse */
1332 leftjoinlist = deconstruct_recurse(root, j->larg,
1333 parent_domain,
1334 jtitem,
1335 item_list);
1336 left_item = (JoinTreeItem *) llast(*item_list);
1337 rightjoinlist = deconstruct_recurse(root, j->rarg,
1338 parent_domain,
1339 jtitem,
1340 item_list);
1341 right_item = (JoinTreeItem *) llast(*item_list);
1342 /* Compute qualscope etc */
1343 jtitem->qualscope = bms_union(left_item->qualscope,
1344 right_item->qualscope);
1345 /* SEMI join never has rtindex, so don't add to anything */
1346 Assert(j->rtindex == 0);
1347 jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1348 right_item->inner_join_rels);
1349 jtitem->left_rels = left_item->qualscope;
1350 jtitem->right_rels = right_item->qualscope;
1351 /* Semi join adds no restrictions for quals */
1352 jtitem->nonnullable_rels = NULL;
1353 break;
1354 case JOIN_FULL:
1355 /* The FULL JOIN's quals need their very own domain */
1356 fj_domain = makeNode(JoinDomain);
1357 root->join_domains = lappend(root->join_domains, fj_domain);
1358 jtitem->jdomain = fj_domain;
1359 /* Recurse, giving each side its own join domain */
1360 child_domain = makeNode(JoinDomain);
1361 child_domain->jd_relids = NULL; /* filled by recursion */
1362 root->join_domains = lappend(root->join_domains, child_domain);
1363 leftjoinlist = deconstruct_recurse(root, j->larg,
1364 child_domain,
1365 jtitem,
1366 item_list);
1367 left_item = (JoinTreeItem *) llast(*item_list);
1368 fj_domain->jd_relids = bms_copy(child_domain->jd_relids);
1369 child_domain = makeNode(JoinDomain);
1370 child_domain->jd_relids = NULL; /* filled by recursion */
1371 root->join_domains = lappend(root->join_domains, child_domain);
1372 rightjoinlist = deconstruct_recurse(root, j->rarg,
1373 child_domain,
1374 jtitem,
1375 item_list);
1376 right_item = (JoinTreeItem *) llast(*item_list);
1377 /* Compute qualscope etc */
1378 fj_domain->jd_relids = bms_add_members(fj_domain->jd_relids,
1379 child_domain->jd_relids);
1380 parent_domain->jd_relids = bms_add_members(parent_domain->jd_relids,
1381 fj_domain->jd_relids);
1382 jtitem->qualscope = bms_union(left_item->qualscope,
1383 right_item->qualscope);
1384 Assert(j->rtindex != 0);
1385 parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
1386 j->rtindex);
1387 jtitem->qualscope = bms_add_member(jtitem->qualscope,
1388 j->rtindex);
1389 root->outer_join_rels = bms_add_member(root->outer_join_rels,
1390 j->rtindex);
1392 left_item->qualscope);
1394 right_item->qualscope);
1395 jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1396 right_item->inner_join_rels);
1397 jtitem->left_rels = left_item->qualscope;
1398 jtitem->right_rels = right_item->qualscope;
1399 /* each side is both outer and inner */
1400 jtitem->nonnullable_rels = jtitem->qualscope;
1401 break;
1402 default:
1403 /* JOIN_RIGHT was eliminated during reduce_outer_joins() */
1404 elog(ERROR, "unrecognized join type: %d",
1405 (int) j->jointype);
1406 leftjoinlist = rightjoinlist = NIL; /* keep compiler quiet */
1407 break;
1408 }
1409
1410 /*
1411 * Compute the output joinlist. We fold subproblems together except
1412 * at a FULL JOIN or where join_collapse_limit would be exceeded.
1413 */
1414 if (j->jointype == JOIN_FULL)
1415 {
1416 /* force the join order exactly at this node */
1417 joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist));
1418 }
1419 else if (list_length(leftjoinlist) + list_length(rightjoinlist) <=
1421 {
1422 /* OK to combine subproblems */
1423 joinlist = list_concat(leftjoinlist, rightjoinlist);
1424 }
1425 else
1426 {
1427 /* can't combine, but needn't force join order above here */
1428 Node *leftpart,
1429 *rightpart;
1430
1431 /* avoid creating useless 1-element sublists */
1432 if (list_length(leftjoinlist) == 1)
1433 leftpart = (Node *) linitial(leftjoinlist);
1434 else
1435 leftpart = (Node *) leftjoinlist;
1436 if (list_length(rightjoinlist) == 1)
1437 rightpart = (Node *) linitial(rightjoinlist);
1438 else
1439 rightpart = (Node *) rightjoinlist;
1440 joinlist = list_make2(leftpart, rightpart);
1441 }
1442 }
1443 else
1444 {
1445 elog(ERROR, "unrecognized node type: %d",
1446 (int) nodeTag(jtnode));
1447 joinlist = NIL; /* keep compiler quiet */
1448 }
1449
1450 /* Finally, we can add the new JoinTreeItem to item_list */
1451 *item_list = lappend(*item_list, jtitem);
1452
1453 return joinlist;
1454}
#define palloc0_object(type)
Definition: fe_memutils.h:75
int remaining
Definition: informix.c:692
int join_collapse_limit
Definition: initsplan.c:40
int from_collapse_limit
Definition: initsplan.c:39
static void mark_rels_nulled_by_join(PlannerInfo *root, Index ojrelid, Relids lower_rels)
Definition: initsplan.c:1666
#define makeNode(_type_)
Definition: nodes.h:157
@ JOIN_FULL
Definition: nodes.h:297
#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:65
JoinDomain * jdomain
Definition: initsplan.c:64

References Assert(), bms_add_member(), bms_add_members(), bms_copy(), bms_make_singleton(), bms_union(), deconstruct_recurse(), 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(), and deconstruct_recurse().

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

2557{
2558 Relids relids;
2559 bool is_pushed_down;
2560 bool pseudoconstant = false;
2561 bool maybe_equivalence;
2562 bool maybe_outer_join;
2563 RestrictInfo *restrictinfo;
2564
2565 /*
2566 * Retrieve all relids mentioned within the clause.
2567 */
2568 relids = pull_varnos(root, clause);
2569
2570 /*
2571 * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels
2572 * that aren't within its syntactic scope; however, if we pulled up a
2573 * LATERAL subquery then we might find such references in quals that have
2574 * been pulled up. We need to treat such quals as belonging to the join
2575 * level that includes every rel they reference. Although we could make
2576 * pull_up_subqueries() place such quals correctly to begin with, it's
2577 * easier to handle it here. When we find a clause that contains Vars
2578 * outside its syntactic scope, locate the nearest parent join level that
2579 * includes all the required rels and add the clause to that level's
2580 * lateral_clauses list. We'll process it when we reach that join level.
2581 */
2582 if (!bms_is_subset(relids, qualscope))
2583 {
2584 JoinTreeItem *pitem;
2585
2586 Assert(root->hasLateralRTEs); /* shouldn't happen otherwise */
2587 Assert(sjinfo == NULL); /* mustn't postpone past outer join */
2588 for (pitem = jtitem->jti_parent; pitem; pitem = pitem->jti_parent)
2589 {
2590 if (bms_is_subset(relids, pitem->qualscope))
2591 {
2592 pitem->lateral_clauses = lappend(pitem->lateral_clauses,
2593 clause);
2594 return;
2595 }
2596
2597 /*
2598 * We should not be postponing any quals past an outer join. If
2599 * this Assert fires, pull_up_subqueries() messed up.
2600 */
2601 Assert(pitem->sjinfo == NULL);
2602 }
2603 elog(ERROR, "failed to postpone qual containing lateral reference");
2604 }
2605
2606 /*
2607 * If it's an outer-join clause, also check that relids is a subset of
2608 * ojscope. (This should not fail if the syntactic scope check passed.)
2609 */
2610 if (ojscope && !bms_is_subset(relids, ojscope))
2611 elog(ERROR, "JOIN qualification cannot refer to other relations");
2612
2613 /*
2614 * If the clause is variable-free, our normal heuristic for pushing it
2615 * down to just the mentioned rels doesn't work, because there are none.
2616 *
2617 * If the clause is an outer-join clause, we must force it to the OJ's
2618 * semantic level to preserve semantics.
2619 *
2620 * Otherwise, when the clause contains volatile functions, we force it to
2621 * be evaluated at its original syntactic level. This preserves the
2622 * expected semantics.
2623 *
2624 * When the clause contains no volatile functions either, it is actually a
2625 * pseudoconstant clause that will not change value during any one
2626 * execution of the plan, and hence can be used as a one-time qual in a
2627 * gating Result plan node. We put such a clause into the regular
2628 * RestrictInfo lists for the moment, but eventually createplan.c will
2629 * pull it out and make a gating Result node immediately above whatever
2630 * plan node the pseudoconstant clause is assigned to. It's usually best
2631 * to put a gating node as high in the plan tree as possible.
2632 */
2633 if (bms_is_empty(relids))
2634 {
2635 if (ojscope)
2636 {
2637 /* clause is attached to outer join, eval it there */
2638 relids = bms_copy(ojscope);
2639 /* mustn't use as gating qual, so don't mark pseudoconstant */
2640 }
2641 else if (contain_volatile_functions(clause))
2642 {
2643 /* eval at original syntactic level */
2644 relids = bms_copy(qualscope);
2645 /* again, can't mark pseudoconstant */
2646 }
2647 else
2648 {
2649 /*
2650 * If we are in the top-level join domain, we can push the qual to
2651 * the top of the plan tree. Otherwise, be conservative and eval
2652 * it at original syntactic level. (Ideally we'd push it to the
2653 * top of the current join domain in all cases, but that causes
2654 * problems if we later rearrange outer-join evaluation order.
2655 * Pseudoconstant quals below the top level are a pretty odd case,
2656 * so it's not clear that it's worth working hard on.)
2657 */
2658 if (jtitem->jdomain == (JoinDomain *) linitial(root->join_domains))
2659 relids = bms_copy(jtitem->jdomain->jd_relids);
2660 else
2661 relids = bms_copy(qualscope);
2662 /* mark as gating qual */
2663 pseudoconstant = true;
2664 /* tell createplan.c to check for gating quals */
2665 root->hasPseudoConstantQuals = true;
2666 }
2667 }
2668
2669 /*----------
2670 * Check to see if clause application must be delayed by outer-join
2671 * considerations.
2672 *
2673 * A word about is_pushed_down: we mark the qual as "pushed down" if
2674 * it is (potentially) applicable at a level different from its original
2675 * syntactic level. This flag is used to distinguish OUTER JOIN ON quals
2676 * from other quals pushed down to the same joinrel. The rules are:
2677 * WHERE quals and INNER JOIN quals: is_pushed_down = true.
2678 * Non-degenerate OUTER JOIN quals: is_pushed_down = false.
2679 * Degenerate OUTER JOIN quals: is_pushed_down = true.
2680 * A "degenerate" OUTER JOIN qual is one that doesn't mention the
2681 * non-nullable side, and hence can be pushed down into the nullable side
2682 * without changing the join result. It is correct to treat it as a
2683 * regular filter condition at the level where it is evaluated.
2684 *
2685 * Note: it is not immediately obvious that a simple boolean is enough
2686 * for this: if for some reason we were to attach a degenerate qual to
2687 * its original join level, it would need to be treated as an outer join
2688 * qual there. However, this cannot happen, because all the rels the
2689 * clause mentions must be in the outer join's min_righthand, therefore
2690 * the join it needs must be formed before the outer join; and we always
2691 * attach quals to the lowest level where they can be evaluated. But
2692 * if we were ever to re-introduce a mechanism for delaying evaluation
2693 * of "expensive" quals, this area would need work.
2694 *
2695 * Note: generally, use of is_pushed_down has to go through the macro
2696 * RINFO_IS_PUSHED_DOWN, because that flag alone is not always sufficient
2697 * to tell whether a clause must be treated as pushed-down in context.
2698 * This seems like another reason why it should perhaps be rethought.
2699 *----------
2700 */
2701 if (bms_overlap(relids, outerjoin_nonnullable))
2702 {
2703 /*
2704 * The qual is attached to an outer join and mentions (some of the)
2705 * rels on the nonnullable side, so it's not degenerate. If the
2706 * caller wants to postpone handling such clauses, just add it to
2707 * postponed_oj_qual_list and return. (The work we've done up to here
2708 * will have to be redone later, but there's not much of it.)
2709 */
2710 if (postponed_oj_qual_list != NULL)
2711 {
2712 *postponed_oj_qual_list = lappend(*postponed_oj_qual_list, clause);
2713 return;
2714 }
2715
2716 /*
2717 * We can't use such a clause to deduce equivalence (the left and
2718 * right sides might be unequal above the join because one of them has
2719 * gone to NULL) ... but we might be able to use it for more limited
2720 * deductions, if it is mergejoinable. So consider adding it to the
2721 * lists of set-aside outer-join clauses.
2722 */
2723 is_pushed_down = false;
2724 maybe_equivalence = false;
2725 maybe_outer_join = true;
2726
2727 /*
2728 * Now force the qual to be evaluated exactly at the level of joining
2729 * corresponding to the outer join. We cannot let it get pushed down
2730 * into the nonnullable side, since then we'd produce no output rows,
2731 * rather than the intended single null-extended row, for any
2732 * nonnullable-side rows failing the qual.
2733 */
2734 Assert(ojscope);
2735 relids = ojscope;
2736 Assert(!pseudoconstant);
2737 }
2738 else
2739 {
2740 /*
2741 * Normal qual clause or degenerate outer-join clause. Either way, we
2742 * can mark it as pushed-down.
2743 */
2744 is_pushed_down = true;
2745
2746 /*
2747 * It's possible that this is an IS NULL clause that's redundant with
2748 * a lower antijoin; if so we can just discard it. We need not test
2749 * in any of the other cases, because this will only be possible for
2750 * pushed-down clauses.
2751 */
2753 return;
2754
2755 /* Feed qual to the equivalence machinery, if allowed by caller */
2756 maybe_equivalence = allow_equivalence;
2757
2758 /*
2759 * Since it doesn't mention the LHS, it's certainly not useful as a
2760 * set-aside OJ clause, even if it's in an OJ.
2761 */
2762 maybe_outer_join = false;
2763 }
2764
2765 /*
2766 * Build the RestrictInfo node itself.
2767 */
2768 restrictinfo = make_restrictinfo(root,
2769 (Expr *) clause,
2770 is_pushed_down,
2771 has_clone,
2772 is_clone,
2773 pseudoconstant,
2774 security_level,
2775 relids,
2776 incompatible_relids,
2777 outerjoin_nonnullable);
2778
2779 /*
2780 * If it's a join clause, add vars used in the clause to targetlists of
2781 * their relations, so that they will be emitted by the plan nodes that
2782 * scan those relations (else they won't be available at the join node!).
2783 *
2784 * Normally we mark the vars as needed at the join identified by "relids".
2785 * However, if this is a clone clause then ignore the outer-join relids in
2786 * that set. Otherwise, vars appearing in a cloned clause would end up
2787 * marked as having to propagate to the highest one of the commuting
2788 * joins, which would often be an overestimate. For such clauses, correct
2789 * var propagation is ensured by making ojscope include input rels from
2790 * both sides of the join.
2791 *
2792 * See also rebuild_joinclause_attr_needed, which has to partially repeat
2793 * this work after removal of an outer join.
2794 *
2795 * Note: if the clause gets absorbed into an EquivalenceClass then this
2796 * may be unnecessary, but for now we have to do it to cover the case
2797 * where the EC becomes ec_broken and we end up reinserting the original
2798 * clauses into the plan.
2799 */
2800 if (bms_membership(relids) == BMS_MULTIPLE)
2801 {
2802 List *vars = pull_var_clause(clause,
2806 Relids where_needed;
2807
2808 if (is_clone)
2809 where_needed = bms_intersect(relids, root->all_baserels);
2810 else
2811 where_needed = relids;
2812 add_vars_to_targetlist(root, vars, where_needed);
2813 list_free(vars);
2814 }
2815
2816 /*
2817 * We check "mergejoinability" of every clause, not only join clauses,
2818 * because we want to know about equivalences between vars of the same
2819 * relation, or between vars and consts.
2820 */
2821 check_mergejoinable(restrictinfo);
2822
2823 /*
2824 * If it is a true equivalence clause, send it to the EquivalenceClass
2825 * machinery. We do *not* attach it directly to any restriction or join
2826 * lists. The EC code will propagate it to the appropriate places later.
2827 *
2828 * If the clause has a mergejoinable operator, yet isn't an equivalence
2829 * because it is an outer-join clause, the EC code may still be able to do
2830 * something with it. We add it to appropriate lists for further
2831 * consideration later. Specifically:
2832 *
2833 * If it is a left or right outer-join qualification that relates the two
2834 * sides of the outer join (no funny business like leftvar1 = leftvar2 +
2835 * rightvar), we add it to root->left_join_clauses or
2836 * root->right_join_clauses according to which side the nonnullable
2837 * variable appears on.
2838 *
2839 * If it is a full outer-join qualification, we add it to
2840 * root->full_join_clauses. (Ideally we'd discard cases that aren't
2841 * leftvar = rightvar, as we do for left/right joins, but this routine
2842 * doesn't have the info needed to do that; and the current usage of the
2843 * full_join_clauses list doesn't require that, so it's not currently
2844 * worth complicating this routine's API to make it possible.)
2845 *
2846 * If none of the above hold, pass it off to
2847 * distribute_restrictinfo_to_rels().
2848 *
2849 * In all cases, it's important to initialize the left_ec and right_ec
2850 * fields of a mergejoinable clause, so that all possibly mergejoinable
2851 * expressions have representations in EquivalenceClasses. If
2852 * process_equivalence is successful, it will take care of that;
2853 * otherwise, we have to call initialize_mergeclause_eclasses to do it.
2854 */
2855 if (restrictinfo->mergeopfamilies)
2856 {
2857 if (maybe_equivalence)
2858 {
2859 if (process_equivalence(root, &restrictinfo, jtitem->jdomain))
2860 return;
2861 /* EC rejected it, so set left_ec/right_ec the hard way ... */
2862 if (restrictinfo->mergeopfamilies) /* EC might have changed this */
2864 /* ... and fall through to distribute_restrictinfo_to_rels */
2865 }
2866 else if (maybe_outer_join && restrictinfo->can_join)
2867 {
2868 /* we need to set up left_ec/right_ec the hard way */
2870 /* now see if it should go to any outer-join lists */
2871 Assert(sjinfo != NULL);
2872 if (bms_is_subset(restrictinfo->left_relids,
2873 outerjoin_nonnullable) &&
2874 !bms_overlap(restrictinfo->right_relids,
2875 outerjoin_nonnullable))
2876 {
2877 /* we have outervar = innervar */
2879
2880 ojcinfo->rinfo = restrictinfo;
2881 ojcinfo->sjinfo = sjinfo;
2882 root->left_join_clauses = lappend(root->left_join_clauses,
2883 ojcinfo);
2884 return;
2885 }
2886 if (bms_is_subset(restrictinfo->right_relids,
2887 outerjoin_nonnullable) &&
2888 !bms_overlap(restrictinfo->left_relids,
2889 outerjoin_nonnullable))
2890 {
2891 /* we have innervar = outervar */
2893
2894 ojcinfo->rinfo = restrictinfo;
2895 ojcinfo->sjinfo = sjinfo;
2896 root->right_join_clauses = lappend(root->right_join_clauses,
2897 ojcinfo);
2898 return;
2899 }
2900 if (sjinfo->jointype == JOIN_FULL)
2901 {
2902 /* FULL JOIN (above tests cannot match in this case) */
2904
2905 ojcinfo->rinfo = restrictinfo;
2906 ojcinfo->sjinfo = sjinfo;
2907 root->full_join_clauses = lappend(root->full_join_clauses,
2908 ojcinfo);
2909 return;
2910 }
2911 /* nope, so fall through to distribute_restrictinfo_to_rels */
2912 }
2913 else
2914 {
2915 /* we still need to set up left_ec/right_ec */
2917 }
2918 }
2919
2920 /* No EC special case applies, so push it into the clause lists */
2922}
@ BMS_MULTIPLE
Definition: bitmapset.h:73
bool process_equivalence(PlannerInfo *root, RestrictInfo **p_restrictinfo, JoinDomain *jdomain)
Definition: equivclass.c:117
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3213
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
Definition: initsplan.c:2935
void initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:1462
RestrictInfo * rinfo
Definition: pathnodes.h:2961
SpecialJoinInfo * sjinfo
Definition: pathnodes.h:2962

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

2479{
2480 ListCell *lc;
2481
2482 foreach(lc, clauses)
2483 {
2484 Node *clause = (Node *) lfirst(lc);
2485
2487 jtitem,
2488 sjinfo,
2489 security_level,
2490 qualscope,
2491 ojscope,
2492 outerjoin_nonnullable,
2493 incompatible_relids,
2494 allow_equivalence,
2495 has_clone,
2496 is_clone,
2497 postponed_oj_qual_list);
2498 }
2499}
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:2545

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

3215{
3216 Relids relids = restrictinfo->required_relids;
3217
3218 if (!bms_is_empty(relids))
3219 {
3220 int relid;
3221
3222 if (bms_get_singleton_member(relids, &relid))
3223 {
3224 /*
3225 * There is only one relation participating in the clause, so it
3226 * is a restriction clause for that relation.
3227 */
3228 add_base_clause_to_rel(root, relid, restrictinfo);
3229 }
3230 else
3231 {
3232 /*
3233 * The clause is a join clause, since there is more than one rel
3234 * in its relid set.
3235 */
3236
3237 /*
3238 * Check for hashjoinable operators. (We don't bother setting the
3239 * hashjoin info except in true join clauses.)
3240 */
3241 check_hashjoinable(restrictinfo);
3242
3243 /*
3244 * Likewise, check if the clause is suitable to be used with a
3245 * Memoize node to cache inner tuples during a parameterized
3246 * nested loop.
3247 */
3248 check_memoizable(restrictinfo);
3249
3250 /*
3251 * Add clause to the join lists of all the relevant relations.
3252 */
3253 add_join_clause_to_rels(root, restrictinfo, relids);
3254 }
3255 }
3256 else
3257 {
3258 /*
3259 * clause references no rels, and therefore we have no place to attach
3260 * it. Shouldn't get here if callers are working properly.
3261 */
3262 elog(ERROR, "cannot cope with variable-free clause");
3263 }
3264}
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:2980
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 add_non_redundant_clauses(), distribute_qual_to_rels(), generate_base_implied_equalities_broken(), generate_base_implied_equalities_const(), process_implied_equality(), reconsider_outer_join_clauses(), and remove_leftjoinrel_from_query().

◆ expr_is_nonnullable()

static bool expr_is_nonnullable ( PlannerInfo root,
Expr expr 
)
static

Definition at line 3055 of file initsplan.c.

3056{
3057 RelOptInfo *rel;
3058 Var *var;
3059
3060 /* For now only check simple Vars */
3061 if (!IsA(expr, Var))
3062 return false;
3063
3064 var = (Var *) expr;
3065
3066 /* could the Var be nulled by any outer joins? */
3067 if (!bms_is_empty(var->varnullingrels))
3068 return false;
3069
3070 /* system columns cannot be NULL */
3071 if (var->varattno < 0)
3072 return true;
3073
3074 /* is the column defined NOT NULL? */
3075 rel = find_base_rel(root, var->varno);
3076 if (var->varattno > 0 &&
3078 return true;
3079
3080 return false;
3081}
Bitmapset * notnullattnums
Definition: pathnodes.h:963

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

707{
708 RangeTblEntry *rte = root->simple_rte_array[rtindex];
709 List *vars;
710 List *newvars;
711 Relids where_needed;
712 ListCell *lc;
713
714 /* No cross-references are possible if it's not LATERAL */
715 if (!rte->lateral)
716 return;
717
718 /* Fetch the appropriate variables */
719 if (rte->rtekind == RTE_RELATION)
721 else if (rte->rtekind == RTE_SUBQUERY)
722 vars = pull_vars_of_level((Node *) rte->subquery, 1);
723 else if (rte->rtekind == RTE_FUNCTION)
724 vars = pull_vars_of_level((Node *) rte->functions, 0);
725 else if (rte->rtekind == RTE_TABLEFUNC)
726 vars = pull_vars_of_level((Node *) rte->tablefunc, 0);
727 else if (rte->rtekind == RTE_VALUES)
729 else
730 {
731 Assert(false);
732 return; /* keep compiler quiet */
733 }
734
735 if (vars == NIL)
736 return; /* nothing to do */
737
738 /* Copy each Var (or PlaceHolderVar) and adjust it to match our level */
739 newvars = NIL;
740 foreach(lc, vars)
741 {
742 Node *node = (Node *) lfirst(lc);
743
744 node = copyObject(node);
745 if (IsA(node, Var))
746 {
747 Var *var = (Var *) node;
748
749 /* Adjustment is easy since it's just one node */
750 var->varlevelsup = 0;
751 }
752 else if (IsA(node, PlaceHolderVar))
753 {
754 PlaceHolderVar *phv = (PlaceHolderVar *) node;
755 int levelsup = phv->phlevelsup;
756
757 /* Have to work harder to adjust the contained expression too */
758 if (levelsup != 0)
759 IncrementVarSublevelsUp(node, -levelsup, 0);
760
761 /*
762 * If we pulled the PHV out of a subquery RTE, its expression
763 * needs to be preprocessed. subquery_planner() already did this
764 * for level-zero PHVs in function and values RTEs, though.
765 */
766 if (levelsup > 0)
767 phv->phexpr = preprocess_phv_expression(root, phv->phexpr);
768 }
769 else
770 Assert(false);
771 newvars = lappend(newvars, node);
772 }
773
775
776 /*
777 * We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
778 * of a cheat: a more formal approach would be to mark each one as needed
779 * at the join of the LATERAL RTE with its source RTE. But it will work,
780 * and it's much less tedious than computing a separate where_needed for
781 * each Var.
782 */
783 where_needed = bms_make_singleton(rtindex);
784
785 /*
786 * Push Vars into their source relations' targetlists, and PHVs into
787 * root->placeholder_list.
788 */
789 add_vars_to_targetlist(root, newvars, where_needed);
790
791 /*
792 * Remember the lateral references for rebuild_lateral_attr_needed and
793 * create_lateral_join_info.
794 */
795 brel->lateral_vars = newvars;
796}
@ RTE_VALUES
Definition: parsenodes.h:1031
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
@ RTE_FUNCTION
Definition: parsenodes.h:1029
@ RTE_TABLEFUNC
Definition: parsenodes.h:1030
@ RTE_RELATION
Definition: parsenodes.h:1026
Expr * preprocess_phv_expression(PlannerInfo *root, Expr *expr)
Definition: planner.c:1344
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:928
Index phlevelsup
Definition: pathnodes.h:2835
TableFunc * tablefunc
Definition: parsenodes.h:1193
struct TableSampleClause * tablesample
Definition: parsenodes.h:1107
Query * subquery
Definition: parsenodes.h:1113
List * values_lists
Definition: parsenodes.h:1199
List * functions
Definition: parsenodes.h:1186
RTEKind rtekind
Definition: parsenodes.h:1056
Index varlevelsup
Definition: primnodes.h:294
List * pull_vars_of_level(Node *node, int levelsup)
Definition: var.c:339

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

659{
660 Index rti;
661
662 /* We need do nothing if the query contains no LATERAL RTEs */
663 if (!root->hasLateralRTEs)
664 return;
665
666 /*
667 * Examine all baserels (the rel array has been set up by now).
668 */
669 for (rti = 1; rti < root->simple_rel_array_size; rti++)
670 {
671 RelOptInfo *brel = root->simple_rel_array[rti];
672
673 /* there may be empty slots corresponding to non-baserel RTEs */
674 if (brel == NULL)
675 continue;
676
677 Assert(brel->relid == rti); /* sanity check on array */
678
679 /*
680 * This bit is less obvious than it might look. We ignore appendrel
681 * otherrels and consider only their parent baserels. In a case where
682 * a LATERAL-containing UNION ALL subquery was pulled up, it is the
683 * otherrel that is actually going to be in the plan. However, we
684 * want to mark all its lateral references as needed by the parent,
685 * because it is the parent's relid that will be used for join
686 * planning purposes. And the parent's RTE will contain all the
687 * lateral references we need to know, since the pulled-up member is
688 * nothing but a copy of parts of the original RTE's subquery. We
689 * could visit the parent's children instead and transform their
690 * references back to the parent's relid, but it would be much more
691 * complicated for no real gain. (Important here is that the child
692 * members have not yet received any processing beyond being pulled
693 * up.) Similarly, in appendrels created by inheritance expansion,
694 * it's sufficient to look at the parent relation.
695 */
696
697 /* ignore RTEs that are "other rels" */
698 if (brel->reloptkind != RELOPT_BASEREL)
699 continue;
700
702 }
703}
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:706

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

3512{
3513 Relids result = bms_copy(domain_relids);
3514 ListCell *lc;
3515
3516 /* Top-level join domain? */
3517 if (bms_equal(result, root->all_query_rels))
3518 return result;
3519
3520 /* Nope, look for lower outer joins that could potentially commute out */
3521 foreach(lc, root->join_info_list)
3522 {
3523 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
3524
3525 if (sjinfo->jointype == JOIN_LEFT &&
3526 bms_is_member(sjinfo->ojrelid, result))
3527 {
3528 result = bms_del_member(result, sjinfo->ojrelid);
3529 result = bms_del_members(result, sjinfo->syn_righthand);
3530 }
3531 }
3532 return result;
3533}
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 1708 of file initsplan.c.

1713{
1715 Relids clause_relids;
1716 Relids strict_relids;
1717 Relids min_lefthand;
1718 Relids min_righthand;
1719 Relids commute_below_l;
1720 Relids commute_below_r;
1721 ListCell *l;
1722
1723 /*
1724 * We should not see RIGHT JOIN here because left/right were switched
1725 * earlier
1726 */
1727 Assert(jointype != JOIN_INNER);
1728 Assert(jointype != JOIN_RIGHT);
1729
1730 /*
1731 * Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of
1732 * rels appearing on the nullable side of an outer join. (It's somewhat
1733 * unclear what that would mean, anyway: what should we mark when a result
1734 * row is generated from no element of the nullable relation?) So,
1735 * complain if any nullable rel is FOR [KEY] UPDATE/SHARE.
1736 *
1737 * You might be wondering why this test isn't made far upstream in the
1738 * parser. It's because the parser hasn't got enough info --- consider
1739 * FOR UPDATE applied to a view. Only after rewriting and flattening do
1740 * we know whether the view contains an outer join.
1741 *
1742 * We use the original RowMarkClause list here; the PlanRowMark list would
1743 * list everything.
1744 */
1745 foreach(l, root->parse->rowMarks)
1746 {
1747 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
1748
1749 if (bms_is_member(rc->rti, right_rels) ||
1750 (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels)))
1751 ereport(ERROR,
1752 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1753 /*------
1754 translator: %s is a SQL row locking clause such as FOR UPDATE */
1755 errmsg("%s cannot be applied to the nullable side of an outer join",
1756 LCS_asString(rc->strength))));
1757 }
1758
1759 sjinfo->syn_lefthand = left_rels;
1760 sjinfo->syn_righthand = right_rels;
1761 sjinfo->jointype = jointype;
1762 sjinfo->ojrelid = ojrelid;
1763 /* these fields may get added to later: */
1764 sjinfo->commute_above_l = NULL;
1765 sjinfo->commute_above_r = NULL;
1766 sjinfo->commute_below_l = NULL;
1767 sjinfo->commute_below_r = NULL;
1768
1769 compute_semijoin_info(root, sjinfo, clause);
1770
1771 /* If it's a full join, no need to be very smart */
1772 if (jointype == JOIN_FULL)
1773 {
1774 sjinfo->min_lefthand = bms_copy(left_rels);
1775 sjinfo->min_righthand = bms_copy(right_rels);
1776 sjinfo->lhs_strict = false; /* don't care about this */
1777 return sjinfo;
1778 }
1779
1780 /*
1781 * Retrieve all relids mentioned within the join clause.
1782 */
1783 clause_relids = pull_varnos(root, (Node *) clause);
1784
1785 /*
1786 * For which relids is the clause strict, ie, it cannot succeed if the
1787 * rel's columns are all NULL?
1788 */
1789 strict_relids = find_nonnullable_rels((Node *) clause);
1790
1791 /* Remember whether the clause is strict for any LHS relations */
1792 sjinfo->lhs_strict = bms_overlap(strict_relids, left_rels);
1793
1794 /*
1795 * Required LHS always includes the LHS rels mentioned in the clause. We
1796 * may have to add more rels based on lower outer joins; see below.
1797 */
1798 min_lefthand = bms_intersect(clause_relids, left_rels);
1799
1800 /*
1801 * Similarly for required RHS. But here, we must also include any lower
1802 * inner joins, to ensure we don't try to commute with any of them.
1803 */
1804 min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
1805 right_rels);
1806
1807 /*
1808 * Now check previous outer joins for ordering restrictions.
1809 *
1810 * commute_below_l and commute_below_r accumulate the relids of lower
1811 * outer joins that we think this one can commute with. These decisions
1812 * are just tentative within this loop, since we might find an
1813 * intermediate outer join that prevents commutation. Surviving relids
1814 * will get merged into the SpecialJoinInfo structs afterwards.
1815 */
1816 commute_below_l = commute_below_r = NULL;
1817 foreach(l, root->join_info_list)
1818 {
1819 SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
1820 bool have_unsafe_phvs;
1821
1822 /*
1823 * A full join is an optimization barrier: we can't associate into or
1824 * out of it. Hence, if it overlaps either LHS or RHS of the current
1825 * rel, expand that side's min relset to cover the whole full join.
1826 */
1827 if (otherinfo->jointype == JOIN_FULL)
1828 {
1829 Assert(otherinfo->ojrelid != 0);
1830 if (bms_overlap(left_rels, otherinfo->syn_lefthand) ||
1831 bms_overlap(left_rels, otherinfo->syn_righthand))
1832 {
1833 min_lefthand = bms_add_members(min_lefthand,
1834 otherinfo->syn_lefthand);
1835 min_lefthand = bms_add_members(min_lefthand,
1836 otherinfo->syn_righthand);
1837 min_lefthand = bms_add_member(min_lefthand,
1838 otherinfo->ojrelid);
1839 }
1840 if (bms_overlap(right_rels, otherinfo->syn_lefthand) ||
1841 bms_overlap(right_rels, otherinfo->syn_righthand))
1842 {
1843 min_righthand = bms_add_members(min_righthand,
1844 otherinfo->syn_lefthand);
1845 min_righthand = bms_add_members(min_righthand,
1846 otherinfo->syn_righthand);
1847 min_righthand = bms_add_member(min_righthand,
1848 otherinfo->ojrelid);
1849 }
1850 /* Needn't do anything else with the full join */
1851 continue;
1852 }
1853
1854 /*
1855 * If our join condition contains any PlaceHolderVars that need to be
1856 * evaluated above the lower OJ, then we can't commute with it.
1857 */
1858 if (otherinfo->ojrelid != 0)
1859 have_unsafe_phvs =
1861 (Node *) clause,
1862 otherinfo->ojrelid);
1863 else
1864 have_unsafe_phvs = false;
1865
1866 /*
1867 * For a lower OJ in our LHS, if our join condition uses the lower
1868 * join's RHS and is not strict for that rel, we must preserve the
1869 * ordering of the two OJs, so add lower OJ's full syntactic relset to
1870 * min_lefthand. (We must use its full syntactic relset, not just its
1871 * min_lefthand + min_righthand. This is because there might be other
1872 * OJs below this one that this one can commute with, but we cannot
1873 * commute with them if we don't with this one.) Also, if we have
1874 * unsafe PHVs or the current join is a semijoin or antijoin, we must
1875 * preserve ordering regardless of strictness.
1876 *
1877 * Note: I believe we have to insist on being strict for at least one
1878 * rel in the lower OJ's min_righthand, not its whole syn_righthand.
1879 *
1880 * When we don't need to preserve ordering, check to see if outer join
1881 * identity 3 applies, and if so, remove the lower OJ's ojrelid from
1882 * our min_lefthand so that commutation is allowed.
1883 */
1884 if (bms_overlap(left_rels, otherinfo->syn_righthand))
1885 {
1886 if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
1887 (have_unsafe_phvs ||
1888 jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
1889 !bms_overlap(strict_relids, otherinfo->min_righthand)))
1890 {
1891 /* Preserve ordering */
1892 min_lefthand = bms_add_members(min_lefthand,
1893 otherinfo->syn_lefthand);
1894 min_lefthand = bms_add_members(min_lefthand,
1895 otherinfo->syn_righthand);
1896 if (otherinfo->ojrelid != 0)
1897 min_lefthand = bms_add_member(min_lefthand,
1898 otherinfo->ojrelid);
1899 }
1900 else if (jointype == JOIN_LEFT &&
1901 otherinfo->jointype == JOIN_LEFT &&
1902 bms_overlap(strict_relids, otherinfo->min_righthand) &&
1903 !bms_overlap(clause_relids, otherinfo->syn_lefthand))
1904 {
1905 /* Identity 3 applies, so remove the ordering restriction */
1906 min_lefthand = bms_del_member(min_lefthand, otherinfo->ojrelid);
1907 /* Record the (still tentative) commutability relationship */
1908 commute_below_l =
1909 bms_add_member(commute_below_l, otherinfo->ojrelid);
1910 }
1911 }
1912
1913 /*
1914 * For a lower OJ in our RHS, if our join condition does not use the
1915 * lower join's RHS and the lower OJ's join condition is strict, we
1916 * can interchange the ordering of the two OJs; otherwise we must add
1917 * the lower OJ's full syntactic relset to min_righthand.
1918 *
1919 * Also, if our join condition does not use the lower join's LHS
1920 * either, force the ordering to be preserved. Otherwise we can end
1921 * up with SpecialJoinInfos with identical min_righthands, which can
1922 * confuse join_is_legal (see discussion in backend/optimizer/README).
1923 *
1924 * Also, we must preserve ordering anyway if we have unsafe PHVs, or
1925 * if either this join or the lower OJ is a semijoin or antijoin.
1926 *
1927 * When we don't need to preserve ordering, check to see if outer join
1928 * identity 3 applies, and if so, remove the lower OJ's ojrelid from
1929 * our min_righthand so that commutation is allowed.
1930 */
1931 if (bms_overlap(right_rels, otherinfo->syn_righthand))
1932 {
1933 if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
1934 !bms_overlap(clause_relids, otherinfo->min_lefthand) ||
1935 have_unsafe_phvs ||
1936 jointype == JOIN_SEMI ||
1937 jointype == JOIN_ANTI ||
1938 otherinfo->jointype == JOIN_SEMI ||
1939 otherinfo->jointype == JOIN_ANTI ||
1940 !otherinfo->lhs_strict)
1941 {
1942 /* Preserve ordering */
1943 min_righthand = bms_add_members(min_righthand,
1944 otherinfo->syn_lefthand);
1945 min_righthand = bms_add_members(min_righthand,
1946 otherinfo->syn_righthand);
1947 if (otherinfo->ojrelid != 0)
1948 min_righthand = bms_add_member(min_righthand,
1949 otherinfo->ojrelid);
1950 }
1951 else if (jointype == JOIN_LEFT &&
1952 otherinfo->jointype == JOIN_LEFT &&
1953 otherinfo->lhs_strict)
1954 {
1955 /* Identity 3 applies, so remove the ordering restriction */
1956 min_righthand = bms_del_member(min_righthand,
1957 otherinfo->ojrelid);
1958 /* Record the (still tentative) commutability relationship */
1959 commute_below_r =
1960 bms_add_member(commute_below_r, otherinfo->ojrelid);
1961 }
1962 }
1963 }
1964
1965 /*
1966 * Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
1967 * this join's nullable side, then ensure that min_righthand contains the
1968 * full eval_at set of the PHV. This ensures that the PHV actually can be
1969 * evaluated within the RHS. Note that this works only because we should
1970 * already have determined the final eval_at level for any PHV
1971 * syntactically within this join.
1972 */
1973 foreach(l, root->placeholder_list)
1974 {
1975 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
1976 Relids ph_syn_level = phinfo->ph_var->phrels;
1977
1978 /* Ignore placeholder if it didn't syntactically come from RHS */
1979 if (!bms_is_subset(ph_syn_level, right_rels))
1980 continue;
1981
1982 /* Else, prevent join from being formed before we eval the PHV */
1983 min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
1984 }
1985
1986 /*
1987 * If we found nothing to put in min_lefthand, punt and make it the full
1988 * LHS, to avoid having an empty min_lefthand which will confuse later
1989 * processing. (We don't try to be smart about such cases, just correct.)
1990 * Likewise for min_righthand.
1991 */
1992 if (bms_is_empty(min_lefthand))
1993 min_lefthand = bms_copy(left_rels);
1994 if (bms_is_empty(min_righthand))
1995 min_righthand = bms_copy(right_rels);
1996
1997 /* Now they'd better be nonempty */
1998 Assert(!bms_is_empty(min_lefthand));
1999 Assert(!bms_is_empty(min_righthand));
2000 /* Shouldn't overlap either */
2001 Assert(!bms_overlap(min_lefthand, min_righthand));
2002
2003 sjinfo->min_lefthand = min_lefthand;
2004 sjinfo->min_righthand = min_righthand;
2005
2006 /*
2007 * Now that we've identified the correct min_lefthand and min_righthand,
2008 * any commute_below_l or commute_below_r relids that have not gotten
2009 * added back into those sets (due to intervening outer joins) are indeed
2010 * commutable with this one.
2011 *
2012 * First, delete any subsequently-added-back relids (this is easier than
2013 * maintaining commute_below_l/r precisely through all the above).
2014 */
2015 commute_below_l = bms_del_members(commute_below_l, min_lefthand);
2016 commute_below_r = bms_del_members(commute_below_r, min_righthand);
2017
2018 /* Anything left? */
2019 if (commute_below_l || commute_below_r)
2020 {
2021 /* Yup, so we must update the derived data in the SpecialJoinInfos */
2022 sjinfo->commute_below_l = commute_below_l;
2023 sjinfo->commute_below_r = commute_below_r;
2024 foreach(l, root->join_info_list)
2025 {
2026 SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
2027
2028 if (bms_is_member(otherinfo->ojrelid, commute_below_l))
2029 otherinfo->commute_above_l =
2030 bms_add_member(otherinfo->commute_above_l, ojrelid);
2031 else if (bms_is_member(otherinfo->ojrelid, commute_below_r))
2032 otherinfo->commute_above_r =
2033 bms_add_member(otherinfo->commute_above_r, ojrelid);
2034 }
2035 }
2036
2037 return sjinfo;
2038}
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:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
Definition: initsplan.c:2048
@ JOIN_RIGHT
Definition: nodes.h:298
const char * LCS_asString(LockClauseStrength strength)
Definition: analyze.c:3407
bool contain_placeholder_references_to(PlannerInfo *root, Node *clause, int relid)
Definition: placeholder.c:491
PlaceHolderVar * ph_var
Definition: pathnodes.h:3123
LockClauseStrength strength
Definition: parsenodes.h:1589
Relids commute_above_l
Definition: pathnodes.h:2938

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

1668{
1669 int relid = -1;
1670
1671 while ((relid = bms_next_member(lower_rels, relid)) > 0)
1672 {
1673 RelOptInfo *rel = root->simple_rel_array[relid];
1674
1675 /* ignore the RTE_GROUP RTE */
1676 if (relid == root->group_rtindex)
1677 continue;
1678
1679 if (rel == NULL) /* must be an outer join */
1680 {
1681 Assert(bms_is_member(relid, root->outer_join_rels));
1682 continue;
1683 }
1684 rel->nulling_relids = bms_add_member(rel->nulling_relids, ojrelid);
1685 }
1686}
Relids nulling_relids
Definition: pathnodes.h:965

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

3618{
3619 List *newlist = NIL;
3620 ListCell *lc;
3621
3622 foreach(lc, root->fkey_list)
3623 {
3624 ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
3625 RelOptInfo *con_rel;
3626 RelOptInfo *ref_rel;
3627 int colno;
3628
3629 /*
3630 * Either relid might identify a rel that is in the query's rtable but
3631 * isn't referenced by the jointree, or has been removed by join
3632 * removal, so that it won't have a RelOptInfo. Hence don't use
3633 * find_base_rel() here. We can ignore such FKs.
3634 */
3635 if (fkinfo->con_relid >= root->simple_rel_array_size ||
3636 fkinfo->ref_relid >= root->simple_rel_array_size)
3637 continue; /* just paranoia */
3638 con_rel = root->simple_rel_array[fkinfo->con_relid];
3639 if (con_rel == NULL)
3640 continue;
3641 ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3642 if (ref_rel == NULL)
3643 continue;
3644
3645 /*
3646 * Ignore FK unless both rels are baserels. This gets rid of FKs that
3647 * link to inheritance child rels (otherrels).
3648 */
3649 if (con_rel->reloptkind != RELOPT_BASEREL ||
3650 ref_rel->reloptkind != RELOPT_BASEREL)
3651 continue;
3652
3653 /*
3654 * Scan the columns and try to match them to eclasses and quals.
3655 *
3656 * Note: for simple inner joins, any match should be in an eclass.
3657 * "Loose" quals that syntactically match an FK equality must have
3658 * been rejected for EC status because they are outer-join quals or
3659 * similar. We can still consider them to match the FK.
3660 */
3661 for (colno = 0; colno < fkinfo->nkeys; colno++)
3662 {
3663 EquivalenceClass *ec;
3664 AttrNumber con_attno,
3665 ref_attno;
3666 Oid fpeqop;
3667 ListCell *lc2;
3668
3669 ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
3670 /* Don't bother looking for loose quals if we got an EC match */
3671 if (ec != NULL)
3672 {
3673 fkinfo->nmatched_ec++;
3674 if (ec->ec_has_const)
3675 fkinfo->nconst_ec++;
3676 continue;
3677 }
3678
3679 /*
3680 * Scan joininfo list for relevant clauses. Either rel's joininfo
3681 * list would do equally well; we use con_rel's.
3682 */
3683 con_attno = fkinfo->conkey[colno];
3684 ref_attno = fkinfo->confkey[colno];
3685 fpeqop = InvalidOid; /* we'll look this up only if needed */
3686
3687 foreach(lc2, con_rel->joininfo)
3688 {
3689 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
3690 OpExpr *clause = (OpExpr *) rinfo->clause;
3691 Var *leftvar;
3692 Var *rightvar;
3693
3694 /* Only binary OpExprs are useful for consideration */
3695 if (!IsA(clause, OpExpr) ||
3696 list_length(clause->args) != 2)
3697 continue;
3698 leftvar = (Var *) get_leftop((Expr *) clause);
3699 rightvar = (Var *) get_rightop((Expr *) clause);
3700
3701 /* Operands must be Vars, possibly with RelabelType */
3702 while (leftvar && IsA(leftvar, RelabelType))
3703 leftvar = (Var *) ((RelabelType *) leftvar)->arg;
3704 if (!(leftvar && IsA(leftvar, Var)))
3705 continue;
3706 while (rightvar && IsA(rightvar, RelabelType))
3707 rightvar = (Var *) ((RelabelType *) rightvar)->arg;
3708 if (!(rightvar && IsA(rightvar, Var)))
3709 continue;
3710
3711 /* Now try to match the vars to the current foreign key cols */
3712 if (fkinfo->ref_relid == leftvar->varno &&
3713 ref_attno == leftvar->varattno &&
3714 fkinfo->con_relid == rightvar->varno &&
3715 con_attno == rightvar->varattno)
3716 {
3717 /* Vars match, but is it the right operator? */
3718 if (clause->opno == fkinfo->conpfeqop[colno])
3719 {
3720 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3721 rinfo);
3722 fkinfo->nmatched_ri++;
3723 }
3724 }
3725 else if (fkinfo->ref_relid == rightvar->varno &&
3726 ref_attno == rightvar->varattno &&
3727 fkinfo->con_relid == leftvar->varno &&
3728 con_attno == leftvar->varattno)
3729 {
3730 /*
3731 * Reverse match, must check commutator operator. Look it
3732 * up if we didn't already. (In the worst case we might
3733 * do multiple lookups here, but that would require an FK
3734 * equality operator without commutator, which is
3735 * unlikely.)
3736 */
3737 if (!OidIsValid(fpeqop))
3738 fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
3739 if (clause->opno == fpeqop)
3740 {
3741 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3742 rinfo);
3743 fkinfo->nmatched_ri++;
3744 }
3745 }
3746 }
3747 /* If we found any matching loose quals, count col as matched */
3748 if (fkinfo->rinfos[colno])
3749 fkinfo->nmatched_rcols++;
3750 }
3751
3752 /*
3753 * Currently, we drop multicolumn FKs that aren't fully matched to the
3754 * query. Later we might figure out how to derive some sort of
3755 * estimate from them, in which case this test should be weakened to
3756 * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3757 */
3758 if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3759 newlist = lappend(newlist, fkinfo);
3760 }
3761 /* Replace fkey_list, thereby discarding any useless entries */
3762 root->fkey_list = newlist;
3763}
int16 AttrNumber
Definition: attnum.h:21
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2560
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:78
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:95
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:83
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:1292
List * joininfo
Definition: pathnodes.h:1018

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

3306{
3307 RestrictInfo *restrictinfo;
3308 Node *clause;
3309 Relids relids;
3310 bool pseudoconstant = false;
3311
3312 /*
3313 * Build the new clause. Copy to ensure it shares no substructure with
3314 * original (this is necessary in case there are subselects in there...)
3315 */
3316 clause = (Node *) make_opclause(opno,
3317 BOOLOID, /* opresulttype */
3318 false, /* opretset */
3319 copyObject(item1),
3320 copyObject(item2),
3321 InvalidOid,
3322 collation);
3323
3324 /* If both constant, try to reduce to a boolean constant. */
3325 if (both_const)
3326 {
3327 clause = eval_const_expressions(root, clause);
3328
3329 /* If we produced const TRUE, just drop the clause */
3330 if (clause && IsA(clause, Const))
3331 {
3332 Const *cclause = (Const *) clause;
3333
3334 Assert(cclause->consttype == BOOLOID);
3335 if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
3336 return NULL;
3337 }
3338 }
3339
3340 /*
3341 * The rest of this is a very cut-down version of distribute_qual_to_rels.
3342 * We can skip most of the work therein, but there are a couple of special
3343 * cases we still have to handle.
3344 *
3345 * Retrieve all relids mentioned within the possibly-simplified clause.
3346 */
3347 relids = pull_varnos(root, clause);
3348 Assert(bms_is_subset(relids, qualscope));
3349
3350 /*
3351 * If the clause is variable-free, our normal heuristic for pushing it
3352 * down to just the mentioned rels doesn't work, because there are none.
3353 * Apply it as a gating qual at the appropriate level (see comments for
3354 * get_join_domain_min_rels).
3355 */
3356 if (bms_is_empty(relids))
3357 {
3358 /* eval at join domain's safe level */
3359 relids = get_join_domain_min_rels(root, qualscope);
3360 /* mark as gating qual */
3361 pseudoconstant = true;
3362 /* tell createplan.c to check for gating quals */
3363 root->hasPseudoConstantQuals = true;
3364 }
3365
3366 /*
3367 * Build the RestrictInfo node itself.
3368 */
3369 restrictinfo = make_restrictinfo(root,
3370 (Expr *) clause,
3371 true, /* is_pushed_down */
3372 false, /* !has_clone */
3373 false, /* !is_clone */
3374 pseudoconstant,
3375 security_level,
3376 relids,
3377 NULL, /* incompatible_relids */
3378 NULL); /* outer_relids */
3379
3380 /*
3381 * If it's a join clause, add vars used in the clause to targetlists of
3382 * their relations, so that they will be emitted by the plan nodes that
3383 * scan those relations (else they won't be available at the join node!).
3384 *
3385 * Typically, we'd have already done this when the component expressions
3386 * were first seen by distribute_qual_to_rels; but it is possible that
3387 * some of the Vars could have missed having that done because they only
3388 * appeared in single-relation clauses originally. So do it here for
3389 * safety.
3390 *
3391 * See also rebuild_joinclause_attr_needed, which has to partially repeat
3392 * this work after removal of an outer join. (Since we will put this
3393 * clause into the joininfo lists, that function needn't do any extra work
3394 * to find it.)
3395 */
3396 if (bms_membership(relids) == BMS_MULTIPLE)
3397 {
3398 List *vars = pull_var_clause(clause,
3402
3404 list_free(vars);
3405 }
3406
3407 /*
3408 * Check mergejoinability. This will usually succeed, since the op came
3409 * from an EquivalenceClass; but we could have reduced the original clause
3410 * to a constant.
3411 */
3412 check_mergejoinable(restrictinfo);
3413
3414 /*
3415 * Note we don't do initialize_mergeclause_eclasses(); the caller can
3416 * handle that much more cheaply than we can. It's okay to call
3417 * distribute_restrictinfo_to_rels() before that happens.
3418 */
3419
3420 /*
3421 * Push the new clause into all the appropriate restrictinfo lists.
3422 */
3424
3425 return restrictinfo;
3426}
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:3511
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
Oid consttype
Definition: primnodes.h:329

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

1618{
1619 RangeTblEntry *rte = root->simple_rte_array[rti];
1620 Index security_level = 0;
1621 ListCell *lc;
1622
1623 /*
1624 * Each element of the securityQuals list has been preprocessed into an
1625 * implicitly-ANDed list of clauses. All the clauses in a given sublist
1626 * should get the same security level, but successive sublists get higher
1627 * levels.
1628 */
1629 foreach(lc, rte->securityQuals)
1630 {
1631 List *qualset = (List *) lfirst(lc);
1632
1633 /*
1634 * We cheat to the extent of passing ojscope = qualscope rather than
1635 * its more logical value of NULL. The only effect this has is to
1636 * force a Var-free qual to be evaluated at the rel rather than being
1637 * pushed up to top of tree, which we don't want.
1638 */
1640 jtitem,
1641 NULL,
1642 security_level,
1643 jtitem->qualscope,
1644 jtitem->qualscope,
1645 NULL,
1646 NULL,
1647 true,
1648 false, false, /* not clones */
1649 NULL);
1650 security_level++;
1651 }
1652
1653 /* Assert that qual_security_level is higher than anything we just used */
1654 Assert(security_level <= root->qual_security_level);
1655}

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

Referenced by deconstruct_distribute().

◆ rebuild_joinclause_attr_needed()

void rebuild_joinclause_attr_needed ( PlannerInfo root)

Definition at line 3545 of file initsplan.c.

3546{
3547 /*
3548 * We must examine all join clauses, but there's no value in processing
3549 * any join clause more than once. So it's slightly annoying that we have
3550 * to find them via the per-base-relation joininfo lists. Avoid duplicate
3551 * processing by tracking the rinfo_serial numbers of join clauses we've
3552 * already seen. (This doesn't work for is_clone clauses, so we must
3553 * waste effort on them.)
3554 */
3555 Bitmapset *seen_serials = NULL;
3556 Index rti;
3557
3558 /* Scan all baserels for join clauses */
3559 for (rti = 1; rti < root->simple_rel_array_size; rti++)
3560 {
3561 RelOptInfo *brel = root->simple_rel_array[rti];
3562 ListCell *lc;
3563
3564 if (brel == NULL)
3565 continue;
3566 if (brel->reloptkind != RELOPT_BASEREL)
3567 continue;
3568
3569 foreach(lc, brel->joininfo)
3570 {
3571 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
3572 Relids relids = rinfo->required_relids;
3573
3574 if (!rinfo->is_clone) /* else serial number is not unique */
3575 {
3576 if (bms_is_member(rinfo->rinfo_serial, seen_serials))
3577 continue; /* saw it already */
3578 seen_serials = bms_add_member(seen_serials,
3579 rinfo->rinfo_serial);
3580 }
3581
3582 if (bms_membership(relids) == BMS_MULTIPLE)
3583 {
3584 List *vars = pull_var_clause((Node *) rinfo->clause,
3588 Relids where_needed;
3589
3590 if (rinfo->is_clone)
3591 where_needed = bms_intersect(relids, root->all_baserels);
3592 else
3593 where_needed = relids;
3594 add_vars_to_attr_needed(root, vars, where_needed);
3595 list_free(vars);
3596 }
3597 }
3598 }
3599}
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:353

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

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ rebuild_lateral_attr_needed()

void rebuild_lateral_attr_needed ( PlannerInfo root)

Definition at line 807 of file initsplan.c.

808{
809 Index rti;
810
811 /* We need do nothing if the query contains no LATERAL RTEs */
812 if (!root->hasLateralRTEs)
813 return;
814
815 /* Examine the same baserels that find_lateral_references did */
816 for (rti = 1; rti < root->simple_rel_array_size; rti++)
817 {
818 RelOptInfo *brel = root->simple_rel_array[rti];
819 Relids where_needed;
820
821 if (brel == NULL)
822 continue;
823 if (brel->reloptkind != RELOPT_BASEREL)
824 continue;
825
826 /*
827 * We don't need to repeat all of extract_lateral_references, since it
828 * kindly saved the extracted Vars/PHVs in lateral_vars.
829 */
830 if (brel->lateral_vars == NIL)
831 continue;
832
833 where_needed = bms_make_singleton(rti);
834
835 add_vars_to_attr_needed(root, brel->lateral_vars, where_needed);
836 }
837}

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

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ remove_useless_groupby_columns()

void remove_useless_groupby_columns ( PlannerInfo root)

Definition at line 412 of file initsplan.c.

413{
414 Query *parse = root->parse;
415 Bitmapset **groupbyattnos;
416 Bitmapset **surplusvars;
417 bool tryremove = false;
418 ListCell *lc;
419 int relid;
420
421 /* No chance to do anything if there are less than two GROUP BY items */
422 if (list_length(root->processed_groupClause) < 2)
423 return;
424
425 /* Don't fiddle with the GROUP BY clause if the query has grouping sets */
426 if (parse->groupingSets)
427 return;
428
429 /*
430 * Scan the GROUP BY clause to find GROUP BY items that are simple Vars.
431 * Fill groupbyattnos[k] with a bitmapset of the column attnos of RTE k
432 * that are GROUP BY items.
433 */
434 groupbyattnos = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
435 (list_length(parse->rtable) + 1));
436 foreach(lc, root->processed_groupClause)
437 {
439 TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
440 Var *var = (Var *) tle->expr;
441
442 /*
443 * Ignore non-Vars and Vars from other query levels.
444 *
445 * XXX in principle, stable expressions containing Vars could also be
446 * removed, if all the Vars are functionally dependent on other GROUP
447 * BY items. But it's not clear that such cases occur often enough to
448 * be worth troubling over.
449 */
450 if (!IsA(var, Var) ||
451 var->varlevelsup > 0)
452 continue;
453
454 /* OK, remember we have this Var */
455 relid = var->varno;
456 Assert(relid <= list_length(parse->rtable));
457
458 /*
459 * If this isn't the first column for this relation then we now have
460 * multiple columns. That means there might be some that can be
461 * removed.
462 */
463 tryremove |= !bms_is_empty(groupbyattnos[relid]);
464 groupbyattnos[relid] = bms_add_member(groupbyattnos[relid],
466 }
467
468 /*
469 * No Vars or didn't find multiple Vars for any relation in the GROUP BY?
470 * If so, nothing can be removed, so don't waste more effort trying.
471 */
472 if (!tryremove)
473 return;
474
475 /*
476 * Consider each relation and see if it is possible to remove some of its
477 * Vars from GROUP BY. For simplicity and speed, we do the actual removal
478 * in a separate pass. Here, we just fill surplusvars[k] with a bitmapset
479 * of the column attnos of RTE k that are removable GROUP BY items.
480 */
481 surplusvars = NULL; /* don't allocate array unless required */
482 relid = 0;
483 foreach(lc, parse->rtable)
484 {
486 RelOptInfo *rel;
487 Bitmapset *relattnos;
488 Bitmapset *best_keycolumns = NULL;
489 int32 best_nkeycolumns = PG_INT32_MAX;
490
491 relid++;
492
493 /* Only plain relations could have primary-key constraints */
494 if (rte->rtekind != RTE_RELATION)
495 continue;
496
497 /*
498 * We must skip inheritance parent tables as some of the child rels
499 * may cause duplicate rows. This cannot happen with partitioned
500 * tables, however.
501 */
502 if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
503 continue;
504
505 /* Nothing to do unless this rel has multiple Vars in GROUP BY */
506 relattnos = groupbyattnos[relid];
507 if (bms_membership(relattnos) != BMS_MULTIPLE)
508 continue;
509
510 rel = root->simple_rel_array[relid];
511
512 /*
513 * Now check each index for this relation to see if there are any with
514 * columns which are a proper subset of the grouping columns for this
515 * relation.
516 */
518 {
519 Bitmapset *ind_attnos;
520 bool nulls_check_ok;
521
522 /*
523 * Skip any non-unique and deferrable indexes. Predicate indexes
524 * have not been checked yet, so we must skip those too as the
525 * predOK check that's done later might fail.
526 */
527 if (!index->unique || !index->immediate || index->indpred != NIL)
528 continue;
529
530 /* For simplicity, we currently don't support expression indexes */
531 if (index->indexprs != NIL)
532 continue;
533
534 ind_attnos = NULL;
535 nulls_check_ok = true;
536 for (int i = 0; i < index->nkeycolumns; i++)
537 {
538 /*
539 * We must insist that the index columns are all defined NOT
540 * NULL otherwise duplicate NULLs could exist. However, we
541 * can relax this check when the index is defined with NULLS
542 * NOT DISTINCT as there can only be 1 NULL row, therefore
543 * functional dependency on the unique columns is maintained,
544 * despite the NULL.
545 */
546 if (!index->nullsnotdistinct &&
547 !bms_is_member(index->indexkeys[i],
548 rel->notnullattnums))
549 {
550 nulls_check_ok = false;
551 break;
552 }
553
554 ind_attnos =
555 bms_add_member(ind_attnos,
556 index->indexkeys[i] -
558 }
559
560 if (!nulls_check_ok)
561 continue;
562
563 /*
564 * Skip any indexes where the indexed columns aren't a proper
565 * subset of the GROUP BY.
566 */
567 if (bms_subset_compare(ind_attnos, relattnos) != BMS_SUBSET1)
568 continue;
569
570 /*
571 * Record the attribute numbers from the index with the fewest
572 * columns. This allows the largest number of columns to be
573 * removed from the GROUP BY clause. In the future, we may wish
574 * to consider using the narrowest set of columns and looking at
575 * pg_statistic.stawidth as it might be better to use an index
576 * with, say two INT4s, rather than, say, one long varlena column.
577 */
578 if (index->nkeycolumns < best_nkeycolumns)
579 {
580 best_keycolumns = ind_attnos;
581 best_nkeycolumns = index->nkeycolumns;
582 }
583 }
584
585 /* Did we find a suitable index? */
586 if (!bms_is_empty(best_keycolumns))
587 {
588 /*
589 * To easily remember whether we've found anything to do, we don't
590 * allocate the surplusvars[] array until we find something.
591 */
592 if (surplusvars == NULL)
593 surplusvars = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
594 (list_length(parse->rtable) + 1));
595
596 /* Remember the attnos of the removable columns */
597 surplusvars[relid] = bms_difference(relattnos, best_keycolumns);
598 }
599 }
600
601 /*
602 * If we found any surplus Vars, build a new GROUP BY clause without them.
603 * (Note: this may leave some TLEs with unreferenced ressortgroupref
604 * markings, but that's harmless.)
605 */
606 if (surplusvars != NULL)
607 {
608 List *new_groupby = NIL;
609
610 foreach(lc, root->processed_groupClause)
611 {
613 TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
614 Var *var = (Var *) tle->expr;
615
616 /*
617 * New list must include non-Vars, outer Vars, and anything not
618 * marked as surplus.
619 */
620 if (!IsA(var, Var) ||
621 var->varlevelsup > 0 ||
623 surplusvars[var->varno]))
624 new_groupby = lappend(new_groupby, sgc);
625 }
626
627 root->processed_groupClause = new_groupby;
628 }
629}
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:346
BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:445
@ BMS_SUBSET1
Definition: bitmapset.h:63
#define PG_INT32_MAX
Definition: c.h:560
int32_t int32
Definition: c.h:498
int i
Definition: isn.c:74
void * palloc0(Size size)
Definition: mcxt.c:1347
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
List * indexlist
Definition: pathnodes.h:971
Expr * expr
Definition: primnodes.h:2219
Definition: type.h:96
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:367

References Assert(), bms_add_member(), bms_difference(), bms_is_empty, bms_is_member(), bms_membership(), BMS_MULTIPLE, BMS_SUBSET1, bms_subset_compare(), TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, foreach_node, get_sortgroupclause_tle(), i, if(), RelOptInfo::indexlist, RangeTblEntry::inh, IsA, lappend(), lfirst_node, list_length(), NIL, RelOptInfo::notnullattnums, palloc0(), parse(), PG_INT32_MAX, root, RTE_RELATION, RangeTblEntry::rtekind, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by query_planner().

◆ restriction_is_always_false()

bool restriction_is_always_false ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3149 of file initsplan.c.

3151{
3152 /*
3153 * For a clone clause, we don't have a reliable way to determine if the
3154 * input expression of a NullTest is non-nullable: nullingrel bits in
3155 * clone clauses may not reflect reality, so we dare not draw conclusions
3156 * from clones about whether Vars are guaranteed not-null.
3157 */
3158 if (restrictinfo->has_clone || restrictinfo->is_clone)
3159 return false;
3160
3161 /* Check for NullTest qual */
3162 if (IsA(restrictinfo->clause, NullTest))
3163 {
3164 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3165
3166 /* is this NullTest an IS_NULL qual? */
3167 if (nulltest->nulltesttype != IS_NULL)
3168 return false;
3169
3170 return expr_is_nonnullable(root, nulltest->arg);
3171 }
3172
3173 /* If it's an OR, check its sub-clauses */
3174 if (restriction_is_or_clause(restrictinfo))
3175 {
3176 ListCell *lc;
3177
3178 Assert(is_orclause(restrictinfo->orclause));
3179
3180 /*
3181 * Currently, when processing OR expressions, we only return true when
3182 * all of the OR branches are always false. This could perhaps be
3183 * expanded to remove OR branches that are provably false. This may
3184 * be a useful thing to do as it could result in the OR being left
3185 * with a single arg. That's useful as it would allow the OR
3186 * condition to be replaced with its single argument which may allow
3187 * use of an index for faster filtering on the remaining condition.
3188 */
3189 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3190 {
3191 Node *orarg = (Node *) lfirst(lc);
3192
3193 if (!IsA(orarg, RestrictInfo) ||
3195 return false;
3196 }
3197 return true;
3198 }
3199
3200 return false;
3201}
static bool expr_is_nonnullable(PlannerInfo *root, Expr *expr)
Definition: initsplan.c:3055
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:116
@ IS_NULL
Definition: primnodes.h:1957
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:407
NullTestType nulltesttype
Definition: primnodes.h:1964
Expr * arg
Definition: primnodes.h:1963

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

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

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3091 of file initsplan.c.

3093{
3094 /*
3095 * For a clone clause, we don't have a reliable way to determine if the
3096 * input expression of a NullTest is non-nullable: nullingrel bits in
3097 * clone clauses may not reflect reality, so we dare not draw conclusions
3098 * from clones about whether Vars are guaranteed not-null.
3099 */
3100 if (restrictinfo->has_clone || restrictinfo->is_clone)
3101 return false;
3102
3103 /* Check for NullTest qual */
3104 if (IsA(restrictinfo->clause, NullTest))
3105 {
3106 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3107
3108 /* is this NullTest an IS_NOT_NULL qual? */
3109 if (nulltest->nulltesttype != IS_NOT_NULL)
3110 return false;
3111
3112 return expr_is_nonnullable(root, nulltest->arg);
3113 }
3114
3115 /* If it's an OR, check its sub-clauses */
3116 if (restriction_is_or_clause(restrictinfo))
3117 {
3118 ListCell *lc;
3119
3120 Assert(is_orclause(restrictinfo->orclause));
3121
3122 /*
3123 * if any of the given OR branches is provably always true then the
3124 * entire condition is true.
3125 */
3126 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3127 {
3128 Node *orarg = (Node *) lfirst(lc);
3129
3130 if (!IsA(orarg, RestrictInfo))
3131 continue;
3132
3134 return true;
3135 }
3136 }
3137
3138 return false;
3139}
@ IS_NOT_NULL
Definition: primnodes.h:1957

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

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

Variable Documentation

◆ from_collapse_limit

int from_collapse_limit

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 40 of file initsplan.c.

Referenced by deconstruct_recurse().