PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 bool is_partial_agg_memory_risky (PlannerInfo *root)
 
static void create_agg_clause_infos (PlannerInfo *root)
 
static void create_grouping_expr_infos (PlannerInfo *root)
 
static EquivalenceClassget_eclass_for_sortgroupclause (PlannerInfo *root, SortGroupClause *sgc, Expr *expr)
 
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 setup_eager_aggregation (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)
 
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

Function Documentation

◆ add_base_clause_to_rel()

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

Definition at line 3348 of file initsplan.c.

3350{
3351 RelOptInfo *rel = find_base_rel(root, relid);
3352 RangeTblEntry *rte = root->simple_rte_array[relid];
3353
3354 Assert(bms_membership(restrictinfo->required_relids) == BMS_SINGLETON);
3355
3356 /*
3357 * For inheritance parent tables, we must always record the RestrictInfo
3358 * in baserestrictinfo as is. If we were to transform or skip adding it,
3359 * then the original wouldn't be available in apply_child_basequals. Since
3360 * there are two RangeTblEntries for inheritance parents, one with
3361 * inh==true and the other with inh==false, we're still able to apply this
3362 * optimization to the inh==false one. The inh==true one is what
3363 * apply_child_basequals() sees, whereas the inh==false one is what's used
3364 * for the scan node in the final plan.
3365 *
3366 * We make an exception to this for partitioned tables. For these, we
3367 * always apply the constant-TRUE and constant-FALSE transformations. A
3368 * qual which is either of these for a partitioned table must also be that
3369 * for all of its child partitions.
3370 */
3371 if (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE)
3372 {
3373 /* Don't add the clause if it is always true */
3375 return;
3376
3377 /*
3378 * Substitute the origin qual with constant-FALSE if it is provably
3379 * always false.
3380 *
3381 * Note that we need to keep the same rinfo_serial, since it is in
3382 * practice the same condition. We also need to reset the
3383 * last_rinfo_serial counter, which is essential to ensure that the
3384 * RestrictInfos for the "same" qual condition get identical serial
3385 * numbers (see deconstruct_distribute_oj_quals).
3386 */
3388 {
3389 int save_rinfo_serial = restrictinfo->rinfo_serial;
3390 int save_last_rinfo_serial = root->last_rinfo_serial;
3391
3393 (Expr *) makeBoolConst(false, false),
3394 restrictinfo->is_pushed_down,
3395 restrictinfo->has_clone,
3396 restrictinfo->is_clone,
3397 restrictinfo->pseudoconstant,
3398 0, /* security_level */
3399 restrictinfo->required_relids,
3400 restrictinfo->incompatible_relids,
3401 restrictinfo->outer_relids);
3402 restrictinfo->rinfo_serial = save_rinfo_serial;
3403 root->last_rinfo_serial = save_last_rinfo_serial;
3404 }
3405 }
3406
3407 /* Add clause to rel's restriction list */
3409
3410 /* Update security level info */
3412 restrictinfo->security_level);
3413}
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:765
@ BMS_SINGLETON
Definition bitmapset.h:72
#define Min(x, y)
Definition c.h:1093
#define Assert(condition)
Definition c.h:945
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition initsplan.c:3423
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition initsplan.c:3488
List * lappend(List *list, void *datum)
Definition list.c:339
Node * makeBoolConst(bool value, bool isnull)
Definition makefuncs.c:408
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:544
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)
List * baserestrictinfo
Definition pathnodes.h:1130
Index baserestrict_min_security
Definition pathnodes.h:1134

References Assert, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, bms_membership(), BMS_SINGLETON, fb(), find_base_rel(), lappend(), make_restrictinfo(), makeBoolConst(), Min, restriction_is_always_false(), restriction_is_always_true(), and root.

Referenced by distribute_restrictinfo_to_rels().

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 166 of file initsplan.c.

167{
168 if (jtnode == NULL)
169 return;
170 if (IsA(jtnode, RangeTblRef))
171 {
172 int varno = ((RangeTblRef *) jtnode)->rtindex;
173
174 (void) build_simple_rel(root, varno, NULL);
175 }
176 else if (IsA(jtnode, FromExpr))
177 {
178 FromExpr *f = (FromExpr *) jtnode;
179 ListCell *l;
180
181 foreach(l, f->fromlist)
183 }
184 else if (IsA(jtnode, JoinExpr))
185 {
186 JoinExpr *j = (JoinExpr *) jtnode;
187
190 }
191 else
192 elog(ERROR, "unrecognized node type: %d",
193 (int) nodeTag(jtnode));
194}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition initsplan.c:166
int j
Definition isn.c:78
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define nodeTag(nodeptr)
Definition nodes.h:139
#define lfirst(lc)
Definition pg_list.h:172
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition relnode.c:212
List * fromlist
Definition primnodes.h:2383

References add_base_rels_to_query(), build_simple_rel(), elog, ERROR, fb(), 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 204 of file initsplan.c.

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

References expand_inherited_rtentry(), fb(), 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 361 of file initsplan.c.

363{
364 ListCell *temp;
365
367
368 foreach(temp, vars)
369 {
370 Node *node = (Node *) lfirst(temp);
371
372 if (IsA(node, Var))
373 {
374 Var *var = (Var *) node;
375 RelOptInfo *rel = find_base_rel(root, var->varno);
376 int attno = var->varattno;
377
379 continue;
380 Assert(attno >= rel->min_attr && attno <= rel->max_attr);
381 attno -= rel->min_attr;
382 rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
384 }
385 else if (IsA(node, PlaceHolderVar))
386 {
389
390 phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
392 }
393 else
394 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
395 }
396}
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:901
#define bms_is_empty(a)
Definition bitmapset.h:118
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
Definition placeholder.c:83
Definition nodes.h:135
Relids relids
Definition pathnodes.h:1009
AttrNumber min_attr
Definition pathnodes.h:1063
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270

References Assert, bms_add_members(), bms_is_empty, bms_is_subset(), elog, ERROR, fb(), find_base_rel(), find_placeholder_info(), IsA, lfirst, RelOptInfo::min_attr, nodeTag, 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 290 of file initsplan.c.

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

References Assert, bms_add_members(), bms_is_empty, bms_is_subset(), copyObject, elog, ERROR, PathTarget::exprs, fb(), find_base_rel(), find_placeholder_info(), IsA, lappend(), lfirst, RelOptInfo::min_attr, nodeTag, 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 243 of file initsplan.c.

