diff options
Diffstat (limited to 'src/backend/optimizer/path/pathkeys.c')
-rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 143 |
1 files changed, 37 insertions, 106 deletions
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 20a5644edd8..8561e5ffe26 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -28,8 +28,6 @@ #include "utils/lsyscache.h" -static PathKey *makePathKey(EquivalenceClass *eclass, Oid opfamily, - int strategy, bool nulls_first); static PathKey *make_canonical_pathkey(PlannerInfo *root, EquivalenceClass *eclass, Oid opfamily, int strategy, bool nulls_first); @@ -42,34 +40,15 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey); ****************************************************************************/ /* - * makePathKey - * create a PathKey node - * - * This does not promise to create a canonical PathKey, it's merely a - * convenience routine to build the specified node. - */ -static PathKey * -makePathKey(EquivalenceClass *eclass, Oid opfamily, - int strategy, bool nulls_first) -{ - PathKey *pk = makeNode(PathKey); - - pk->pk_eclass = eclass; - pk->pk_opfamily = opfamily; - pk->pk_strategy = strategy; - pk->pk_nulls_first = nulls_first; - - return pk; -} - -/* * make_canonical_pathkey * Given the parameters for a PathKey, find any pre-existing matching * pathkey in the query's list of "canonical" pathkeys. Make a new * entry if there's not one already. * * Note that this function must not be used until after we have completed - * merging EquivalenceClasses. + * merging EquivalenceClasses. (We don't try to enforce that here; instead, + * equivclass.c will complain if a merge occurs after root->canon_pathkeys + * has become nonempty.) */ static PathKey * make_canonical_pathkey(PlannerInfo *root, @@ -100,7 +79,12 @@ make_canonical_pathkey(PlannerInfo *root, */ oldcontext = MemoryContextSwitchTo(root->planner_cxt); - pk = makePathKey(eclass, opfamily, strategy, nulls_first); + pk = makeNode(PathKey); + pk->pk_eclass = eclass; + pk->pk_opfamily = opfamily; + pk->pk_strategy = strategy; + pk->pk_nulls_first = nulls_first; + root->canon_pathkeys = lappend(root->canon_pathkeys, pk); MemoryContextSwitchTo(oldcontext); @@ -112,8 +96,7 @@ make_canonical_pathkey(PlannerInfo *root, * pathkey_is_redundant * Is a pathkey redundant with one already in the given list? * - * Both the given pathkey and the list members must be canonical for this - * to work properly. We detect two cases: + * We detect two cases: * * 1. If the new pathkey's equivalence class contains a constant, and isn't * below an outer join, then we can disregard it as a sort key. An example: @@ -135,6 +118,12 @@ make_canonical_pathkey(PlannerInfo *root, * Note in particular that we need not compare opfamily (all the opfamilies * of the EC have the same notion of equality) nor sort direction. * + * Both the given pathkey and the list members must be canonical for this + * to work properly, but that's okay since we no longer ever construct any + * non-canonical pathkeys. (Note: the notion of a pathkey *list* being + * canonical includes the additional requirement of no redundant entries, + * which is exactly what we are checking for here.) + * * Because the equivclass.c machinery forms only one copy of any EC per query, * pointer comparison is enough to decide whether canonical ECs are the same. */ @@ -144,9 +133,6 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys) EquivalenceClass *new_ec = new_pathkey->pk_eclass; ListCell *lc; - /* Assert we've been given canonical pathkeys */ - Assert(!new_ec->ec_merged); - /* Check for EC containing a constant --- unconditionally redundant */ if (EC_MUST_BE_REDUNDANT(new_ec)) return true; @@ -156,9 +142,6 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys) { PathKey *old_pathkey = (PathKey *) lfirst(lc); - /* Assert we've been given canonical pathkeys */ - Assert(!old_pathkey->pk_eclass->ec_merged); - if (new_ec == old_pathkey->pk_eclass) return true; } @@ -170,53 +153,22 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys) * canonicalize_pathkeys * Convert a not-necessarily-canonical pathkeys list to canonical form. * - * Note that this function must not be used until after we have completed - * merging EquivalenceClasses. + * This is a no-op now that all pathkeys are canonical, but we keep it + * to avoid possibly breaking plug-ins in the 9.2 release cycle. + * + * Since the previous implementation made a fresh List, we use list_copy + * (NOT list_copy_deep) to preserve that behavior. */ List * canonicalize_pathkeys(PlannerInfo *root, List *pathkeys) { - List *new_pathkeys = NIL; - ListCell *l; - - foreach(l, pathkeys) - { - PathKey *pathkey = (PathKey *) lfirst(l); - EquivalenceClass *eclass; - PathKey *cpathkey; - - /* Find the canonical (merged) EquivalenceClass */ - eclass = pathkey->pk_eclass; - while (eclass->ec_merged) - eclass = eclass->ec_merged; - - /* - * If we can tell it's redundant just from the EC, skip. - * pathkey_is_redundant would notice that, but we needn't even bother - * constructing the node... - */ - if (EC_MUST_BE_REDUNDANT(eclass)) - continue; - - /* OK, build a canonicalized PathKey struct */ - cpathkey = make_canonical_pathkey(root, - eclass, - pathkey->pk_opfamily, - pathkey->pk_strategy, - pathkey->pk_nulls_first); - - /* Add to list unless redundant */ - if (!pathkey_is_redundant(cpathkey, new_pathkeys)) - new_pathkeys = lappend(new_pathkeys, cpathkey); - } - return new_pathkeys; + return list_copy(pathkeys); } /* * make_pathkey_from_sortinfo * Given an expression and sort-order information, create a PathKey. - * If canonicalize = true, the result is a "canonical" PathKey, - * otherwise not. (But note it might be redundant anyway.) + * The result is always a "canonical" PathKey, but it might be redundant. * * If the PathKey is being generated from a SortGroupClause, sortref should be * the SortGroupClause's SortGroupRef; otherwise zero. @@ -229,9 +181,6 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys) * create_it is TRUE if we should create any missing EquivalenceClass * needed to represent the sort key. If it's FALSE, we return NULL if the * sort key isn't already present in any EquivalenceClass. - * - * canonicalize should always be TRUE after EquivalenceClass merging has - * been performed, but FALSE if we haven't done EquivalenceClass merging yet. */ static PathKey * make_pathkey_from_sortinfo(PlannerInfo *root, @@ -251,6 +200,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root, List *opfamilies; EquivalenceClass *eclass; + Assert(canonicalize); + strategy = reverse_sort ? BTGreaterStrategyNumber : BTLessStrategyNumber; /* @@ -281,11 +232,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root, return NULL; /* And finally we can find or create a PathKey node */ - if (canonicalize) - return make_canonical_pathkey(root, eclass, opfamily, - strategy, nulls_first); - else - return makePathKey(eclass, opfamily, strategy, nulls_first); + return make_canonical_pathkey(root, eclass, opfamily, + strategy, nulls_first); } /* @@ -341,9 +289,8 @@ make_pathkey_from_sortop(PlannerInfo *root, * Compare two pathkeys to see if they are equivalent, and if not whether * one is "better" than the other. * - * This function may only be applied to canonicalized pathkey lists. - * In the canonical representation, pathkeys can be checked for equality - * by simple pointer comparison. + * We assume the pathkeys are canonical, and so they can be checked for + * equality by simple pointer comparison. */ PathKeysComparison compare_pathkeys(List *keys1, List *keys2) @@ -364,15 +311,6 @@ compare_pathkeys(List *keys1, List *keys2) PathKey *pathkey1 = (PathKey *) lfirst(key1); PathKey *pathkey2 = (PathKey *) lfirst(key2); - /* - * XXX would like to check that we've been given canonicalized input, - * but PlannerInfo not accessible here... - */ -#ifdef NOT_USED - Assert(list_member_ptr(root->canon_pathkeys, pathkey1)); - Assert(list_member_ptr(root->canon_pathkeys, pathkey2)); -#endif - if (pathkey1 != pathkey2) return PATHKEYS_DIFFERENT; /* no need to keep looking */ } @@ -414,7 +352,7 @@ pathkeys_contained_in(List *keys1, List *keys2) * Return NULL if no such path. * * 'paths' is a list of possible paths that all generate the same relation - * 'pathkeys' represents a required ordering (already canonicalized!) + * 'pathkeys' represents a required ordering (in canonical form!) * 'required_outer' denotes allowable outer relations for parameterized paths * 'cost_criterion' is STARTUP_COST or TOTAL_COST */ @@ -455,7 +393,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, * parameter. * * 'paths' is a list of possible paths that all generate the same relation - * 'pathkeys' represents a required ordering (already canonicalized!) + * 'pathkeys' represents a required ordering (in canonical form!) * 'required_outer' denotes allowable outer relations for parameterized paths * 'fraction' is the fraction of the total tuples expected to be retrieved */ @@ -829,12 +767,8 @@ build_join_pathkeys(PlannerInfo *root, * Generate a pathkeys list that represents the sort order specified * by a list of SortGroupClauses * - * If canonicalize is TRUE, the resulting PathKeys are all in canonical form; - * otherwise not. canonicalize should always be TRUE after EquivalenceClass - * merging has been performed, but FALSE if we haven't done EquivalenceClass - * merging yet. (We provide this option because grouping_planner() needs to - * be able to represent requested pathkeys before the equivalence classes have - * been created for the query.) + * The resulting PathKeys are always in canonical form. (Actually, there + * is no longer any code anywhere that creates non-canonical PathKeys.) * * 'sortclauses' is a list of SortGroupClause nodes * 'tlist' is the targetlist to find the referenced tlist entries in @@ -848,6 +782,8 @@ make_pathkeys_for_sortclauses(PlannerInfo *root, List *pathkeys = NIL; ListCell *l; + Assert(canonicalize); + foreach(l, sortclauses) { SortGroupClause *sortcl = (SortGroupClause *) lfirst(l); @@ -862,15 +798,10 @@ make_pathkeys_for_sortclauses(PlannerInfo *root, sortcl->nulls_first, sortcl->tleSortGroupRef, true, - canonicalize); + true); /* Canonical form eliminates redundant ordering keys */ - if (canonicalize) - { - if (!pathkey_is_redundant(pathkey, pathkeys)) - pathkeys = lappend(pathkeys, pathkey); - } - else + if (!pathkey_is_redundant(pathkey, pathkeys)) pathkeys = lappend(pathkeys, pathkey); } return pathkeys; |