diff options
Diffstat (limited to 'src/backend/optimizer')
-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 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 64 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planagg.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 40 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 21 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 49 | ||||
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/util/predtest.c | 1 |
13 files changed, 224 insertions, 77 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) { /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index c74125f1f75..f01114c673a 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -105,7 +105,7 @@ static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tidquals); static FunctionScan *make_functionscan(List *qptlist, List *qpqual, Index scanrelid, Node *funcexpr, List *funccolnames, - List *funccoltypes, List *funccoltypmods); + List *funccoltypes, List *funccoltypmods, List *funccolcollations); static ValuesScan *make_valuesscan(List *qptlist, List *qpqual, Index scanrelid, List *values_lists); static CteScan *make_ctescan(List *qptlist, List *qpqual, @@ -133,12 +133,13 @@ static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, Oid *mergefamilies, + Oid *mergecollations, int *mergestrategies, bool *mergenullsfirst, Plan *lefttree, Plan *righttree, JoinType jointype); static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols, - AttrNumber *sortColIdx, Oid *sortOperators, bool *nullsFirst, + AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst, double limit_tuples); static Plan *prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, @@ -146,6 +147,7 @@ static Plan *prepare_sort_from_pathkeys(PlannerInfo *root, int *p_numsortkeys, AttrNumber **p_sortColIdx, Oid **p_sortOperators, + Oid **p_collations, bool **p_nullsFirst); static Material *make_material(Plan *lefttree); @@ -671,6 +673,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) &node->numCols, &node->sortColIdx, &node->sortOperators, + &node->collations, &node->nullsFirst); /* @@ -685,6 +688,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) int numsortkeys; AttrNumber *sortColIdx; Oid *sortOperators; + Oid *collations; bool *nullsFirst; /* Build the child plan */ @@ -696,6 +700,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) &numsortkeys, &sortColIdx, &sortOperators, + &collations, &nullsFirst); /* @@ -710,13 +715,15 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) elog(ERROR, "MergeAppend child's targetlist doesn't match MergeAppend"); Assert(memcmp(sortOperators, node->sortOperators, numsortkeys * sizeof(Oid)) == 0); + Assert(memcmp(collations, node->collations, + numsortkeys * sizeof(Oid)) == 0); Assert(memcmp(nullsFirst, node->nullsFirst, numsortkeys * sizeof(bool)) == 0); /* Now, insert a Sort node if subplan isn't sufficiently ordered */ if (!pathkeys_contained_in(pathkeys, subpath->pathkeys)) subplan = (Plan *) make_sort(root, subplan, numsortkeys, - sortColIdx, sortOperators, nullsFirst, + sortColIdx, sortOperators, collations, nullsFirst, best_path->limit_tuples); subplans = lappend(subplans, subplan); @@ -1569,7 +1576,8 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path, rte->funcexpr, rte->eref->colnames, rte->funccoltypes, - rte->funccoltypmods); + rte->funccoltypmods, + rte->funccolcollations); copy_path_costsize(&scan_plan->scan.plan, best_path); @@ -1847,6 +1855,7 @@ create_mergejoin_plan(PlannerInfo *root, List *innerpathkeys; int nClauses; Oid *mergefamilies; + Oid *mergecollations; int *mergestrategies; bool *mergenullsfirst; MergeJoin *join_plan; @@ -1946,6 +1955,7 @@ create_mergejoin_plan(PlannerInfo *root, nClauses = list_length(mergeclauses); Assert(nClauses == list_length(best_path->path_mergeclauses)); mergefamilies = (Oid *) palloc(nClauses * sizeof(Oid)); + mergecollations = (Oid *) palloc(nClauses * sizeof(Oid)); mergestrategies = (int *) palloc(nClauses * sizeof(int)); mergenullsfirst = (bool *) palloc(nClauses * sizeof(bool)); @@ -2074,12 +2084,14 @@ create_mergejoin_plan(PlannerInfo *root, /* pathkeys should match each other too (more debugging) */ 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"); /* OK, save info for executor */ mergefamilies[i] = opathkey->pk_opfamily; + mergecollations[i] = opathkey->pk_collation; mergestrategies[i] = opathkey->pk_strategy; mergenullsfirst[i] = opathkey->pk_nulls_first; i++; @@ -2099,6 +2111,7 @@ create_mergejoin_plan(PlannerInfo *root, otherclauses, mergeclauses, mergefamilies, + mergecollations, mergestrategies, mergenullsfirst, outer_plan, @@ -2528,6 +2541,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index) /* Found a match */ result = makeVar(index->rel->relid, pos + 1, exprType(lfirst(indexpr_item)), -1, + exprCollation(lfirst(indexpr_item)), 0); return (Node *) result; } @@ -2881,7 +2895,8 @@ make_functionscan(List *qptlist, Node *funcexpr, List *funccolnames, List *funccoltypes, - List *funccoltypmods) + List *funccoltypmods, + List *funccolcollations) { FunctionScan *node = makeNode(FunctionScan); Plan *plan = &node->scan.plan; @@ -2896,6 +2911,7 @@ make_functionscan(List *qptlist, node->funccolnames = funccolnames; node->funccoltypes = funccoltypes; node->funccoltypmods = funccoltypmods; + node->funccolcollations = funccolcollations; return node; } @@ -3181,6 +3197,7 @@ make_mergejoin(List *tlist, List *otherclauses, List *mergeclauses, Oid *mergefamilies, + Oid *mergecollations, int *mergestrategies, bool *mergenullsfirst, Plan *lefttree, @@ -3197,6 +3214,7 @@ make_mergejoin(List *tlist, plan->righttree = righttree; node->mergeclauses = mergeclauses; node->mergeFamilies = mergefamilies; + node->mergeCollations = mergecollations; node->mergeStrategies = mergestrategies; node->mergeNullsFirst = mergenullsfirst; node->join.jointype = jointype; @@ -3214,7 +3232,7 @@ make_mergejoin(List *tlist, */ static Sort * make_sort(PlannerInfo *root, Plan *lefttree, int numCols, - AttrNumber *sortColIdx, Oid *sortOperators, bool *nullsFirst, + AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst, double limit_tuples) { Sort *node = makeNode(Sort); @@ -3238,6 +3256,7 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols, node->numCols = numCols; node->sortColIdx = sortColIdx; node->sortOperators = sortOperators; + node->collations = collations; node->nullsFirst = nullsFirst; return node; @@ -3253,9 +3272,9 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols, * max possible number of columns. Return value is the new column count. */ static int -add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first, +add_sort_column(AttrNumber colIdx, Oid sortOp, Oid coll, bool nulls_first, int numCols, AttrNumber *sortColIdx, - Oid *sortOperators, bool *nullsFirst) + Oid *sortOperators, Oid *collations, bool *nullsFirst) { int i; @@ -3271,7 +3290,8 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first, * opposite nulls direction is redundant. */ if (sortColIdx[i] == colIdx && - sortOperators[numCols] == sortOp) + sortOperators[numCols] == sortOp && + collations[numCols] == coll) { /* Already sorting by this col, so extra sort key is useless */ return numCols; @@ -3281,6 +3301,7 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first, /* Add the column */ sortColIdx[numCols] = colIdx; sortOperators[numCols] = sortOp; + collations[numCols] = coll; nullsFirst[numCols] = nulls_first; return numCols + 1; } @@ -3320,6 +3341,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, int *p_numsortkeys, AttrNumber **p_sortColIdx, Oid **p_sortOperators, + Oid **p_collations, bool **p_nullsFirst) { List *tlist = lefttree->targetlist; @@ -3327,6 +3349,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, int numsortkeys; AttrNumber *sortColIdx; Oid *sortOperators; + Oid *collations; bool *nullsFirst; /* @@ -3335,6 +3358,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, numsortkeys = list_length(pathkeys); sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber)); sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid)); + collations = (Oid *) palloc(numsortkeys * sizeof(Oid)); nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool)); numsortkeys = 0; @@ -3493,9 +3517,10 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, */ numsortkeys = add_sort_column(tle->resno, sortop, + pathkey->pk_collation, pathkey->pk_nulls_first, numsortkeys, - sortColIdx, sortOperators, nullsFirst); + sortColIdx, sortOperators, collations, nullsFirst); } Assert(numsortkeys > 0); @@ -3504,6 +3529,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, *p_numsortkeys = numsortkeys; *p_sortColIdx = sortColIdx; *p_sortOperators = sortOperators; + *p_collations = collations; *p_nullsFirst = nullsFirst; return lefttree; @@ -3525,6 +3551,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, int numsortkeys; AttrNumber *sortColIdx; Oid *sortOperators; + Oid *collations; bool *nullsFirst; /* Compute sort column info, and adjust lefttree as needed */ @@ -3533,11 +3560,12 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, &numsortkeys, &sortColIdx, &sortOperators, + &collations, &nullsFirst); /* Now build the Sort node */ return make_sort(root, lefttree, numsortkeys, - sortColIdx, sortOperators, nullsFirst, limit_tuples); + sortColIdx, sortOperators, collations, nullsFirst, limit_tuples); } /* @@ -3555,6 +3583,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree) int numsortkeys; AttrNumber *sortColIdx; Oid *sortOperators; + Oid *collations; bool *nullsFirst; /* @@ -3563,6 +3592,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree) numsortkeys = list_length(sortcls); sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber)); sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid)); + collations = (Oid *) palloc(numsortkeys * sizeof(Oid)); nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool)); numsortkeys = 0; @@ -3578,15 +3608,16 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree) * redundantly. */ numsortkeys = add_sort_column(tle->resno, sortcl->sortop, + exprCollation((Node *) tle->expr), sortcl->nulls_first, numsortkeys, - sortColIdx, sortOperators, nullsFirst); + sortColIdx, sortOperators, collations, nullsFirst); } Assert(numsortkeys > 0); return make_sort(root, lefttree, numsortkeys, - sortColIdx, sortOperators, nullsFirst, -1.0); + sortColIdx, sortOperators, collations, nullsFirst, -1.0); } /* @@ -3614,6 +3645,7 @@ make_sort_from_groupcols(PlannerInfo *root, int numsortkeys; AttrNumber *sortColIdx; Oid *sortOperators; + Oid *collations; bool *nullsFirst; /* @@ -3622,6 +3654,7 @@ make_sort_from_groupcols(PlannerInfo *root, numsortkeys = list_length(groupcls); sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber)); sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid)); + collations = (Oid *) palloc(numsortkeys * sizeof(Oid)); nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool)); numsortkeys = 0; @@ -3637,16 +3670,17 @@ make_sort_from_groupcols(PlannerInfo *root, * redundantly. */ numsortkeys = add_sort_column(tle->resno, grpcl->sortop, + exprCollation((Node *) tle->expr), grpcl->nulls_first, numsortkeys, - sortColIdx, sortOperators, nullsFirst); + sortColIdx, sortOperators, collations, nullsFirst); grpno++; } Assert(numsortkeys > 0); return make_sort(root, lefttree, numsortkeys, - sortColIdx, sortOperators, nullsFirst, -1.0); + sortColIdx, sortOperators, collations, nullsFirst, -1.0); } static Material * diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index dfbc624aa8b..f885385296e 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -561,7 +561,8 @@ make_agg_subplan(PlannerInfo *root, RelOptInfo *rel, PrivateMMAggInfo *info) */ info->param = SS_make_initplan_from_plan(&subroot, plan, exprType((Node *) tle->expr), - -1); + -1, + exprCollation((Node *) tle->expr)); /* * Put the updated list of InitPlans back into the outer PlannerInfo. diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 02f5cabd25c..867238ecc8b 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -213,9 +213,11 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, newrte->funcexpr = NULL; newrte->funccoltypes = NIL; newrte->funccoltypmods = NIL; + newrte->funccolcollations = NIL; newrte->values_lists = NIL; newrte->ctecoltypes = NIL; newrte->ctecoltypmods = NIL; + newrte->ctecolcollations = NIL; glob->finalrtable = lappend(glob->finalrtable, newrte); @@ -1119,6 +1121,7 @@ set_dummy_tlist_references(Plan *plan, int rtoffset) tle->resno, exprType((Node *) oldvar), exprTypmod((Node *) oldvar), + exprCollation((Node *) oldvar), 0); if (IsA(oldvar, Var)) { diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index febec1e15f0..29eb9dced45 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -157,6 +157,7 @@ replace_outer_var(PlannerInfo *root, Var *var) retval->paramid = i; retval->paramtype = var->vartype; retval->paramtypmod = var->vartypmod; + retval->paramcollation = var->varcollid; retval->location = -1; return retval; @@ -185,6 +186,7 @@ assign_nestloop_param(PlannerInfo *root, Var *var) retval->paramid = i; retval->paramtype = var->vartype; retval->paramtypmod = var->vartypmod; + retval->paramcollation = var->varcollid; retval->location = -1; return retval; @@ -225,6 +227,7 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg) retval->paramid = i; retval->paramtype = agg->aggtype; retval->paramtypmod = -1; + retval->paramcollation = agg->collid; retval->location = -1; return retval; @@ -236,7 +239,7 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg) * This is used to allocate PARAM_EXEC slots for subplan outputs. */ static Param * -generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod) +generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation) { Param *retval; PlannerParamItem *pitem; @@ -246,6 +249,7 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod) retval->paramid = list_length(root->glob->paramlist); retval->paramtype = paramtype; retval->paramtypmod = paramtypmod; + retval->paramcollation = paramcollation; retval->location = -1; pitem = makeNode(PlannerParamItem); @@ -270,7 +274,7 @@ SS_assign_special_param(PlannerInfo *root) Param *param; /* We generate a Param of datatype INTERNAL */ - param = generate_new_param(root, INTERNALOID, -1); + param = generate_new_param(root, INTERNALOID, -1, InvalidOid); /* ... but the caller only cares about its ID */ return param->paramid; } @@ -278,13 +282,13 @@ SS_assign_special_param(PlannerInfo *root) /* * Get the datatype of the first column of the plan's output. * - * This is stored for ARRAY_SUBLINK execution and for exprType()/exprTypmod(), + * This is stored for ARRAY_SUBLINK execution and for exprType()/exprTypmod()/exprCollation(), * which have no way to get at the plan associated with a SubPlan node. * We really only need the info for EXPR_SUBLINK and ARRAY_SUBLINK subplans, * but for consistency we save it always. */ static void -get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod) +get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod, Oid *colcollation) { /* In cases such as EXISTS, tlist might be empty; arbitrarily use VOID */ if (plan->targetlist) @@ -296,11 +300,13 @@ get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod) { *coltype = exprType((Node *) tent->expr); *coltypmod = exprTypmod((Node *) tent->expr); + *colcollation = exprCollation((Node *) tent->expr); return; } } *coltype = VOIDOID; *coltypmod = -1; + *colcollation = InvalidOid; } /* @@ -470,7 +476,7 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, splan->subLinkType = subLinkType; splan->testexpr = NULL; splan->paramIds = NIL; - get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod); + get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod, &splan->firstColCollation); splan->useHashTable = false; splan->unknownEqFalse = unknownEqFalse; splan->setParam = NIL; @@ -523,7 +529,7 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, Param *prm; Assert(testexpr == NULL); - prm = generate_new_param(root, BOOLOID, -1); + prm = generate_new_param(root, BOOLOID, -1, InvalidOid); splan->setParam = list_make1_int(prm->paramid); isInitPlan = true; result = (Node *) prm; @@ -537,7 +543,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, Assert(testexpr == NULL); prm = generate_new_param(root, exprType((Node *) te->expr), - exprTypmod((Node *) te->expr)); + exprTypmod((Node *) te->expr), + exprCollation((Node *) te->expr)); splan->setParam = list_make1_int(prm->paramid); isInitPlan = true; result = (Node *) prm; @@ -556,7 +563,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, format_type_be(exprType((Node *) te->expr))); prm = generate_new_param(root, arraytype, - exprTypmod((Node *) te->expr)); + exprTypmod((Node *) te->expr), + exprCollation((Node *) te->expr)); splan->setParam = list_make1_int(prm->paramid); isInitPlan = true; result = (Node *) prm; @@ -708,7 +716,8 @@ generate_subquery_params(PlannerInfo *root, List *tlist, List **paramIds) param = generate_new_param(root, exprType((Node *) tent->expr), - exprTypmod((Node *) tent->expr)); + exprTypmod((Node *) tent->expr), + exprCollation((Node *) tent->expr)); result = lappend(result, param); ids = lappend_int(ids, param->paramid); } @@ -964,7 +973,7 @@ SS_process_ctes(PlannerInfo *root) splan->subLinkType = CTE_SUBLINK; splan->testexpr = NULL; splan->paramIds = NIL; - get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod); + get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod, &splan->firstColCollation); splan->useHashTable = false; splan->unknownEqFalse = false; splan->setParam = NIL; @@ -999,7 +1008,7 @@ SS_process_ctes(PlannerInfo *root) * Assign a param to represent the query output. We only really care * about reserving a parameter ID number. */ - prm = generate_new_param(root, INTERNALOID, -1); + prm = generate_new_param(root, INTERNALOID, -1, InvalidOid); splan->setParam = list_make1_int(prm->paramid); /* @@ -1565,7 +1574,8 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect, oc = lnext(oc); param = generate_new_param(root, exprType(rightarg), - exprTypmod(rightarg)); + exprTypmod(rightarg), + exprCollation(rightarg)); tlist = lappend(tlist, makeTargetEntry((Expr *) rightarg, resno++, @@ -2352,7 +2362,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context) */ Param * SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, - Oid resulttype, int32 resulttypmod) + Oid resulttype, int32 resulttypmod, Oid resultcollation) { SubPlan *node; Param *prm; @@ -2388,7 +2398,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, */ node = makeNode(SubPlan); node->subLinkType = EXPR_SUBLINK; - get_first_col_type(plan, &node->firstColType, &node->firstColTypmod); + get_first_col_type(plan, &node->firstColType, &node->firstColTypmod, &node->firstColCollation); node->plan_id = list_length(root->glob->subplans); root->init_plans = lappend(root->init_plans, node); @@ -2403,7 +2413,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, /* * Make a Param that will be the subplan's output. */ - prm = generate_new_param(root, resulttype, resulttypmod); + prm = generate_new_param(root, resulttype, resulttypmod, resultcollation); node->setParam = list_make1_int(prm->paramid); /* Label the subplan for EXPLAIN purposes */ diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index f92bcd41b1a..bd678ac7ede 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -445,6 +445,7 @@ inline_set_returning_functions(PlannerInfo *root) rte->funcexpr = NULL; rte->funccoltypes = NIL; rte->funccoltypmods = NIL; + rte->funccolcollations = NIL; } } } diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 36c19438c04..34b38eb3298 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -100,6 +100,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) SelfItemPointerAttributeNumber, TIDOID, -1, + InvalidOid, 0); snprintf(resname, sizeof(resname), "ctid%u", rc->rti); tle = makeTargetEntry((Expr *) var, @@ -115,6 +116,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) TableOidAttributeNumber, OIDOID, -1, + InvalidOid, 0); snprintf(resname, sizeof(resname), "tableoid%u", rc->rti); tle = makeTargetEntry((Expr *) var, @@ -257,6 +259,7 @@ expand_targetlist(List *tlist, int command_type, */ Oid atttype = att_tup->atttypid; int32 atttypmod = att_tup->atttypmod; + Oid attcollation = att_tup->attcollation; Node *new_expr; switch (command_type) @@ -296,6 +299,7 @@ expand_targetlist(List *tlist, int command_type, attrno, atttype, atttypmod, + attcollation, 0); } else diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 449c8dab501..f62af6c37da 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -86,7 +86,7 @@ static List *generate_setop_tlist(List *colTypes, int flag, bool hack_constants, List *input_tlist, List *refnames_tlist); -static List *generate_append_tlist(List *colTypes, bool flag, +static List *generate_append_tlist(List *colTypes, List *colCollations, bool flag, List *input_plans, List *refnames_tlist); static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist); @@ -348,7 +348,7 @@ generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root, /* * Generate tlist for RecursiveUnion plan node --- same as in Append cases */ - tlist = generate_append_tlist(setOp->colTypes, false, + tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false, list_make2(lplan, rplan), refnames_tlist); @@ -443,7 +443,7 @@ generate_union_plan(SetOperationStmt *op, PlannerInfo *root, * concerned, but we must make it look real anyway for the benefit of the * next plan level up. */ - tlist = generate_append_tlist(op->colTypes, false, + tlist = generate_append_tlist(op->colTypes, op->colCollations, false, planlist, refnames_tlist); /* @@ -534,7 +534,7 @@ generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root, * column is shown as a variable not a constant, else setrefs.c will get * confused. */ - tlist = generate_append_tlist(op->colTypes, true, + tlist = generate_append_tlist(op->colTypes, op->colCollations, true, planlist, refnames_tlist); /* @@ -885,6 +885,7 @@ generate_setop_tlist(List *colTypes, int flag, inputtle->resno, exprType((Node *) inputtle->expr), exprTypmod((Node *) inputtle->expr), + exprCollation((Node *) inputtle->expr), 0); if (exprType(expr) != colType) { @@ -936,13 +937,14 @@ generate_setop_tlist(List *colTypes, int flag, * The Vars are always generated with varno 0. */ static List * -generate_append_tlist(List *colTypes, bool flag, +generate_append_tlist(List *colTypes, List*colCollations, bool flag, List *input_plans, List *refnames_tlist) { List *tlist = NIL; int resno = 1; ListCell *curColType; + ListCell *curColCollation; ListCell *ref_tl_item; int colindex; TargetEntry *tle; @@ -997,10 +999,11 @@ generate_append_tlist(List *colTypes, bool flag, * Now we can build the tlist for the Append. */ colindex = 0; - forboth(curColType, colTypes, ref_tl_item, refnames_tlist) + forthree(curColType, colTypes, curColCollation, colCollations, ref_tl_item, refnames_tlist) { Oid colType = lfirst_oid(curColType); int32 colTypmod = colTypmods[colindex++]; + Oid colColl = lfirst_oid(curColCollation); TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item); Assert(reftle->resno == resno); @@ -1009,6 +1012,7 @@ generate_append_tlist(List *colTypes, bool flag, resno, colType, colTypmod, + colColl, 0); tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, @@ -1025,6 +1029,7 @@ generate_append_tlist(List *colTypes, bool flag, resno, INT4OID, -1, + InvalidOid, 0); tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, @@ -1344,6 +1349,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation, char *attname; Oid atttypid; int32 atttypmod; + Oid attcollation; int new_attno; att = old_tupdesc->attrs[old_attno]; @@ -1356,6 +1362,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation, attname = NameStr(att->attname); atttypid = att->atttypid; atttypmod = att->atttypmod; + attcollation = att->attcollation; /* * When we are generating the "translation list" for the parent table @@ -1367,6 +1374,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation, (AttrNumber) (old_attno + 1), atttypid, atttypmod, + attcollation, 0)); continue; } @@ -1409,6 +1417,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation, (AttrNumber) (new_attno + 1), atttypid, atttypmod, + attcollation, 0)); } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 86990c87252..fa0952618b1 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -100,7 +100,7 @@ static List *simplify_and_arguments(List *args, bool *haveNull, bool *forceFalse); static Node *simplify_boolean_equality(Oid opno, List *args); static Expr *simplify_function(Oid funcid, - Oid result_type, int32 result_typmod, List **args, + Oid result_type, int32 result_typmod, Oid collid, List **args, bool has_named_args, bool allow_inline, eval_const_expressions_context *context); @@ -114,7 +114,7 @@ static List *fetch_function_defaults(HeapTuple func_tuple); static void recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple); static Expr *evaluate_function(Oid funcid, - Oid result_type, int32 result_typmod, List *args, + Oid result_type, int32 result_typmod, Oid collid, List *args, HeapTuple func_tuple, eval_const_expressions_context *context); static Expr *inline_function(Oid funcid, Oid result_type, List *args, @@ -156,6 +156,7 @@ make_opclause(Oid opno, Oid opresulttype, bool opretset, expr->args = list_make2(leftop, rightop); else expr->args = list_make1(leftop); + expr->collid = select_common_collation(NULL, expr->args, false); expr->location = -1; return (Expr *) expr; } @@ -1973,7 +1974,7 @@ set_coercionform_dontcare_walker(Node *node, void *context) */ static bool rowtype_field_matches(Oid rowtypeid, int fieldnum, - Oid expectedtype, int32 expectedtypmod) + Oid expectedtype, int32 expectedtypmod, Oid expectedcollation) { TupleDesc tupdesc; Form_pg_attribute attr; @@ -1990,7 +1991,8 @@ rowtype_field_matches(Oid rowtypeid, int fieldnum, attr = tupdesc->attrs[fieldnum - 1]; if (attr->attisdropped || attr->atttypid != expectedtype || - attr->atttypmod != expectedtypmod) + attr->atttypmod != expectedtypmod || + attr->attcollation != expectedcollation) { ReleaseTupleDesc(tupdesc); return false; @@ -2121,6 +2123,7 @@ eval_const_expressions_mutator(Node *node, int16 typLen; bool typByVal; Datum pval; + Const *cnst; Assert(prm->ptype == param->paramtype); get_typlenbyval(param->paramtype, &typLen, &typByVal); @@ -2128,12 +2131,14 @@ eval_const_expressions_mutator(Node *node, pval = prm->value; else pval = datumCopy(prm->value, typByVal, typLen); - return (Node *) makeConst(param->paramtype, + cnst = makeConst(param->paramtype, param->paramtypmod, (int) typLen, pval, prm->isnull, typByVal); + cnst->constcollid = param->paramcollation; + return (Node *) cnst; } } } @@ -2173,6 +2178,7 @@ eval_const_expressions_mutator(Node *node, */ simple = simplify_function(expr->funcid, expr->funcresulttype, exprTypmod(node), + expr->collid, &args, has_named_args, true, context); if (simple) /* successfully simplified it */ @@ -2190,6 +2196,7 @@ eval_const_expressions_mutator(Node *node, newexpr->funcretset = expr->funcretset; newexpr->funcformat = expr->funcformat; newexpr->args = args; + newexpr->collid = expr->collid; newexpr->location = expr->location; return (Node *) newexpr; } @@ -2221,6 +2228,7 @@ eval_const_expressions_mutator(Node *node, */ simple = simplify_function(expr->opfuncid, expr->opresulttype, -1, + expr->collid, &args, false, true, context); if (simple) /* successfully simplified it */ @@ -2250,6 +2258,7 @@ eval_const_expressions_mutator(Node *node, newexpr->opresulttype = expr->opresulttype; newexpr->opretset = expr->opretset; newexpr->args = args; + newexpr->collid = expr->collid; newexpr->location = expr->location; return (Node *) newexpr; } @@ -2314,6 +2323,7 @@ eval_const_expressions_mutator(Node *node, */ simple = simplify_function(expr->opfuncid, expr->opresulttype, -1, + expr->collid, &args, false, false, context); if (simple) /* successfully simplified it */ @@ -2342,6 +2352,7 @@ eval_const_expressions_mutator(Node *node, newexpr->opresulttype = expr->opresulttype; newexpr->opretset = expr->opretset; newexpr->args = args; + newexpr->collid = expr->collid; newexpr->location = expr->location; return (Node *) newexpr; } @@ -2493,7 +2504,7 @@ eval_const_expressions_mutator(Node *node, getTypeInputInfo(expr->resulttype, &infunc, &intypioparam); simple = simplify_function(outfunc, - CSTRINGOID, -1, + CSTRINGOID, -1, InvalidOid, &args, false, true, context); if (simple) /* successfully simplified output fn */ @@ -2510,8 +2521,11 @@ eval_const_expressions_mutator(Node *node, Int32GetDatum(-1), false, true)); + /* preserve collation of input expression */ simple = simplify_function(infunc, - expr->resulttype, -1, + expr->resulttype, + -1, + exprCollation((Node *) arg), &args, false, true, context); if (simple) /* successfully simplified input fn */ @@ -2690,6 +2704,7 @@ eval_const_expressions_mutator(Node *node, /* Otherwise we need a new CASE node */ newcase = makeNode(CaseExpr); newcase->casetype = caseexpr->casetype; + newcase->casecollation = caseexpr->casecollation; newcase->arg = (Expr *) newarg; newcase->args = newargs; newcase->defresult = (Expr *) defresult; @@ -2782,6 +2797,7 @@ eval_const_expressions_mutator(Node *node, newcoalesce = makeNode(CoalesceExpr); newcoalesce->coalescetype = coalesceexpr->coalescetype; + newcoalesce->coalescecollation = coalesceexpr->coalescecollation; newcoalesce->args = newargs; newcoalesce->location = coalesceexpr->location; return (Node *) newcoalesce; @@ -2811,11 +2827,13 @@ eval_const_expressions_mutator(Node *node, if (rowtype_field_matches(((Var *) arg)->vartype, fselect->fieldnum, fselect->resulttype, - fselect->resulttypmod)) + fselect->resulttypmod, + fselect->resultcollation)) return (Node *) makeVar(((Var *) arg)->varno, fselect->fieldnum, fselect->resulttype, fselect->resulttypmod, + fselect->resultcollation, ((Var *) arg)->varlevelsup); } if (arg && IsA(arg, RowExpr)) @@ -2831,9 +2849,11 @@ eval_const_expressions_mutator(Node *node, if (rowtype_field_matches(rowexpr->row_typeid, fselect->fieldnum, fselect->resulttype, - fselect->resulttypmod) && + fselect->resulttypmod, + fselect->resultcollation) && fselect->resulttype == exprType(fld) && - fselect->resulttypmod == exprTypmod(fld)) + fselect->resulttypmod == exprTypmod(fld) && + fselect->resultcollation == exprCollation(fld)) return fld; } } @@ -2842,6 +2862,7 @@ eval_const_expressions_mutator(Node *node, newfselect->fieldnum = fselect->fieldnum; newfselect->resulttype = fselect->resulttype; newfselect->resulttypmod = fselect->resulttypmod; + newfselect->resultcollation = fselect->resultcollation; return (Node *) newfselect; } if (IsA(node, NullTest)) @@ -3299,7 +3320,7 @@ simplify_boolean_equality(Oid opno, List *args) * pass-by-reference, and it may get modified even if simplification fails. */ static Expr * -simplify_function(Oid funcid, Oid result_type, int32 result_typmod, +simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid, List **args, bool has_named_args, bool allow_inline, @@ -3330,7 +3351,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, else if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args)) *args = add_function_defaults(*args, result_type, func_tuple, context); - newexpr = evaluate_function(funcid, result_type, result_typmod, *args, + newexpr = evaluate_function(funcid, result_type, result_typmod, collid, *args, func_tuple, context); if (!newexpr && allow_inline) @@ -3581,7 +3602,8 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple) * simplify the function. */ static Expr * -evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args, +evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid, + List *args, HeapTuple func_tuple, eval_const_expressions_context *context) { @@ -3664,6 +3686,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args, newexpr->funcretset = false; newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */ newexpr->args = args; + newexpr->collid = collid; newexpr->location = -1; return evaluate_expr((Expr *) newexpr, result_type, result_typmod); diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index adbe45caec4..1f79ba24fb3 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -198,10 +198,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, info->indexkeys = (int *) palloc(sizeof(int) * ncolumns); info->opfamily = (Oid *) palloc(sizeof(Oid) * ncolumns); info->opcintype = (Oid *) palloc(sizeof(Oid) * ncolumns); + info->indexcollations = (Oid *) palloc(sizeof(Oid) * ncolumns); for (i = 0; i < ncolumns; i++) { info->indexkeys[i] = index->indkey.values[i]; + info->indexcollations[i] = indexRelation->rd_indcollation[i]; info->opfamily[i] = indexRelation->rd_opfamily[i]; info->opcintype[i] = indexRelation->rd_opcintype[i]; } @@ -634,6 +636,7 @@ get_relation_constraints(PlannerInfo *root, i, att->atttypid, att->atttypmod, + att->attcollation, 0); ntest->nulltesttype = IS_NOT_NULL; ntest->argisrow = type_is_rowtype(att->atttypid); @@ -797,6 +800,7 @@ build_physical_tlist(PlannerInfo *root, RelOptInfo *rel) attrno, att_tup->atttypid, att_tup->atttypmod, + att_tup->attcollation, 0); tlist = lappend(tlist, diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 6e80b4c0c7b..4561e8e92f1 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -912,6 +912,7 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info) state->constexpr.xpr.type = T_Const; state->constexpr.consttype = ARR_ELEMTYPE(arrayval); state->constexpr.consttypmod = -1; + state->constexpr.constcollid = arrayconst->constcollid; state->constexpr.constlen = elmlen; state->constexpr.constbyval = elmbyval; lsecond(state->opexpr.args) = &state->constexpr; |