244{
245 List *tlist_vars = pull_var_clause((Node *) final_tlist,
249
250 if (tlist_vars != NIL)
251 {
253 list_free(tlist_vars);
254 }
255
256 /*
257 * If there's a HAVING clause, we'll need the Vars it uses, too. Note
258 * that HAVING can contain Aggrefs but not WindowFuncs.
259 */
260 if (root->parse->havingQual)
261 {
262 List *having_vars = pull_var_clause(root->parse->havingQual,
265
266 if (having_vars != NIL)
267 {
271 }
272 }
273}
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:290
void list_free(List *list)
Definition list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition optimizer.h:198
#define PVC_RECURSE_WINDOWFUNCS
Definition optimizer.h:200
#define PVC_INCLUDE_PLACEHOLDERS
Definition optimizer.h:201
#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(), fb(), 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 3788 of file initsplan.c.

3795{
3797 Expr *clause;
3798
3799 /*
3800 * Build the new clause. Copy to ensure it shares no substructure with
3801 * original (this is necessary in case there are subselects in there...)
3802 */
3803 clause = make_opclause(opno,
3804 BOOLOID, /* opresulttype */
3805 false, /* opretset */
3808 InvalidOid,
3809 collation);
3810
3811 /*
3812 * Build the RestrictInfo node itself.
3813 */
3815 clause,
3816 true, /* is_pushed_down */
3817 false, /* !has_clone */
3818 false, /* !is_clone */
3819 false, /* pseudoconstant */
3820 security_level, /* security_level */
3821 qualscope, /* required_relids */
3822 NULL, /* incompatible_relids */
3823 NULL); /* outer_relids */
3824
3825 /* Set mergejoinability/hashjoinability flags */
3829
3830 return restrictinfo;
3831}
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition initsplan.c:4165
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition initsplan.c:4128
static void check_memoizable(RestrictInfo *restrictinfo)
Definition initsplan.c:4193
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition makefuncs.c:701
#define InvalidOid

References check_hashjoinable(), check_memoizable(), check_mergejoinable(), copyObject, fb(), 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 4165 of file initsplan.c.

4166{
4167 Expr *clause = restrictinfo->clause;
4168 Oid opno;
4169 Node *leftarg;
4170
4171 if (restrictinfo->pseudoconstant)
4172 return;
4173 if (!is_opclause(clause))
4174 return;
4175 if (list_length(((OpExpr *) clause)->args) != 2)
4176 return;
4177
4178 opno = ((OpExpr *) clause)->opno;
4179 leftarg = linitial(((OpExpr *) clause)->args);
4180
4181 if (op_hashjoinable(opno, exprType(leftarg)) &&
4183 restrictinfo->hashjoinoperator = opno;
4184}
bool contain_volatile_functions(Node *clause)
Definition clauses.c:549
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition lsyscache.c:1657
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

References contain_volatile_functions(), exprType(), fb(), 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 4193 of file initsplan.c.

4194{
4195 TypeCacheEntry *typentry;
4196 Expr *clause = restrictinfo->clause;
4197 Oid lefttype;
4198 Oid righttype;
4199
4200 if (restrictinfo->pseudoconstant)
4201 return;
4202 if (!is_opclause(clause))
4203 return;
4204 if (list_length(((OpExpr *) clause)->args) != 2)
4205 return;
4206
4207 lefttype = exprType(linitial(((OpExpr *) clause)->args));
4208
4209 typentry = lookup_type_cache(lefttype, TYPECACHE_HASH_PROC |
4211
4212 if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
4213 restrictinfo->left_hasheqoperator = typentry->eq_opr;
4214
4215 righttype = exprType(lsecond(((OpExpr *) clause)->args));
4216
4217 /*
4218 * Lookup the right type, unless it's the same as the left type, in which
4219 * case typentry is already pointing to the required TypeCacheEntry.
4220 */
4221 if (lefttype != righttype)
4222 typentry = lookup_type_cache(righttype, TYPECACHE_HASH_PROC |
4224
4225 if (OidIsValid(typentry->hash_proc) && OidIsValid(typentry->eq_opr))
4226 restrictinfo->right_hasheqoperator = typentry->eq_opr;
4227}
#define OidIsValid(objectId)
Definition c.h:860
#define lsecond(l)
Definition pg_list.h:183
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_EQ_OPR
Definition typcache.h:138
#define TYPECACHE_HASH_PROC
Definition typcache.h:142

References TypeCacheEntry::eq_opr, exprType(), fb(), 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 4128 of file initsplan.c.

4129{
4130 Expr *clause = restrictinfo->clause;
4131 Oid opno;
4132 Node *leftarg;
4133
4134 if (restrictinfo->pseudoconstant)
4135 return;
4136 if (!is_opclause(clause))
4137 return;
4138 if (list_length(((OpExpr *) clause)->args) != 2)
4139 return;
4140
4141 opno = ((OpExpr *) clause)->opno;
4142 leftarg = linitial(((OpExpr *) clause)->args);
4143
4144 if (op_mergejoinable(opno, exprType(leftarg)) &&
4146 restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
4147
4148 /*
4149 * Note: op_mergejoinable is just a hint; if we fail to find the operator
4150 * in any btree opfamilies, mergeopfamilies remains NIL and so the clause
4151 * is not treated as mergejoinable.
4152 */
4153}
bool op_mergejoinable(Oid opno, Oid inputtype)
Definition lsyscache.c:1606
List * get_mergejoin_opfamilies(Oid opno)
Definition lsyscache.c:430

References contain_volatile_functions(), exprType(), fb(), 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 3303 of file initsplan.c.

3304{
3306 ListCell *lc;
3307
3308 /* Check for IS NULL, and identify the Var forced to NULL */
3310 if (forced_null_var == NULL)
3311 return false;
3312
3313 /*
3314 * If the Var comes from the nullable side of a lower antijoin, the IS
3315 * NULL condition is necessarily true. If it's not nulled by anything,
3316 * there is no point in searching the join_info_list. Otherwise, we need
3317 * to find out whether the nulling rel is an antijoin.
3318 */
3319 if (forced_null_var->varnullingrels == NULL)
3320 return false;
3321
3322 foreach(lc, root->join_info_list)
3323 {
3325
3326 /*
3327 * This test will not succeed if sjinfo->ojrelid is zero, which is
3328 * possible for an antijoin that was converted from a semijoin; but in
3329 * such a case the Var couldn't have come from its nullable side.
3330 */
3331 if (sjinfo->jointype == JOIN_ANTI && sjinfo->ojrelid != 0 &&
3332 bms_is_member(sjinfo->ojrelid, forced_null_var->varnullingrels))
3333 return true;
3334 }
3335
3336 return false;
3337}
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Var * find_forced_null_var(Node *node)
Definition clauses.c:1995
@ JOIN_ANTI
Definition nodes.h:318
JoinType jointype
Definition pathnodes.h:3217

References bms_is_member(), fb(), 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 2416 of file initsplan.c.

2417{
2418 List *semi_operators;
2419 List *semi_rhs_exprs;
2420 bool all_btree;
2421 bool all_hash;
2422 ListCell *lc;
2423
2424 /* Initialize semijoin-related fields in case we can't unique-ify */
2425 sjinfo->semi_can_btree = false;
2426 sjinfo->semi_can_hash = false;
2427 sjinfo->semi_operators = NIL;
2428 sjinfo->semi_rhs_exprs = NIL;
2429
2430 /* Nothing more to do if it's not a semijoin */
2431 if (sjinfo->jointype != JOIN_SEMI)
2432 return;
2433
2434 /*
2435 * Look to see whether the semijoin's join quals consist of AND'ed
2436 * equality operators, with (only) RHS variables on only one side of each
2437 * one. If so, we can figure out how to enforce uniqueness for the RHS.
2438 *
2439 * Note that the input clause list is the list of quals that are
2440 * *syntactically* associated with the semijoin, which in practice means
2441 * the synthesized comparison list for an IN or the WHERE of an EXISTS.
2442 * Particularly in the latter case, it might contain clauses that aren't
2443 * *semantically* associated with the join, but refer to just one side or
2444 * the other. We can ignore such clauses here, as they will just drop
2445 * down to be processed within one side or the other. (It is okay to
2446 * consider only the syntactically-associated clauses here because for a
2447 * semijoin, no higher-level quals could refer to the RHS, and so there
2448 * can be no other quals that are semantically associated with this join.
2449 * We do things this way because it is useful to have the set of potential
2450 * unique-ification expressions before we can extract the list of quals
2451 * that are actually semantically associated with the particular join.)
2452 *
2453 * Note that the semi_operators list consists of the joinqual operators
2454 * themselves (but commuted if needed to put the RHS value on the right).
2455 * These could be cross-type operators, in which case the operator
2456 * actually needed for uniqueness is a related single-type operator. We
2457 * assume here that that operator will be available from the btree or hash
2458 * opclass when the time comes ... if not, create_unique_plan() will fail.
2459 */
2460 semi_operators = NIL;
2461 semi_rhs_exprs = NIL;
2462 all_btree = true;
2463 all_hash = enable_hashagg; /* don't consider hash if not enabled */
2464 foreach(lc, clause)
2465 {
2466 OpExpr *op = (OpExpr *) lfirst(lc);
2467 Oid opno;
2468 Node *left_expr;
2474
2475 /* Is it a binary opclause? */
2476 if (!IsA(op, OpExpr) ||
2477 list_length(op->args) != 2)
2478 {
2479 /* No, but does it reference both sides? */
2480 all_varnos = pull_varnos(root, (Node *) op);
2481 if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
2483 {
2484 /*
2485 * Clause refers to only one rel, so ignore it --- unless it
2486 * contains volatile functions, in which case we'd better
2487 * punt.
2488 */
2489 if (contain_volatile_functions((Node *) op))
2490 return;
2491 continue;
2492 }
2493 /* Non-operator clause referencing both sides, must punt */
2494 return;
2495 }
2496
2497 /* Extract data from binary opclause */
2498 opno = op->opno;
2499 left_expr = linitial(op->args);
2500 right_expr = lsecond(op->args);
2505
2506 /* Does it reference both sides? */
2507 if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
2509 {
2510 /*
2511 * Clause refers to only one rel, so ignore it --- unless it
2512 * contains volatile functions, in which case we'd better punt.
2513 */
2514 if (contain_volatile_functions((Node *) op))
2515 return;
2516 continue;
2517 }
2518
2519 /* check rel membership of arguments */
2520 if (!bms_is_empty(right_varnos) &&
2523 {
2524 /* typical case, right_expr is RHS variable */
2525 }
2526 else if (!bms_is_empty(left_varnos) &&
2529 {
2530 /* flipped case, left_expr is RHS variable */
2531 opno = get_commutator(opno);
2532 if (!OidIsValid(opno))
2533 return;
2535 }
2536 else
2537 {
2538 /* mixed membership of args, punt */
2539 return;
2540 }
2541
2542 /* all operators must be btree equality or hash equality */
2543 if (all_btree)
2544 {
2545 /* oprcanmerge is considered a hint... */
2546 if (!op_mergejoinable(opno, opinputtype) ||
2548 all_btree = false;
2549 }
2550 if (all_hash)
2551 {
2552 /* ... but oprcanhash had better be correct */
2553 if (!op_hashjoinable(opno, opinputtype))
2554 all_hash = false;
2555 }
2556 if (!(all_btree || all_hash))
2557 return;
2558
2559 /* so far so good, keep building lists */
2560 semi_operators = lappend_oid(semi_operators, opno);
2561 semi_rhs_exprs = lappend(semi_rhs_exprs, copyObject(right_expr));
2562 }
2563
2564 /* Punt if we didn't find at least one column to unique-ify */
2565 if (semi_rhs_exprs == NIL)
2566 return;
2567
2568 /*
2569 * The expressions we'd need to unique-ify mustn't be volatile.
2570 */
2571 if (contain_volatile_functions((Node *) semi_rhs_exprs))
2572 return;
2573
2574 /*
2575 * If we get here, we can unique-ify the semijoin's RHS using at least one
2576 * of sorting and hashing. Save the information about how to do that.
2577 */
2578 sjinfo->semi_can_btree = all_btree;
2579 sjinfo->semi_can_hash = all_hash;
2580 sjinfo->semi_operators = semi_operators;
2581 sjinfo->semi_rhs_exprs = semi_rhs_exprs;
2582}
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:575
bool enable_hashagg
Definition costsize.c:153
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
Oid get_commutator(Oid opno)
Definition lsyscache.c:1729
@ JOIN_SEMI
Definition nodes.h:317
Oid opno
Definition primnodes.h:851
List * args
Definition primnodes.h:869
List * semi_rhs_exprs
Definition pathnodes.h:3228
Relids syn_righthand
Definition pathnodes.h:3216
List * semi_operators
Definition pathnodes.h:3227
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(), fb(), 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_agg_clause_infos()

static void create_agg_clause_infos ( PlannerInfo root)
static

Definition at line 751 of file initsplan.c.

752{
754 List *agg_clause_list = NIL;
755 List *tlist_vars = NIL;
757 bool eager_agg_applicable = true;
758 ListCell *lc;
759
760 Assert(root->agg_clause_list == NIL);
761 Assert(root->tlist_vars == NIL);
762
763 tlist_exprs = pull_var_clause((Node *) root->processed_tlist,
767
768 /*
769 * Aggregates within the HAVING clause need to be processed in the same
770 * way as those in the targetlist. Note that HAVING can contain Aggrefs
771 * but not WindowFuncs.
772 */
773 if (root->parse->havingQual != NULL)
774 {
776
777 having_exprs = pull_var_clause((Node *) root->parse->havingQual,
780 if (having_exprs != NIL)
781 {
784 }
785 }
786
787 foreach(lc, tlist_exprs)
788 {
789 Expr *expr = (Expr *) lfirst(lc);
790 Aggref *aggref;
791 Relids agg_eval_at;
793
794 /* For now we don't try to support GROUPING() expressions */
795 if (IsA(expr, GroupingFunc))
796 {
797 eager_agg_applicable = false;
798 break;
799 }
800
801 /* Collect plain Vars for future reference */
802 if (IsA(expr, Var))
803 {
804 tlist_vars = list_append_unique(tlist_vars, expr);
805 continue;
806 }
807
808 aggref = castNode(Aggref, expr);
809
810 Assert(aggref->aggorder == NIL);
811 Assert(aggref->aggdistinct == NIL);
812
813 /*
814 * If there are any securityQuals, do not try to apply eager
815 * aggregation if any non-leakproof aggregate functions are present.
816 * This is overly strict, but for now...
817 */
818 if (root->qual_security_level > 0 &&
820 {
821 eager_agg_applicable = false;
822 break;
823 }
824
825 agg_eval_at = pull_varnos(root, (Node *) aggref);
826
827 /*
828 * If all base relations in the query are referenced by aggregate
829 * functions, then eager aggregation is not applicable.
830 */
832 if (bms_is_subset(root->all_baserels, aggregate_relids))
833 {
834 eager_agg_applicable = false;
835 break;
836 }
837
838 /* OK, create the AggClauseInfo node */
840 ac_info->aggref = aggref;
841 ac_info->agg_eval_at = agg_eval_at;
842
843 /* ... and add it to the list */
844 agg_clause_list = list_append_unique(agg_clause_list, ac_info);
845 }
846
848
850 {
851 root->agg_clause_list = agg_clause_list;
852 root->tlist_vars = tlist_vars;
853 }
854 else
855 {
856 list_free_deep(agg_clause_list);
857 list_free(tlist_vars);
858 }
859}
List * list_append_unique(List *list, void *datum)
Definition list.c:1343
List * list_concat(List *list1, const List *list2)
Definition list.c:561
void list_free_deep(List *list)
Definition list.c:1560
bool get_func_leakproof(Oid funcid)
Definition lsyscache.c:2057
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
#define PVC_RECURSE_PLACEHOLDERS
Definition optimizer.h:202
#define PVC_INCLUDE_AGGREGATES
Definition optimizer.h:197
Oid aggfnoid
Definition primnodes.h:464
List * aggdistinct
Definition primnodes.h:494
List * aggorder
Definition primnodes.h:491

References Aggref::aggdistinct, Aggref::aggfnoid, Aggref::aggorder, Assert, bms_add_members(), bms_is_subset(), castNode, fb(), get_func_leakproof(), IsA, lfirst, list_append_unique(), list_concat(), list_free(), list_free_deep(), makeNode, NIL, pull_var_clause(), pull_varnos(), PVC_INCLUDE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS, PVC_RECURSE_WINDOWFUNCS, and root.

Referenced by setup_eager_aggregation().

◆ create_grouping_expr_infos()

static void create_grouping_expr_infos ( PlannerInfo root)
static

Definition at line 869 of file initsplan.c.

870{
871 List *exprs = NIL;
873 List *ecs = NIL;
874 ListCell *lc,
875 *lc1,
876 *lc2,
877 *lc3;
878
879 Assert(root->group_expr_list == NIL);
880
881 foreach(lc, root->processed_groupClause)
882 {
884 TargetEntry *tle = get_sortgroupclause_tle(sgc, root->processed_tlist);
887
888 Assert(tle->ressortgroupref > 0);
889
890 /*
891 * For now we only support plain Vars as grouping expressions.
892 */
893 if (!IsA(tle->expr, Var))
894 return;
895
896 /*
897 * Eager aggregation is only possible if equality implies image
898 * equality for each grouping key. Otherwise, placing keys with
899 * different byte images into the same group may result in the loss of
900 * information that could be necessary to evaluate upper qual clauses.
901 *
902 * For instance, the NUMERIC data type is not supported, as values
903 * that are considered equal by the equality operator (e.g., 0 and
904 * 0.0) can have different scales.
905 */
908 if (!OidIsValid(tce->btree_opf) ||
909 !OidIsValid(tce->btree_opintype))
910 return;
911
913 tce->btree_opintype,
914 tce->btree_opintype,
918 tce->typcollation,
919 ObjectIdGetDatum(tce->btree_opintype))))
920 return;
921
922 exprs = lappend(exprs, tle->expr);
923 sortgrouprefs = lappend_int(sortgrouprefs, tle->ressortgroupref);
925 }
926
927 /*
928 * Construct a GroupingExprInfo for each expression.
929 */
930 forthree(lc1, exprs, lc2, sortgrouprefs, lc3, ecs)
931 {
932 Expr *expr = (Expr *) lfirst(lc1);
933 int sortgroupref = lfirst_int(lc2);
936
938 ge_info->expr = (Expr *) copyObject(expr);
939 ge_info->sortgroupref = sortgroupref;
940 ge_info->ec = ec;
941
942 root->group_expr_list = lappend(root->group_expr_list, ge_info);
943 }
944}
Datum OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
Definition fmgr.c:1413
static EquivalenceClass * get_eclass_for_sortgroupclause(PlannerInfo *root, SortGroupClause *sgc, Expr *expr)
Definition initsplan.c:952
List * lappend_int(List *list, int datum)
Definition list.c:357
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition lsyscache.c:915
#define BTEQUALIMAGE_PROC
Definition nbtree.h:720
#define lfirst_node(type, lc)
Definition pg_list.h:176
#define lfirst_int(lc)
Definition pg_list.h:173
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition pg_list.h:563
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition tlist.c:376
#define TYPECACHE_BTREE_OPFAMILY
Definition typcache.h:147

References Assert, BTEQUALIMAGE_PROC, copyObject, DatumGetBool(), exprType(), fb(), forthree, get_eclass_for_sortgroupclause(), get_opfamily_proc(), get_sortgroupclause_tle(), IsA, lappend(), lappend_int(), lfirst, lfirst_int, lfirst_node, lookup_type_cache(), makeNode, NIL, ObjectIdGetDatum(), OidFunctionCall1Coll(), OidIsValid, root, and TYPECACHE_BTREE_OPFAMILY.

Referenced by setup_eager_aggregation().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 1213 of file initsplan.c.

1214{
1215 bool found_laterals = false;
1216 Index rti;
1217 ListCell *lc;
1218
1219 /* We need do nothing if the query contains no LATERAL RTEs */
1220 if (!root->hasLateralRTEs)
1221 return;
1222
1223 /* We'll need to have the ph_eval_at values for PlaceHolderVars */
1224 Assert(root->placeholdersFrozen);
1225
1226 /*
1227 * Examine all baserels (the rel array has been set up by now).
1228 */
1229 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1230 {
1231 RelOptInfo *brel = root->simple_rel_array[rti];
1232 Relids lateral_relids;
1233
1234 /* there may be empty slots corresponding to non-baserel RTEs */
1235 if (brel == NULL)
1236 continue;
1237
1238 Assert(brel->relid == rti); /* sanity check on array */
1239
1240 /* ignore RTEs that are "other rels" */
1241 if (brel->reloptkind != RELOPT_BASEREL)
1242 continue;
1243
1244 lateral_relids = NULL;
1245
1246 /* consider each laterally-referenced Var or PHV */
1247 foreach(lc, brel->lateral_vars)
1248 {
1249 Node *node = (Node *) lfirst(lc);
1250
1251 if (IsA(node, Var))
1252 {
1253 Var *var = (Var *) node;
1254
1255 found_laterals = true;
1256 lateral_relids = bms_add_member(lateral_relids,
1257 var->varno);
1258 }
1259 else if (IsA(node, PlaceHolderVar))
1260 {
1261 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1263
1264 found_laterals = true;
1265 lateral_relids = bms_add_members(lateral_relids,
1266 phinfo->ph_eval_at);
1267 }
1268 else
1269 Assert(false);
1270 }
1271
1272 /* We now have all the simple lateral refs from this rel */
1273 brel->direct_lateral_relids = lateral_relids;
1274 brel->lateral_relids = bms_copy(lateral_relids);
1275 }
1276
1277 /*
1278 * Now check for lateral references within PlaceHolderVars, and mark their
1279 * eval_at rels as having lateral references to the source rels.
1280 *
1281 * For a PHV that is due to be evaluated at a baserel, mark its source(s)
1282 * as direct lateral dependencies of the baserel (adding onto the ones
1283 * recorded above). If it's due to be evaluated at a join, mark its
1284 * source(s) as indirect lateral dependencies of each baserel in the join,
1285 * ie put them into lateral_relids but not direct_lateral_relids. This is
1286 * appropriate because we can't put any such baserel on the outside of a
1287 * join to one of the PHV's lateral dependencies, but on the other hand we
1288 * also can't yet join it directly to the dependency.
1289 */
1290 foreach(lc, root->placeholder_list)
1291 {
1293 Relids eval_at = phinfo->ph_eval_at;
1295 int varno;
1296
1297 if (phinfo->ph_lateral == NULL)
1298 continue; /* PHV is uninteresting if no lateral refs */
1299
1300 found_laterals = true;
1301
1302 /*
1303 * Include only baserels not outer joins in the evaluation sites'
1304 * lateral relids. This avoids problems when outer join order gets
1305 * rearranged, and it should still ensure that the lateral values are
1306 * available when needed.
1307 */
1308 lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels);
1310
1311 if (bms_get_singleton_member(eval_at, &varno))
1312 {
1313 /* Evaluation site is a baserel */
1314 RelOptInfo *brel = find_base_rel(root, varno);
1315
1316 brel->direct_lateral_relids =
1317 bms_add_members(brel->direct_lateral_relids,
1318 lateral_refs);
1319 brel->lateral_relids =
1320 bms_add_members(brel->lateral_relids,
1321 lateral_refs);
1322 }
1323 else
1324 {
1325 /* Evaluation site is a join */
1326 varno = -1;
1327 while ((varno = bms_next_member(eval_at, varno)) >= 0)
1328 {
1330
1331 if (brel == NULL)
1332 continue; /* ignore outer joins in eval_at */
1333 brel->lateral_relids = bms_add_members(brel->lateral_relids,
1334 lateral_refs);
1335 }
1336 }
1337 }
1338
1339 /*
1340 * If we found no actual lateral references, we're done; but reset the
1341 * hasLateralRTEs flag to avoid useless work later.
1342 */
1343 if (!found_laterals)
1344 {
1345 root->hasLateralRTEs = false;
1346 return;
1347 }
1348
1349 /*
1350 * Calculate the transitive closure of the lateral_relids sets, so that
1351 * they describe both direct and indirect lateral references. If relation
1352 * X references Y laterally, and Y references Z laterally, then we will
1353 * have to scan X on the inside of a nestloop with Z, so for all intents
1354 * and purposes X is laterally dependent on Z too.
1355 *
1356 * This code is essentially Warshall's algorithm for transitive closure.
1357 * The outer loop considers each baserel, and propagates its lateral
1358 * dependencies to those baserels that have a lateral dependency on it.
1359 */
1360 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1361 {
1362 RelOptInfo *brel = root->simple_rel_array[rti];
1364 Index rti2;
1365
1366 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
1367 continue;
1368
1369 /* need not consider baserel further if it has no lateral refs */
1370 outer_lateral_relids = brel->lateral_relids;
1372 continue;
1373
1374 /* else scan all baserels */
1375 for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
1376 {
1377 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1378
1379 if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
1380 continue;
1381
1382 /* if brel2 has lateral ref to brel, propagate brel's refs */
1383 if (bms_is_member(rti, brel2->lateral_relids))
1384 brel2->lateral_relids = bms_add_members(brel2->lateral_relids,
1386 }
1387 }
1388
1389 /*
1390 * Now that we've identified all lateral references, mark each baserel
1391 * with the set of relids of rels that reference it laterally (possibly
1392 * indirectly) --- that is, the inverse mapping of lateral_relids.
1393 */
1394 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1395 {
1396 RelOptInfo *brel = root->simple_rel_array[rti];
1397 Relids lateral_relids;
1398 int rti2;
1399
1400 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
1401 continue;
1402
1403 /* Nothing to do at rels with no lateral refs */
1404 lateral_relids = brel->lateral_relids;
1405 if (bms_is_empty(lateral_relids))
1406 continue;
1407
1408 /* No rel should have a lateral dependency on itself */
1409 Assert(!bms_is_member(rti, lateral_relids));
1410
1411 /* Mark this rel's referencees */
1412 rti2 = -1;
1413 while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
1414 {
1415 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1416
1417 if (brel2 == NULL)
1418 continue; /* must be an OJ */
1419
1420 Assert(brel2->reloptkind == RELOPT_BASEREL);
1421 brel2->lateral_referencers =
1422 bms_add_member(brel2->lateral_referencers, rti);
1423 }
1424 }
1425}
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:1290
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition bitmapset.c:708
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122
unsigned int Index
Definition c.h:700
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition relnode.c:584
Relids lateral_relids
Definition pathnodes.h:1052

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(), fb(), find_base_rel(), find_base_rel_ignore_join(), find_placeholder_info(), IsA, RelOptInfo::lateral_relids, lfirst, RELOPT_BASEREL, root, and Var::varno.

Referenced by query_planner().

◆ deconstruct_distribute()

static void deconstruct_distribute ( PlannerInfo root,
JoinTreeItem jtitem 
)
static

Definition at line 1832 of file initsplan.c.

1833{
1834 Node *jtnode = jtitem->jtnode;
1835
1836 if (IsA(jtnode, RangeTblRef))
1837 {
1838 int varno = ((RangeTblRef *) jtnode)->rtindex;
1839
1840 /* Deal with any securityQuals attached to the RTE */
1841 if (root->qual_security_level > 0)
1843 varno,
1844 jtitem);
1845 }
1846 else if (IsA(jtnode, FromExpr))
1847 {
1848 FromExpr *f = (FromExpr *) jtnode;
1849
1850 /*
1851 * Process any lateral-referencing quals that were postponed to this
1852 * level by children.
1853 */
1854 distribute_quals_to_rels(root, jtitem->lateral_clauses,
1855 jtitem,
1856 NULL,
1857 root->qual_security_level,
1858 jtitem->qualscope,
1859 NULL, NULL, NULL,
1860 true, false, false,
1861 NULL);
1862
1863 /*
1864 * Now process the top-level quals.
1865 */
1867 jtitem,
1868 NULL,
1869 root->qual_security_level,
1870 jtitem->qualscope,
1871 NULL, NULL, NULL,
1872 true, false, false,
1873 NULL);
1874 }
1875 else if (IsA(jtnode, JoinExpr))
1876 {
1877 JoinExpr *j = (JoinExpr *) jtnode;
1879 List *my_quals;
1880 SpecialJoinInfo *sjinfo;
1882
1883 /*
1884 * Include lateral-referencing quals postponed from children in
1885 * my_quals, so that they'll be handled properly in
1886 * make_outerjoininfo. (This is destructive to
1887 * jtitem->lateral_clauses, but we won't use that again.)
1888 */
1889 my_quals = list_concat(jtitem->lateral_clauses,
1890 (List *) j->quals);
1891
1892 /*
1893 * For an OJ, form the SpecialJoinInfo now, so that we can pass it to
1894 * distribute_qual_to_rels. We must compute its ojscope too.
1895 *
1896 * Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we
1897 * want ojscope = NULL for distribute_qual_to_rels.
1898 */
1899 if (j->jointype != JOIN_INNER)
1900 {
1901 sjinfo = make_outerjoininfo(root,
1902 jtitem->left_rels,
1903 jtitem->right_rels,
1904 jtitem->inner_join_rels,
1905 j->jointype,
1906 j->rtindex,
1907 my_quals);
1908 jtitem->sjinfo = sjinfo;
1909 if (j->jointype == JOIN_SEMI)
1910 ojscope = NULL;
1911 else
1912 ojscope = bms_union(sjinfo->min_lefthand,
1913 sjinfo->min_righthand);
1914 }
1915 else
1916 {
1917 sjinfo = NULL;
1918 ojscope = NULL;
1919 }
1920
1921 /*
1922 * If it's a left join with a join clause that is strict for the LHS,
1923 * then we need to postpone handling of any non-degenerate join
1924 * clauses, in case the join is able to commute with another left join
1925 * per identity 3. (Degenerate clauses need not be postponed, since
1926 * they will drop down below this join anyway.)
1927 */
1928 if (j->jointype == JOIN_LEFT && sjinfo->lhs_strict)
1929 {
1930 postponed_oj_qual_list = &jtitem->oj_joinclauses;
1931
1932 /*
1933 * Add back any commutable lower OJ relids that were removed from
1934 * min_lefthand or min_righthand, else the ojscope cross-check in
1935 * distribute_qual_to_rels will complain. Since we are postponing
1936 * processing of non-degenerate clauses, this addition doesn't
1937 * affect anything except that cross-check. Real clause
1938 * positioning decisions will be made later, when we revisit the
1939 * postponed clauses.
1940 */
1943 }
1944 else
1946
1947 /* Process the JOIN's qual clauses */
1949 jtitem,
1950 sjinfo,
1951 root->qual_security_level,
1952 jtitem->qualscope,
1953 ojscope, jtitem->nonnullable_rels,
1954 NULL, /* incompatible_relids */
1955 true, /* allow_equivalence */
1956 false, false, /* not clones */
1958
1959 /* And add the SpecialJoinInfo to join_info_list */
1960 if (sjinfo)
1961 root->join_info_list = lappend(root->join_info_list, sjinfo);
1962 }
1963 else
1964 {
1965 elog(ERROR, "unrecognized node type: %d",
1966 (int) nodeTag(jtnode));
1967 }
1968}
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:2835
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:2076
static void process_security_barrier_quals(PlannerInfo *root, int rti, JoinTreeItem *jtitem)
Definition initsplan.c:1984
@ JOIN_INNER
Definition nodes.h:303
@ JOIN_LEFT
Definition nodes.h:304
Node * quals
Definition primnodes.h:2384
Relids min_righthand
Definition pathnodes.h:3214
Relids commute_below_l
Definition pathnodes.h:3221
Relids min_lefthand
Definition pathnodes.h:3213
Relids commute_below_r
Definition pathnodes.h:3222

References bms_add_members(), bms_union(), SpecialJoinInfo::commute_below_l, SpecialJoinInfo::commute_below_r, distribute_quals_to_rels(), elog, ERROR, fb(), IsA, j, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, JoinTreeItem::jtnode, lappend(), SpecialJoinInfo::lhs_strict, list_concat(), make_outerjoininfo(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, nodeTag, process_security_barrier_quals(), FromExpr::quals, 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 2594 of file initsplan.c.

2597{
2598 SpecialJoinInfo *sjinfo = jtitem->sjinfo;
2599 Relids qualscope,
2600 ojscope,
2601 nonnullable_rels;
2602
2603 /* Recompute syntactic and semantic scopes of this left join */
2604 qualscope = bms_union(sjinfo->syn_lefthand, sjinfo->syn_righthand);
2605 qualscope = bms_add_member(qualscope, sjinfo->ojrelid);
2606 ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
2607 nonnullable_rels = sjinfo->syn_lefthand;
2608
2609 /*
2610 * If this join can commute with any other ones per outer-join identity 3,
2611 * and it is the one providing the join clause with flexible semantics,
2612 * then we have to generate variants of the join clause with different
2613 * nullingrels labeling. Otherwise, just push out the postponed clause
2614 * as-is.
2615 */
2616 Assert(sjinfo->lhs_strict); /* else we shouldn't be here */
2617 if (sjinfo->commute_above_r || sjinfo->commute_below_l)
2618 {
2623 List *quals;
2625 ListCell *lc;
2626
2627 /* Identify the outer joins this one commutes with */
2628 joins_above = sjinfo->commute_above_r;
2629 joins_below = sjinfo->commute_below_l;
2630
2631 /*
2632 * Generate qual variants with different sets of nullingrels bits.
2633 *
2634 * We only need bit-sets that correspond to the successively less
2635 * deeply syntactically-nested subsets of this join and its
2636 * commutators. That's true first because obviously only those forms
2637 * of the Vars and PHVs could appear elsewhere in the query, and
2638 * second because the outer join identities do not provide a way to
2639 * re-order such joins in a way that would require different marking.
2640 * (That is, while the current join may commute with several others,
2641 * none of those others can commute with each other.) To visit the
2642 * interesting joins in syntactic nesting order, we rely on the
2643 * jtitems list to be ordered that way.
2644 *
2645 * We first strip out all the nullingrels bits corresponding to
2646 * commuting joins below this one, and then successively put them back
2647 * as we crawl up the join stack.
2648 */
2649 quals = jtitem->oj_joinclauses;
2651 quals = (List *) remove_nulling_relids((Node *) quals,
2653 NULL);
2654
2655 /*
2656 * We'll need to mark the lower versions of the quals as not safe to
2657 * apply above not-yet-processed joins of the stack. This prevents
2658 * possibly applying a cloned qual at the wrong join level.
2659 */
2662 sjinfo->ojrelid);
2663
2664 /*
2665 * Each time we produce RestrictInfo(s) from these quals, reset the
2666 * last_rinfo_serial counter, so that the RestrictInfos for the "same"
2667 * qual condition get identical serial numbers. (This relies on the
2668 * fact that we're not changing the qual list in any way that'd affect
2669 * the number of RestrictInfos built from it.) This'll allow us to
2670 * detect duplicative qual usage later.
2671 */
2672 save_last_rinfo_serial = root->last_rinfo_serial;
2673
2675 foreach(lc, jtitems)
2676 {
2679 bool below_sjinfo = false;
2680 bool above_sjinfo = false;
2683 bool allow_equivalence,
2684 has_clone,
2685 is_clone;
2686
2687 if (othersj == NULL)
2688 continue; /* not an outer-join item, ignore */
2689
2690 if (bms_is_member(othersj->ojrelid, joins_below))
2691 {
2692 /* othersj commutes with sjinfo from below left */
2693 below_sjinfo = true;
2694 }
2695 else if (othersj == sjinfo)
2696 {
2697 /* found our join in syntactic order */
2699 }
2700 else if (bms_is_member(othersj->ojrelid, joins_above))
2701 {
2702 /* othersj commutes with sjinfo from above */
2703 above_sjinfo = true;
2704 }
2705 else
2706 {
2707 /* othersj is not relevant, ignore */
2708 continue;
2709 }
2710
2711 /* Reset serial counter for this version of the quals */
2712 root->last_rinfo_serial = save_last_rinfo_serial;
2713
2714 /*
2715 * When we are looking at joins above sjinfo, we are envisioning
2716 * pushing sjinfo to above othersj, so add othersj's nulling bit
2717 * before distributing the quals. We should add it to Vars coming
2718 * from the current join's LHS: we want to transform the second
2719 * form of OJ identity 3 to the first form, in which Vars of
2720 * relation B will appear nulled by the syntactically-upper OJ
2721 * within the Pbc clause, but those of relation C will not. (In
2722 * the notation used by optimizer/README, we're converting a qual
2723 * of the form Pbc to Pb*c.) Of course, we must also remove that
2724 * bit from the incompatible_joins value, else we'll make a qual
2725 * that can't be placed anywhere.
2726 */
2727 if (above_sjinfo)
2728 {
2729 quals = (List *)
2730 add_nulling_relids((Node *) quals,
2731 sjinfo->syn_lefthand,
2732 bms_make_singleton(othersj->ojrelid));
2734 othersj->ojrelid);
2735 }
2736
2737 /* Compute qualscope and ojscope for this join level */
2740 if (above_sjinfo)
2741 {
2742 /* othersj is not yet in joins_so_far, but we need it */
2744 othersj->ojrelid);
2746 othersj->ojrelid);
2747 /* sjinfo is in joins_so_far, and we don't want it */
2749 sjinfo->ojrelid);
2750 }
2751
2752 /*
2753 * We generate EquivalenceClasses only from the first form of the
2754 * quals, with the fewest nullingrels bits set. An EC made from
2755 * this version of the quals can be useful below the outer-join
2756 * nest, whereas versions with some nullingrels bits set would not
2757 * be. We cannot generate ECs from more than one version, or
2758 * we'll make nonsensical conclusions that Vars with nullingrels
2759 * bits set are equal to their versions without. Fortunately,
2760 * such ECs wouldn't be very useful anyway, because they'd equate
2761 * values not observable outside the join nest. (See
2762 * optimizer/README.)
2763 *
2764 * The first form of the quals is also the only one marked as
2765 * has_clone rather than is_clone.
2766 */
2768 has_clone = allow_equivalence;
2769 is_clone = !has_clone;
2770
2773 sjinfo,
2774 root->qual_security_level,
2776 this_ojscope, nonnullable_rels,
2779 has_clone,
2780 is_clone,
2781 NULL); /* no more postponement */
2782
2783 /*
2784 * Adjust qual nulling bits for next level up, if needed. We
2785 * don't want to put sjinfo's own bit in at all, and if we're
2786 * above sjinfo then we did it already. Here, we should mark all
2787 * Vars coming from the lower join's RHS. (Again, we are
2788 * converting a qual of the form Pbc to Pb*c, but now we are
2789 * putting back bits that were there in the parser output and were
2790 * temporarily stripped above.) Update incompatible_joins too.
2791 */
2792 if (below_sjinfo)
2793 {
2794 quals = (List *)
2795 add_nulling_relids((Node *) quals,
2796 othersj->syn_righthand,
2797 bms_make_singleton(othersj->ojrelid));
2799 othersj->ojrelid);
2800 }
2801
2802 /* ... and track joins processed so far */
2804 }
2805 }
2806 else
2807 {
2808 /* No commutation possible, just process the postponed clauses */
2809 distribute_quals_to_rels(root, jtitem->oj_joinclauses,
2810 jtitem,
2811 sjinfo,
2812 root->qual_security_level,
2813 qualscope,
2814 ojscope, nonnullable_rels,
2815 NULL, /* incompatible_relids */
2816 true, /* allow_equivalence */
2817 false, false, /* not clones */
2818 NULL); /* no more postponement */
2819 }
2820}
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:142
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition bitmapset.c:852
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:3220
Relids syn_lefthand
Definition pathnodes.h:3215

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(), fb(), lfirst, SpecialJoinInfo::lhs_strict, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, JoinTreeItem::nonnullable_rels, 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 1452 of file initsplan.c.

