diff options
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 75 | ||||
-rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 32 |
3 files changed, 84 insertions, 27 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 6c98c49bff8..ffb066283f2 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -1795,6 +1795,7 @@ cost_mergejoin(MergePath *path, PlannerInfo *root, SpecialJoinInfo *sjinfo) ipathkey = (PathKey *) linitial(ipathkeys); /* debugging check */ if (opathkey->pk_opfamily != ipathkey->pk_opfamily || + opathkey->pk_collation != ipathkey->pk_collation || opathkey->pk_strategy != ipathkey->pk_strategy || opathkey->pk_nulls_first != ipathkey->pk_nulls_first) elog(ERROR, "left and right pathkeys do not match in mergejoin"); @@ -2045,6 +2046,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey) { cache = (MergeScanSelCache *) lfirst(lc); if (cache->opfamily == pathkey->pk_opfamily && + cache->collation == pathkey->pk_collation && cache->strategy == pathkey->pk_strategy && cache->nulls_first == pathkey->pk_nulls_first) return cache; @@ -2054,6 +2056,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey) mergejoinscansel(root, (Node *) rinfo->clause, pathkey->pk_opfamily, + pathkey->pk_collation, pathkey->pk_strategy, pathkey->pk_nulls_first, &leftstartsel, @@ -2066,6 +2069,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey) cache = (MergeScanSelCache *) palloc(sizeof(MergeScanSelCache)); cache->opfamily = pathkey->pk_opfamily; + cache->collation = pathkey->pk_collation; cache->strategy = pathkey->pk_strategy; cache->nulls_first = pathkey->pk_nulls_first; cache->leftstartsel = leftstartsel; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index a3101d7ea73..65bc9be8da8 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -23,6 +23,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_type.h" #include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/pathnode.h" @@ -99,15 +100,15 @@ static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, Relids outer_relids, bool isouterjoin); static bool match_boolean_index_clause(Node *clause, int indexcol, IndexOptInfo *index); -static bool match_special_index_operator(Expr *clause, Oid opfamily, +static bool match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily, bool indexkey_on_left); static Expr *expand_boolean_index_clause(Node *clause, int indexcol, IndexOptInfo *index); -static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily); +static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation); static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo, IndexOptInfo *index, int indexcol); -static List *prefix_quals(Node *leftop, Oid opfamily, +static List *prefix_quals(Node *leftop, Oid opfamily, Oid collation, Const *prefix, Pattern_Prefix_Status pstatus); static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop); @@ -1142,7 +1143,9 @@ group_clauses_by_indexkey(IndexOptInfo *index, * and * (2) must contain an operator which is in the same family as the index * operator for this column, or is a "special" operator as recognized - * by match_special_index_operator(). + * by match_special_index_operator(); + * and + * (3) must match the collation of the index. * * Our definition of "const" is pretty liberal: we allow Vars belonging * to the caller-specified outer_relids relations (which had better not @@ -1198,6 +1201,7 @@ match_clause_to_indexcol(IndexOptInfo *index, SaOpControl saop_control) { Expr *clause = rinfo->clause; + Oid collation = index->indexcollations[indexcol]; Oid opfamily = index->opfamily[indexcol]; Node *leftop, *rightop; @@ -1280,7 +1284,8 @@ match_clause_to_indexcol(IndexOptInfo *index, bms_is_subset(right_relids, outer_relids) && !contain_volatile_functions(rightop)) { - if (is_indexable_operator(expr_op, opfamily, true)) + if (is_indexable_operator(expr_op, opfamily, true) && + (!collation || collation == exprCollation((Node *) clause))) return true; /* @@ -1288,7 +1293,7 @@ match_clause_to_indexcol(IndexOptInfo *index, * is a "special" indexable operator. */ if (plain_op && - match_special_index_operator(clause, opfamily, true)) + match_special_index_operator(clause, collation, opfamily, true)) return true; return false; } @@ -1298,14 +1303,15 @@ match_clause_to_indexcol(IndexOptInfo *index, bms_is_subset(left_relids, outer_relids) && !contain_volatile_functions(leftop)) { - if (is_indexable_operator(expr_op, opfamily, false)) + if (is_indexable_operator(expr_op, opfamily, false) && + (!collation || collation == exprCollation((Node *) clause))) return true; /* * If we didn't find a member of the index's opfamily, see whether it * is a "special" indexable operator. */ - if (match_special_index_operator(clause, opfamily, false)) + if (match_special_index_operator(clause, collation, opfamily, false)) return true; return false; } @@ -1391,6 +1397,9 @@ match_rowcompare_to_indexcol(IndexOptInfo *index, else return false; + if (index->indexcollations[indexcol] != linitial_oid(clause->collids)) + return false; + /* We're good if the operator is the right type of opfamily member */ switch (get_op_opfamily_strategy(expr_op, opfamily)) { @@ -2380,7 +2389,7 @@ match_boolean_index_clause(Node *clause, * Return 'true' if we can do something with it anyway. */ static bool -match_special_index_operator(Expr *clause, Oid opfamily, +match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily, bool indexkey_on_left) { bool isIndexable = false; @@ -2495,7 +2504,7 @@ match_special_index_operator(Expr *clause, Oid opfamily, isIndexable = (opfamily == TEXT_PATTERN_BTREE_FAM_OID) || (opfamily == TEXT_BTREE_FAM_OID && - (pstatus == Pattern_Prefix_Exact || lc_collate_is_c())); + (pstatus == Pattern_Prefix_Exact || lc_collate_is_c(idxcolcollation))); break; case OID_BPCHAR_LIKE_OP: @@ -2505,7 +2514,7 @@ match_special_index_operator(Expr *clause, Oid opfamily, isIndexable = (opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) || (opfamily == BPCHAR_BTREE_FAM_OID && - (pstatus == Pattern_Prefix_Exact || lc_collate_is_c())); + (pstatus == Pattern_Prefix_Exact || lc_collate_is_c(idxcolcollation))); break; case OID_NAME_LIKE_OP: @@ -2526,6 +2535,25 @@ match_special_index_operator(Expr *clause, Oid opfamily, break; } + if (!isIndexable) + return false; + + /* + * For case-insensitive matching, we also need to check that the + * collations match. + */ + switch (expr_op) + { + case OID_TEXT_ICLIKE_OP: + case OID_TEXT_ICREGEXEQ_OP: + case OID_BPCHAR_ICLIKE_OP: + case OID_BPCHAR_ICREGEXEQ_OP: + case OID_NAME_ICLIKE_OP: + case OID_NAME_ICREGEXEQ_OP: + isIndexable = (idxcolcollation == exprCollation((Node *) clause)); + break; + } + return isIndexable; } @@ -2561,6 +2589,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) { List *clausegroup = (List *) lfirst(lc); Oid curFamily = index->opfamily[indexcol]; + Oid curCollation = index->indexcollations[indexcol]; ListCell *lc2; foreach(lc2, clausegroup) @@ -2592,7 +2621,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) { resultquals = list_concat(resultquals, expand_indexqual_opclause(rinfo, - curFamily)); + curFamily, + curCollation)); } else if (IsA(clause, ScalarArrayOpExpr)) { @@ -2693,7 +2723,7 @@ expand_boolean_index_clause(Node *clause, * expand special cases that were accepted by match_special_index_operator(). */ static List * -expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily) +expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation) { Expr *clause = rinfo->clause; @@ -2724,7 +2754,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily) { pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like, &prefix, &rest); - return prefix_quals(leftop, opfamily, prefix, pstatus); + return prefix_quals(leftop, opfamily, collation, prefix, pstatus); } break; @@ -2736,7 +2766,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily) /* the right-hand const is type text for all of these */ pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, &prefix, &rest); - return prefix_quals(leftop, opfamily, prefix, pstatus); + return prefix_quals(leftop, opfamily, collation, prefix, pstatus); } break; @@ -2748,7 +2778,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily) /* the right-hand const is type text for all of these */ pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex, &prefix, &rest); - return prefix_quals(leftop, opfamily, prefix, pstatus); + return prefix_quals(leftop, opfamily, collation, prefix, pstatus); } break; @@ -2760,7 +2790,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily) /* the right-hand const is type text for all of these */ pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, &prefix, &rest); - return prefix_quals(leftop, opfamily, prefix, pstatus); + return prefix_quals(leftop, opfamily, collation, prefix, pstatus); } break; @@ -2814,6 +2844,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, ListCell *largs_cell; ListCell *rargs_cell; ListCell *opnos_cell; + ListCell *collids_cell; /* We have to figure out (again) how the first col matches */ var_on_left = match_index_to_operand((Node *) linitial(clause->largs), @@ -2845,6 +2876,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, largs_cell = lnext(list_head(clause->largs)); rargs_cell = lnext(list_head(clause->rargs)); opnos_cell = lnext(list_head(clause->opnos)); + collids_cell = lnext(list_head(clause->collids)); while (largs_cell != NULL) { @@ -2891,6 +2923,10 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, != op_strategy) break; + /* Does collation match? */ + if (lfirst_oid(collids_cell) != index->indexcollations[i]) + break; + /* Add opfamily and datatypes to lists */ get_op_opfamily_properties(expr_op, index->opfamily[i], false, &op_strategy, @@ -2974,6 +3010,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, rc->opnos = new_ops; rc->opfamilies = list_truncate(list_copy(clause->opfamilies), matching_cols); + rc->collids = list_truncate(list_copy(clause->collids), + matching_cols); rc->largs = list_truncate((List *) copyObject(clause->largs), matching_cols); rc->rargs = list_truncate((List *) copyObject(clause->rargs), @@ -2998,7 +3036,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, * operators and operand datatypes. */ static List * -prefix_quals(Node *leftop, Oid opfamily, +prefix_quals(Node *leftop, Oid opfamily, Oid collation, Const *prefix_const, Pattern_Prefix_Status pstatus) { List *result; @@ -3100,6 +3138,7 @@ prefix_quals(Node *leftop, Oid opfamily, if (oproid == InvalidOid) elog(ERROR, "no < operator for opfamily %u", opfamily); fmgr_info(get_opcode(oproid), <proc); + fmgr_info_collation(collation, <proc); greaterstr = make_greater_string(prefix_const, <proc); if (greaterstr) { diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index d5536fc2b36..fd759281ed5 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -18,6 +18,7 @@ #include "postgres.h" #include "access/skey.h" +#include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" @@ -30,10 +31,10 @@ #include "utils/lsyscache.h" -static PathKey *makePathKey(EquivalenceClass *eclass, Oid opfamily, +static PathKey *makePathKey(EquivalenceClass *eclass, Oid opfamily, Oid collation, int strategy, bool nulls_first); static PathKey *make_canonical_pathkey(PlannerInfo *root, - EquivalenceClass *eclass, Oid opfamily, + EquivalenceClass *eclass, Oid opfamily, Oid collation, int strategy, bool nulls_first); static bool pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys); static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, @@ -53,13 +54,14 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey); * convenience routine to build the specified node. */ static PathKey * -makePathKey(EquivalenceClass *eclass, Oid opfamily, +makePathKey(EquivalenceClass *eclass, Oid opfamily, Oid collation, int strategy, bool nulls_first) { PathKey *pk = makeNode(PathKey); pk->pk_eclass = eclass; pk->pk_opfamily = opfamily; + pk->pk_collation = collation; pk->pk_strategy = strategy; pk->pk_nulls_first = nulls_first; @@ -77,7 +79,7 @@ makePathKey(EquivalenceClass *eclass, Oid opfamily, */ static PathKey * make_canonical_pathkey(PlannerInfo *root, - EquivalenceClass *eclass, Oid opfamily, + EquivalenceClass *eclass, Oid opfamily, Oid collation, int strategy, bool nulls_first) { PathKey *pk; @@ -93,6 +95,7 @@ make_canonical_pathkey(PlannerInfo *root, pk = (PathKey *) lfirst(lc); if (eclass == pk->pk_eclass && opfamily == pk->pk_opfamily && + collation == pk->pk_collation && strategy == pk->pk_strategy && nulls_first == pk->pk_nulls_first) return pk; @@ -104,7 +107,7 @@ make_canonical_pathkey(PlannerInfo *root, */ oldcontext = MemoryContextSwitchTo(root->planner_cxt); - pk = makePathKey(eclass, opfamily, strategy, nulls_first); + pk = makePathKey(eclass, opfamily, collation, strategy, nulls_first); root->canon_pathkeys = lappend(root->canon_pathkeys, pk); MemoryContextSwitchTo(oldcontext); @@ -206,6 +209,7 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys) cpathkey = make_canonical_pathkey(root, eclass, pathkey->pk_opfamily, + pathkey->pk_collation, pathkey->pk_strategy, pathkey->pk_nulls_first); @@ -247,6 +251,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root, Oid equality_op; List *opfamilies; EquivalenceClass *eclass; + Oid collation; strategy = reverse_sort ? BTGreaterStrategyNumber : BTLessStrategyNumber; @@ -301,12 +306,14 @@ make_pathkey_from_sortinfo(PlannerInfo *root, if (!eclass) return NULL; + collation = exprCollation((Node *) expr); + /* And finally we can find or create a PathKey node */ if (canonicalize) - return make_canonical_pathkey(root, eclass, opfamily, + return make_canonical_pathkey(root, eclass, opfamily, collation, strategy, nulls_first); else - return makePathKey(eclass, opfamily, strategy, nulls_first); + return makePathKey(eclass, opfamily, collation, strategy, nulls_first); } /* @@ -605,7 +612,8 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno) ListCell *temp; Index relid; Oid reloid, - vartypeid; + vartypeid, + varcollid; int32 type_mod; foreach(temp, rel->reltargetlist) @@ -620,8 +628,9 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno) relid = rel->relid; reloid = getrelid(relid, root->parse->rtable); get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod); + varcollid = get_attcollation(reloid, varattno); - return makeVar(relid, varattno, vartypeid, type_mod, 0); + return makeVar(relid, varattno, vartypeid, type_mod, varcollid, 0); } /* @@ -703,6 +712,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, make_canonical_pathkey(root, outer_ec, sub_pathkey->pk_opfamily, + sub_pathkey->pk_collation, sub_pathkey->pk_strategy, sub_pathkey->pk_nulls_first); } @@ -805,6 +815,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, outer_pk = make_canonical_pathkey(root, outer_ec, sub_pathkey->pk_opfamily, + sub_pathkey->pk_collation, sub_pathkey->pk_strategy, sub_pathkey->pk_nulls_first); /* score = # of equivalence peers */ @@ -1326,6 +1337,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root, pathkey = make_canonical_pathkey(root, ec, linitial_oid(ec->ec_opfamilies), + DEFAULT_COLLATION_OID, BTLessStrategyNumber, false); /* can't be redundant because no duplicate ECs */ @@ -1419,6 +1431,7 @@ make_inner_pathkeys_for_merge(PlannerInfo *root, pathkey = make_canonical_pathkey(root, ieclass, opathkey->pk_opfamily, + opathkey->pk_collation, opathkey->pk_strategy, opathkey->pk_nulls_first); @@ -1539,6 +1552,7 @@ right_merge_direction(PlannerInfo *root, PathKey *pathkey) PathKey *query_pathkey = (PathKey *) lfirst(l); if (pathkey->pk_eclass == query_pathkey->pk_eclass && + pathkey->pk_collation == query_pathkey->pk_collation && pathkey->pk_opfamily == query_pathkey->pk_opfamily) { /* |