diff options
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r-- | src/backend/optimizer/path/equivclass.c | 44 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 18 | ||||
-rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 17 |
3 files changed, 65 insertions, 14 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index b653d6cb35c..c115c2148db 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -491,6 +491,15 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids, * sortref is the SortGroupRef of the originating SortGroupClause, if any, * or zero if not. (It should never be zero if the expression is volatile!) * + * If rel is not NULL, it identifies a specific relation we're considering + * a path for, and indicates that child EC members for that relation can be + * considered. Otherwise child members are ignored. (Note: since child EC + * members aren't guaranteed unique, a non-NULL value means that there could + * be more than one EC that matches the expression; if so it's order-dependent + * which one you get. This is annoying but it only happens in corner cases, + * so for now we live with just reporting the first match. See also + * generate_implied_equalities_for_indexcol and match_pathkeys_to_index.) + * * If create_it is TRUE, we'll build a new EquivalenceClass when there is no * match. If create_it is FALSE, we just return NULL when no match. * @@ -511,6 +520,7 @@ get_eclass_for_sort_expr(PlannerInfo *root, Oid opcintype, Oid collation, Index sortref, + Relids rel, bool create_it) { EquivalenceClass *newec; @@ -549,6 +559,13 @@ get_eclass_for_sort_expr(PlannerInfo *root, EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); /* + * Ignore child members unless they match the request. + */ + if (cur_em->em_is_child && + !bms_equal(cur_em->em_relids, rel)) + continue; + + /* * If below an outer join, don't match constants: they're not as * constant as they look. */ @@ -1505,6 +1522,7 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo, { EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); + Assert(!cur_em->em_is_child); /* no children yet */ if (equal(outervar, cur_em->em_expr)) { match = true; @@ -1626,6 +1644,7 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) foreach(lc2, cur_ec->ec_members) { coal_em = (EquivalenceMember *) lfirst(lc2); + Assert(!coal_em->em_is_child); /* no children yet */ if (IsA(coal_em->em_expr, CoalesceExpr)) { CoalesceExpr *cexpr = (CoalesceExpr *) coal_em->em_expr; @@ -1747,6 +1766,8 @@ exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2) { EquivalenceMember *em = (EquivalenceMember *) lfirst(lc2); + if (em->em_is_child) + continue; /* ignore children here */ if (equal(item1, em->em_expr)) item1member = true; else if (equal(item2, em->em_expr)) @@ -1800,6 +1821,9 @@ add_child_rel_equivalences(PlannerInfo *root, { EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); + if (cur_em->em_is_child) + continue; /* ignore children here */ + /* Does it reference (only) parent_rel? */ if (bms_equal(cur_em->em_relids, parent_rel->relids)) { @@ -1908,7 +1932,16 @@ generate_implied_equalities_for_indexcol(PlannerInfo *root, !bms_is_subset(rel->relids, cur_ec->ec_relids)) continue; - /* Scan members, looking for a match to the indexable column */ + /* + * Scan members, looking for a match to the indexable column. Note + * that child EC members are considered, but only when they belong to + * the target relation. (Unlike regular members, the same expression + * could be a child member of more than one EC. Therefore, it's + * potentially order-dependent which EC a child relation's index + * column gets matched to. This is annoying but it only happens in + * corner cases, so for now we live with just reporting the first + * match. See also get_eclass_for_sort_expr.) + */ cur_em = NULL; foreach(lc2, cur_ec->ec_members) { @@ -1933,6 +1966,9 @@ generate_implied_equalities_for_indexcol(PlannerInfo *root, Oid eq_op; RestrictInfo *rinfo; + if (other_em->em_is_child) + continue; /* ignore children here */ + /* Make sure it'll be a join to a different rel */ if (other_em == cur_em || bms_overlap(other_em->em_relids, rel->relids)) @@ -2187,8 +2223,10 @@ eclass_useful_for_merging(EquivalenceClass *eclass, { EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc); - if (!cur_em->em_is_child && - !bms_overlap(cur_em->em_relids, rel->relids)) + if (cur_em->em_is_child) + continue; /* ignore children here */ + + if (!bms_overlap(cur_em->em_relids, rel->relids)) return true; } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 2f088b79787..89b42da6b46 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -2157,7 +2157,14 @@ match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys, if (pathkey->pk_eclass->ec_has_volatile) return; - /* Try to match eclass member expression(s) to index */ + /* + * Try to match eclass member expression(s) to index. Note that child + * EC members are considered, but only when they belong to the target + * relation. (Unlike regular members, the same expression could be a + * child member of more than one EC. Therefore, the same index could + * be considered to match more than one pathkey list, which is OK + * here. See also get_eclass_for_sort_expr.) + */ foreach(lc2, pathkey->pk_eclass->ec_members) { EquivalenceMember *member = (EquivalenceMember *) lfirst(lc2); @@ -2581,15 +2588,6 @@ match_index_to_operand(Node *operand, int indkey; /* - * Ignore any PlaceHolderVar nodes above the operand. This is needed so - * that we can successfully use expression-index constraints pushed down - * through appendrels (UNION ALL). It's safe because a PlaceHolderVar - * appearing in a relation-scan-level expression is certainly a no-op. - */ - while (operand && IsA(operand, PlaceHolderVar)) - operand = (Node *) ((PlaceHolderVar *) operand)->phexpr; - - /* * Ignore any RelabelType node above the operand. This is needed to be * able to apply indexscanning in binary-compatible-operator cases. Note: * we can assume there is at most one RelabelType node; diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 653387e582d..4ff8016666d 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -221,6 +221,11 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys) * If the PathKey is being generated from a SortGroupClause, sortref should be * the SortGroupClause's SortGroupRef; otherwise zero. * + * If rel is not NULL, it identifies a specific relation we're considering + * a path for, and indicates that child EC members for that relation can be + * considered. Otherwise child members are ignored. (See the comments for + * get_eclass_for_sort_expr.) + * * 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. @@ -237,6 +242,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root, bool reverse_sort, bool nulls_first, Index sortref, + Relids rel, bool create_it, bool canonicalize) { @@ -268,7 +274,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root, /* Now find or (optionally) create a matching EquivalenceClass */ eclass = get_eclass_for_sort_expr(root, expr, opfamilies, opcintype, collation, - sortref, create_it); + sortref, rel, create_it); /* Fail if no EC and !create_it */ if (!eclass) @@ -320,6 +326,7 @@ make_pathkey_from_sortop(PlannerInfo *root, (strategy == BTGreaterStrategyNumber), nulls_first, sortref, + NULL, create_it, canonicalize); } @@ -546,6 +553,7 @@ build_index_pathkeys(PlannerInfo *root, reverse_sort, nulls_first, 0, + index->rel->relids, false, true); @@ -636,6 +644,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, sub_member->em_datatype, sub_eclass->ec_collation, 0, + rel->relids, false); /* @@ -680,6 +689,9 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, Oid sub_expr_coll = sub_eclass->ec_collation; ListCell *k; + if (sub_member->em_is_child) + continue; /* ignore children here */ + foreach(k, sub_tlist) { TargetEntry *tle = (TargetEntry *) lfirst(k); @@ -719,6 +731,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, sub_expr_type, sub_expr_coll, 0, + rel->relids, false); /* @@ -910,6 +923,7 @@ initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo) lefttype, ((OpExpr *) clause)->inputcollid, 0, + NULL, true); restrictinfo->right_ec = get_eclass_for_sort_expr(root, @@ -918,6 +932,7 @@ initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo) righttype, ((OpExpr *) clause)->inputcollid, 0, + NULL, true); } |