1453{
1454 List *result;
1456 List *item_list = NIL;
1457 ListCell *lc;
1458
1459 /*
1460 * After this point, no more PlaceHolderInfos may be made, because
1461 * make_outerjoininfo requires all active placeholders to be present in
1462 * root->placeholder_list while we crawl up the join tree.
1463 */
1464 root->placeholdersFrozen = true;
1465
1466 /* Fetch the already-created top-level join domain for the query */
1467 top_jdomain = linitial_node(JoinDomain, root->join_domains);
1468 top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
1469
1470 /* Start recursion at top of jointree */
1471 Assert(root->parse->jointree != NULL &&
1472 IsA(root->parse->jointree, FromExpr));
1473
1474 /* These are filled as we scan the jointree */
1475 root->all_baserels = NULL;
1476 root->outer_join_rels = NULL;
1477
1478 /* Perform the initial scan of the jointree */
1479 result = deconstruct_recurse(root, (Node *) root->parse->jointree,
1481 &item_list);
1482
1483 /* Now we can form the value of all_query_rels, too */
1484 root->all_query_rels = bms_union(root->all_baserels, root->outer_join_rels);
1485
1486 /* ... which should match what we computed for the top join domain */
1487 Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
1488
1489 /* Now scan all the jointree nodes again, and distribute quals */
1490 foreach(lc, item_list)
1491 {
1493
1495 }
1496
1497 /*
1498 * If there were any special joins then we may have some postponed LEFT
1499 * JOIN clauses to deal with.
1500 */
1501 if (root->join_info_list)
1502 {
1503 foreach(lc, item_list)
1504 {
1506
1507 if (jtitem->oj_joinclauses != NIL)
1509 }
1510 }
1511
1512 /* Don't need the JoinTreeItems any more */
1514
1515 return result;
1516}
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, JoinTreeItem *parent_jtitem, List **item_list)
Definition initsplan.c:1534
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition initsplan.c:2594
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition initsplan.c:1832
#define linitial_node(type, l)
Definition pg_list.h:181

