diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 41c1bb64e2c..e8de3afe3b5 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -29,19 +29,19 @@ static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *restrictlist, List *mergeclause_list, JoinType jointype, SpecialJoinInfo *sjinfo, - Relids param_source_rels, Relids extra_lateral_rels); + Relids param_source_rels); static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *restrictlist, List *mergeclause_list, JoinType jointype, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, - Relids param_source_rels, Relids extra_lateral_rels); + Relids param_source_rels); static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *restrictlist, JoinType jointype, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, - Relids param_source_rels, Relids extra_lateral_rels); + Relids param_source_rels); static List *select_mergejoin_clauses(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, @@ -87,7 +87,6 @@ add_paths_to_joinrel(PlannerInfo *root, bool mergejoin_allowed = true; SemiAntiJoinFactors semifactors; Relids param_source_rels = NULL; - Relids extra_lateral_rels = NULL; ListCell *lc; /* @@ -153,59 +152,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)) - param_source_rels = bms_join(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_lateral_rels = bms_add_members(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_lateral_rels = bms_del_members(extra_lateral_rels, joinrel->relids); - if (bms_is_empty(extra_lateral_rels)) - extra_lateral_rels = NULL; + param_source_rels = bms_add_members(param_source_rels, + joinrel->lateral_relids); /* * 1. Consider mergejoin paths where both relations must be explicitly @@ -215,7 +169,7 @@ add_paths_to_joinrel(PlannerInfo *root, sort_inner_and_outer(root, joinrel, outerrel, innerrel, restrictlist, mergeclause_list, jointype, sjinfo, - param_source_rels, extra_lateral_rels); + param_source_rels); /* * 2. Consider paths where the outer relation need not be explicitly @@ -228,7 +182,7 @@ add_paths_to_joinrel(PlannerInfo *root, match_unsorted_outer(root, joinrel, outerrel, innerrel, restrictlist, mergeclause_list, jointype, sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + param_source_rels); #ifdef NOT_USED @@ -247,7 +201,7 @@ add_paths_to_joinrel(PlannerInfo *root, match_unsorted_inner(root, joinrel, outerrel, innerrel, restrictlist, mergeclause_list, jointype, sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + param_source_rels); #endif /* @@ -259,7 +213,7 @@ add_paths_to_joinrel(PlannerInfo *root, hash_inner_and_outer(root, joinrel, outerrel, innerrel, restrictlist, jointype, sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + param_source_rels); } /* @@ -353,7 +307,6 @@ try_nestloop_path(PlannerInfo *root, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, Relids param_source_rels, - Relids extra_lateral_rels, Path *outer_path, Path *inner_path, List *restrict_clauses, @@ -382,9 +335,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_lateral_rels); + required_outer = bms_add_members(required_outer, joinrel->lateral_relids); /* * Do a precheck to quickly eliminate obviously-inferior paths. We @@ -434,7 +391,6 @@ try_mergejoin_path(PlannerInfo *root, JoinType jointype, SpecialJoinInfo *sjinfo, Relids param_source_rels, - Relids extra_lateral_rels, Path *outer_path, Path *inner_path, List *restrict_clauses, @@ -464,7 +420,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_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 @@ -523,7 +479,6 @@ try_hashjoin_path(PlannerInfo *root, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, Relids param_source_rels, - Relids extra_lateral_rels, Path *outer_path, Path *inner_path, List *restrict_clauses, @@ -550,7 +505,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_lateral_rels); + required_outer = bms_add_members(required_outer, joinrel->lateral_relids); /* * See comments in try_nestloop_path(). Also note that hashjoin paths @@ -630,7 +585,6 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel, * 'jointype' is the type of join to do * 'sjinfo' is extra info about the join for selectivity estimation * 'param_source_rels' are OK targets for parameterization of result paths - * 'extra_lateral_rels' are additional parameterization for result paths */ static void sort_inner_and_outer(PlannerInfo *root, @@ -641,8 +595,7 @@ sort_inner_and_outer(PlannerInfo *root, List *mergeclause_list, JoinType jointype, SpecialJoinInfo *sjinfo, - Relids param_source_rels, - Relids extra_lateral_rels) + Relids param_source_rels) { Path *outer_path; Path *inner_path; @@ -772,7 +725,6 @@ sort_inner_and_outer(PlannerInfo *root, jointype, sjinfo, param_source_rels, - extra_lateral_rels, outer_path, inner_path, restrictlist, @@ -818,7 +770,6 @@ sort_inner_and_outer(PlannerInfo *root, * 'sjinfo' is extra info about the join for selectivity estimation * 'semifactors' contains valid data if jointype is SEMI or ANTI * 'param_source_rels' are OK targets for parameterization of result paths - * 'extra_lateral_rels' are additional parameterization for result paths */ static void match_unsorted_outer(PlannerInfo *root, @@ -830,8 +781,7 @@ match_unsorted_outer(PlannerInfo *root, JoinType jointype, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, - Relids param_source_rels, - Relids extra_lateral_rels) + Relids param_source_rels) { JoinType save_jointype = jointype; bool nestjoinOK; @@ -961,7 +911,6 @@ match_unsorted_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, outerpath, inner_cheapest_total, restrictlist, @@ -987,7 +936,6 @@ match_unsorted_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, outerpath, innerpath, restrictlist, @@ -1002,7 +950,6 @@ match_unsorted_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, outerpath, matpath, restrictlist, @@ -1058,7 +1005,6 @@ match_unsorted_outer(PlannerInfo *root, jointype, sjinfo, param_source_rels, - extra_lateral_rels, outerpath, inner_cheapest_total, restrictlist, @@ -1157,7 +1103,6 @@ match_unsorted_outer(PlannerInfo *root, jointype, sjinfo, param_source_rels, - extra_lateral_rels, outerpath, innerpath, restrictlist, @@ -1203,7 +1148,6 @@ match_unsorted_outer(PlannerInfo *root, jointype, sjinfo, param_source_rels, - extra_lateral_rels, outerpath, innerpath, restrictlist, @@ -1238,7 +1182,6 @@ match_unsorted_outer(PlannerInfo *root, * 'sjinfo' is extra info about the join for selectivity estimation * 'semifactors' contains valid data if jointype is SEMI or ANTI * 'param_source_rels' are OK targets for parameterization of result paths - * 'extra_lateral_rels' are additional parameterization for result paths */ static void hash_inner_and_outer(PlannerInfo *root, @@ -1249,8 +1192,7 @@ hash_inner_and_outer(PlannerInfo *root, JoinType jointype, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, - Relids param_source_rels, - Relids extra_lateral_rels) + Relids param_source_rels) { bool isouterjoin = IS_OUTER_JOIN(jointype); List *hashclauses; @@ -1324,7 +1266,6 @@ hash_inner_and_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, cheapest_total_outer, cheapest_total_inner, restrictlist, @@ -1344,7 +1285,6 @@ hash_inner_and_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, cheapest_total_outer, cheapest_total_inner, restrictlist, @@ -1357,7 +1297,6 @@ hash_inner_and_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, cheapest_startup_outer, cheapest_total_inner, restrictlist, @@ -1382,7 +1321,6 @@ hash_inner_and_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, cheapest_startup_outer, cheapest_total_inner, restrictlist, @@ -1420,7 +1358,6 @@ hash_inner_and_outer(PlannerInfo *root, sjinfo, semifactors, param_source_rels, - extra_lateral_rels, outerpath, innerpath, restrictlist, diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 3fc7e5cf67a..9b1f33e7aa4 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -376,7 +376,7 @@ build_join_rel(PlannerInfo *root, joinrel->attr_needed = NULL; joinrel->attr_widths = NULL; joinrel->lateral_vars = NIL; - joinrel->lateral_relids = NULL; + joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids); joinrel->lateral_referencers = NULL; joinrel->indexlist = NIL; joinrel->pages = 0; diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index a1c03832f81..ff877c9707d 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -343,7 +343,7 @@ typedef struct PlannerInfo * 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) + * (this is now used for join rels too, but we won't move it till 9.5) * 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) @@ -362,7 +362,7 @@ typedef struct PlannerInfo * and fdw_private are filled during initial path creation. * * 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. * * The presence of the remaining fields depends on the restrictions * and joins that the relation participates in: