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

Go to the source code of this file.

Data Structures

struct  JoinTreeItem
 

Typedefs

typedef struct JoinTreeItem JoinTreeItem
 

Functions

static 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

typedef struct JoinTreeItem JoinTreeItem

Function Documentation

◆ add_base_clause_to_rel()

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

Definition at line 3349 of file initsplan.c.

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

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

Referenced by distribute_restrictinfo_to_rels().

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 165 of file initsplan.c.

166{
167 if (jtnode == NULL)
168 return;
169 if (IsA(jtnode, RangeTblRef))
170 {
171 int varno = ((RangeTblRef *) jtnode)->rtindex;
172
173 (void) build_simple_rel(root, varno, NULL);
174 }
175 else if (IsA(jtnode, FromExpr))
176 {
177 FromExpr *f = (FromExpr *) jtnode;
178 ListCell *l;
179
180 foreach(l, f->fromlist)
182 }
183 else if (IsA(jtnode, JoinExpr))
184 {
185 JoinExpr *j = (JoinExpr *) jtnode;
186
189 }
190 else
191 elog(ERROR, "unrecognized node type: %d",
192 (int) nodeTag(jtnode));
193}
#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:165
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:206
List * fromlist
Definition: primnodes.h:2357

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

Referenced by add_base_rels_to_query(), and query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 203 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_vars_to_attr_needed()

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

Definition at line 360 of file initsplan.c.

362{
363 ListCell *temp;
364
365 Assert(!bms_is_empty(where_needed));
366
367 foreach(temp, vars)
368 {
369 Node *node = (Node *) lfirst(temp);
370
371 if (IsA(node, Var))
372 {
373 Var *var = (Var *) node;
374 RelOptInfo *rel = find_base_rel(root, var->varno);
375 int attno = var->varattno;
376
377 if (bms_is_subset(where_needed, rel->relids))
378 continue;
379 Assert(attno >= rel->min_attr && attno <= rel->max_attr);
380 attno -= rel->min_attr;
381 rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
382 where_needed);
383 }
384 else if (IsA(node, PlaceHolderVar))
385 {
386 PlaceHolderVar *phv = (PlaceHolderVar *) node;
388
389 phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
390 where_needed);
391 }
392 else
393 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
394 }
395}
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:916
#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 ph_needed
Definition: pathnodes.h:3317
Relids relids
Definition: pathnodes.h:927
AttrNumber min_attr
Definition: pathnodes.h:979
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Definition: regcomp.c:282

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

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

◆ add_vars_to_targetlist()

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

Definition at line 289 of file initsplan.c.

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

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

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

◆ build_base_rel_tlists()

void build_base_rel_tlists ( PlannerInfo root,
List final_tlist 
)

Definition at line 242 of file initsplan.c.