References Assert, bms_equal(), bms_union(), deconstruct_distribute(), deconstruct_distribute_oj_quals(), deconstruct_recurse(), fb(), IsA, lfirst, linitial_node, list_free_deep(), NIL, 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 1534 of file initsplan.c.

1538{
1539 List *joinlist;
1541
1542 Assert(jtnode != NULL);
1543
1544 /* Make the new JoinTreeItem, but don't add it to item_list yet */
1546 jtitem->jtnode = jtnode;
1547 jtitem->jti_parent = parent_jtitem;
1548
1549 if (IsA(jtnode, RangeTblRef))
1550 {
1551 int varno = ((RangeTblRef *) jtnode)->rtindex;
1552
1553 /* Fill all_baserels as we encounter baserel jointree nodes */
1554 root->all_baserels = bms_add_member(root->all_baserels, varno);
1555 /* This node belongs to parent_domain */
1556 jtitem->jdomain = parent_domain;
1557 parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
1558 varno);
1559 /* qualscope is just the one RTE */
1560 jtitem->qualscope = bms_make_singleton(varno);
1561 /* A single baserel does not create an inner join */
1562 jtitem->inner_join_rels = NULL;
1563 joinlist = list_make1(jtnode);
1564 }
1565 else if (IsA(jtnode, FromExpr))
1566 {
1567 FromExpr *f = (FromExpr *) jtnode;
1568 int remaining;
1569 ListCell *l;
1570
1571 /* This node belongs to parent_domain, as do its children */
1572 jtitem->jdomain = parent_domain;
1573
1574 /*
1575 * Recurse to handle child nodes, and compute output joinlist. We
1576 * collapse subproblems into a single joinlist whenever the resulting
1577 * joinlist wouldn't exceed from_collapse_limit members. Also, always
1578 * collapse one-element subproblems, since that won't lengthen the
1579 * joinlist anyway.
1580 */
1581 jtitem->qualscope = NULL;
1582 jtitem->inner_join_rels = NULL;
1583 joinlist = NIL;
1585 foreach(l, f->fromlist)
1586 {
1589 int sub_members;
1590
1593 jtitem,
1594 item_list);
1596 jtitem->qualscope = bms_add_members(jtitem->qualscope,
1597 sub_item->qualscope);
1598 jtitem->inner_join_rels = sub_item->inner_join_rels;
1600 remaining--;
1601 if (sub_members <= 1 ||
1604 else
1606 }
1607
1608 /*
1609 * A FROM with more than one list element is an inner join subsuming
1610 * all below it, so we should report inner_join_rels = qualscope. If
1611 * there was exactly one element, we should (and already did) report
1612 * whatever its inner_join_rels were. If there were no elements (is
1613 * that still possible?) the initialization before the loop fixed it.
1614 */
1615 if (list_length(f->fromlist) > 1)
1616 jtitem->inner_join_rels = jtitem->qualscope;
1617 }
1618 else if (IsA(jtnode, JoinExpr))
1619 {
1620 JoinExpr *j = (JoinExpr *) jtnode;
1622 *fj_domain;
1624 *right_item;
1627
1628 switch (j->jointype)
1629 {
1630 case JOIN_INNER:
1631 /* This node belongs to parent_domain, as do its children */
1632 jtitem->jdomain = parent_domain;
1633 /* Recurse */
1636 jtitem,
1637 item_list);
1641 jtitem,
1642 item_list);
1644 /* Compute qualscope etc */
1645 jtitem->qualscope = bms_union(left_item->qualscope,
1646 right_item->qualscope);
1647 jtitem->inner_join_rels = jtitem->qualscope;
1648 jtitem->left_rels = left_item->qualscope;
1649 jtitem->right_rels = right_item->qualscope;
1650 /* Inner join adds no restrictions for quals */
1651 jtitem->nonnullable_rels = NULL;
1652 break;
1653 case JOIN_LEFT:
1654 case JOIN_ANTI:
1655 /* Make new join domain for my quals and the RHS */
1657 child_domain->jd_relids = NULL; /* filled by recursion */
1658 root->join_domains = lappend(root->join_domains, child_domain);
1659 jtitem->jdomain = child_domain;
1660 /* Recurse */
1663 jtitem,
1664 item_list);
1668 jtitem,
1669 item_list);
1671 /* Compute join domain contents, qualscope etc */
1672 parent_domain->jd_relids =
1673 bms_add_members(parent_domain->jd_relids,
1674 child_domain->jd_relids);
1675 jtitem->qualscope = bms_union(left_item->qualscope,
1676 right_item->qualscope);
1677 /* caution: ANTI join derived from SEMI will lack rtindex */
1678 if (j->rtindex != 0)
1679 {
1680 parent_domain->jd_relids =
1681 bms_add_member(parent_domain->jd_relids,
1682 j->rtindex);
1683 jtitem->qualscope = bms_add_member(jtitem->qualscope,
1684 j->rtindex);
1685 root->outer_join_rels = bms_add_member(root->outer_join_rels,
1686 j->rtindex);
1688 right_item->qualscope);
1689 }
1690 jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1691 right_item->inner_join_rels);
1692 jtitem->left_rels = left_item->qualscope;
1693 jtitem->right_rels = right_item->qualscope;
1694 jtitem->nonnullable_rels = left_item->qualscope;
1695 break;
1696 case JOIN_SEMI:
1697 /* This node belongs to parent_domain, as do its children */
1698 jtitem->jdomain = parent_domain;
1699 /* Recurse */
1702 jtitem,
1703 item_list);
1707 jtitem,
1708 item_list);
1710 /* Compute qualscope etc */
1711 jtitem->qualscope = bms_union(left_item->qualscope,
1712 right_item->qualscope);
1713 /* SEMI join never has rtindex, so don't add to anything */
1714 Assert(j->rtindex == 0);
1715 jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1716 right_item->inner_join_rels);
1717 jtitem->left_rels = left_item->qualscope;
1718 jtitem->right_rels = right_item->qualscope;
1719 /* Semi join adds no restrictions for quals */
1720 jtitem->nonnullable_rels = NULL;
1721 break;
1722 case JOIN_FULL:
1723 /* The FULL JOIN's quals need their very own domain */
1725 root->join_domains = lappend(root->join_domains, fj_domain);
1726 jtitem->jdomain = fj_domain;
1727 /* Recurse, giving each side its own join domain */
1729 child_domain->jd_relids = NULL; /* filled by recursion */
1730 root->join_domains = lappend(root->join_domains, child_domain);
1733 jtitem,
1734 item_list);
1736 fj_domain->jd_relids = bms_copy(child_domain->jd_relids);
1738 child_domain->jd_relids = NULL; /* filled by recursion */
1739 root->join_domains = lappend(root->join_domains, child_domain);
1742 jtitem,
1743 item_list);
1745 /* Compute qualscope etc */
1746 fj_domain->jd_relids = bms_add_members(fj_domain->jd_relids,
1747 child_domain->jd_relids);
1748 parent_domain->jd_relids = bms_add_members(parent_domain->jd_relids,
1749 fj_domain->jd_relids);
1750 jtitem->qualscope = bms_union(left_item->qualscope,
1751 right_item->qualscope);
1752 Assert(j->rtindex != 0);
1753 parent_domain->jd_relids = bms_add_member(parent_domain->jd_relids,
1754 j->rtindex);
1755 jtitem->qualscope = bms_add_member(jtitem->qualscope,
1756 j->rtindex);
1757 root->outer_join_rels = bms_add_member(root->outer_join_rels,
1758 j->rtindex);
1760 left_item->qualscope);
1762 right_item->qualscope);
1763 jtitem->inner_join_rels = bms_union(left_item->inner_join_rels,
1764 right_item->inner_join_rels);
1765 jtitem->left_rels = left_item->qualscope;
1766 jtitem->right_rels = right_item->qualscope;
1767 /* each side is both outer and inner */
1768 jtitem->nonnullable_rels = jtitem->qualscope;
1769 break;
1770 default:
1771 /* JOIN_RIGHT was eliminated during reduce_outer_joins() */
1772 elog(ERROR, "unrecognized join type: %d",
1773 (int) j->jointype);
1774 leftjoinlist = rightjoinlist = NIL; /* keep compiler quiet */
1775 break;
1776 }
1777
1778 /*
1779 * Compute the output joinlist. We fold subproblems together except
1780 * at a FULL JOIN or where join_collapse_limit would be exceeded.
1781 */
1782 if (j->jointype == JOIN_FULL)
1783 {
1784 /* force the join order exactly at this node */
1786 }
1789 {
1790 /* OK to combine subproblems */
1792 }
1793 else
1794 {
1795 /* can't combine, but needn't force join order above here */
1796 Node *leftpart,
1797 *rightpart;
1798
1799 /* avoid creating useless 1-element sublists */
1800 if (list_length(leftjoinlist) == 1)
1802 else
1804 if (list_length(rightjoinlist) == 1)
1806 else
1809 }
1810 }
1811 else
1812 {
1813 elog(ERROR, "unrecognized node type: %d",
1814 (int) nodeTag(jtnode));
1815 joinlist = NIL; /* keep compiler quiet */
1816 }
1817
1818 /* Finally, we can add the new JoinTreeItem to item_list */
1820
1821 return joinlist;
1822}
#define palloc0_object(type)
Definition fe_memutils.h:75
int remaining
Definition informix.c:692
int join_collapse_limit
Definition initsplan.c:42
int from_collapse_limit
Definition initsplan.c:41
static void mark_rels_nulled_by_join(PlannerInfo *root, Index ojrelid, Relids lower_rels)
Definition initsplan.c:2034
@ JOIN_FULL
Definition nodes.h:305
#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

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_make_singleton(), bms_union(), deconstruct_recurse(), elog, ERROR, fb(), from_collapse_limit, FromExpr::fromlist, IsA, j, JOIN_ANTI, join_collapse_limit, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, JoinTreeItem::jtnode, lappend(), lfirst, linitial, list_concat(), list_length(), list_make1, list_make2, llast, makeNode, mark_rels_nulled_by_join(), NIL, nodeTag, palloc0_object, remaining, 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 2913 of file initsplan.c.

