From 73779316a164bee22c301c5e4d518d4afb92066e Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov Date: Wed, 13 Jun 2018 20:56:03 +0300 Subject: [PATCH 1/2] Preparatory refactoring --- src/backend/nodes/equalfuncs.c | 7 +- src/backend/optimizer/path/indxpath.c | 16 +- src/backend/optimizer/path/joinpath.c | 6 +- src/backend/optimizer/plan/analyzejoins.c | 233 +++++++++++++++--------------- src/backend/optimizer/plan/planmain.c | 2 +- src/backend/optimizer/util/pathnode.c | 2 +- src/backend/optimizer/util/relnode.c | 26 ++-- src/include/nodes/relation.h | 6 +- src/include/optimizer/pathnode.h | 5 + src/include/optimizer/paths.h | 2 +- src/include/optimizer/planmain.h | 5 +- 11 files changed, 157 insertions(+), 153 deletions(-) diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 6a971d0..fd02dc8 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -166,9 +166,10 @@ _equalVar(const Var *a, const Var *b) COMPARE_SCALAR_FIELD(vartypmod); COMPARE_SCALAR_FIELD(varcollid); COMPARE_SCALAR_FIELD(varlevelsup); - COMPARE_SCALAR_FIELD(varnoold); - COMPARE_SCALAR_FIELD(varoattno); - COMPARE_LOCATION_FIELD(location); + /* + * Parse location and old varno/varattno may differ even when + * the variables are logically the same. + */ return true; } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index f295558..78b05f1 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -2961,10 +2961,10 @@ ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel, } /* - * relation_has_unique_index_for + * relation_get_unique_index_for * Determine whether the relation provably has at most one row satisfying * a set of equality conditions, because the conditions constrain all - * columns of some unique index. + * columns of some unique index, and return that index. * * The conditions can be represented in either or both of two ways: * 1. A list of RestrictInfo nodes, where the caller has already determined @@ -2982,8 +2982,8 @@ ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel, * this routine automatically adds in any usable baserestrictinfo clauses. * (Note that the passed-in restrictlist will be destructively modified!) */ -bool -relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, +IndexOptInfo * +relation_get_unique_index_for(PlannerInfo *root, RelOptInfo *rel, List *restrictlist, List *exprlist, List *oprlist) { @@ -2993,7 +2993,7 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, /* Short-circuit if no indexes... */ if (rel->indexlist == NIL) - return false; + return NULL; /* * Examine the rel's restriction clauses for usable var = const clauses @@ -3034,7 +3034,7 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, /* Short-circuit the easy case */ if (restrictlist == NIL && exprlist == NIL) - return false; + return NULL; /* Examine each index of the relation ... */ foreach(ic, rel->indexlist) @@ -3131,10 +3131,10 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, /* Matched all columns of this index? */ if (c == ind->ncolumns) - return true; + return ind; } - return false; + return NULL; } /* diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 642f951..0c11761 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -176,7 +176,8 @@ add_paths_to_joinrel(PlannerInfo *root, innerrel, JOIN_INNER, restrictlist, - false); + false, + NULL /*unique_index*/); break; default: extra.inner_unique = innerrel_is_unique(root, @@ -185,7 +186,8 @@ add_paths_to_joinrel(PlannerInfo *root, innerrel, jointype, restrictlist, - false); + false, + NULL /*unique_index*/); break; } diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 0e73f9c..c03010c 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -39,14 +39,15 @@ static void remove_rel_from_query(PlannerInfo *root, int relid, static List *remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved); static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel); static bool rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, - List *clause_list); + List *clause_list, IndexOptInfo **unique_index); static Oid distinct_col_search(int colno, List *colnos, List *opids); static bool is_innerrel_unique_for(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, - List *restrictlist); + List *restrictlist, + IndexOptInfo **unique_index); /* @@ -58,7 +59,7 @@ static bool is_innerrel_unique_for(PlannerInfo *root, * data structures that have to be updated are accessible via "root". */ List * -remove_useless_joins(PlannerInfo *root, List *joinlist) +remove_useless_left_joins(PlannerInfo *root, List *joinlist) { ListCell *lc; @@ -146,55 +147,17 @@ clause_sides_match_join(RestrictInfo *rinfo, Relids outerrelids, } /* - * join_is_removable - * Check whether we need not perform this special join at all, because - * it will just duplicate its left input. - * - * This is true for a left join for which the join condition cannot match - * more than one inner-side row. (There are other possibly interesting - * cases, but we don't have the infrastructure to prove them.) We also - * have to check that the inner side doesn't generate any variables needed - * above the join. + * Check whether any attributes of the relation are used above the + * join specified by joinrelids. */ static bool -join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) +rel_used_above_join(PlannerInfo *root, Relids joinrelids, RelOptInfo *rel) { - int innerrelid; - RelOptInfo *innerrel; - Relids joinrelids; - List *clause_list = NIL; ListCell *l; int attroff; /* - * Must be a non-delaying left join to a single baserel, else we aren't - * going to be able to do anything with it. - */ - if (sjinfo->jointype != JOIN_LEFT || - sjinfo->delay_upper_joins) - return false; - - if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid)) - return false; - - innerrel = find_base_rel(root, innerrelid); - - /* - * Before we go to the effort of checking whether any innerrel variables - * are needed above the join, make a quick check to eliminate cases in - * which we will surely be unable to prove uniqueness of the innerrel. - */ - if (!rel_supports_distinctness(root, innerrel)) - return false; - - /* Compute the relid set for the join we are considering */ - joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand); - - /* - * We can't remove the join if any inner-rel attributes are used above the - * join. - * - * Note that this test only detects use of inner-rel attributes in higher + * This test only detects use of inner-rel attributes in higher * join conditions and the target list. There might be such attributes in * pushed-down conditions at this join, too. We check that case below. * @@ -203,101 +166,112 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) * theory that the system attributes are somewhat less likely to be wanted * and should be tested last. */ - for (attroff = innerrel->max_attr - innerrel->min_attr; + for (attroff = rel->max_attr - rel->min_attr; attroff >= 0; attroff--) { - if (!bms_is_subset(innerrel->attr_needed[attroff], joinrelids)) - return false; + if (!bms_is_subset(rel->attr_needed[attroff], joinrelids)) + return true; } /* - * Similarly check that the inner rel isn't needed by any PlaceHolderVars + * Similarly check that the relation isn't needed by any PlaceHolderVars * that will be used above the join. We only need to fail if such a PHV - * actually references some inner-rel attributes; but the correct check + * actually references some relation attributes; but the correct check * for that is relatively expensive, so we first check against ph_eval_at, - * which must mention the inner rel if the PHV uses any inner-rel attrs as + * which must mention the relation if the PHV uses any relation attrs as * non-lateral references. Note that if the PHV's syntactic scope is just - * the inner rel, we can't drop the rel even if the PHV is variable-free. + * the given relation, we can't drop the rel even if the PHV is variable-free. */ foreach(l, root->placeholder_list) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l); - if (bms_overlap(phinfo->ph_lateral, innerrel->relids)) - return false; /* it references innerrel laterally */ + if (bms_overlap(phinfo->ph_lateral, rel->relids)) + return true; /* it references this relation laterally */ if (bms_is_subset(phinfo->ph_needed, joinrelids)) continue; /* PHV is not used above the join */ - if (!bms_overlap(phinfo->ph_eval_at, innerrel->relids)) - continue; /* it definitely doesn't reference innerrel */ - if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids)) - return false; /* there isn't any other place to eval PHV */ + if (!bms_overlap(phinfo->ph_eval_at, rel->relids)) + continue; /* it definitely doesn't reference this relation */ + if (bms_is_subset(phinfo->ph_eval_at, rel->relids)) + return true; /* there isn't any other place to eval PHV */ if (bms_overlap(pull_varnos((Node *) phinfo->ph_var->phexpr), - innerrel->relids)) - return false; /* it does reference innerrel */ + rel->relids)) + return true; /* it does reference this relation */ } /* - * Search for mergejoinable clauses that constrain the inner rel against - * either the outer rel or a pseudoconstant. If an operator is - * mergejoinable then it behaves like equality for some btree opclass, so - * it's what we want. The mergejoinability test also eliminates clauses - * containing volatile functions, which we couldn't depend on. + * Check for pushed-down clauses referencing the inner rel. If there is + * such a clause then join removal has to be disallowed. We have to + * check this despite the previous attr_needed checks because of the + * possibility of pushed-down clauses referencing the rel. */ - foreach(l, innerrel->joininfo) + foreach(l, rel->joininfo) { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); + if (RINFO_IS_PUSHED_DOWN(restrictinfo, joinrelids) + && bms_is_member(rel->relid, restrictinfo->clause_relids)) + return true; + } - /* - * If it's not a join clause for this outer join, we can't use it. - * Note that if the clause is pushed-down, then it is logically from - * above the outer join, even if it references no other rels (it might - * be from WHERE, for example). - */ - if (RINFO_IS_PUSHED_DOWN(restrictinfo, joinrelids)) - { - /* - * If such a clause actually references the inner rel then join - * removal has to be disallowed. We have to check this despite - * the previous attr_needed checks because of the possibility of - * pushed-down clauses referencing the rel. - */ - if (bms_is_member(innerrelid, restrictinfo->clause_relids)) - return false; - continue; /* else, ignore; not useful here */ - } + return false; +} - /* Ignore if it's not a mergejoinable clause */ - if (!restrictinfo->can_join || - restrictinfo->mergeopfamilies == NIL) - continue; /* not mergejoinable */ - /* - * Check if clause has the form "outer op inner" or "inner op outer", - * and if so mark which side is inner. - */ - if (!clause_sides_match_join(restrictinfo, sjinfo->min_lefthand, - innerrel->relids)) - continue; /* no good for these input relations */ +/* + * join_is_removable + * Check whether we need not perform this special join at all, because + * it will just duplicate its left input. + * + * This is true for a left join for which the join condition cannot match + * more than one inner-side row. (There are other possibly interesting + * cases, but we don't have the infrastructure to prove them.) We also + * have to check that the inner side doesn't generate any variables needed + * above the join. + */ +static bool +join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) +{ + int innerrelid; + RelOptInfo *innerrel; + Relids joinrelids; - /* OK, add to list */ - clause_list = lappend(clause_list, restrictinfo); - } + /* + * Must be a non-delaying left join to a single baserel, else we aren't + * going to be able to do anything with it. + */ + if (sjinfo->jointype != JOIN_LEFT || + sjinfo->delay_upper_joins) + return false; + + if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid)) + return false; + + innerrel = find_base_rel(root, innerrelid); /* - * Now that we have the relevant equality join clauses, try to prove the - * innerrel distinct. + * Before we go to the effort of checking whether any innerrel variables + * are needed above the join, make a quick check to eliminate cases in + * which we will surely be unable to prove uniqueness of the innerrel. */ - if (rel_is_distinct_for(root, innerrel, clause_list)) - return true; + if (!rel_supports_distinctness(root, innerrel)) + return false; + + /* Compute the relid set for the join we are considering */ + joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand); /* - * Some day it would be nice to check for other methods of establishing - * distinctness. + * We can't remove the join if any inner-rel attributes are used above the + * join. */ - return false; -} + if (rel_used_above_join(root, joinrelids, innerrel)) + return false; + + return is_innerrel_unique_for(root, joinrelids, sjinfo->min_lefthand, + innerrel, sjinfo->jointype, innerrel->joininfo, + NULL /*unique_index*/); +} /* * Remove the target relid from the planner's data structures, having @@ -568,7 +542,7 @@ reduce_unique_semijoins(PlannerInfo *root) /* Test whether the innerrel is unique for those clauses. */ if (!innerrel_is_unique(root, joinrelids, sjinfo->min_lefthand, innerrel, - JOIN_SEMI, restrictlist, true)) + JOIN_SEMI, restrictlist, true, NULL /*unique_index*/)) continue; /* OK, remove the SpecialJoinInfo from the list. */ @@ -601,7 +575,7 @@ rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel) * reference to unique indexes. Make sure there's at least one * suitable unique index. It must be immediately enforced, and if * it's a partial index, it must match the query. (Keep these - * conditions in sync with relation_has_unique_index_for!) + * conditions in sync with relation_get_unique_index_for!) */ ListCell *lc; @@ -643,9 +617,13 @@ rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel) * Note that the passed-in clause_list may be destructively modified! This * is OK for current uses, because the clause_list is built by the caller for * the sole purpose of passing to this function. + * + * If unique_index is not null, it is set to point to the index that guarantees + * uniqueness for a base relation. */ static bool -rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list) +rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list, + IndexOptInfo **unique_index) { /* * We could skip a couple of tests here if we assume all callers checked @@ -658,11 +636,14 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list) { /* * Examine the indexes to see if we have a matching unique index. - * relation_has_unique_index_for automatically adds any usable + * relation_get_unique_index_for automatically adds any usable * restriction clauses for the rel, so we needn't do that here. */ - if (relation_has_unique_index_for(root, rel, clause_list, NIL, NIL)) - return true; + IndexOptInfo *index = relation_get_unique_index_for(root, rel, clause_list, + NIL, NIL); + if (unique_index) + *unique_index = index; + return index != NULL; } else if (rel->rtekind == RTE_SUBQUERY) { @@ -966,6 +947,9 @@ distinct_col_search(int colno, List *colnos, List *opids) * heuristic about whether to cache negative answers; it should be "true" * if making an inquiry that is not part of the normal bottom-up join search * sequence. + * + * If unique_index_out is not null, it is set to point to the index that + * guarantees uniqueness of a base relation. */ bool innerrel_is_unique(PlannerInfo *root, @@ -974,10 +958,15 @@ innerrel_is_unique(PlannerInfo *root, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, - bool force_cache) + bool force_cache, + IndexOptInfo **unique_index_out) { MemoryContext old_context; ListCell *lc; + IndexOptInfo *unique_index = NULL; + + if (unique_index_out) + *unique_index_out = NULL; /* Certainly can't prove uniqueness when there are no joinclauses */ if (restrictlist == NIL) @@ -999,10 +988,14 @@ innerrel_is_unique(PlannerInfo *root, */ foreach(lc, innerrel->unique_for_rels) { - Relids unique_for_rels = (Relids) lfirst(lc); + Relids unique_for_rels = (Relids) linitial(lfirst(lc)); if (bms_is_subset(unique_for_rels, outerrelids)) + { + if (unique_index_out) + *unique_index_out = lsecond(lfirst(lc)); return true; /* Success! */ + } } /* @@ -1019,7 +1012,7 @@ innerrel_is_unique(PlannerInfo *root, /* No cached information, so try to make the proof. */ if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel, - jointype, restrictlist)) + jointype, restrictlist, &unique_index)) { /* * Cache the positive result for future probes, being sure to keep it @@ -1033,9 +1026,12 @@ innerrel_is_unique(PlannerInfo *root, */ old_context = MemoryContextSwitchTo(root->planner_cxt); innerrel->unique_for_rels = lappend(innerrel->unique_for_rels, - bms_copy(outerrelids)); + list_make2(bms_copy(outerrelids), unique_index)); MemoryContextSwitchTo(old_context); + if (unique_index_out) + *unique_index_out = unique_index; + return true; /* Success! */ } else @@ -1081,7 +1077,8 @@ is_innerrel_unique_for(PlannerInfo *root, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, - List *restrictlist) + List *restrictlist, + IndexOptInfo **unique_index) { List *clause_list = NIL; ListCell *lc; @@ -1123,5 +1120,5 @@ is_innerrel_unique_for(PlannerInfo *root, } /* Let rel_is_distinct_for() do the hard work */ - return rel_is_distinct_for(root, innerrel, clause_list); + return rel_is_distinct_for(root, innerrel, clause_list, unique_index); } diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 7a34abc..8e4abbe 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -190,7 +190,7 @@ query_planner(PlannerInfo *root, List *tlist, * jointree preprocessing, but the necessary information isn't available * until we've built baserel data structures and classified qual clauses. */ - joinlist = remove_useless_joins(root, joinlist); + joinlist = remove_useless_left_joins(root, joinlist); /* * Also, reduce any semijoins with unique inner rels to plain inner joins. diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index dbf9adc..e0abc2c 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1583,7 +1583,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, * clauses for the rel, as well. */ if (rel->rtekind == RTE_RELATION && sjinfo->semi_can_btree && - relation_has_unique_index_for(root, rel, NIL, + relation_get_unique_index_for(root, rel, NIL, sjinfo->semi_rhs_exprs, sjinfo->semi_operators)) { diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 82b7842..845bb93 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -38,14 +38,10 @@ typedef struct JoinHashEntry static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel); -static List *build_joinrel_restrictlist(PlannerInfo *root, - RelOptInfo *joinrel, - RelOptInfo *outer_rel, - RelOptInfo *inner_rel); static void build_joinrel_joinlist(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel); -static List *subbuild_joinrel_restrictlist(RelOptInfo *joinrel, +static List *subbuild_joinrel_restrictlist(Relids joinrelids, List *joininfo_list, List *new_restrictlist); static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel, @@ -505,7 +501,7 @@ build_join_rel(PlannerInfo *root, */ if (restrictlist_ptr) *restrictlist_ptr = build_joinrel_restrictlist(root, - joinrel, + joinrel->relids, outer_rel, inner_rel); return joinrel; @@ -607,7 +603,7 @@ build_join_rel(PlannerInfo *root, * caller might or might not need the restrictlist, but I need it anyway * for set_joinrel_size_estimates().) */ - restrictlist = build_joinrel_restrictlist(root, joinrel, + restrictlist = build_joinrel_restrictlist(root, joinrel->relids, outer_rel, inner_rel); if (restrictlist_ptr) *restrictlist_ptr = restrictlist; @@ -964,7 +960,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * the various joinlist entries ultimately refer to RestrictInfos * pushed into them by distribute_restrictinfo_to_rels(). * - * 'joinrel' is a join relation node + * 'joinrelids' is a join relation id set * 'outer_rel' and 'inner_rel' are a pair of relations that can be joined * to form joinrel. * @@ -977,9 +973,9 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * RestrictInfo nodes are no longer context-dependent. Instead, just include * the original nodes in the lists made for the join relation. */ -static List * +List * build_joinrel_restrictlist(PlannerInfo *root, - RelOptInfo *joinrel, + Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel) { @@ -990,8 +986,8 @@ build_joinrel_restrictlist(PlannerInfo *root, * eliminating any duplicates (important since we will see many of the * same clauses arriving from both input relations). */ - result = subbuild_joinrel_restrictlist(joinrel, outer_rel->joininfo, NIL); - result = subbuild_joinrel_restrictlist(joinrel, inner_rel->joininfo, result); + result = subbuild_joinrel_restrictlist(joinrelids, outer_rel->joininfo, NIL); + result = subbuild_joinrel_restrictlist(joinrelids, inner_rel->joininfo, result); /* * Add on any clauses derived from EquivalenceClasses. These cannot be @@ -1000,7 +996,7 @@ build_joinrel_restrictlist(PlannerInfo *root, */ result = list_concat(result, generate_join_implied_equalities(root, - joinrel->relids, + joinrelids, outer_rel->relids, inner_rel)); @@ -1026,7 +1022,7 @@ build_joinrel_joinlist(RelOptInfo *joinrel, } static List * -subbuild_joinrel_restrictlist(RelOptInfo *joinrel, +subbuild_joinrel_restrictlist(Relids joinrelids, List *joininfo_list, List *new_restrictlist) { @@ -1036,7 +1032,7 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel, { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - if (bms_is_subset(rinfo->required_relids, joinrel->relids)) + if (bms_is_subset(rinfo->required_relids, joinrelids)) { /* * This clause becomes a restriction clause for the joinrel, since diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 5af4840..362ae10 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -505,8 +505,10 @@ typedef struct PartitionSchemeData *PartitionScheme; * populate these fields, for base rels; but someday they might be used for * join rels too: * - * unique_for_rels - list of Relid sets, each one being a set of other - * rels for which this one has been proven unique + * unique_for_rels - list of (Relids, IndexOptInfo*) lists, where Relids + * is a set of other rels for which this one has been proven + * unique, and IndexOptInfo* is an index that makes it unique, + * if any. * non_unique_for_rels - list of Relid sets, each one being a set of * other rels for which we have tried and failed to prove * this one unique diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index e99ae36..da1cc30 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -271,6 +271,11 @@ extern RelOptInfo *build_join_rel(PlannerInfo *root, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List **restrictlist_ptr); + +extern List *build_joinrel_restrictlist(PlannerInfo *root, + Relids joinrelids, + RelOptInfo *outer_rel, + RelOptInfo *inner_rel); extern Relids min_join_parameterization(PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index cafde30..57ee855 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -71,7 +71,7 @@ extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel); * routines to generate index paths */ extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel); -extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, +extern IndexOptInfo *relation_get_unique_index_for(PlannerInfo *root, RelOptInfo *rel, List *restrictlist, List *exprlist, List *oprlist); extern bool indexcol_is_bool_constant_for_query(IndexOptInfo *index, diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index c8ab028..4805f74 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -103,13 +103,14 @@ extern void match_foreign_keys_to_quals(PlannerInfo *root); /* * prototypes for plan/analyzejoins.c */ -extern List *remove_useless_joins(PlannerInfo *root, List *joinlist); +extern List *remove_useless_left_joins(PlannerInfo *root, List *joinlist); extern void reduce_unique_semijoins(PlannerInfo *root); extern bool query_supports_distinctness(Query *query); extern bool query_is_distinct_for(Query *query, List *colnos, List *opids); extern bool innerrel_is_unique(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, - JoinType jointype, List *restrictlist, bool force_cache); + JoinType jointype, List *restrictlist, bool force_cache, + IndexOptInfo **unique_index); /* * prototypes for plan/setrefs.c -- 2.7.4