diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 012c14bf29af37ff48897edbc85a0cb79f1db1a7..c709105d4fe09e6e9fd2835c51969f26fa813a0b 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1891,13 +1891,13 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) WRITE_NODE_FIELD(cheapest_total_path); WRITE_NODE_FIELD(cheapest_unique_path); WRITE_NODE_FIELD(cheapest_parameterized_paths); + WRITE_BITMAPSET_FIELD(lateral_relids); WRITE_UINT_FIELD(relid); WRITE_OID_FIELD(reltablespace); WRITE_ENUM_FIELD(rtekind, RTEKind); WRITE_INT_FIELD(min_attr); WRITE_INT_FIELD(max_attr); WRITE_NODE_FIELD(lateral_vars); - WRITE_BITMAPSET_FIELD(lateral_relids); WRITE_BITMAPSET_FIELD(lateral_referencers); WRITE_NODE_FIELD(indexlist); WRITE_UINT_FIELD(pages); diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index a35c881fd92bde6ed13c7273b254d3cac034a1e8..0f04033166588adc157d18f5d50ce1c1f07ddb30 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -86,7 +86,6 @@ add_paths_to_joinrel(PlannerInfo *root, extra.mergeclause_list = NIL; extra.sjinfo = sjinfo; extra.param_source_rels = NULL; - extra.extra_lateral_rels = NULL; /* * Find potential mergejoin clauses. We can skip this if we are not @@ -151,60 +150,14 @@ add_paths_to_joinrel(PlannerInfo *root, } /* - * However, when a LATERAL subquery is involved, we have to be a bit - * laxer, because there will simply not be any paths for the joinrel that - * aren't parameterized by whatever the subquery is parameterized by, - * unless its parameterization is resolved within the joinrel. Hence, add - * to param_source_rels anything that is laterally referenced in either - * input and is not in the join already. + * However, when a LATERAL subquery is involved, there will simply not be + * any paths for the joinrel that aren't parameterized by whatever the + * subquery is parameterized by, unless its parameterization is resolved + * within the joinrel. So we might as well allow additional dependencies + * on whatever residual lateral dependencies the joinrel will have. */ - foreach(lc, root->lateral_info_list) - { - LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc); - - if (bms_is_subset(ljinfo->lateral_rhs, joinrel->relids)) - extra.param_source_rels = bms_join(extra.param_source_rels, - bms_difference(ljinfo->lateral_lhs, - joinrel->relids)); - } - - /* - * Another issue created by LATERAL references is that PlaceHolderVars - * that need to be computed at this join level might contain lateral - * references to rels not in the join, meaning that the paths for the join - * would need to be marked as parameterized by those rels, independently - * of all other considerations. Set extra_lateral_rels to the set of such - * rels. This will not affect our decisions as to which paths to - * generate; we merely add these rels to their required_outer sets. - */ - foreach(lc, root->placeholder_list) - { - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); - - /* PHVs without lateral refs can be skipped over quickly */ - if (phinfo->ph_lateral == NULL) - continue; - /* Is it due to be evaluated at this join, and not in either input? */ - if (bms_is_subset(phinfo->ph_eval_at, joinrel->relids) && - !bms_is_subset(phinfo->ph_eval_at, outerrel->relids) && - !bms_is_subset(phinfo->ph_eval_at, innerrel->relids)) - { - /* Yes, remember its lateral rels */ - extra.extra_lateral_rels = bms_add_members(extra.extra_lateral_rels, - phinfo->ph_lateral); - } - } - - /* - * Make sure extra_lateral_rels doesn't list anything within the join, and - * that it's NULL if empty. (This allows us to use bms_add_members to add - * it to required_outer below, while preserving the property that - * required_outer is exactly NULL if empty.) - */ - extra.extra_lateral_rels = bms_del_members(extra.extra_lateral_rels, - joinrel->relids); - if (bms_is_empty(extra.extra_lateral_rels)) - extra.extra_lateral_rels = NULL; + extra.param_source_rels = bms_add_members(extra.param_source_rels, + joinrel->lateral_relids); /* * 1. Consider mergejoin paths where both relations must be explicitly @@ -386,9 +339,13 @@ try_nestloop_path(PlannerInfo *root, /* * Independently of that, add parameterization needed for any - * PlaceHolderVars that need to be computed at the join. + * PlaceHolderVars that need to be computed at the join. We can handle + * that just by adding joinrel->lateral_relids; that might include some + * rels that are already in required_outer, but no harm done. (Note that + * lateral_relids is exactly NULL if empty, so this will not break the + * property that required_outer is too.) */ - required_outer = bms_add_members(required_outer, extra->extra_lateral_rels); + required_outer = bms_add_members(required_outer, joinrel->lateral_relids); /* * Do a precheck to quickly eliminate obviously-inferior paths. We @@ -465,7 +422,7 @@ try_mergejoin_path(PlannerInfo *root, * Independently of that, add parameterization needed for any * PlaceHolderVars that need to be computed at the join. */ - required_outer = bms_add_members(required_outer, extra->extra_lateral_rels); + required_outer = bms_add_members(required_outer, joinrel->lateral_relids); /* * If the given paths are already well enough ordered, we can skip doing @@ -547,7 +504,7 @@ try_hashjoin_path(PlannerInfo *root, * Independently of that, add parameterization needed for any * PlaceHolderVars that need to be computed at the join. */ - required_outer = bms_add_members(required_outer, extra->extra_lateral_rels); + required_outer = bms_add_members(required_outer, joinrel->lateral_relids); /* * See comments in try_nestloop_path(). Also note that hashjoin paths diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 8cc7bd771b32f5d466f1e18889ec387a852982e6..b197f144117f3b0e479919f33c203266c55b89b7 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -103,7 +103,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) /* cheap startup cost is interesting iff not all tuples to be retrieved */ rel->consider_startup = (root->tuple_fraction > 0); rel->consider_param_startup = false; /* might get changed later */ - rel->consider_parallel = false; /* might get changed later */ + rel->consider_parallel = false; /* might get changed later */ rel->reltargetlist = NIL; rel->pathlist = NIL; rel->ppilist = NIL; @@ -111,11 +111,11 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->cheapest_total_path = NULL; rel->cheapest_unique_path = NULL; rel->cheapest_parameterized_paths = NIL; + rel->lateral_relids = NULL; rel->relid = relid; rel->rtekind = rte->rtekind; /* min_attr, max_attr, attr_needed, attr_widths are set below */ rel->lateral_vars = NIL; - rel->lateral_relids = NULL; rel->lateral_referencers = NULL; rel->indexlist = NIL; rel->pages = 0; @@ -373,6 +373,7 @@ build_join_rel(PlannerInfo *root, joinrel->cheapest_total_path = NULL; joinrel->cheapest_unique_path = NULL; joinrel->cheapest_parameterized_paths = NIL; + joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids); joinrel->relid = 0; /* indicates not a baserel */ joinrel->rtekind = RTE_JOIN; joinrel->min_attr = 0; @@ -380,7 +381,6 @@ build_join_rel(PlannerInfo *root, joinrel->attr_needed = NULL; joinrel->attr_widths = NULL; joinrel->lateral_vars = NIL; - joinrel->lateral_relids = NULL; joinrel->lateral_referencers = NULL; joinrel->indexlist = NIL; joinrel->pages = 0; @@ -448,15 +448,15 @@ build_join_rel(PlannerInfo *root, * Set the consider_parallel flag if this joinrel could potentially be * scanned within a parallel worker. If this flag is false for either * inner_rel or outer_rel, then it must be false for the joinrel also. - * Even if both are true, there might be parallel-restricted quals at - * our level. + * Even if both are true, there might be parallel-restricted quals at our + * level. * - * Note that if there are more than two rels in this relation, they - * could be divided between inner_rel and outer_rel in any arbitary - * way. We assume this doesn't matter, because we should hit all the - * same baserels and joinclauses while building up to this joinrel no - * matter which we take; therefore, we should make the same decision - * here however we get here. + * Note that if there are more than two rels in this relation, they could + * be divided between inner_rel and outer_rel in any arbitary way. We + * assume this doesn't matter, because we should hit all the same baserels + * and joinclauses while building up to this joinrel no matter which we + * take; therefore, we should make the same decision here however we get + * here. */ if (inner_rel->consider_parallel && outer_rel->consider_parallel && !has_parallel_hazard((Node *) restrictlist, false)) diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 9a0dd28195f1ddf22fa2ef6822c52207832e7529..6de07a1fbd0467db6faad7babf1df1ed8407be00 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -99,15 +99,15 @@ typedef struct PlannerGlobal Index lastRowMarkId; /* highest PlanRowMark ID assigned */ - int lastPlanNodeId; /* highest plan node ID assigned */ + int lastPlanNodeId; /* highest plan node ID assigned */ bool transientPlan; /* redo plan when TransactionXmin changes? */ bool hasRowSecurity; /* row security applied? */ - bool parallelModeOK; /* parallel mode potentially OK? */ + bool parallelModeOK; /* parallel mode potentially OK? */ - bool parallelModeNeeded; /* parallel mode actually required? */ + bool parallelModeNeeded; /* parallel mode actually required? */ } PlannerGlobal; /* macro for fetching the Plan associated with a SubPlan node */ @@ -357,6 +357,7 @@ typedef struct PlannerInfo * (no duplicates) output from relation; NULL if not yet requested * cheapest_parameterized_paths - best paths for their parameterizations; * always includes cheapest_total_path, even if that's unparameterized + * lateral_relids - required outer rels for LATERAL, as a Relids set * * If the relation is a base relation it will have these fields set: * @@ -371,8 +372,6 @@ typedef struct PlannerInfo * zero means not computed yet * lateral_vars - lateral cross-references of rel, if any (list of * Vars and PlaceHolderVars) - * lateral_relids - required outer rels for LATERAL, as a Relids set - * (for child rels this can be more than lateral_vars) * lateral_referencers - relids of rels that reference this one laterally * indexlist - list of IndexOptInfo nodes for relation's indexes * (always NIL if it's not a table) @@ -388,7 +387,7 @@ typedef struct PlannerInfo * set_subquery_pathlist processes the object. * * For otherrels that are appendrel members, these fields are filled - * in just as for a baserel. + * in just as for a baserel, except we don't bother with lateral_vars. * * If the relation is either a foreign table or a join of foreign tables that * all belong to the same foreign server, these fields will be set: @@ -463,6 +462,10 @@ typedef struct RelOptInfo struct Path *cheapest_unique_path; List *cheapest_parameterized_paths; + /* parameterization information needed for both base rels and join rels */ + /* (see also lateral_vars and lateral_referencers) */ + Relids lateral_relids; /* minimum parameterization of rel */ + /* information about a base rel (not set for join rels!) */ Index relid; Oid reltablespace; /* containing tablespace */ @@ -472,7 +475,6 @@ typedef struct RelOptInfo Relids *attr_needed; /* array indexed [min_attr .. max_attr] */ int32 *attr_widths; /* array indexed [min_attr .. max_attr] */ List *lateral_vars; /* LATERAL Vars and PHVs referenced by rel */ - Relids lateral_relids; /* minimum parameterization of rel */ Relids lateral_referencers; /* rels that reference me laterally */ List *indexlist; /* list of IndexOptInfo */ BlockNumber pages; /* size estimates derived from pg_class */ @@ -1717,7 +1719,6 @@ typedef struct SemiAntiJoinFactors * sjinfo is extra info about special joins for selectivity estimation * semifactors is as shown above (only valid for SEMI or ANTI joins) * param_source_rels are OK targets for parameterization of result paths - * extra_lateral_rels are additional parameterization for result paths */ typedef struct JoinPathExtraData { @@ -1726,7 +1727,6 @@ typedef struct JoinPathExtraData SpecialJoinInfo *sjinfo; SemiAntiJoinFactors semifactors; Relids param_source_rels; - Relids extra_lateral_rels; } JoinPathExtraData; /*