2925{
2926 Relids relids;
2927 bool is_pushed_down;
2928 bool pseudoconstant = false;
2929 bool maybe_equivalence;
2930 bool maybe_outer_join;
2932
2933 /*
2934 * Retrieve all relids mentioned within the clause.
2935 */
2936 relids = pull_varnos(root, clause);
2937
2938 /*
2939 * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels
2940 * that aren't within its syntactic scope; however, if we pulled up a
2941 * LATERAL subquery then we might find such references in quals that have
2942 * been pulled up. We need to treat such quals as belonging to the join
2943 * level that includes every rel they reference. Although we could make
2944 * pull_up_subqueries() place such quals correctly to begin with, it's
2945 * easier to handle it here. When we find a clause that contains Vars
2946 * outside its syntactic scope, locate the nearest parent join level that
2947 * includes all the required rels and add the clause to that level's
2948 * lateral_clauses list. We'll process it when we reach that join level.
2949 */
2950 if (!bms_is_subset(relids, qualscope))
2951 {
2953
2954 Assert(root->hasLateralRTEs); /* shouldn't happen otherwise */
2955 Assert(sjinfo == NULL); /* mustn't postpone past outer join */
2956 for (pitem = jtitem->jti_parent; pitem; pitem = pitem->jti_parent)
2957 {
2958 if (bms_is_subset(relids, pitem->qualscope))
2959 {
2960 pitem->lateral_clauses = lappend(pitem->lateral_clauses,
2961 clause);
2962 return;
2963 }
2964
2965 /*
2966 * We should not be postponing any quals past an outer join. If
2967 * this Assert fires, pull_up_subqueries() messed up.
2968 */
2969 Assert(pitem->sjinfo == NULL);
2970 }
2971 elog(ERROR, "failed to postpone qual containing lateral reference");
2972 }
2973
2974 /*
2975 * If it's an outer-join clause, also check that relids is a subset of
2976 * ojscope. (This should not fail if the syntactic scope check passed.)
2977 */
2978 if (ojscope && !bms_is_subset(relids, ojscope))
2979 elog(ERROR, "JOIN qualification cannot refer to other relations");
2980
2981 /*
2982 * If the clause is variable-free, our normal heuristic for pushing it
2983 * down to just the mentioned rels doesn't work, because there are none.
2984 *
2985 * If the clause is an outer-join clause, we must force it to the OJ's
2986 * semantic level to preserve semantics.
2987 *
2988 * Otherwise, when the clause contains volatile functions, we force it to
2989 * be evaluated at its original syntactic level. This preserves the
2990 * expected semantics.
2991 *
2992 * When the clause contains no volatile functions either, it is actually a
2993 * pseudoconstant clause that will not change value during any one
2994 * execution of the plan, and hence can be used as a one-time qual in a
2995 * gating Result plan node. We put such a clause into the regular
2996 * RestrictInfo lists for the moment, but eventually createplan.c will
2997 * pull it out and make a gating Result node immediately above whatever
2998 * plan node the pseudoconstant clause is assigned to. It's usually best
2999 * to put a gating node as high in the plan tree as possible.
3000 */
3001 if (bms_is_empty(relids))
3002 {
3003 if (ojscope)
3004 {
3005 /* clause is attached to outer join, eval it there */
3006 relids = bms_copy(ojscope);
3007 /* mustn't use as gating qual, so don't mark pseudoconstant */
3008 }
3009 else if (contain_volatile_functions(clause))
3010 {
3011 /* eval at original syntactic level */
3012 relids = bms_copy(qualscope);
3013 /* again, can't mark pseudoconstant */
3014 }
3015 else
3016 {
3017 /*
3018 * If we are in the top-level join domain, we can push the qual to
3019 * the top of the plan tree. Otherwise, be conservative and eval
3020 * it at original syntactic level. (Ideally we'd push it to the
3021 * top of the current join domain in all cases, but that causes
3022 * problems if we later rearrange outer-join evaluation order.
3023 * Pseudoconstant quals below the top level are a pretty odd case,
3024 * so it's not clear that it's worth working hard on.)
3025 */
3026 if (jtitem->jdomain == (JoinDomain *) linitial(root->join_domains))
3027 relids = bms_copy(jtitem->jdomain->jd_relids);
3028 else
3029 relids = bms_copy(qualscope);
3030 /* mark as gating qual */
3031 pseudoconstant = true;
3032 /* tell createplan.c to check for gating quals */
3033 root->hasPseudoConstantQuals = true;
3034 }
3035 }
3036
3037 /*----------
3038 * Check to see if clause application must be delayed by outer-join
3039 * considerations.
3040 *
3041 * A word about is_pushed_down: we mark the qual as "pushed down" if
3042 * it is (potentially) applicable at a level different from its original
3043 * syntactic level. This flag is used to distinguish OUTER JOIN ON quals
3044 * from other quals pushed down to the same joinrel. The rules are:
3045 * WHERE quals and INNER JOIN quals: is_pushed_down = true.
3046 * Non-degenerate OUTER JOIN quals: is_pushed_down = false.
3047 * Degenerate OUTER JOIN quals: is_pushed_down = true.
3048 * A "degenerate" OUTER JOIN qual is one that doesn't mention the
3049 * non-nullable side, and hence can be pushed down into the nullable side
3050 * without changing the join result. It is correct to treat it as a
3051 * regular filter condition at the level where it is evaluated.
3052 *
3053 * Note: it is not immediately obvious that a simple boolean is enough
3054 * for this: if for some reason we were to attach a degenerate qual to
3055 * its original join level, it would need to be treated as an outer join
3056 * qual there. However, this cannot happen, because all the rels the
3057 * clause mentions must be in the outer join's min_righthand, therefore
3058 * the join it needs must be formed before the outer join; and we always
3059 * attach quals to the lowest level where they can be evaluated. But
3060 * if we were ever to re-introduce a mechanism for delaying evaluation
3061 * of "expensive" quals, this area would need work.
3062 *
3063 * Note: generally, use of is_pushed_down has to go through the macro
3064 * RINFO_IS_PUSHED_DOWN, because that flag alone is not always sufficient
3065 * to tell whether a clause must be treated as pushed-down in context.
3066 * This seems like another reason why it should perhaps be rethought.
3067 *----------
3068 */
3070 {
3071 /*
3072 * The qual is attached to an outer join and mentions (some of the)
3073 * rels on the nonnullable side, so it's not degenerate. If the
3074 * caller wants to postpone handling such clauses, just add it to
3075 * postponed_oj_qual_list and return. (The work we've done up to here
3076 * will have to be redone later, but there's not much of it.)
3077 */
3079 {
3081 return;
3082 }
3083
3084 /*
3085 * We can't use such a clause to deduce equivalence (the left and
3086 * right sides might be unequal above the join because one of them has
3087 * gone to NULL) ... but we might be able to use it for more limited
3088 * deductions, if it is mergejoinable. So consider adding it to the
3089 * lists of set-aside outer-join clauses.
3090 */
3091 is_pushed_down = false;
3092 maybe_equivalence = false;
3093 maybe_outer_join = true;
3094
3095 /*
3096 * Now force the qual to be evaluated exactly at the level of joining
3097 * corresponding to the outer join. We cannot let it get pushed down
3098 * into the nonnullable side, since then we'd produce no output rows,
3099 * rather than the intended single null-extended row, for any
3100 * nonnullable-side rows failing the qual.
3101 */
3102 Assert(ojscope);
3103 relids = ojscope;
3105 }
3106 else
3107 {
3108 /*
3109 * Normal qual clause or degenerate outer-join clause. Either way, we
3110 * can mark it as pushed-down.
3111 */
3112 is_pushed_down = true;
3113
3114 /*
3115 * It's possible that this is an IS NULL clause that's redundant with
3116 * a lower antijoin; if so we can just discard it. We need not test
3117 * in any of the other cases, because this will only be possible for
3118 * pushed-down clauses.
3119 */
3121 return;
3122
3123 /* Feed qual to the equivalence machinery, if allowed by caller */
3125
3126 /*
3127 * Since it doesn't mention the LHS, it's certainly not useful as a
3128 * set-aside OJ clause, even if it's in an OJ.
3129 */
3130 maybe_outer_join = false;
3131 }
3132
3133 /*
3134 * Build the RestrictInfo node itself.
3135 */
3137 (Expr *) clause,
3138 is_pushed_down,
3139 has_clone,
3140 is_clone,
3142 security_level,
3143 relids,
3144 incompatible_relids,
3146
3147 /*
3148 * If it's a join clause, add vars used in the clause to targetlists of
3149 * their relations, so that they will be emitted by the plan nodes that
3150 * scan those relations (else they won't be available at the join node!).
3151 *
3152 * Normally we mark the vars as needed at the join identified by "relids".
3153 * However, if this is a clone clause then ignore the outer-join relids in
3154 * that set. Otherwise, vars appearing in a cloned clause would end up
3155 * marked as having to propagate to the highest one of the commuting
3156 * joins, which would often be an overestimate. For such clauses, correct
3157 * var propagation is ensured by making ojscope include input rels from
3158 * both sides of the join.
3159 *
3160 * See also rebuild_joinclause_attr_needed, which has to partially repeat
3161 * this work after removal of an outer join.
3162 *
3163 * Note: if the clause gets absorbed into an EquivalenceClass then this
3164 * may be unnecessary, but for now we have to do it to cover the case
3165 * where the EC becomes ec_broken and we end up reinserting the original
3166 * clauses into the plan.
3167 */
3168 if (bms_membership(relids) == BMS_MULTIPLE)
3169 {
3170 List *vars = pull_var_clause(clause,
3175
3176 if (is_clone)
3177 where_needed = bms_intersect(relids, root->all_baserels);
3178 else
3179 where_needed = relids;
3181 list_free(vars);
3182 }
3183
3184 /*
3185 * We check "mergejoinability" of every clause, not only join clauses,
3186 * because we want to know about equivalences between vars of the same
3187 * relation, or between vars and consts.
3188 */
3190
3191 /*
3192 * If it is a true equivalence clause, send it to the EquivalenceClass
3193 * machinery. We do *not* attach it directly to any restriction or join
3194 * lists. The EC code will propagate it to the appropriate places later.
3195 *
3196 * If the clause has a mergejoinable operator, yet isn't an equivalence
3197 * because it is an outer-join clause, the EC code may still be able to do
3198 * something with it. We add it to appropriate lists for further
3199 * consideration later. Specifically:
3200 *
3201 * If it is a left or right outer-join qualification that relates the two
3202 * sides of the outer join (no funny business like leftvar1 = leftvar2 +
3203 * rightvar), we add it to root->left_join_clauses or
3204 * root->right_join_clauses according to which side the nonnullable
3205 * variable appears on.
3206 *
3207 * If it is a full outer-join qualification, we add it to
3208 * root->full_join_clauses. (Ideally we'd discard cases that aren't
3209 * leftvar = rightvar, as we do for left/right joins, but this routine
3210 * doesn't have the info needed to do that; and the current usage of the
3211 * full_join_clauses list doesn't require that, so it's not currently
3212 * worth complicating this routine's API to make it possible.)
3213 *
3214 * If none of the above hold, pass it off to
3215 * distribute_restrictinfo_to_rels().
3216 *
3217 * In all cases, it's important to initialize the left_ec and right_ec
3218 * fields of a mergejoinable clause, so that all possibly mergejoinable
3219 * expressions have representations in EquivalenceClasses. If
3220 * process_equivalence is successful, it will take care of that;
3221 * otherwise, we have to call initialize_mergeclause_eclasses to do it.
3222 */
3223 if (restrictinfo->mergeopfamilies)
3224 {
3226 {
3228 return;
3229 /* EC rejected it, so set left_ec/right_ec the hard way ... */
3230 if (restrictinfo->mergeopfamilies) /* EC might have changed this */
3232 /* ... and fall through to distribute_restrictinfo_to_rels */
3233 }
3234 else if (maybe_outer_join && restrictinfo->can_join)
3235 {
3236 /* we need to set up left_ec/right_ec the hard way */
3238 /* now see if it should go to any outer-join lists */
3239 Assert(sjinfo != NULL);
3240 if (bms_is_subset(restrictinfo->left_relids,
3242 !bms_overlap(restrictinfo->right_relids,
3244 {
3245 /* we have outervar = innervar */
3247
3248 ojcinfo->rinfo = restrictinfo;
3249 ojcinfo->sjinfo = sjinfo;
3250 root->left_join_clauses = lappend(root->left_join_clauses,
3251 ojcinfo);
3252 return;
3253 }
3254 if (bms_is_subset(restrictinfo->right_relids,
3256 !bms_overlap(restrictinfo->left_relids,
3258 {
3259 /* we have innervar = outervar */
3261
3262 ojcinfo->rinfo = restrictinfo;
3263 ojcinfo->sjinfo = sjinfo;
3264 root->right_join_clauses = lappend(root->right_join_clauses,
3265 ojcinfo);
3266 return;
3267 }
3268 if (sjinfo->jointype == JOIN_FULL)
3269 {
3270 /* FULL JOIN (above tests cannot match in this case) */
3272
3273 ojcinfo->rinfo = restrictinfo;
3274 ojcinfo->sjinfo = sjinfo;
3275 root->full_join_clauses = lappend(root->full_join_clauses,
3276 ojcinfo);
3277 return;
3278 }
3279 /* nope, so fall through to distribute_restrictinfo_to_rels */
3280 }
3281 else
3282 {
3283 /* we still need to set up left_ec/right_ec */
3285 }
3286 }
3287
3288 /* No EC special case applies, so push it into the clause lists */
3290}
@ BMS_MULTIPLE
Definition bitmapset.h:73
bool process_equivalence(PlannerInfo *root, RestrictInfo **p_restrictinfo, JoinDomain *jdomain)
Definition equivclass.c:179
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition initsplan.c:3559
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
Definition initsplan.c:3303
void initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition pathkeys.c:1463

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, fb(), initialize_mergeclause_eclasses(), JOIN_FULL, SpecialJoinInfo::jointype, lappend(), linitial, list_free(), make_restrictinfo(), makeNode, process_equivalence(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, JoinTreeItem::qualscope, root, and JoinTreeItem::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 2835 of file initsplan.c.

2847{
2848 ListCell *lc;
2849
2850 foreach(lc, clauses)
2851 {
2852 Node *clause = (Node *) lfirst(lc);
2853
2855 jtitem,
2856 sjinfo,
2857 security_level,
2858 qualscope,
2859 ojscope,
2861 incompatible_relids,
2863 has_clone,
2864 is_clone,
2866 }
2867}
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:2913

References distribute_qual_to_rels(), fb(), 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 3559 of file initsplan.c.

3561{
3562 Relids relids = restrictinfo->required_relids;
3563
3564 if (!bms_is_empty(relids))
3565 {
3566 int relid;
3567
3568 if (bms_get_singleton_member(relids, &relid))
3569 {
3570 /*
3571 * There is only one relation participating in the clause, so it
3572 * is a restriction clause for that relation.
3573 */
3575 }
3576 else
3577 {
3578 /*
3579 * The clause is a join clause, since there is more than one rel
3580 * in its relid set.
3581 */
3582
3583 /*
3584 * Check for hashjoinable operators. (We don't bother setting the
3585 * hashjoin info except in true join clauses.)
3586 */
3588
3589 /*
3590 * Likewise, check if the clause is suitable to be used with a
3591 * Memoize node to cache inner tuples during a parameterized
3592 * nested loop.
3593 */
3595
3596 /*
3597 * Add clause to the join lists of all the relevant relations.
3598 */
3600 }
3601 }
3602 else
3603 {
3604 /*
3605 * clause references no rels, and therefore we have no place to attach
3606 * it. Shouldn't get here if callers are working properly.
3607 */
3608 elog(ERROR, "cannot cope with variable-free clause");
3609 }
3610}
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition initsplan.c:3348
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, fb(), 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().

◆ extract_lateral_references()

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

Definition at line 1074 of file initsplan.c.

1075{
1076 RangeTblEntry *rte = root->simple_rte_array[rtindex];
1077 List *vars;
1078 List *newvars;
1080 ListCell *lc;
1081
1082 /* No cross-references are possible if it's not LATERAL */
1083 if (!rte->lateral)
1084 return;
1085
1086 /* Fetch the appropriate variables */
1087 if (rte->rtekind == RTE_RELATION)
1088 vars = pull_vars_of_level((Node *) rte->tablesample, 0);
1089 else if (rte->rtekind == RTE_SUBQUERY)
1090 vars = pull_vars_of_level((Node *) rte->subquery, 1);
1091 else if (rte->rtekind == RTE_FUNCTION)
1092 vars = pull_vars_of_level((Node *) rte->functions, 0);
1093 else if (rte->rtekind == RTE_TABLEFUNC)
1094 vars = pull_vars_of_level((Node *) rte->tablefunc, 0);
1095 else if (rte->rtekind == RTE_VALUES)
1096 vars = pull_vars_of_level((Node *) rte->values_lists, 0);
1097 else
1098 {
1099 Assert(false);
1100 return; /* keep compiler quiet */
1101 }
1102
1103 if (vars == NIL)
1104 return; /* nothing to do */
1105
1106 /* Copy each Var (or PlaceHolderVar) and adjust it to match our level */
1107 newvars = NIL;
1108 foreach(lc, vars)
1109 {
1110 Node *node = (Node *) lfirst(lc);
1111
1112 node = copyObject(node);
1113 if (IsA(node, Var))
1114 {
1115 Var *var = (Var *) node;
1116
1117 /* Adjustment is easy since it's just one node */
1118 var->varlevelsup = 0;
1119 }
1120 else if (IsA(node, PlaceHolderVar))
1121 {
1122 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1123 int levelsup = phv->phlevelsup;
1124
1125 /* Have to work harder to adjust the contained expression too */
1126 if (levelsup != 0)
1127 IncrementVarSublevelsUp(node, -levelsup, 0);
1128
1129 /*
1130 * If we pulled the PHV out of a subquery RTE, its expression
1131 * needs to be preprocessed. subquery_planner() already did this
1132 * for level-zero PHVs in function and values RTEs, though.
1133 */
1134 if (levelsup > 0)
1135 phv->phexpr = preprocess_phv_expression(root, phv->phexpr);
1136 }
1137 else
1138 Assert(false);
1139 newvars = lappend(newvars, node);
1140 }
1141
1142 list_free(vars);
1143
1144 /*
1145 * We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
1146 * of a cheat: a more formal approach would be to mark each one as needed
1147 * at the join of the LATERAL RTE with its source RTE. But it will work,
1148 * and it's much less tedious than computing a separate where_needed for
1149 * each Var.
1150 */
1152
1153 /*
1154 * Push Vars into their source relations' targetlists, and PHVs into
1155 * root->placeholder_list.
1156 */
1158
1159 /*
1160 * Remember the lateral references for rebuild_lateral_attr_needed and
1161 * create_lateral_join_info.
1162 */
1163 brel->lateral_vars = newvars;
1164}
@ RTE_VALUES
@ RTE_SUBQUERY
@ RTE_FUNCTION
@ RTE_TABLEFUNC
@ RTE_RELATION
Expr * preprocess_phv_expression(PlannerInfo *root, Expr *expr)
Definition planner.c:1481
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Index varlevelsup
Definition primnodes.h:295
List * pull_vars_of_level(Node *node, int levelsup)
Definition var.c:339

References add_vars_to_targetlist(), Assert, bms_make_singleton(), copyObject, fb(), IncrementVarSublevelsUp(), IsA, lappend(), lfirst, list_free(), NIL, preprocess_phv_expression(), pull_vars_of_level(), root, RTE_FUNCTION, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, and Var::varlevelsup.

Referenced by find_lateral_references().

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 1026 of file initsplan.c.

1027{
1028 Index rti;
1029
1030 /* We need do nothing if the query contains no LATERAL RTEs */
1031 if (!root->hasLateralRTEs)
1032 return;
1033
1034 /*
1035 * Examine all baserels (the rel array has been set up by now).
1036 */
1037 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1038 {
1039 RelOptInfo *brel = root->simple_rel_array[rti];
1040
1041 /* there may be empty slots corresponding to non-baserel RTEs */
1042 if (brel == NULL)
1043 continue;
1044
1045 Assert(brel->relid == rti); /* sanity check on array */
1046
1047 /*
1048 * This bit is less obvious than it might look. We ignore appendrel
1049 * otherrels and consider only their parent baserels. In a case where
1050 * a LATERAL-containing UNION ALL subquery was pulled up, it is the
1051 * otherrel that is actually going to be in the plan. However, we
1052 * want to mark all its lateral references as needed by the parent,
1053 * because it is the parent's relid that will be used for join
1054 * planning purposes. And the parent's RTE will contain all the
1055 * lateral references we need to know, since the pulled-up member is
1056 * nothing but a copy of parts of the original RTE's subquery. We
1057 * could visit the parent's children instead and transform their
1058 * references back to the parent's relid, but it would be much more
1059 * complicated for no real gain. (Important here is that the child
1060 * members have not yet received any processing beyond being pulled
1061 * up.) Similarly, in appendrels created by inheritance expansion,
1062 * it's sufficient to look at the parent relation.
1063 */
1064
1065 /* ignore RTEs that are "other rels" */
1066 if (brel->reloptkind != RELOPT_BASEREL)
1067 continue;
1068
1070 }
1071}
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition initsplan.c:1074

References Assert, extract_lateral_references(), fb(), RELOPT_BASEREL, and root.

Referenced by query_planner().

◆ get_eclass_for_sortgroupclause()

static EquivalenceClass * get_eclass_for_sortgroupclause ( PlannerInfo root,
SortGroupClause sgc,
Expr expr 
)
static

Definition at line 952 of file initsplan.c.

954{
955 Oid opfamily,
956 opcintype,
957 collation;
958 CompareType cmptype;
961
962 /* Punt if the group clause is not sortable */
963 if (!OidIsValid(sgc->sortop))
964 return NULL;
965
966 /* Find the operator in pg_amop --- failure shouldn't happen */
967 if (!get_ordering_op_properties(sgc->sortop,
968 &opfamily, &opcintype, &cmptype))
969 elog(ERROR, "operator %u is not a valid ordering operator",
970 sgc->sortop);
971
972 /* Because SortGroupClause doesn't carry collation, consult the expr */
973 collation = exprCollation((Node *) expr);
974
975 /*
976 * EquivalenceClasses need to contain opfamily lists based on the family
977 * membership of mergejoinable equality operators, which could belong to
978 * more than one opfamily. So we have to look up the opfamily's equality
979 * operator and get its membership.
980 */
982 opcintype,
983 opcintype,
984 COMPARE_EQ);
985 if (!OidIsValid(equality_op)) /* shouldn't happen */
986 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
987 COMPARE_EQ, opcintype, opcintype, opfamily);
989 if (!opfamilies) /* certainly should find some */
990 elog(ERROR, "could not find opfamilies for equality operator %u",
992
993 /* Now find a matching EquivalenceClass */
994 return get_eclass_for_sort_expr(root, expr, opfamilies, opcintype,
995 collation, sgc->tleSortGroupRef,
996 NULL, false);
997}
CompareType
Definition cmptype.h:32
@ COMPARE_EQ
Definition cmptype.h:36
EquivalenceClass * get_eclass_for_sort_expr(PlannerInfo *root, Expr *expr, List *opfamilies, Oid opcintype, Oid collation, Index sortref, Relids rel, bool create_it)
Definition equivclass.c:736
bool get_ordering_op_properties(Oid opno, Oid *opfamily, Oid *opcintype, CompareType *cmptype)
Definition lsyscache.c:261
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:199
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826

References COMPARE_EQ, elog, ERROR, exprCollation(), fb(), get_eclass_for_sort_expr(), get_mergejoin_opfamilies(), get_opfamily_member_for_cmptype(), get_ordering_op_properties(), OidIsValid, and root.

Referenced by create_grouping_expr_infos().

◆ get_join_domain_min_rels()

static Relids get_join_domain_min_rels ( PlannerInfo root,
Relids  domain_relids 
)
static

Definition at line 3857 of file initsplan.c.

3858{
3859 Relids result = bms_copy(domain_relids);
3860 ListCell *lc;
3861
3862 /* Top-level join domain? */
3863 if (bms_equal(result, root->all_query_rels))
3864 return result;
3865
3866 /* Nope, look for lower outer joins that could potentially commute out */
3867 foreach(lc, root->join_info_list)
3868 {
3870
3871 if (sjinfo->jointype == JOIN_LEFT &&
3872 bms_is_member(sjinfo->ojrelid, result))
3873 {
3874 result = bms_del_member(result, sjinfo->ojrelid);
3875 result = bms_del_members(result, sjinfo->syn_righthand);
3876 }
3877 }
3878 return result;
3879}
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1145

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

Referenced by process_implied_equality().

◆ is_partial_agg_memory_risky()

static bool is_partial_agg_memory_risky ( PlannerInfo root)
static

Definition at line 730 of file initsplan.c.

731{
732 ListCell *lc;
733
734 foreach(lc, root->aggtransinfos)
735 {
737
738 if (transinfo->aggtransspace < 0)
739 return true;
740 }
741
742 return false;
743}

References fb(), lfirst_node, and root.

Referenced by setup_eager_aggregation().

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

2081{
2085 Relids min_lefthand;
2086 Relids min_righthand;
2087 Relids commute_below_l;
2088 Relids commute_below_r;
2089 ListCell *l;
2090
2091 /*
2092 * We should not see RIGHT JOIN here because left/right were switched
2093 * earlier
2094 */
2095 Assert(jointype != JOIN_INNER);
2096 Assert(jointype != JOIN_RIGHT);
2097
2098 /*
2099 * Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of
2100 * rels appearing on the nullable side of an outer join. (It's somewhat
2101 * unclear what that would mean, anyway: what should we mark when a result
2102 * row is generated from no element of the nullable relation?) So,
2103 * complain if any nullable rel is FOR [KEY] UPDATE/SHARE.
2104 *
2105 * You might be wondering why this test isn't made far upstream in the
2106 * parser. It's because the parser hasn't got enough info --- consider
2107 * FOR UPDATE applied to a view. Only after rewriting and flattening do
2108 * we know whether the view contains an outer join.
2109 *
2110 * We use the original RowMarkClause list here; the PlanRowMark list would
2111 * list everything.
2112 */
2113 foreach(l, root->parse->rowMarks)
2114 {
2115 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
2116
2117 if (bms_is_member(rc->rti, right_rels) ||
2118 (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels)))
2119 ereport(ERROR,
2121 /*------
2122 translator: %s is a SQL row locking clause such as FOR UPDATE */
2123 errmsg("%s cannot be applied to the nullable side of an outer join",
2124 LCS_asString(rc->strength))));
2125 }
2126
2127 sjinfo->syn_lefthand = left_rels;
2128 sjinfo->syn_righthand = right_rels;
2129 sjinfo->jointype = jointype;
2130 sjinfo->ojrelid = ojrelid;
2131 /* these fields may get added to later: */
2132 sjinfo->commute_above_l = NULL;
2133 sjinfo->commute_above_r = NULL;
2134 sjinfo->commute_below_l = NULL;
2135 sjinfo->commute_below_r = NULL;
2136
2137 compute_semijoin_info(root, sjinfo, clause);
2138
2139 /* If it's a full join, no need to be very smart */
2140 if (jointype == JOIN_FULL)
2141 {
2142 sjinfo->min_lefthand = bms_copy(left_rels);
2143 sjinfo->min_righthand = bms_copy(right_rels);
2144 sjinfo->lhs_strict = false; /* don't care about this */
2145 return sjinfo;
2146 }
2147
2148 /*
2149 * Retrieve all relids mentioned within the join clause.
2150 */
2151 clause_relids = pull_varnos(root, (Node *) clause);
2152
2153 /*
2154 * For which relids is the clause strict, ie, it cannot succeed if the
2155 * rel's columns are all NULL?
2156 */
2158
2159 /* Remember whether the clause is strict for any LHS relations */
2160 sjinfo->lhs_strict = bms_overlap(strict_relids, left_rels);
2161
2162 /*
2163 * Required LHS always includes the LHS rels mentioned in the clause. We
2164 * may have to add more rels based on lower outer joins; see below.
2165 */
2166 min_lefthand = bms_intersect(clause_relids, left_rels);
2167
2168 /*
2169 * Similarly for required RHS. But here, we must also include any lower
2170 * inner joins, to ensure we don't try to commute with any of them.
2171 */
2172 min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
2173 right_rels);
2174
2175 /*
2176 * Now check previous outer joins for ordering restrictions.
2177 *
2178 * commute_below_l and commute_below_r accumulate the relids of lower
2179 * outer joins that we think this one can commute with. These decisions
2180 * are just tentative within this loop, since we might find an
2181 * intermediate outer join that prevents commutation. Surviving relids
2182 * will get merged into the SpecialJoinInfo structs afterwards.
2183 */
2184 commute_below_l = commute_below_r = NULL;
2185 foreach(l, root->join_info_list)
2186 {
2188 bool have_unsafe_phvs;
2189
2190 /*
2191 * A full join is an optimization barrier: we can't associate into or
2192 * out of it. Hence, if it overlaps either LHS or RHS of the current
2193 * rel, expand that side's min relset to cover the whole full join.
2194 */
2195 if (otherinfo->jointype == JOIN_FULL)
2196 {
2197 Assert(otherinfo->ojrelid != 0);
2198 if (bms_overlap(left_rels, otherinfo->syn_lefthand) ||
2199 bms_overlap(left_rels, otherinfo->syn_righthand))
2200 {
2201 min_lefthand = bms_add_members(min_lefthand,
2202 otherinfo->syn_lefthand);
2203 min_lefthand = bms_add_members(min_lefthand,
2204 otherinfo->syn_righthand);
2205 min_lefthand = bms_add_member(min_lefthand,
2206 otherinfo->ojrelid);
2207 }
2208 if (bms_overlap(right_rels, otherinfo->syn_lefthand) ||
2209 bms_overlap(right_rels, otherinfo->syn_righthand))
2210 {
2211 min_righthand = bms_add_members(min_righthand,
2212 otherinfo->syn_lefthand);
2213 min_righthand = bms_add_members(min_righthand,
2214 otherinfo->syn_righthand);
2215 min_righthand = bms_add_member(min_righthand,
2216 otherinfo->ojrelid);
2217 }
2218 /* Needn't do anything else with the full join */
2219 continue;
2220 }
2221
2222 /*
2223 * If our join condition contains any PlaceHolderVars that need to be
2224 * evaluated above the lower OJ, then we can't commute with it.
2225 */
2226 if (otherinfo->ojrelid != 0)
2229 (Node *) clause,
2230 otherinfo->ojrelid);
2231 else
2232 have_unsafe_phvs = false;
2233
2234 /*
2235 * For a lower OJ in our LHS, if our join condition uses the lower
2236 * join's RHS and is not strict for that rel, we must preserve the
2237 * ordering of the two OJs, so add lower OJ's full syntactic relset to
2238 * min_lefthand. (We must use its full syntactic relset, not just its
2239 * min_lefthand + min_righthand. This is because there might be other
2240 * OJs below this one that this one can commute with, but we cannot
2241 * commute with them if we don't with this one.) Also, if we have
2242 * unsafe PHVs or the current join is a semijoin or antijoin, we must
2243 * preserve ordering regardless of strictness.
2244 *
2245 * Note: I believe we have to insist on being strict for at least one
2246 * rel in the lower OJ's min_righthand, not its whole syn_righthand.
2247 *
2248 * When we don't need to preserve ordering, check to see if outer join
2249 * identity 3 applies, and if so, remove the lower OJ's ojrelid from
2250 * our min_lefthand so that commutation is allowed.
2251 */
2252 if (bms_overlap(left_rels, otherinfo->syn_righthand))
2253 {
2254 if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
2256 jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
2257 !bms_overlap(strict_relids, otherinfo->min_righthand)))
2258 {
2259 /* Preserve ordering */
2260 min_lefthand = bms_add_members(min_lefthand,
2261 otherinfo->syn_lefthand);
2262 min_lefthand = bms_add_members(min_lefthand,
2263 otherinfo->syn_righthand);
2264 if (otherinfo->ojrelid != 0)
2265 min_lefthand = bms_add_member(min_lefthand,
2266 otherinfo->ojrelid);
2267 }
2268 else if (jointype == JOIN_LEFT &&
2269 otherinfo->jointype == JOIN_LEFT &&
2270 bms_overlap(strict_relids, otherinfo->min_righthand) &&
2271 !bms_overlap(clause_relids, otherinfo->syn_lefthand))
2272 {
2273 /* Identity 3 applies, so remove the ordering restriction */
2274 min_lefthand = bms_del_member(min_lefthand, otherinfo->ojrelid);
2275 /* Record the (still tentative) commutability relationship */
2276 commute_below_l =
2277 bms_add_member(commute_below_l, otherinfo->ojrelid);
2278 }
2279 }
2280
2281 /*
2282 * For a lower OJ in our RHS, if our join condition does not use the
2283 * lower join's RHS and the lower OJ's join condition is strict, we
2284 * can interchange the ordering of the two OJs; otherwise we must add
2285 * the lower OJ's full syntactic relset to min_righthand.
2286 *
2287 * Also, if our join condition does not use the lower join's LHS
2288 * either, force the ordering to be preserved. Otherwise we can end
2289 * up with SpecialJoinInfos with identical min_righthands, which can
2290 * confuse join_is_legal (see discussion in backend/optimizer/README).
2291 *
2292 * Also, we must preserve ordering anyway if we have unsafe PHVs, or
2293 * if either this join or the lower OJ is a semijoin or antijoin.
2294 *
2295 * When we don't need to preserve ordering, check to see if outer join
2296 * identity 3 applies, and if so, remove the lower OJ's ojrelid from
2297 * our min_righthand so that commutation is allowed.
2298 */
2299 if (bms_overlap(right_rels, otherinfo->syn_righthand))
2300 {
2301 if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
2302 !bms_overlap(clause_relids, otherinfo->min_lefthand) ||
2304 jointype == JOIN_SEMI ||
2305 jointype == JOIN_ANTI ||
2306 otherinfo->jointype == JOIN_SEMI ||
2307 otherinfo->jointype == JOIN_ANTI ||
2308 !otherinfo->lhs_strict)
2309 {
2310 /* Preserve ordering */
2311 min_righthand = bms_add_members(min_righthand,
2312 otherinfo->syn_lefthand);
2313 min_righthand = bms_add_members(min_righthand,
2314 otherinfo->syn_righthand);
2315 if (otherinfo->ojrelid != 0)
2316 min_righthand = bms_add_member(min_righthand,
2317 otherinfo->ojrelid);
2318 }
2319 else if (jointype == JOIN_LEFT &&
2320 otherinfo->jointype == JOIN_LEFT &&
2321 otherinfo->lhs_strict)
2322 {
2323 /* Identity 3 applies, so remove the ordering restriction */
2324 min_righthand = bms_del_member(min_righthand,
2325 otherinfo->ojrelid);
2326 /* Record the (still tentative) commutability relationship */
2327 commute_below_r =
2328 bms_add_member(commute_below_r, otherinfo->ojrelid);
2329 }
2330 }
2331 }
2332
2333 /*
2334 * Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
2335 * this join's nullable side, then ensure that min_righthand contains the
2336 * full eval_at set of the PHV. This ensures that the PHV actually can be
2337 * evaluated within the RHS. Note that this works only because we should
2338 * already have determined the final eval_at level for any PHV
2339 * syntactically within this join.
2340 */
2341 foreach(l, root->placeholder_list)
2342 {
2344 Relids ph_syn_level = phinfo->ph_var->phrels;
2345
2346 /* Ignore placeholder if it didn't syntactically come from RHS */
2347 if (!bms_is_subset(ph_syn_level, right_rels))
2348 continue;
2349
2350 /* Else, prevent join from being formed before we eval the PHV */
2351 min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
2352 }
2353
2354 /*
2355 * If we found nothing to put in min_lefthand, punt and make it the full
2356 * LHS, to avoid having an empty min_lefthand which will confuse later
2357 * processing. (We don't try to be smart about such cases, just correct.)
2358 * Likewise for min_righthand.
2359 */
2360 if (bms_is_empty(min_lefthand))
2361 min_lefthand = bms_copy(left_rels);
2362 if (bms_is_empty(min_righthand))
2363 min_righthand = bms_copy(right_rels);
2364
2365 /* Now they'd better be nonempty */
2366 Assert(!bms_is_empty(min_lefthand));
2367 Assert(!bms_is_empty(min_righthand));
2368 /* Shouldn't overlap either */
2369 Assert(!bms_overlap(min_lefthand, min_righthand));
2370
2371 sjinfo->min_lefthand = min_lefthand;
2372 sjinfo->min_righthand = min_righthand;
2373
2374 /*
2375 * Now that we've identified the correct min_lefthand and min_righthand,
2376 * any commute_below_l or commute_below_r relids that have not gotten
2377 * added back into those sets (due to intervening outer joins) are indeed
2378 * commutable with this one.
2379 *
2380 * First, delete any subsequently-added-back relids (this is easier than
2381 * maintaining commute_below_l/r precisely through all the above).
2382 */
2383 commute_below_l = bms_del_members(commute_below_l, min_lefthand);
2384 commute_below_r = bms_del_members(commute_below_r, min_righthand);
2385
2386 /* Anything left? */
2387 if (commute_below_l || commute_below_r)
2388 {
2389 /* Yup, so we must update the derived data in the SpecialJoinInfos */
2390 sjinfo->commute_below_l = commute_below_l;
2391 sjinfo->commute_below_r = commute_below_r;
2392 foreach(l, root->join_info_list)
2393 {
2395
2396 if (bms_is_member(otherinfo->ojrelid, commute_below_l))
2398 bms_add_member(otherinfo->commute_above_l, ojrelid);
2399 else if (bms_is_member(otherinfo->ojrelid, commute_below_r))
2400 otherinfo->commute_above_r =
2401 bms_add_member(otherinfo->commute_above_r, ojrelid);
2402 }
2403 }
2404
2405 return sjinfo;
2406}
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1093
Relids find_nonnullable_rels(Node *clause)
Definition clauses.c:1474
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereport(elevel,...)
Definition elog.h:150
static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
Definition initsplan.c:2416
@ JOIN_RIGHT
Definition nodes.h:306
static char * errmsg
const char * LCS_asString(LockClauseStrength strength)
Definition analyze.c:3353
bool contain_placeholder_references_to(PlannerInfo *root, Node *clause, int relid)
LockClauseStrength strength
Relids commute_above_l
Definition pathnodes.h:3219

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, fb(), 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, 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 2034 of file initsplan.c.

2036{
2037 int relid = -1;
2038
2039 while ((relid = bms_next_member(lower_rels, relid)) > 0)
2040 {
2041 RelOptInfo *rel = root->simple_rel_array[relid];
2042
2043 /* ignore the RTE_GROUP RTE */
2044 if (relid == root->group_rtindex)
2045 continue;
2046
2047 if (rel == NULL) /* must be an outer join */
2048 {
2049 Assert(bms_is_member(relid, root->outer_join_rels));
2050 continue;
2051 }
2052 rel->nulling_relids = bms_add_member(rel->nulling_relids, ojrelid);
2053 }
2054}
Relids nulling_relids
Definition pathnodes.h:1073

References Assert, bms_add_member(), bms_is_member(), bms_next_member(), fb(), 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 3963 of file initsplan.c.

3964{
3965 List *newlist = NIL;
3966 ListCell *lc;
3967
3968 foreach(lc, root->fkey_list)
3969 {
3973 int colno;
3974
3975 /*
3976 * Either relid might identify a rel that is in the query's rtable but
3977 * isn't referenced by the jointree, or has been removed by join
3978 * removal, so that it won't have a RelOptInfo. Hence don't use
3979 * find_base_rel() here. We can ignore such FKs.
3980 */
3981 if (fkinfo->con_relid >= root->simple_rel_array_size ||
3982 fkinfo->ref_relid >= root->simple_rel_array_size)
3983 continue; /* just paranoia */
3984 con_rel = root->simple_rel_array[fkinfo->con_relid];
3985 if (con_rel == NULL)
3986 continue;
3987 ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3988 if (ref_rel == NULL)
3989 continue;
3990
3991 /*
3992 * Ignore FK unless both rels are baserels. This gets rid of FKs that
3993 * link to inheritance child rels (otherrels).
3994 */
3995 if (con_rel->reloptkind != RELOPT_BASEREL ||
3996 ref_rel->reloptkind != RELOPT_BASEREL)
3997 continue;
3998
3999 /*
4000 * Scan the columns and try to match them to eclasses and quals.
4001 *
4002 * Note: for simple inner joins, any match should be in an eclass.
4003 * "Loose" quals that syntactically match an FK equality must have
4004 * been rejected for EC status because they are outer-join quals or
4005 * similar. We can still consider them to match the FK.
4006 */
4007 for (colno = 0; colno < fkinfo->nkeys; colno++)
4008 {
4009 EquivalenceClass *ec;
4011 ref_attno;
4012 Oid fpeqop;
4013 ListCell *lc2;
4014
4016 /* Don't bother looking for loose quals if we got an EC match */
4017 if (ec != NULL)
4018 {
4019 fkinfo->nmatched_ec++;
4020 if (ec->ec_has_const)
4021 fkinfo->nconst_ec++;
4022 continue;
4023 }
4024
4025 /*
4026 * Scan joininfo list for relevant clauses. Either rel's joininfo
4027 * list would do equally well; we use con_rel's.
4028 */
4029 con_attno = fkinfo->conkey[colno];
4030 ref_attno = fkinfo->confkey[colno];
4031 fpeqop = InvalidOid; /* we'll look this up only if needed */
4032
4033 foreach(lc2, con_rel->joininfo)
4034 {
4035 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
4036 OpExpr *clause = (OpExpr *) rinfo->clause;
4037 Var *leftvar;
4038 Var *rightvar;
4039
4040 /* Only binary OpExprs are useful for consideration */
4041 if (!IsA(clause, OpExpr) ||
4042 list_length(clause->args) != 2)
4043 continue;
4044 leftvar = (Var *) get_leftop((Expr *) clause);
4045 rightvar = (Var *) get_rightop((Expr *) clause);
4046
4047 /* Operands must be Vars, possibly with RelabelType */
4048 while (leftvar && IsA(leftvar, RelabelType))
4049 leftvar = (Var *) ((RelabelType *) leftvar)->arg;
4050 if (!(leftvar && IsA(leftvar, Var)))
4051 continue;
4052 while (rightvar && IsA(rightvar, RelabelType))
4053 rightvar = (Var *) ((RelabelType *) rightvar)->arg;
4054 if (!(rightvar && IsA(rightvar, Var)))
4055 continue;
4056
4057 /* Now try to match the vars to the current foreign key cols */
4058 if (fkinfo->ref_relid == leftvar->varno &&
4059 ref_attno == leftvar->varattno &&
4060 fkinfo->con_relid == rightvar->varno &&
4061 con_attno == rightvar->varattno)
4062 {
4063 /* Vars match, but is it the right operator? */
4064 if (clause->opno == fkinfo->conpfeqop[colno])
4065 {
4066 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
4067 rinfo);
4068 fkinfo->nmatched_ri++;
4069 }
4070 }
4071 else if (fkinfo->ref_relid == rightvar->varno &&
4072 ref_attno == rightvar->varattno &&
4073 fkinfo->con_relid == leftvar->varno &&
4074 con_attno == leftvar->varattno)
4075 {
4076 /*
4077 * Reverse match, must check commutator operator. Look it
4078 * up if we didn't already. (In the worst case we might
4079 * do multiple lookups here, but that would require an FK
4080 * equality operator without commutator, which is
4081 * unlikely.)
4082 */
4083 if (!OidIsValid(fpeqop))
4084 fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
4085 if (clause->opno == fpeqop)
4086 {
4087 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
4088 rinfo);
4089 fkinfo->nmatched_ri++;
4090 }
4091 }
4092 }
4093 /* If we found any matching loose quals, count col as matched */
4094 if (fkinfo->rinfos[colno])
4095 fkinfo->nmatched_rcols++;
4096 }
4097
4098 /*
4099 * Currently, we drop multicolumn FKs that aren't fully matched to the
4100 * query. Later we might figure out how to derive some sort of
4101 * estimate from them, in which case this test should be weakened to
4102 * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
4103 */
4104 if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
4106 }
4107 /* Replace fkey_list, thereby discarding any useless entries */
4108 root->fkey_list = newlist;
4109}
int16 AttrNumber
Definition attnum.h:21
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
static Node * get_rightop(const void *clause)
Definition nodeFuncs.h:95
static Node * get_leftop(const void *clause)
Definition nodeFuncs.h:83
Expr * clause
Definition pathnodes.h:2888