243{
244 List *tlist_vars = pull_var_clause((Node *) final_tlist,
248
249 if (tlist_vars != NIL)
250 {
252 list_free(tlist_vars);
253 }
254
255 /*
256 * If there's a HAVING clause, we'll need the Vars it uses, too. Note
257 * that HAVING can contain Aggrefs but not WindowFuncs.
258 */
259 if (root->parse->havingQual)
260 {
261 List *having_vars = pull_var_clause(root->parse->havingQual,
264
265 if (having_vars != NIL)
266 {
267 add_vars_to_targetlist(root, having_vars,
269 list_free(having_vars);
270 }
271 }
272}
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:289
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:189
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:191
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:192
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
List * pull_var_clause(Node *node, int flags)
Definition: var.c:653

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

Referenced by distribute_row_identity_vars(), and query_planner().

◆ build_implied_join_equality()

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

Definition at line 3789 of file initsplan.c.

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

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

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

◆ check_hashjoinable()

static void check_hashjoinable ( RestrictInfo restrictinfo)
static

Definition at line 4166 of file initsplan.c.

4167{
4168 Expr *clause = restrictinfo->clause;
4169 Oid opno;
4170 Node *leftarg;
4171
4172 if (restrictinfo->pseudoconstant)
4173 return;
4174 if (!is_opclause(clause))
4175 return;
4176 if (list_length(((OpExpr *) clause)->args) != 2)
4177 return;
4178
4179 opno = ((OpExpr *) clause)->opno;
4180 leftarg = linitial(((OpExpr *) clause)->args);
4181
4182 if (op_hashjoinable(opno, exprType(leftarg)) &&
4183 !contain_volatile_functions((Node *) restrictinfo))
4184 restrictinfo->hashjoinoperator = opno;
4185}
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:550
bool op_hashjoinable(Oid opno, Oid inputtype)
Definition: lsyscache.c:1604
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:76
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
unsigned int Oid
Definition: postgres_ext.h:32
Expr * clause
Definition: pathnodes.h:2792

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

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

◆ check_memoizable()

static void check_memoizable ( RestrictInfo restrictinfo)
static

Definition at line 4194 of file initsplan.c.

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

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

Referenced by build_implied_join_equality(), and distribute_restrictinfo_to_rels().

◆ check_mergejoinable()

static void check_mergejoinable ( RestrictInfo restrictinfo)
static

Definition at line 4129 of file initsplan.c.

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

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

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

◆ check_redundant_nullability_qual()

static bool check_redundant_nullability_qual ( PlannerInfo root,
Node clause 
)
static

Definition at line 3304 of file initsplan.c.

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

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

Referenced by distribute_qual_to_rels().

◆ compute_semijoin_info()

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

Definition at line 2417 of file initsplan.c.

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

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

Referenced by make_outerjoininfo().

◆ create_agg_clause_infos()

static void create_agg_clause_infos ( PlannerInfo root)
static

Definition at line 752 of file initsplan.c.

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

References AggClauseInfo::agg_eval_at, Aggref::aggdistinct, Aggref::aggfnoid, Aggref::aggorder, AggClauseInfo::aggref, Assert(), bms_add_members(), bms_is_subset(), castNode, 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 870 of file initsplan.c.

871{
872 List *exprs = NIL;
873 List *sortgrouprefs = NIL;
874 List *ecs = NIL;
875 ListCell *lc,
876 *lc1,
877 *lc2,
878 *lc3;
879
880 Assert(root->group_expr_list == NIL);
881
882 foreach(lc, root->processed_groupClause)
883 {
885 TargetEntry *tle = get_sortgroupclause_tle(sgc, root->processed_tlist);
886 TypeCacheEntry *tce;
887 Oid equalimageproc;
888
889 Assert(tle->ressortgroupref > 0);
890
891 /*
892 * For now we only support plain Vars as grouping expressions.
893 */
894 if (!IsA(tle->expr, Var))
895 return;
896
897 /*
898 * Eager aggregation is only possible if equality implies image
899 * equality for each grouping key. Otherwise, placing keys with
900 * different byte images into the same group may result in the loss of
901 * information that could be necessary to evaluate upper qual clauses.
902 *
903 * For instance, the NUMERIC data type is not supported, as values
904 * that are considered equal by the equality operator (e.g., 0 and
905 * 0.0) can have different scales.
906 */
907 tce = lookup_type_cache(exprType((Node *) tle->expr),
909 if (!OidIsValid(tce->btree_opf) ||
911 return;
912
913 equalimageproc = get_opfamily_proc(tce->btree_opf,
914 tce->btree_opintype,
915 tce->btree_opintype,
917 if (!OidIsValid(equalimageproc) ||
918 !DatumGetBool(OidFunctionCall1Coll(equalimageproc,
919 tce->typcollation,
921 return;
922
923 exprs = lappend(exprs, tle->expr);
924 sortgrouprefs = lappend_int(sortgrouprefs, tle->ressortgroupref);
925 ecs = lappend(ecs, get_eclass_for_sortgroupclause(root, sgc, tle->expr));
926 }
927
928 /*
929 * Construct a GroupingExprInfo for each expression.
930 */
931 forthree(lc1, exprs, lc2, sortgrouprefs, lc3, ecs)
932 {
933 Expr *expr = (Expr *) lfirst(lc1);
934 int sortgroupref = lfirst_int(lc2);
936 GroupingExprInfo *ge_info;
937
938 ge_info = makeNode(GroupingExprInfo);
939 ge_info->expr = (Expr *) copyObject(expr);
940 ge_info->sortgroupref = sortgroupref;
941 ge_info->ec = ec;
942
943 root->group_expr_list = lappend(root->group_expr_list, ge_info);
944 }
945}
Datum OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
Definition: fmgr.c:1412
static EquivalenceClass * get_eclass_for_sortgroupclause(PlannerInfo *root, SortGroupClause *sgc, Expr *expr)
Definition: initsplan.c:953
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:889
#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:262
Expr * expr
Definition: primnodes.h:2239
Index ressortgroupref
Definition: primnodes.h:2245
Oid btree_opintype
Definition: typcache.h:59
Oid typcollation
Definition: typcache.h:48
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:367
#define TYPECACHE_BTREE_OPFAMILY
Definition: typcache.h:147

References Assert(), BTEQUALIMAGE_PROC, TypeCacheEntry::btree_opf, TypeCacheEntry::btree_opintype, copyObject, DatumGetBool(), GroupingExprInfo::expr, TargetEntry::expr, exprType(), 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, TargetEntry::ressortgroupref, root, GroupingExprInfo::sortgroupref, TypeCacheEntry::typcollation, and TYPECACHE_BTREE_OPFAMILY.

Referenced by setup_eager_aggregation().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 1214 of file initsplan.c.

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

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

Referenced by query_planner().

◆ deconstruct_distribute()

static void deconstruct_distribute ( PlannerInfo root,
JoinTreeItem jtitem 
)
static

Definition at line 1833 of file initsplan.c.

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

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

Referenced by deconstruct_jointree().

◆ deconstruct_distribute_oj_quals()

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

Definition at line 2595 of file initsplan.c.

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

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

Referenced by deconstruct_jointree().

◆ deconstruct_jointree()

List * deconstruct_jointree ( PlannerInfo root)

Definition at line 1453 of file initsplan.c.

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

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

Referenced by query_planner().

◆ deconstruct_recurse()

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

Definition at line 1535 of file initsplan.c.

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

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

Referenced by deconstruct_jointree(), and deconstruct_recurse().

◆ distribute_qual_to_rels()

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

Definition at line 2914 of file initsplan.c.

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

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

Referenced by distribute_quals_to_rels().

◆ distribute_quals_to_rels()

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

Definition at line 2836 of file initsplan.c.

2848{
2849 ListCell *lc;
2850
2851 foreach(lc, clauses)
2852 {
2853 Node *clause = (Node *) lfirst(lc);
2854
2856 jtitem,
2857 sjinfo,
2858 security_level,
2859 qualscope,
2860 ojscope,
2861 outerjoin_nonnullable,
2862 incompatible_relids,
2863 allow_equivalence,
2864 has_clone,
2865 is_clone,
2866 postponed_oj_qual_list);
2867 }
2868}
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:2914

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

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

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3560 of file initsplan.c.

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

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

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

◆ extract_lateral_references()

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

Definition at line 1075 of file initsplan.c.

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

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

Referenced by find_lateral_references().

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 1027 of file initsplan.c.

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

References Assert(), extract_lateral_references(), RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, 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 953 of file initsplan.c.

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

References COMPARE_EQ, elog, ERROR, exprCollation(), get_eclass_for_sort_expr(), get_mergejoin_opfamilies(), get_opfamily_member_for_cmptype(), get_ordering_op_properties(), OidIsValid, root, SortGroupClause::sortop, and SortGroupClause::tleSortGroupRef.

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

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

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

Referenced by process_implied_equality().

◆ is_partial_agg_memory_risky()

static bool is_partial_agg_memory_risky ( PlannerInfo root)
static

Definition at line 731 of file initsplan.c.

732{
733 ListCell *lc;
734
735 foreach(lc, root->aggtransinfos)
736 {
737 AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
738
739 if (transinfo->aggtransspace < 0)
740 return true;
741 }
742
743 return false;
744}
int32 aggtransspace
Definition: pathnodes.h:3695

References AggTransInfo::aggtransspace, 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 2077 of file initsplan.c.

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

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

Referenced by deconstruct_distribute().

◆ mark_rels_nulled_by_join()

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

Definition at line 2035 of file initsplan.c.

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

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

Referenced by deconstruct_recurse().

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 3964 of file initsplan.c.

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

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

Referenced by query_planner().

◆ process_implied_equality()

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

Definition at line 3645 of file initsplan.c.

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

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

Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().

◆ process_security_barrier_quals()

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

Definition at line 1985 of file initsplan.c.

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

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

Referenced by deconstruct_distribute().

◆ rebuild_joinclause_attr_needed()

void rebuild_joinclause_attr_needed ( PlannerInfo root)

Definition at line 3892 of file initsplan.c.

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

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

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ rebuild_lateral_attr_needed()

void rebuild_lateral_attr_needed ( PlannerInfo root)

Definition at line 1176 of file initsplan.c.

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

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

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ remove_useless_groupby_columns()

void remove_useless_groupby_columns ( PlannerInfo root)

Definition at line 419 of file initsplan.c.

420{
421 Query *parse = root->parse;
422 Bitmapset **groupbyattnos;
423 Bitmapset **surplusvars;
424 bool tryremove = false;
425 ListCell *lc;
426 int relid;
427
428 /* No chance to do anything if there are less than two GROUP BY items */
429 if (list_length(root->processed_groupClause) < 2)
430 return;
431
432 /* Don't fiddle with the GROUP BY clause if the query has grouping sets */
433 if (parse->groupingSets)
434 return;
435
436 /*
437 * Scan the GROUP BY clause to find GROUP BY items that are simple Vars.
438 * Fill groupbyattnos[k] with a bitmapset of the column attnos of RTE k
439 * that are GROUP BY items.
440 */
441 groupbyattnos = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
442 (list_length(parse->rtable) + 1));
443 foreach(lc, root->processed_groupClause)
444 {
446 TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
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 */
470 tryremove |= !bms_is_empty(groupbyattnos[relid]);
471 groupbyattnos[relid] = bms_add_member(groupbyattnos[relid],
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;
494 Bitmapset *relattnos;
495 Bitmapset *best_keycolumns = NULL;
496 int32 best_nkeycolumns = PG_INT32_MAX;
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];
514 if (bms_membership(relattnos) != BMS_MULTIPLE)
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 {
526 Bitmapset *ind_attnos;
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
541 ind_attnos = NULL;
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 =
562 bms_add_member(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 */
574 if (bms_subset_compare(ind_attnos, relattnos) != BMS_SUBSET1)
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 {
587 best_keycolumns = ind_attnos;
588 best_nkeycolumns = index->nkeycolumns;
589 }
590 }
591
592 /* Did we find a suitable index? */
593 if (!bms_is_empty(best_keycolumns))
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)
600 surplusvars = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
601 (list_length(parse->rtable) + 1));
602
603 /* Remember the attnos of the removable columns */
604 surplusvars[relid] = bms_difference(relattnos, best_keycolumns);
605 }
606 }
607
608 /*
609 * If we found any surplus Vars, build a new GROUP BY clause without them.
610 * (Note: this may leave some TLEs with unreferenced ressortgroupref
611 * markings, but that's harmless.)
612 */
613 if (surplusvars != NULL)
614 {
615 List *new_groupby = NIL;
616
617 foreach(lc, root->processed_groupClause)
618 {
620 TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
621 Var *var = (Var *) tle->expr;
622
623 /*
624 * New list must include non-Vars, outer Vars, and anything not
625 * marked as surplus.
626 */
627 if (!IsA(var, Var) ||
628 var->varlevelsup > 0 ||
630 surplusvars[var->varno]))
631 new_groupby = lappend(new_groupby, sgc);
632 }
633
634 root->processed_groupClause = new_groupby;
635 }
636}
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:597
int32_t int32
Definition: c.h:537
int i
Definition: isn.c:77
void * palloc0(Size size)
Definition: mcxt.c:1395
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
Bitmapset * notnullattnums
Definition: pathnodes.h:987
List * indexlist
Definition: pathnodes.h:995
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(), TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, foreach_node, get_sortgroupclause_tle(), i, if(), RelOptInfo::indexlist, RangeTblEntry::inh, IsA, lappend(), lfirst_node, list_length(), NIL, RelOptInfo::notnullattnums, palloc0(), parse(), PG_INT32_MAX, root, RTE_RELATION, RangeTblEntry::rtekind, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by query_planner().

◆ restriction_is_always_false()

bool restriction_is_always_false ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3489 of file initsplan.c.

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

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

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

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3424 of file initsplan.c.

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

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

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

◆ setup_eager_aggregation()

void setup_eager_aggregation ( PlannerInfo root)

Definition at line 644 of file initsplan.c.

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

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

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 41 of file initsplan.c.

Referenced by deconstruct_recurse().