diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 342 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 83 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 256 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 7 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 27 |
6 files changed, 298 insertions, 419 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index dabef3c3c7f..ba78252b8f9 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -30,21 +30,13 @@ set_join_pathlist_hook_type set_join_pathlist_hook = NULL; 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); + JoinType jointype, JoinPathExtraData *extra); 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); + JoinType jointype, JoinPathExtraData *extra); 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); + JoinType jointype, JoinPathExtraData *extra); static List *select_mergejoin_clauses(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, @@ -86,13 +78,16 @@ add_paths_to_joinrel(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *restrictlist) { - List *mergeclause_list = NIL; + JoinPathExtraData extra; bool mergejoin_allowed = true; - SemiAntiJoinFactors semifactors; - Relids param_source_rels = NULL; - Relids extra_lateral_rels = NULL; ListCell *lc; + extra.restrictlist = restrictlist; + 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 * interested in doing a mergejoin. However, mergejoin may be our only @@ -100,13 +95,13 @@ add_paths_to_joinrel(PlannerInfo *root, * it's a full join. */ if (enable_mergejoin || jointype == JOIN_FULL) - mergeclause_list = select_mergejoin_clauses(root, - joinrel, - outerrel, - innerrel, - restrictlist, - jointype, - &mergejoin_allowed); + extra.mergeclause_list = select_mergejoin_clauses(root, + joinrel, + outerrel, + innerrel, + restrictlist, + jointype, + &mergejoin_allowed); /* * If it's SEMI or ANTI join, compute correction factors for cost @@ -115,7 +110,7 @@ add_paths_to_joinrel(PlannerInfo *root, if (jointype == JOIN_SEMI || jointype == JOIN_ANTI) compute_semi_anti_join_factors(root, outerrel, innerrel, jointype, sjinfo, restrictlist, - &semifactors); + &extra.semifactors); /* * Decide whether it's sensible to generate parameterized paths for this @@ -142,16 +137,16 @@ add_paths_to_joinrel(PlannerInfo *root, */ if (bms_overlap(joinrel->relids, sjinfo->min_righthand) && !bms_overlap(joinrel->relids, sjinfo->min_lefthand)) - param_source_rels = bms_join(param_source_rels, - bms_difference(root->all_baserels, + extra.param_source_rels = bms_join(extra.param_source_rels, + bms_difference(root->all_baserels, sjinfo->min_righthand)); /* full joins constrain both sides symmetrically */ if (sjinfo->jointype == JOIN_FULL && bms_overlap(joinrel->relids, sjinfo->min_lefthand) && !bms_overlap(joinrel->relids, sjinfo->min_righthand)) - param_source_rels = bms_join(param_source_rels, - bms_difference(root->all_baserels, + extra.param_source_rels = bms_join(extra.param_source_rels, + bms_difference(root->all_baserels, sjinfo->min_lefthand)); } @@ -168,9 +163,9 @@ add_paths_to_joinrel(PlannerInfo *root, 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)); + extra.param_source_rels = bms_join(extra.param_source_rels, + bms_difference(ljinfo->lateral_lhs, + joinrel->relids)); } /* @@ -195,8 +190,8 @@ add_paths_to_joinrel(PlannerInfo *root, !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); + extra.extra_lateral_rels = bms_add_members(extra.extra_lateral_rels, + phinfo->ph_lateral); } } @@ -206,9 +201,10 @@ add_paths_to_joinrel(PlannerInfo *root, * 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; + 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; /* * 1. Consider mergejoin paths where both relations must be explicitly @@ -216,9 +212,7 @@ add_paths_to_joinrel(PlannerInfo *root, */ if (mergejoin_allowed) sort_inner_and_outer(root, joinrel, outerrel, innerrel, - restrictlist, mergeclause_list, jointype, - sjinfo, - param_source_rels, extra_lateral_rels); + jointype, &extra); /* * 2. Consider paths where the outer relation need not be explicitly @@ -229,9 +223,7 @@ add_paths_to_joinrel(PlannerInfo *root, */ if (mergejoin_allowed) match_unsorted_outer(root, joinrel, outerrel, innerrel, - restrictlist, mergeclause_list, jointype, - sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + jointype, &extra); #ifdef NOT_USED @@ -248,9 +240,7 @@ add_paths_to_joinrel(PlannerInfo *root, */ if (mergejoin_allowed) match_unsorted_inner(root, joinrel, outerrel, innerrel, - restrictlist, mergeclause_list, jointype, - sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + jointype, &extra); #endif /* @@ -260,30 +250,24 @@ add_paths_to_joinrel(PlannerInfo *root, */ if (enable_hashjoin || jointype == JOIN_FULL) hash_inner_and_outer(root, joinrel, outerrel, innerrel, - restrictlist, jointype, - sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + jointype, &extra); /* - * 5. If both inner and outer relations are managed by the same FDW, - * give it a chance to push down joins. + * 5. If inner and outer relations are foreign tables (or joins) belonging + * to the same server, give the FDW a chance to push down joins. */ if (joinrel->fdwroutine && joinrel->fdwroutine->GetForeignJoinPaths) joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel, outerrel, innerrel, - restrictlist, jointype, sjinfo, - &semifactors, - param_source_rels, - extra_lateral_rels); + jointype, &extra); + /* * 6. Finally, give extensions a chance to manipulate the path list. */ if (set_join_pathlist_hook) set_join_pathlist_hook(root, joinrel, outerrel, innerrel, - restrictlist, jointype, - sjinfo, &semifactors, - param_source_rels, extra_lateral_rels); + jointype, &extra); } /* @@ -294,15 +278,11 @@ add_paths_to_joinrel(PlannerInfo *root, static void try_nestloop_path(PlannerInfo *root, RelOptInfo *joinrel, - JoinType jointype, - SpecialJoinInfo *sjinfo, - SemiAntiJoinFactors *semifactors, - Relids param_source_rels, - Relids extra_lateral_rels, Path *outer_path, Path *inner_path, - List *restrict_clauses, - List *pathkeys) + List *pathkeys, + JoinType jointype, + JoinPathExtraData *extra) { Relids required_outer; JoinCostWorkspace workspace; @@ -314,7 +294,7 @@ try_nestloop_path(PlannerInfo *root, required_outer = calc_nestloop_required_outer(outer_path, inner_path); if (required_outer && - !bms_overlap(required_outer, param_source_rels)) + !bms_overlap(required_outer, extra->param_source_rels)) { /* * We override the param_source_rels heuristic to accept nestloop @@ -345,7 +325,7 @@ try_nestloop_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, extra->extra_lateral_rels); /* * Do a precheck to quickly eliminate obviously-inferior paths. We @@ -358,7 +338,7 @@ try_nestloop_path(PlannerInfo *root, */ initial_cost_nestloop(root, &workspace, jointype, outer_path, inner_path, - sjinfo, semifactors); + extra->sjinfo, &extra->semifactors); if (add_path_precheck(joinrel, workspace.startup_cost, workspace.total_cost, @@ -369,11 +349,11 @@ try_nestloop_path(PlannerInfo *root, joinrel, jointype, &workspace, - sjinfo, - semifactors, + extra->sjinfo, + &extra->semifactors, outer_path, inner_path, - restrict_clauses, + extra->restrictlist, pathkeys, required_outer)); } @@ -392,17 +372,14 @@ try_nestloop_path(PlannerInfo *root, static void try_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, - JoinType jointype, - SpecialJoinInfo *sjinfo, - Relids param_source_rels, - Relids extra_lateral_rels, Path *outer_path, Path *inner_path, - List *restrict_clauses, List *pathkeys, List *mergeclauses, List *outersortkeys, - List *innersortkeys) + List *innersortkeys, + JoinType jointype, + JoinPathExtraData *extra) { Relids required_outer; JoinCostWorkspace workspace; @@ -414,7 +391,7 @@ try_mergejoin_path(PlannerInfo *root, required_outer = calc_non_nestloop_required_outer(outer_path, inner_path); if (required_outer && - !bms_overlap(required_outer, param_source_rels)) + !bms_overlap(required_outer, extra->param_source_rels)) { /* Waste no memory when we reject a path here */ bms_free(required_outer); @@ -425,7 +402,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, extra->extra_lateral_rels); /* * If the given paths are already well enough ordered, we can skip doing @@ -444,7 +421,7 @@ try_mergejoin_path(PlannerInfo *root, initial_cost_mergejoin(root, &workspace, jointype, mergeclauses, outer_path, inner_path, outersortkeys, innersortkeys, - sjinfo); + extra->sjinfo); if (add_path_precheck(joinrel, workspace.startup_cost, workspace.total_cost, @@ -455,10 +432,10 @@ try_mergejoin_path(PlannerInfo *root, joinrel, jointype, &workspace, - sjinfo, + extra->sjinfo, outer_path, inner_path, - restrict_clauses, + extra->restrictlist, pathkeys, required_outer, mergeclauses, @@ -480,15 +457,11 @@ try_mergejoin_path(PlannerInfo *root, static void try_hashjoin_path(PlannerInfo *root, RelOptInfo *joinrel, - JoinType jointype, - SpecialJoinInfo *sjinfo, - SemiAntiJoinFactors *semifactors, - Relids param_source_rels, - Relids extra_lateral_rels, Path *outer_path, Path *inner_path, - List *restrict_clauses, - List *hashclauses) + List *hashclauses, + JoinType jointype, + JoinPathExtraData *extra) { Relids required_outer; JoinCostWorkspace workspace; @@ -500,7 +473,7 @@ try_hashjoin_path(PlannerInfo *root, required_outer = calc_non_nestloop_required_outer(outer_path, inner_path); if (required_outer && - !bms_overlap(required_outer, param_source_rels)) + !bms_overlap(required_outer, extra->param_source_rels)) { /* Waste no memory when we reject a path here */ bms_free(required_outer); @@ -511,7 +484,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, extra->extra_lateral_rels); /* * See comments in try_nestloop_path(). Also note that hashjoin paths @@ -519,7 +492,7 @@ try_hashjoin_path(PlannerInfo *root, */ initial_cost_hashjoin(root, &workspace, jointype, hashclauses, outer_path, inner_path, - sjinfo, semifactors); + extra->sjinfo, &extra->semifactors); if (add_path_precheck(joinrel, workspace.startup_cost, workspace.total_cost, @@ -530,11 +503,11 @@ try_hashjoin_path(PlannerInfo *root, joinrel, jointype, &workspace, - sjinfo, - semifactors, + extra->sjinfo, + &extra->semifactors, outer_path, inner_path, - restrict_clauses, + extra->restrictlist, required_outer, hashclauses)); } @@ -584,26 +557,16 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel, * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation - * 'restrictlist' contains all of the RestrictInfo nodes for restriction - * clauses that apply to this join - * 'mergeclause_list' is a list of RestrictInfo nodes for available - * mergejoin clauses in this join * '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 + * 'extra' contains additional input values */ 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) + JoinPathExtraData *extra) { Path *outer_path; Path *inner_path; @@ -643,14 +606,14 @@ sort_inner_and_outer(PlannerInfo *root, if (jointype == JOIN_UNIQUE_OUTER) { outer_path = (Path *) create_unique_path(root, outerrel, - outer_path, sjinfo); + outer_path, extra->sjinfo); Assert(outer_path); jointype = JOIN_INNER; } else if (jointype == JOIN_UNIQUE_INNER) { inner_path = (Path *) create_unique_path(root, innerrel, - inner_path, sjinfo); + inner_path, extra->sjinfo); Assert(inner_path); jointype = JOIN_INNER; } @@ -684,7 +647,7 @@ sort_inner_and_outer(PlannerInfo *root, * exactly as-is as well as making variants. */ all_pathkeys = select_outer_pathkeys_for_merge(root, - mergeclause_list, + extra->mergeclause_list, joinrel); foreach(l, all_pathkeys) @@ -707,10 +670,10 @@ sort_inner_and_outer(PlannerInfo *root, cur_mergeclauses = find_mergeclauses_for_pathkeys(root, outerkeys, true, - mergeclause_list); + extra->mergeclause_list); /* Should have used them all... */ - Assert(list_length(cur_mergeclauses) == list_length(mergeclause_list)); + Assert(list_length(cur_mergeclauses) == list_length(extra->mergeclause_list)); /* Build sort pathkeys for the inner side */ innerkeys = make_inner_pathkeys_for_merge(root, @@ -730,17 +693,14 @@ sort_inner_and_outer(PlannerInfo *root, */ try_mergejoin_path(root, joinrel, - jointype, - sjinfo, - param_source_rels, - extra_lateral_rels, outer_path, inner_path, - restrictlist, merge_pathkeys, cur_mergeclauses, outerkeys, - innerkeys); + innerkeys, + jointype, + extra); } } @@ -771,28 +731,16 @@ sort_inner_and_outer(PlannerInfo *root, * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation - * 'restrictlist' contains all of the RestrictInfo nodes for restriction - * clauses that apply to this join - * 'mergeclause_list' is a list of RestrictInfo nodes for available - * mergejoin clauses in this join * 'jointype' is the type of join to do - * '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 + * 'extra' contains additional input values */ 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) + JoinPathExtraData *extra) { JoinType save_jointype = jointype; bool nestjoinOK; @@ -854,7 +802,7 @@ match_unsorted_outer(PlannerInfo *root, if (inner_cheapest_total == NULL) return; inner_cheapest_total = (Path *) - create_unique_path(root, innerrel, inner_cheapest_total, sjinfo); + create_unique_path(root, innerrel, inner_cheapest_total, extra->sjinfo); Assert(inner_cheapest_total); } else if (nestjoinOK) @@ -898,7 +846,7 @@ match_unsorted_outer(PlannerInfo *root, if (outerpath != outerrel->cheapest_total_path) continue; outerpath = (Path *) create_unique_path(root, outerrel, - outerpath, sjinfo); + outerpath, extra->sjinfo); Assert(outerpath); } @@ -918,15 +866,11 @@ match_unsorted_outer(PlannerInfo *root, */ try_nestloop_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, outerpath, inner_cheapest_total, - restrictlist, - merge_pathkeys); + merge_pathkeys, + jointype, + extra); } else if (nestjoinOK) { @@ -944,30 +888,22 @@ match_unsorted_outer(PlannerInfo *root, try_nestloop_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, outerpath, innerpath, - restrictlist, - merge_pathkeys); + merge_pathkeys, + jointype, + extra); } /* Also consider materialized form of the cheapest inner path */ if (matpath != NULL) try_nestloop_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, outerpath, matpath, - restrictlist, - merge_pathkeys); + merge_pathkeys, + jointype, + extra); } /* Can't do anything else if outer path needs to be unique'd */ @@ -982,7 +918,7 @@ match_unsorted_outer(PlannerInfo *root, mergeclauses = find_mergeclauses_for_pathkeys(root, outerpath->pathkeys, true, - mergeclause_list); + extra->mergeclause_list); /* * Done with this outer path if no chance for a mergejoin. @@ -1000,7 +936,7 @@ match_unsorted_outer(PlannerInfo *root, else continue; } - if (useallclauses && list_length(mergeclauses) != list_length(mergeclause_list)) + if (useallclauses && list_length(mergeclauses) != list_length(extra->mergeclause_list)) continue; /* Compute the required ordering of the inner path */ @@ -1016,17 +952,14 @@ match_unsorted_outer(PlannerInfo *root, */ try_mergejoin_path(root, joinrel, - jointype, - sjinfo, - param_source_rels, - extra_lateral_rels, outerpath, inner_cheapest_total, - restrictlist, merge_pathkeys, mergeclauses, NIL, - innersortkeys); + innersortkeys, + jointype, + extra); /* Can't do anything else if inner path needs to be unique'd */ if (save_jointype == JOIN_UNIQUE_INNER) @@ -1115,17 +1048,14 @@ match_unsorted_outer(PlannerInfo *root, newclauses = mergeclauses; try_mergejoin_path(root, joinrel, - jointype, - sjinfo, - param_source_rels, - extra_lateral_rels, outerpath, innerpath, - restrictlist, merge_pathkeys, newclauses, NIL, - NIL); + NIL, + jointype, + extra); cheapest_total_inner = innerpath; } /* Same on the basis of cheapest startup cost ... */ @@ -1161,17 +1091,14 @@ match_unsorted_outer(PlannerInfo *root, } try_mergejoin_path(root, joinrel, - jointype, - sjinfo, - param_source_rels, - extra_lateral_rels, outerpath, innerpath, - restrictlist, merge_pathkeys, newclauses, NIL, - NIL); + NIL, + jointype, + extra); } cheapest_startup_inner = innerpath; } @@ -1193,25 +1120,16 @@ match_unsorted_outer(PlannerInfo *root, * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation - * 'restrictlist' contains all of the RestrictInfo nodes for restriction - * clauses that apply to this join * 'jointype' is the type of join to do - * '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 + * 'extra' contains additional input values */ 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) + JoinPathExtraData *extra) { bool isouterjoin = IS_OUTER_JOIN(jointype); List *hashclauses; @@ -1225,7 +1143,7 @@ hash_inner_and_outer(PlannerInfo *root, * usable with this pair of sub-relations. */ hashclauses = NIL; - foreach(l, restrictlist) + foreach(l, extra->restrictlist) { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); @@ -1276,53 +1194,41 @@ hash_inner_and_outer(PlannerInfo *root, { cheapest_total_outer = (Path *) create_unique_path(root, outerrel, - cheapest_total_outer, sjinfo); + cheapest_total_outer, extra->sjinfo); Assert(cheapest_total_outer); jointype = JOIN_INNER; try_hashjoin_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, cheapest_total_outer, cheapest_total_inner, - restrictlist, - hashclauses); + hashclauses, + jointype, + extra); /* no possibility of cheap startup here */ } else if (jointype == JOIN_UNIQUE_INNER) { cheapest_total_inner = (Path *) create_unique_path(root, innerrel, - cheapest_total_inner, sjinfo); + cheapest_total_inner, extra->sjinfo); Assert(cheapest_total_inner); jointype = JOIN_INNER; try_hashjoin_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, cheapest_total_outer, cheapest_total_inner, - restrictlist, - hashclauses); + hashclauses, + jointype, + extra); if (cheapest_startup_outer != NULL && cheapest_startup_outer != cheapest_total_outer) try_hashjoin_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, cheapest_startup_outer, cheapest_total_inner, - restrictlist, - hashclauses); + hashclauses, + jointype, + extra); } else { @@ -1339,15 +1245,11 @@ hash_inner_and_outer(PlannerInfo *root, if (cheapest_startup_outer != NULL) try_hashjoin_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, cheapest_startup_outer, cheapest_total_inner, - restrictlist, - hashclauses); + hashclauses, + jointype, + extra); foreach(lc1, outerrel->cheapest_parameterized_paths) { @@ -1377,15 +1279,11 @@ hash_inner_and_outer(PlannerInfo *root, try_hashjoin_path(root, joinrel, - jointype, - sjinfo, - semifactors, - param_source_rels, - extra_lateral_rels, outerpath, innerpath, - restrictlist, - hashclauses); + hashclauses, + jointype, + extra); } } } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 3246332d6e3..c8092372831 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -44,6 +44,7 @@ #include "utils/lsyscache.h" +static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path); static Plan *create_scan_plan(PlannerInfo *root, Path *best_path); static List *build_path_tlist(PlannerInfo *root, Path *path); static bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel); @@ -219,7 +220,7 @@ create_plan(PlannerInfo *root, Path *best_path) * create_plan_recurse * Recursive guts of create_plan(). */ -Plan * +static Plan * create_plan_recurse(PlannerInfo *root, Path *best_path) { Plan *plan; @@ -1950,7 +1951,7 @@ create_worktablescan_plan(PlannerInfo *root, Path *best_path, /* * create_foreignscan_plan - * Returns a foreignscan plan for the base relation scanned by 'best_path' + * Returns a foreignscan plan for the relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */ static ForeignScan * @@ -1965,9 +1966,11 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, ListCell *lc; int i; + Assert(rel->fdwroutine != NULL); + /* - * If we're scanning a base relation, look up the OID. - * (We can skip this if scanning a join relation.) + * If we're scanning a base relation, fetch its OID. (Irrelevant if + * scanning a join relation.) */ if (scan_relid > 0) { @@ -1978,7 +1981,6 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, Assert(rte->rtekind == RTE_RELATION); rel_oid = rte->relid; } - Assert(rel->fdwroutine != NULL); /* * Sort clauses into best execution order. We do this first since the FDW @@ -1996,42 +1998,22 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, scan_plan = rel->fdwroutine->GetForeignPlan(root, rel, rel_oid, best_path, tlist, scan_clauses); - /* - * Sanity check. There may be resjunk entries in fdw_ps_tlist that - * are included only to help EXPLAIN deparse plans properly. We require - * that these are at the end, so that when the executor builds the scan - * descriptor based on the non-junk entries, it gets the attribute - * numbers correct. - */ - if (scan_plan->scan.scanrelid == 0) - { - bool found_resjunk = false; - - foreach (lc, scan_plan->fdw_ps_tlist) - { - TargetEntry *tle = lfirst(lc); - - if (tle->resjunk) - found_resjunk = true; - else if (found_resjunk) - elog(ERROR, "junk TLE should not apper prior to valid one"); - } - } - /* Set the relids that are represented by this foreign scan for Explain */ - scan_plan->fdw_relids = best_path->path.parent->relids; /* Copy cost data from Path to Plan; no need to make FDW do this */ copy_path_costsize(&scan_plan->scan.plan, &best_path->path); - /* Track FDW server-id; no need to make FDW do this */ - scan_plan->fdw_handler = rel->fdw_handler; + /* Copy foreign server OID; likewise, no need to make FDW do this */ + scan_plan->fs_server = rel->serverid; + + /* Likewise, copy the relids that are represented by this foreign scan */ + scan_plan->fs_relids = best_path->path.parent->relids; /* * Replace any outer-relation variables with nestloop params in the qual * and fdw_exprs expressions. We do this last so that the FDW doesn't * have to be involved. (Note that parts of fdw_exprs could have come * from join clauses, so doing this beforehand on the scan_clauses - * wouldn't work.) + * wouldn't work.) We assume fdw_scan_tlist contains no such variables. */ if (best_path->path.param_info) { @@ -2087,7 +2069,6 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path, { CustomScan *cplan; RelOptInfo *rel = best_path->path.parent; - ListCell *lc; /* * Sort clauses into the best execution order, although custom-scan @@ -2107,41 +2088,21 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path, Assert(IsA(cplan, CustomScan)); /* - * Sanity check. There may be resjunk entries in custom_ps_tlist that - * are included only to help EXPLAIN deparse plans properly. We require - * that these are at the end, so that when the executor builds the scan - * descriptor based on the non-junk entries, it gets the attribute - * numbers correct. - */ - if (cplan->scan.scanrelid == 0) - { - bool found_resjunk = false; - - foreach (lc, cplan->custom_ps_tlist) - { - TargetEntry *tle = lfirst(lc); - - if (tle->resjunk) - found_resjunk = true; - else if (found_resjunk) - elog(ERROR, "junk TLE should not apper prior to valid one"); - } - } - /* Set the relids that are represented by this custom scan for Explain */ - cplan->custom_relids = best_path->path.parent->relids; - - /* * Copy cost data from Path to Plan; no need to make custom-plan providers * do this */ copy_path_costsize(&cplan->scan.plan, &best_path->path); + /* Likewise, copy the relids that are represented by this custom scan */ + cplan->custom_relids = best_path->path.parent->relids; + /* * Replace any outer-relation variables with nestloop params in the qual * and custom_exprs expressions. We do this last so that the custom-plan * provider doesn't have to be involved. (Note that parts of custom_exprs * could have come from join clauses, so doing this beforehand on the - * scan_clauses wouldn't work.) + * scan_clauses wouldn't work.) We assume custom_scan_tlist contains no + * such variables. */ if (best_path->path.param_info) { @@ -3611,7 +3572,8 @@ make_foreignscan(List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, - List *fdw_private) + List *fdw_private, + List *fdw_scan_tlist) { ForeignScan *node = makeNode(ForeignScan); Plan *plan = &node->scan.plan; @@ -3622,8 +3584,13 @@ make_foreignscan(List *qptlist, plan->lefttree = NULL; plan->righttree = NULL; node->scan.scanrelid = scanrelid; + /* fs_server will be filled in by create_foreignscan_plan */ + node->fs_server = InvalidOid; node->fdw_exprs = fdw_exprs; node->fdw_private = fdw_private; + node->fdw_scan_tlist = fdw_scan_tlist; + /* fs_relids will be filled in by create_foreignscan_plan */ + node->fs_relids = NULL; /* fsSystemCol will be filled in by create_foreignscan_plan */ node->fsSystemCol = false; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 612d32571af..fac51c91474 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -86,12 +86,6 @@ static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte); static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob); static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte); static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset); -static void set_foreignscan_references(PlannerInfo *root, - ForeignScan *fscan, - int rtoffset); -static void set_customscan_references(PlannerInfo *root, - CustomScan *cscan, - int rtoffset); static Plan *set_indexonlyscan_references(PlannerInfo *root, IndexOnlyScan *plan, int rtoffset); @@ -99,6 +93,12 @@ static Plan *set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset); static bool trivial_subqueryscan(SubqueryScan *plan); +static void set_foreignscan_references(PlannerInfo *root, + ForeignScan *fscan, + int rtoffset); +static void set_customscan_references(PlannerInfo *root, + CustomScan *cscan, + int rtoffset); static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset); static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context); static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context); @@ -573,7 +573,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) case T_ForeignScan: set_foreignscan_references(root, (ForeignScan *) plan, rtoffset); break; - case T_CustomScan: set_customscan_references(root, (CustomScan *) plan, rtoffset); break; @@ -891,121 +890,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } /* - * set_foreignscan_references - * Do set_plan_references processing on an ForeignScan - */ -static void -set_foreignscan_references(PlannerInfo *root, - ForeignScan *fscan, - int rtoffset) -{ - if (rtoffset > 0) - { - Bitmapset *tempset = NULL; - int x = -1; - - while ((x = bms_next_member(fscan->fdw_relids, x)) >= 0) - tempset = bms_add_member(tempset, x + rtoffset); - fscan->fdw_relids = tempset; - } - - if (fscan->scan.scanrelid == 0) - { - indexed_tlist *pscan_itlist = build_tlist_index(fscan->fdw_ps_tlist); - - fscan->scan.plan.targetlist = (List *) - fix_upper_expr(root, - (Node *) fscan->scan.plan.targetlist, - pscan_itlist, - INDEX_VAR, - rtoffset); - fscan->scan.plan.qual = (List *) - fix_upper_expr(root, - (Node *) fscan->scan.plan.qual, - pscan_itlist, - INDEX_VAR, - rtoffset); - fscan->fdw_exprs = (List *) - fix_upper_expr(root, - (Node *) fscan->fdw_exprs, - pscan_itlist, - INDEX_VAR, - rtoffset); - fscan->fdw_ps_tlist = - fix_scan_list(root, fscan->fdw_ps_tlist, rtoffset); - pfree(pscan_itlist); - } - else - { - fscan->scan.scanrelid += rtoffset; - fscan->scan.plan.targetlist = - fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset); - fscan->scan.plan.qual = - fix_scan_list(root, fscan->scan.plan.qual, rtoffset); - fscan->fdw_exprs = - fix_scan_list(root, fscan->fdw_exprs, rtoffset); - } -} - -/* - * set_customscan_references - * Do set_plan_references processing on an CustomScan - */ -static void -set_customscan_references(PlannerInfo *root, - CustomScan *cscan, - int rtoffset) -{ - if (rtoffset > 0) - { - Bitmapset *tempset = NULL; - int x = -1; - - while ((x = bms_next_member(cscan->custom_relids, x)) >= 0) - tempset = bms_add_member(tempset, x + rtoffset); - cscan->custom_relids = tempset; - } - - if (cscan->scan.scanrelid == 0) - { - indexed_tlist *pscan_itlist = - build_tlist_index(cscan->custom_ps_tlist); - - cscan->scan.plan.targetlist = (List *) - fix_upper_expr(root, - (Node *) cscan->scan.plan.targetlist, - pscan_itlist, - INDEX_VAR, - rtoffset); - cscan->scan.plan.qual = (List *) - fix_upper_expr(root, - (Node *) cscan->scan.plan.qual, - pscan_itlist, - INDEX_VAR, - rtoffset); - cscan->custom_exprs = (List *) - fix_upper_expr(root, - (Node *) cscan->custom_exprs, - pscan_itlist, - INDEX_VAR, - rtoffset); - cscan->custom_ps_tlist = - fix_scan_list(root, cscan->custom_ps_tlist, rtoffset); - pfree(pscan_itlist); - } - else - { - cscan->scan.scanrelid += rtoffset; - cscan->scan.plan.targetlist = - fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset); - cscan->scan.plan.qual = - fix_scan_list(root, cscan->scan.plan.qual, rtoffset); - cscan->custom_exprs = - fix_scan_list(root, cscan->custom_exprs, rtoffset); - } -} - -/* * set_indexonlyscan_references * Do set_plan_references processing on an IndexOnlyScan * @@ -1180,6 +1064,134 @@ trivial_subqueryscan(SubqueryScan *plan) } /* + * set_foreignscan_references + * Do set_plan_references processing on a ForeignScan + */ +static void +set_foreignscan_references(PlannerInfo *root, + ForeignScan *fscan, + int rtoffset) +{ + /* Adjust scanrelid if it's valid */ + if (fscan->scan.scanrelid > 0) + fscan->scan.scanrelid += rtoffset; + + if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0) + { + /* Adjust tlist, qual, fdw_exprs to reference custom scan tuple */ + indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist); + + fscan->scan.plan.targetlist = (List *) + fix_upper_expr(root, + (Node *) fscan->scan.plan.targetlist, + itlist, + INDEX_VAR, + rtoffset); + fscan->scan.plan.qual = (List *) + fix_upper_expr(root, + (Node *) fscan->scan.plan.qual, + itlist, + INDEX_VAR, + rtoffset); + fscan->fdw_exprs = (List *) + fix_upper_expr(root, + (Node *) fscan->fdw_exprs, + itlist, + INDEX_VAR, + rtoffset); + pfree(itlist); + /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */ + fscan->fdw_scan_tlist = + fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset); + } + else + { + /* Adjust tlist, qual, fdw_exprs in the standard way */ + fscan->scan.plan.targetlist = + fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset); + fscan->scan.plan.qual = + fix_scan_list(root, fscan->scan.plan.qual, rtoffset); + fscan->fdw_exprs = + fix_scan_list(root, fscan->fdw_exprs, rtoffset); + } + + /* Adjust fs_relids if needed */ + if (rtoffset > 0) + { + Bitmapset *tempset = NULL; + int x = -1; + + while ((x = bms_next_member(fscan->fs_relids, x)) >= 0) + tempset = bms_add_member(tempset, x + rtoffset); + fscan->fs_relids = tempset; + } +} + +/* + * set_customscan_references + * Do set_plan_references processing on a CustomScan + */ +static void +set_customscan_references(PlannerInfo *root, + CustomScan *cscan, + int rtoffset) +{ + /* Adjust scanrelid if it's valid */ + if (cscan->scan.scanrelid > 0) + cscan->scan.scanrelid += rtoffset; + + if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0) + { + /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */ + indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist); + + cscan->scan.plan.targetlist = (List *) + fix_upper_expr(root, + (Node *) cscan->scan.plan.targetlist, + itlist, + INDEX_VAR, + rtoffset); + cscan->scan.plan.qual = (List *) + fix_upper_expr(root, + (Node *) cscan->scan.plan.qual, + itlist, + INDEX_VAR, + rtoffset); + cscan->custom_exprs = (List *) + fix_upper_expr(root, + (Node *) cscan->custom_exprs, + itlist, + INDEX_VAR, + rtoffset); + pfree(itlist); + /* custom_scan_tlist itself just needs fix_scan_list() adjustments */ + cscan->custom_scan_tlist = + fix_scan_list(root, cscan->custom_scan_tlist, rtoffset); + } + else + { + /* Adjust tlist, qual, custom_exprs in the standard way */ + cscan->scan.plan.targetlist = + fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset); + cscan->scan.plan.qual = + fix_scan_list(root, cscan->scan.plan.qual, rtoffset); + cscan->custom_exprs = + fix_scan_list(root, cscan->custom_exprs, rtoffset); + } + + /* Adjust custom_relids if needed */ + if (rtoffset > 0) + { + Bitmapset *tempset = NULL; + int x = -1; + + while ((x = bms_next_member(cscan->custom_relids, x)) >= 0) + tempset = bms_add_member(tempset, x + rtoffset); + cscan->custom_relids = tempset; + } +} + +/* * copyVar * Copy a Var node. * diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 0220672fc43..afccee53acf 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2318,12 +2318,14 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, case T_ForeignScan: finalize_primnode((Node *) ((ForeignScan *) plan)->fdw_exprs, &context); + /* We assume fdw_scan_tlist cannot contain Params */ context.paramids = bms_add_members(context.paramids, scan_params); break; case T_CustomScan: finalize_primnode((Node *) ((CustomScan *) plan)->custom_exprs, &context); + /* We assume custom_scan_tlist cannot contain Params */ context.paramids = bms_add_members(context.paramids, scan_params); break; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 894e0db802d..b425680f476 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -380,17 +380,18 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, rel->indexlist = indexinfos; - /* Grab the fdwroutine info using the relcache, while we have it */ + /* Grab foreign-table info using the relcache, while we have it */ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE) { - rel->fdw_handler = GetFdwHandlerByRelId(RelationGetRelid(relation)); + rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation)); rel->fdwroutine = GetFdwRoutineForRelation(relation, true); } else { - rel->fdw_handler = InvalidOid; + rel->serverid = InvalidOid; rel->fdwroutine = NULL; } + heap_close(relation, NoLock); /* diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 56235663d7f..1d635cd6d21 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -14,7 +14,6 @@ */ #include "postgres.h" -#include "foreign/fdwapi.h" #include "optimizer/cost.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" @@ -122,8 +121,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->subplan = NULL; rel->subroot = NULL; rel->subplan_params = NIL; + rel->serverid = InvalidOid; rel->fdwroutine = NULL; - rel->fdw_handler = InvalidOid; rel->fdw_private = NULL; rel->baserestrictinfo = NIL; rel->baserestrictcost.startup = 0; @@ -385,6 +384,7 @@ build_join_rel(PlannerInfo *root, joinrel->subplan = NULL; joinrel->subroot = NULL; joinrel->subplan_params = NIL; + joinrel->serverid = InvalidOid; joinrel->fdwroutine = NULL; joinrel->fdw_private = NULL; joinrel->baserestrictinfo = NIL; @@ -394,6 +394,17 @@ build_join_rel(PlannerInfo *root, joinrel->has_eclass_joins = false; /* + * Set up foreign-join fields if outer and inner relation are foreign + * tables (or joins) belonging to the same server. + */ + if (OidIsValid(outer_rel->serverid) && + inner_rel->serverid == outer_rel->serverid) + { + joinrel->serverid = outer_rel->serverid; + joinrel->fdwroutine = outer_rel->fdwroutine; + } + + /* * Create a new tlist containing just the vars that need to be output from * this join (ie, are needed for higher joinclauses or final output). * @@ -429,18 +440,6 @@ build_join_rel(PlannerInfo *root, sjinfo, restrictlist); /* - * Set FDW handler and routine if both outer and inner relation - * are managed by same FDW driver. - */ - if (OidIsValid(outer_rel->fdw_handler) && - OidIsValid(inner_rel->fdw_handler) && - outer_rel->fdw_handler == inner_rel->fdw_handler) - { - joinrel->fdw_handler = outer_rel->fdw_handler; - joinrel->fdwroutine = GetFdwRoutine(joinrel->fdw_handler); - } - - /* * Add the joinrel to the query's joinrel list, and store it into the * auxiliary hashtable if there is one. NB: GEQO requires us to append * the new joinrel to the end of the list! |