References OpExpr::args, RestrictInfo::clause, EquivalenceClass::ec_has_const, fb(), get_commutator(), get_leftop(), get_rightop(), InvalidOid, IsA, lappend(), lfirst, list_length(), match_eclasses_to_foreign_key_col(), NIL, OidIsValid, OpExpr::opno, RELOPT_BASEREL, 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 3644 of file initsplan.c.

3652{
3654 Node *clause;
3655 Relids relids;
3656 bool pseudoconstant = false;
3657
3658 /*
3659 * Build the new clause. Copy to ensure it shares no substructure with
3660 * original (this is necessary in case there are subselects in there...)
3661 */
3662 clause = (Node *) make_opclause(opno,
3663 BOOLOID, /* opresulttype */
3664 false, /* opretset */
3667 InvalidOid,
3668 collation);
3669
3670 /* If both constant, try to reduce to a boolean constant. */
3671 if (both_const)
3672 {
3673 clause = eval_const_expressions(root, clause);
3674
3675 /* If we produced const TRUE, just drop the clause */
3676 if (clause && IsA(clause, Const))
3677 {
3678 Const *cclause = (Const *) clause;
3679
3680 Assert(cclause->consttype == BOOLOID);
3681 if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
3682 return NULL;
3683 }
3684 }
3685
3686 /*
3687 * The rest of this is a very cut-down version of distribute_qual_to_rels.
3688 * We can skip most of the work therein, but there are a couple of special
3689 * cases we still have to handle.
3690 *
3691 * Retrieve all relids mentioned within the possibly-simplified clause.
3692 */
3693 relids = pull_varnos(root, clause);
3694 Assert(bms_is_subset(relids, qualscope));
3695
3696 /*
3697 * If the clause is variable-free, our normal heuristic for pushing it
3698 * down to just the mentioned rels doesn't work, because there are none.
3699 * Apply it as a gating qual at the appropriate level (see comments for
3700 * get_join_domain_min_rels).
3701 */
3702 if (bms_is_empty(relids))
3703 {
3704 /* eval at join domain's safe level */
3705 relids = get_join_domain_min_rels(root, qualscope);
3706 /* mark as gating qual */
3707 pseudoconstant = true;
3708 /* tell createplan.c to check for gating quals */
3709 root->hasPseudoConstantQuals = true;
3710 }
3711
3712 /*
3713 * Build the RestrictInfo node itself.
3714 */
3716 (Expr *) clause,
3717 true, /* is_pushed_down */
3718 false, /* !has_clone */
3719 false, /* !is_clone */
3721 security_level,
3722 relids,
3723 NULL, /* incompatible_relids */
3724 NULL); /* outer_relids */
3725
3726 /*
3727 * If it's a join clause, add vars used in the clause to targetlists of
3728 * their relations, so that they will be emitted by the plan nodes that
3729 * scan those relations (else they won't be available at the join node!).
3730 *
3731 * Typically, we'd have already done this when the component expressions
3732 * were first seen by distribute_qual_to_rels; but it is possible that
3733 * some of the Vars could have missed having that done because they only
3734 * appeared in single-relation clauses originally. So do it here for
3735 * safety.
3736 *
3737 * See also rebuild_joinclause_attr_needed, which has to partially repeat
3738 * this work after removal of an outer join. (Since we will put this
3739 * clause into the joininfo lists, that function needn't do any extra work
3740 * to find it.)
3741 */
3742 if (bms_membership(relids) == BMS_MULTIPLE)
3743 {
3744 List *vars = pull_var_clause(clause,
3748
3750 list_free(vars);
3751 }
3752
3753 /*
3754 * Check mergejoinability. This will usually succeed, since the op came
3755 * from an EquivalenceClass; but we could have reduced the original clause
3756 * to a constant.
3757 */
3759
3760 /*
3761 * Note we don't do initialize_mergeclause_eclasses(); the caller can
3762 * handle that much more cheaply than we can. It's okay to call
3763 * distribute_restrictinfo_to_rels() before that happens.
3764 */
3765
3766 /*
3767 * Push the new clause into all the appropriate restrictinfo lists.
3768 */
3770
3771 return restrictinfo;
3772}
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition clauses.c:2498
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition initsplan.c:3857

References add_vars_to_targetlist(), Assert, bms_is_empty, bms_is_subset(), bms_membership(), BMS_MULTIPLE, check_mergejoinable(), copyObject, DatumGetBool(), distribute_restrictinfo_to_rels(), eval_const_expressions(), fb(), 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 1984 of file initsplan.c.

1986{
1987 RangeTblEntry *rte = root->simple_rte_array[rti];
1988 Index security_level = 0;
1989 ListCell *lc;
1990
1991 /*
1992 * Each element of the securityQuals list has been preprocessed into an
1993 * implicitly-ANDed list of clauses. All the clauses in a given sublist
1994 * should get the same security level, but successive sublists get higher
1995 * levels.
1996 */
1997 foreach(lc, rte->securityQuals)
1998 {
1999 List *qualset = (List *) lfirst(lc);
2000
2001 /*
2002 * We cheat to the extent of passing ojscope = qualscope rather than
2003 * its more logical value of NULL. The only effect this has is to
2004 * force a Var-free qual to be evaluated at the rel rather than being
2005 * pushed up to top of tree, which we don't want.
2006 */
2008 jtitem,
2009 NULL,
2010 security_level,
2011 jtitem->qualscope,
2012 jtitem->qualscope,
2013 NULL,
2014 NULL,
2015 true,
2016 false, false, /* not clones */
2017 NULL);
2018 security_level++;
2019 }
2020
2021 /* Assert that qual_security_level is higher than anything we just used */
2022 Assert(security_level <= root->qual_security_level);
2023}

References Assert, distribute_quals_to_rels(), fb(), lfirst, and root.

Referenced by deconstruct_distribute().

◆ rebuild_joinclause_attr_needed()

void rebuild_joinclause_attr_needed ( PlannerInfo root)

Definition at line 3891 of file initsplan.c.

3892{
3893 /*
3894 * We must examine all join clauses, but there's no value in processing
3895 * any join clause more than once. So it's slightly annoying that we have
3896 * to find them via the per-base-relation joininfo lists. Avoid duplicate
3897 * processing by tracking the rinfo_serial numbers of join clauses we've
3898 * already seen. (This doesn't work for is_clone clauses, so we must
3899 * waste effort on them.)
3900 */
3902 Index rti;
3903
3904 /* Scan all baserels for join clauses */
3905 for (rti = 1; rti < root->simple_rel_array_size; rti++)
3906 {
3907 RelOptInfo *brel = root->simple_rel_array[rti];
3908 ListCell *lc;
3909
3910 if (brel == NULL)
3911 continue;
3912 if (brel->reloptkind != RELOPT_BASEREL)
3913 continue;
3914
3915 foreach(lc, brel->joininfo)
3916 {
3917 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
3918 Relids relids = rinfo->required_relids;
3919
3920 if (!rinfo->is_clone) /* else serial number is not unique */
3921 {
3923 continue; /* saw it already */
3925 rinfo->rinfo_serial);
3926 }
3927
3928 if (bms_membership(relids) == BMS_MULTIPLE)
3929 {
3930 List *vars = pull_var_clause((Node *) rinfo->clause,
3935
3936 if (rinfo->is_clone)
3937 where_needed = bms_intersect(relids, root->all_baserels);
3938 else
3939 where_needed = relids;
3941 list_free(vars);
3942 }
3943 }
3944 }
3945}
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition initsplan.c:361
Relids required_relids
Definition pathnodes.h:2919

References add_vars_to_attr_needed(), bms_add_member(), bms_intersect(), bms_is_member(), bms_membership(), BMS_MULTIPLE, RestrictInfo::clause, fb(), RestrictInfo::is_clone, lfirst, list_free(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RELOPT_BASEREL, 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 1175 of file initsplan.c.

1176{
1177 Index rti;
1178
1179 /* We need do nothing if the query contains no LATERAL RTEs */
1180 if (!root->hasLateralRTEs)
1181 return;
1182
1183 /* Examine the same baserels that find_lateral_references did */
1184 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1185 {
1186 RelOptInfo *brel = root->simple_rel_array[rti];
1188
1189 if (brel == NULL)
1190 continue;
1191 if (brel->reloptkind != RELOPT_BASEREL)
1192 continue;
1193
1194 /*
1195 * We don't need to repeat all of extract_lateral_references, since it
1196 * kindly saved the extracted Vars/PHVs in lateral_vars.
1197 */
1198 if (brel->lateral_vars == NIL)
1199 continue;
1200
1202
1204 }
1205}

References add_vars_to_attr_needed(), bms_make_singleton(), fb(), NIL, RELOPT_BASEREL, 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 420 of file initsplan.c.

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

References Assert, bms_add_member(), bms_difference(), bms_is_empty, bms_is_member(), bms_membership(), BMS_MULTIPLE, BMS_SUBSET1, bms_subset_compare(), fb(), FirstLowInvalidHeapAttributeNumber, foreach_node, get_sortgroupclause_tle(), i, RelOptInfo::indexlist, IsA, lappend(), lfirst_node, list_length(), NIL, RelOptInfo::notnullattnums, palloc0_array, parse(), PG_INT32_MAX, root, RTE_RELATION, 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 3488 of file initsplan.c.

3490{
3491 /*
3492 * For a clone clause, we don't have a reliable way to determine if the
3493 * input expression of a NullTest is non-nullable: nullingrel bits in
3494 * clone clauses may not reflect reality, so we dare not draw conclusions
3495 * from clones about whether Vars are guaranteed not-null.
3496 */
3497 if (restrictinfo->has_clone || restrictinfo->is_clone)
3498 return false;
3499
3500 /* Check for NullTest qual */
3501 if (IsA(restrictinfo->clause, NullTest))
3502 {
3503 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3504
3505 /* is this NullTest an IS_NULL qual? */
3506 if (nulltest->nulltesttype != IS_NULL)
3507 return false;
3508
3509 /*
3510 * Empty rows can appear NULL in some contexts and NOT NULL in others,
3511 * so avoid this optimization for row expressions.
3512 */
3513 if (nulltest->argisrow)
3514 return false;
3515
3517 }
3518
3519 /* If it's an OR, check its sub-clauses */
3521 {
3522 ListCell *lc;
3523
3524 Assert(is_orclause(restrictinfo->orclause));
3525
3526 /*
3527 * Currently, when processing OR expressions, we only return true when
3528 * all of the OR branches are always false. This could perhaps be
3529 * expanded to remove OR branches that are provably false. This may
3530 * be a useful thing to do as it could result in the OR being left
3531 * with a single arg. That's useful as it would allow the OR
3532 * condition to be replaced with its single argument which may allow
3533 * use of an index for faster filtering on the remaining condition.
3534 */
3535 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3536 {
3537 Node *orarg = (Node *) lfirst(lc);
3538
3539 if (!IsA(orarg, RestrictInfo) ||
3541 return false;
3542 }
3543 return true;
3544 }
3545
3546 return false;
3547}
bool expr_is_nonnullable(PlannerInfo *root, Expr *expr, NotNullSource source)
Definition clauses.c:4749
static bool is_orclause(const void *clause)
Definition nodeFuncs.h:116
@ NOTNULL_SOURCE_RELOPT
Definition optimizer.h:136
@ IS_NULL
Definition primnodes.h:1979
bool restriction_is_or_clause(RestrictInfo *restrictinfo)

References Assert, expr_is_nonnullable(), fb(), IS_NULL, is_orclause(), IsA, lfirst, NOTNULL_SOURCE_RELOPT, restriction_is_always_false(), restriction_is_or_clause(), and root.

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

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3423 of file initsplan.c.

3425{
3426 /*
3427 * For a clone clause, we don't have a reliable way to determine if the
3428 * input expression of a NullTest is non-nullable: nullingrel bits in
3429 * clone clauses may not reflect reality, so we dare not draw conclusions
3430 * from clones about whether Vars are guaranteed not-null.
3431 */
3432 if (restrictinfo->has_clone || restrictinfo->is_clone)
3433 return false;
3434
3435 /* Check for NullTest qual */
3436 if (IsA(restrictinfo->clause, NullTest))
3437 {
3438 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3439
3440 /* is this NullTest an IS_NOT_NULL qual? */
3441 if (nulltest->nulltesttype != IS_NOT_NULL)
3442 return false;
3443
3444 /*
3445 * Empty rows can appear NULL in some contexts and NOT NULL in others,
3446 * so avoid this optimization for row expressions.
3447 */
3448 if (nulltest->argisrow)
3449 return false;
3450
3452 }
3453
3454 /* If it's an OR, check its sub-clauses */
3456 {
3457 ListCell *lc;
3458
3459 Assert(is_orclause(restrictinfo->orclause));
3460
3461 /*
3462 * if any of the given OR branches is provably always true then the
3463 * entire condition is true.
3464 */
3465 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3466 {
3467 Node *orarg = (Node *) lfirst(lc);
3468
3469 if (!IsA(orarg, RestrictInfo))
3470 continue;
3471
3473 return true;
3474 }
3475 }
3476
3477 return false;
3478}
@ IS_NOT_NULL
Definition primnodes.h:1979

References Assert, expr_is_nonnullable(), fb(), IS_NOT_NULL, is_orclause(), IsA, lfirst, NOTNULL_SOURCE_RELOPT, restriction_is_always_true(), restriction_is_or_clause(), and root.

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

◆ setup_eager_aggregation()

void setup_eager_aggregation ( PlannerInfo root)

Definition at line 643 of file initsplan.c.

644{
645 /*
646 * Don't apply eager aggregation if disabled by user.
647 */
649 return;
650
651 /*
652 * Don't apply eager aggregation if there are no available GROUP BY
653 * clauses.
654 */
655 if (!root->processed_groupClause)
656 return;
657
658 /*
659 * For now we don't try to support grouping sets.
660 */
661 if (root->parse->groupingSets)
662 return;
663
664 /*
665 * For now we don't try to support DISTINCT or ORDER BY aggregates.
666 */
667 if (root->numOrderedAggs > 0)
668 return;
669
670 /*
671 * If there are any aggregates that do not support partial mode, or any
672 * partial aggregates that are non-serializable, do not apply eager
673 * aggregation.
674 */
675 if (root->hasNonPartialAggs || root->hasNonSerialAggs)
676 return;
677
678 /*
679 * We don't try to apply eager aggregation if there are set-returning
680 * functions in targetlist.
681 */
682 if (root->parse->hasTargetSRFs)
683 return;
684
685 /*
686 * Eager aggregation only makes sense if there are multiple base rels in
687 * the query.
688 */
689 if (bms_membership(root->all_baserels) != BMS_MULTIPLE)
690 return;
691
692 /*
693 * Don't apply eager aggregation if any aggregate poses a risk of
694 * excessive memory usage during partial aggregation.
695 */
697 return;
698
699 /*
700 * Collect aggregate expressions and plain Vars that appear in the
701 * targetlist and havingQual.
702 */
704
705 /*
706 * If there are no suitable aggregate expressions, we cannot apply eager
707 * aggregation.
708 */
709 if (root->agg_clause_list == NIL)
710 return;
711
712 /*
713 * Collect grouping expressions that appear in grouping clauses.
714 */
716}
bool enable_eager_aggregate
Definition allpaths.c:82
static void create_grouping_expr_infos(PlannerInfo *root)
Definition initsplan.c:869
static bool is_partial_agg_memory_risky(PlannerInfo *root)
Definition initsplan.c:730
static void create_agg_clause_infos(PlannerInfo *root)
Definition initsplan.c:751

References bms_membership(), BMS_MULTIPLE, create_agg_clause_infos(), create_grouping_expr_infos(), enable_eager_aggregate, is_partial_agg_memory_risky(), NIL, and root.

Referenced by query_planner().

Variable Documentation

◆ from_collapse_limit

int from_collapse_limit

Definition at line 41 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 42 of file initsplan.c.

Referenced by deconstruct_recurse().