From a4d41e1ba7e0272412d7bfae5e830f43a20fcded Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 12 Dec 2018 18:45:04 +0100 Subject: [PATCH v2] Reorganize collation lookup time and place Until now, a fmgr C function that makes use of collation information (for example varstr_cmp(), str_toupper()) gets passed the collation OID, looks up the collation with pg_newlocale_from_collation(), and then does something with it. With this change, the lookup is moved earlier, typically during executor initialization. The fmgr functions receive the locale pointer that is the result of that lookup. This makes the collation lookup more similar to the function lookup. In most cases they now happen right next to each other. We also save repeated lookups in repeated function calls. Moreover, this makes the structure and logic of functions like varstr_cmp() easier, because they don't have to deal with a mix of OIDs and locale pointers that are sometimes not set depending on the value of the other. --- contrib/btree_gist/btree_bit.c | 12 +- contrib/btree_gist/btree_bytea.c | 12 +- contrib/btree_gist/btree_numeric.c | 12 +- contrib/btree_gist/btree_text.c | 12 +- contrib/btree_gist/btree_utils_var.c | 14 +- contrib/btree_gist/btree_utils_var.h | 24 +- contrib/citext/citext.c | 31 +-- contrib/ltree/lquery_op.c | 5 +- contrib/pg_trgm/trgm.h | 3 +- contrib/pg_trgm/trgm_regexp.c | 6 +- src/backend/access/brin/brin.c | 12 +- src/backend/access/brin/brin_inclusion.c | 49 ++-- src/backend/access/brin/brin_minmax.c | 21 +- src/backend/access/common/scankey.c | 7 +- src/backend/access/gin/ginutil.c | 7 +- src/backend/access/gist/gist.c | 5 +- src/backend/access/hash/hashutil.c | 5 +- src/backend/access/index/indexam.c | 22 ++ src/backend/access/nbtree/nbtsearch.c | 3 +- src/backend/access/nbtree/nbtutils.c | 11 +- src/backend/access/spgist/spgdoinsert.c | 6 +- src/backend/access/spgist/spgscan.c | 2 +- src/backend/access/spgist/spgtextproc.c | 2 +- src/backend/access/spgist/spgutils.c | 2 +- src/backend/commands/analyze.c | 9 +- src/backend/commands/collationcmds.c | 6 +- src/backend/commands/extension.c | 3 +- src/backend/commands/functioncmds.c | 3 +- src/backend/executor/execExpr.c | 9 +- src/backend/executor/execIndexing.c | 2 +- src/backend/executor/execSRF.c | 3 +- src/backend/executor/functions.c | 8 +- src/backend/executor/nodeAgg.c | 3 +- src/backend/executor/nodeGatherMerge.c | 3 +- src/backend/executor/nodeIndexscan.c | 3 +- src/backend/executor/nodeMergeAppend.c | 3 +- src/backend/executor/nodeMergejoin.c | 3 +- src/backend/executor/nodeWindowAgg.c | 7 +- src/backend/libpq/hba.c | 10 +- src/backend/optimizer/path/indxpath.c | 12 +- src/backend/optimizer/util/plancat.c | 13 +- src/backend/partitioning/partbounds.c | 40 +-- src/backend/partitioning/partprune.c | 11 +- src/backend/regex/regc_pg_locale.c | 58 ++-- src/backend/regex/regcomp.c | 2 +- .../libpqwalreceiver/libpqwalreceiver.c | 2 +- src/backend/statistics/extended_stats.c | 3 +- src/backend/tsearch/spell.c | 2 +- src/backend/tsearch/ts_locale.c | 37 ++- src/backend/tsearch/wparser_def.c | 7 +- src/backend/utils/adt/array_selfuncs.c | 3 +- src/backend/utils/adt/array_typanalyze.c | 5 +- src/backend/utils/adt/array_userfuncs.c | 4 +- src/backend/utils/adt/arrayfuncs.c | 26 +- src/backend/utils/adt/formatting.c | 206 +++++++------- src/backend/utils/adt/jsonb_gin.c | 3 +- src/backend/utils/adt/jsonb_util.c | 3 +- src/backend/utils/adt/like.c | 64 ++--- src/backend/utils/adt/like_match.c | 4 +- src/backend/utils/adt/misc.c | 9 +- src/backend/utils/adt/pg_locale.c | 212 +++++---------- src/backend/utils/adt/regexp.c | 12 +- src/backend/utils/adt/rowtypes.c | 5 +- src/backend/utils/adt/selfuncs.c | 94 +++---- src/backend/utils/adt/varchar.c | 6 +- src/backend/utils/adt/varlena.c | 252 ++++++++---------- src/backend/utils/cache/partcache.c | 11 +- src/backend/utils/cache/relcache.c | 7 + src/backend/utils/cache/typcache.c | 3 +- src/backend/utils/fmgr/README | 4 +- src/backend/utils/fmgr/fmgr.c | 60 ++--- src/backend/utils/sort/tuplesort.c | 5 +- src/include/access/genam.h | 1 + src/include/access/gin_private.h | 4 +- src/include/access/gist_private.h | 2 +- src/include/access/skey.h | 4 +- src/include/access/spgist_private.h | 2 +- src/include/executor/nodeAgg.h | 2 +- src/include/fmgr.h | 123 ++++----- src/include/nodes/execnodes.h | 2 +- src/include/nodes/relation.h | 2 +- src/include/partitioning/partbounds.h | 6 +- src/include/partitioning/partprune.h | 2 +- src/include/regex/regex.h | 5 +- src/include/regex/regguts.h | 2 +- src/include/utils/builtins.h | 2 +- src/include/utils/formatting.h | 6 +- src/include/utils/partcache.h | 4 +- src/include/utils/pg_locale.h | 6 +- src/include/utils/rel.h | 1 + src/include/utils/selfuncs.h | 4 +- src/include/utils/sortsupport.h | 2 +- src/include/utils/typcache.h | 2 +- src/include/utils/varlena.h | 4 +- src/pl/plpgsql/src/pl_comp.c | 7 +- 95 files changed, 828 insertions(+), 912 deletions(-) diff --git a/contrib/btree_gist/btree_bit.c b/contrib/btree_gist/btree_bit.c index 2225244ded..42c2fb9ba4 100644 --- a/contrib/btree_gist/btree_bit.c +++ b/contrib/btree_gist/btree_bit.c @@ -24,7 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_bit_same); /* define for comparison */ static bool -gbt_bitgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_bitgt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(bitgt, PointerGetDatum(a), @@ -32,7 +32,7 @@ gbt_bitgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_bitge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_bitge(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(bitge, PointerGetDatum(a), @@ -40,7 +40,7 @@ gbt_bitge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_biteq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_biteq(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(biteq, PointerGetDatum(a), @@ -48,7 +48,7 @@ gbt_biteq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_bitle(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_bitle(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(bitle, PointerGetDatum(a), @@ -56,7 +56,7 @@ gbt_bitle(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_bitlt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_bitlt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(bitlt, PointerGetDatum(a), @@ -64,7 +64,7 @@ gbt_bitlt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static int32 -gbt_bitcmp(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_bitcmp(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetInt32(DirectFunctionCall2(byteacmp, PointerGetDatum(a), diff --git a/contrib/btree_gist/btree_bytea.c b/contrib/btree_gist/btree_bytea.c index 6b005f0157..9b8208378e 100644 --- a/contrib/btree_gist/btree_bytea.c +++ b/contrib/btree_gist/btree_bytea.c @@ -23,7 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_bytea_same); /* define for comparison */ static bool -gbt_byteagt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_byteagt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(byteagt, PointerGetDatum(a), @@ -31,7 +31,7 @@ gbt_byteagt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_byteage(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_byteage(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(byteage, PointerGetDatum(a), @@ -39,7 +39,7 @@ gbt_byteage(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_byteaeq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_byteaeq(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(byteaeq, PointerGetDatum(a), @@ -47,7 +47,7 @@ gbt_byteaeq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_byteale(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_byteale(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(byteale, PointerGetDatum(a), @@ -55,7 +55,7 @@ gbt_byteale(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_bytealt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_bytealt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(bytealt, PointerGetDatum(a), @@ -63,7 +63,7 @@ gbt_bytealt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static int32 -gbt_byteacmp(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_byteacmp(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetInt32(DirectFunctionCall2(byteacmp, PointerGetDatum(a), diff --git a/contrib/btree_gist/btree_numeric.c b/contrib/btree_gist/btree_numeric.c index b72060cdb6..9666f480c8 100644 --- a/contrib/btree_gist/btree_numeric.c +++ b/contrib/btree_gist/btree_numeric.c @@ -27,7 +27,7 @@ PG_FUNCTION_INFO_V1(gbt_numeric_same); /* define for comparison */ static bool -gbt_numeric_gt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_numeric_gt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(numeric_gt, PointerGetDatum(a), @@ -35,7 +35,7 @@ gbt_numeric_gt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_numeric_ge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_numeric_ge(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(numeric_ge, PointerGetDatum(a), @@ -43,7 +43,7 @@ gbt_numeric_ge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_numeric_eq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_numeric_eq(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(numeric_eq, PointerGetDatum(a), @@ -51,7 +51,7 @@ gbt_numeric_eq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_numeric_le(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_numeric_le(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(numeric_le, PointerGetDatum(a), @@ -59,7 +59,7 @@ gbt_numeric_le(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_numeric_lt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_numeric_lt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2(numeric_lt, PointerGetDatum(a), @@ -67,7 +67,7 @@ gbt_numeric_lt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static int32 -gbt_numeric_cmp(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_numeric_cmp(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetInt32(DirectFunctionCall2(numeric_cmp, PointerGetDatum(a), diff --git a/contrib/btree_gist/btree_text.c b/contrib/btree_gist/btree_text.c index 8019d11281..658e84b0ad 100644 --- a/contrib/btree_gist/btree_text.c +++ b/contrib/btree_gist/btree_text.c @@ -23,7 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_text_same); /* define for comparison */ static bool -gbt_textgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_textgt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2Coll(text_gt, collation, @@ -32,7 +32,7 @@ gbt_textgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_textge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_textge(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2Coll(text_ge, collation, @@ -41,7 +41,7 @@ gbt_textge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_texteq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_texteq(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2Coll(texteq, collation, @@ -50,7 +50,7 @@ gbt_texteq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_textle(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_textle(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2Coll(text_le, collation, @@ -59,7 +59,7 @@ gbt_textle(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static bool -gbt_textlt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_textlt(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetBool(DirectFunctionCall2Coll(text_lt, collation, @@ -68,7 +68,7 @@ gbt_textlt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) } static int32 -gbt_textcmp(const void *a, const void *b, Oid collation, FmgrInfo *flinfo) +gbt_textcmp(const void *a, const void *b, fmLocalePtr collation, FmgrInfo *flinfo) { return DatumGetInt32(DirectFunctionCall2Coll(bttextcmp, collation, diff --git a/contrib/btree_gist/btree_utils_var.c b/contrib/btree_gist/btree_utils_var.c index 670c879e77..3e98f48a5c 100644 --- a/contrib/btree_gist/btree_utils_var.c +++ b/contrib/btree_gist/btree_utils_var.c @@ -24,7 +24,7 @@ typedef struct typedef struct { const gbtree_vinfo *tinfo; - Oid collation; + fmLocalePtr collation; FmgrInfo *flinfo; } gbt_vsrt_arg; @@ -232,7 +232,7 @@ gbt_var_node_truncate(const GBT_VARKEY *node, int32 cpf_length, const gbtree_vin void -gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation, +gbt_var_bin_union(Datum *u, GBT_VARKEY *e, fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) { GBT_VARKEY_R eo = gbt_var_key_readable(e); @@ -321,7 +321,7 @@ gbt_var_fetch(PG_FUNCTION_ARGS) GBT_VARKEY * -gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation, +gbt_var_union(const GistEntryVector *entryvec, int32 *size, fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) { int i = 0, @@ -360,7 +360,7 @@ gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation, bool -gbt_var_same(Datum d1, Datum d2, Oid collation, +gbt_var_same(Datum d1, Datum d2, fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) { GBT_VARKEY *t1 = (GBT_VARKEY *) DatumGetPointer(d1); @@ -378,7 +378,7 @@ gbt_var_same(Datum d1, Datum d2, Oid collation, float * gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n, - Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) + fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) { GBT_VARKEY *orge = (GBT_VARKEY *) DatumGetPointer(o->key); GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(n->key); @@ -458,7 +458,7 @@ gbt_vsrt_cmp(const void *a, const void *b, void *arg) GIST_SPLITVEC * gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v, - Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) + fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) { OffsetNumber i, maxoff = entryvec->n - 1; @@ -556,7 +556,7 @@ bool gbt_var_consistent(GBT_VARKEY_R *key, const void *query, StrategyNumber strategy, - Oid collation, + fmLocalePtr collation, bool is_leaf, const gbtree_vinfo *tinfo, FmgrInfo *flinfo) diff --git a/contrib/btree_gist/btree_utils_var.h b/contrib/btree_gist/btree_utils_var.h index 15d847c139..2334d7392a 100644 --- a/contrib/btree_gist/btree_utils_var.h +++ b/contrib/btree_gist/btree_utils_var.h @@ -34,12 +34,12 @@ typedef struct /* Methods */ - bool (*f_gt) (const void *, const void *, Oid, FmgrInfo *); /* greater than */ - bool (*f_ge) (const void *, const void *, Oid, FmgrInfo *); /* greater equal */ - bool (*f_eq) (const void *, const void *, Oid, FmgrInfo *); /* equal */ - bool (*f_le) (const void *, const void *, Oid, FmgrInfo *); /* less equal */ - bool (*f_lt) (const void *, const void *, Oid, FmgrInfo *); /* less than */ - int32 (*f_cmp) (const void *, const void *, Oid, FmgrInfo *); /* compare */ + bool (*f_gt) (const void *, const void *, fmLocalePtr, FmgrInfo *); /* greater than */ + bool (*f_ge) (const void *, const void *, fmLocalePtr, FmgrInfo *); /* greater equal */ + bool (*f_eq) (const void *, const void *, fmLocalePtr, FmgrInfo *); /* equal */ + bool (*f_le) (const void *, const void *, fmLocalePtr, FmgrInfo *); /* less equal */ + bool (*f_lt) (const void *, const void *, fmLocalePtr, FmgrInfo *); /* less than */ + int32 (*f_cmp) (const void *, const void *, fmLocalePtr, FmgrInfo *); /* compare */ GBT_VARKEY *(*f_l2n) (GBT_VARKEY *, FmgrInfo *flinfo); /* convert leaf to node */ } gbtree_vinfo; @@ -52,22 +52,22 @@ extern GBT_VARKEY *gbt_var_key_copy(const GBT_VARKEY_R *u); extern GISTENTRY *gbt_var_compress(GISTENTRY *entry, const gbtree_vinfo *tinfo); extern GBT_VARKEY *gbt_var_union(const GistEntryVector *entryvec, int32 *size, - Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); + fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); -extern bool gbt_var_same(Datum d1, Datum d2, Oid collation, +extern bool gbt_var_same(Datum d1, Datum d2, fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); extern float *gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n, - Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); + fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); extern bool gbt_var_consistent(GBT_VARKEY_R *key, const void *query, - StrategyNumber strategy, Oid collation, bool is_leaf, + StrategyNumber strategy, fmLocalePtr collation, bool is_leaf, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); extern GIST_SPLITVEC *gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v, - Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); + fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); -extern void gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation, +extern void gbt_var_bin_union(Datum *u, GBT_VARKEY *e, fmLocalePtr collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo); #endif diff --git a/contrib/citext/citext.c b/contrib/citext/citext.c index 24ceeb11fc..7fcf479ea0 100644 --- a/contrib/citext/citext.c +++ b/contrib/citext/citext.c @@ -7,6 +7,7 @@ #include "catalog/pg_collation.h" #include "utils/builtins.h" #include "utils/formatting.h" +#include "utils/pg_locale.h" #include "utils/varlena.h" PG_MODULE_MAGIC; @@ -17,8 +18,8 @@ PG_MODULE_MAGIC; * ==================== */ -static int32 citextcmp(text *left, text *right, Oid collid); -static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid); +static int32 citextcmp(text *left, text *right, fmLocalePtr collation); +static int32 internal_citext_pattern_cmp(text *left, text *right, fmLocalePtr collation); /* * ================= @@ -32,7 +33,7 @@ static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid); * Returns int32 negative, zero, or positive. */ static int32 -citextcmp(text *left, text *right, Oid collid) +citextcmp(text *left, text *right, fmLocalePtr collation) { char *lcstr, *rcstr; @@ -46,12 +47,12 @@ citextcmp(text *left, text *right, Oid collid) * collation-dependent equality and hashing functions. */ - lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID); - rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID); + lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); + rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); result = varstr_cmp(lcstr, strlen(lcstr), rcstr, strlen(rcstr), - collid); + collation); pfree(lcstr); pfree(rcstr); @@ -65,7 +66,7 @@ citextcmp(text *left, text *right, Oid collid) * Returns int32 negative, zero, or positive. */ static int32 -internal_citext_pattern_cmp(text *left, text *right, Oid collid) +internal_citext_pattern_cmp(text *left, text *right, fmLocalePtr collation) { char *lcstr, *rcstr; @@ -73,8 +74,8 @@ internal_citext_pattern_cmp(text *left, text *right, Oid collid) rlen; int32 result; - lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID); - rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID); + lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); + rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); llen = strlen(lcstr); rlen = strlen(rcstr); @@ -143,7 +144,7 @@ citext_hash(PG_FUNCTION_ARGS) char *str; Datum result; - str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID); + str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); result = hash_any((unsigned char *) str, strlen(str)); pfree(str); @@ -163,7 +164,7 @@ citext_hash_extended(PG_FUNCTION_ARGS) char *str; Datum result; - str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID); + str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); result = hash_any_extended((unsigned char *) str, strlen(str), seed); pfree(str); @@ -192,8 +193,8 @@ citext_eq(PG_FUNCTION_ARGS) /* We can't compare lengths in advance of downcasing ... */ - lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID); - rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID); + lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); + rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); /* * Since we only care about equality or not-equality, we can avoid all the @@ -222,8 +223,8 @@ citext_ne(PG_FUNCTION_ARGS) /* We can't compare lengths in advance of downcasing ... */ - lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID); - rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID); + lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); + rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); /* * Since we only care about equality or not-equality, we can avoid all the diff --git a/contrib/ltree/lquery_op.c b/contrib/ltree/lquery_op.c index b6d2deb1af..deed000137 100644 --- a/contrib/ltree/lquery_op.c +++ b/contrib/ltree/lquery_op.c @@ -9,6 +9,7 @@ #include "catalog/pg_collation.h" #include "utils/formatting.h" +#include "utils/pg_locale.h" #include "ltree.h" PG_FUNCTION_INFO_V1(ltq_regex); @@ -90,8 +91,8 @@ bool int ltree_strncasecmp(const char *a, const char *b, size_t s) { - char *al = str_tolower(a, s, DEFAULT_COLLATION_OID); - char *bl = str_tolower(b, s, DEFAULT_COLLATION_OID); + char *al = str_tolower(a, s, pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); + char *bl = str_tolower(b, s, pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); int res; res = strncmp(al, bl, s); diff --git a/contrib/pg_trgm/trgm.h b/contrib/pg_trgm/trgm.h index f0ab50dd05..0dd28aeb50 100644 --- a/contrib/pg_trgm/trgm.h +++ b/contrib/pg_trgm/trgm.h @@ -7,6 +7,7 @@ #include "access/gist.h" #include "access/itup.h" #include "access/stratnum.h" +#include "fmgr.h" #include "storage/bufpage.h" /* @@ -133,7 +134,7 @@ extern TRGM *generate_wildcard_trgm(const char *str, int slen); extern float4 cnt_sml(TRGM *trg1, TRGM *trg2, bool inexact); extern bool trgm_contained_by(TRGM *trg1, TRGM *trg2); extern bool *trgm_presence_map(TRGM *query, TRGM *key); -extern TRGM *createTrgmNFA(text *text_re, Oid collation, +extern TRGM *createTrgmNFA(text *text_re, fmLocalePtr collation, TrgmPackedGraph **graph, MemoryContext rcontext); extern bool trigramsMatchGraph(TrgmPackedGraph *graph, bool *check); diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c index 547e7c094f..f9279ca7d7 100644 --- a/contrib/pg_trgm/trgm_regexp.c +++ b/contrib/pg_trgm/trgm_regexp.c @@ -480,7 +480,7 @@ typedef struct static TRGM *createTrgmNFAInternal(regex_t *regex, TrgmPackedGraph **graph, MemoryContext rcontext); static void RE_compile(regex_t *regex, text *text_re, - int cflags, Oid collation); + int cflags, fmLocalePtr collation); static void getColorInfo(regex_t *regex, TrgmNFA *trgmNFA); static bool convertPgWchar(pg_wchar c, trgm_mb_char *result); static void transformGraph(TrgmNFA *trgmNFA); @@ -520,7 +520,7 @@ static void printTrgmPackedGraph(TrgmPackedGraph *packedGraph, TRGM *trigrams); * context). */ TRGM * -createTrgmNFA(text *text_re, Oid collation, +createTrgmNFA(text *text_re, fmLocalePtr collation, TrgmPackedGraph **graph, MemoryContext rcontext) { TRGM *trg; @@ -731,7 +731,7 @@ trigramsMatchGraph(TrgmPackedGraph *graph, bool *check) * NB: pg_regfree must be applied to regex if this completes successfully. */ static void -RE_compile(regex_t *regex, text *text_re, int cflags, Oid collation) +RE_compile(regex_t *regex, text *text_re, int cflags, fmLocalePtr collation) { int text_re_len = VARSIZE_ANY_EXHDR(text_re); char *text_re_val = VARDATA_ANY(text_re); diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index e95fbbcea7..20050314ba 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -32,6 +32,7 @@ #include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" @@ -243,12 +244,14 @@ brininsert(Relation idxRel, Datum *values, bool *nulls, Datum result; BrinValues *bval; FmgrInfo *addValue; + fmLocalePtr collation; bval = &dtup->bt_columns[keyno]; addValue = index_getprocinfo(idxRel, keyno + 1, BRIN_PROCNUM_ADDVALUE); + collation = index_getcollinfo(idxRel, keyno + 1); result = FunctionCall4Coll(addValue, - idxRel->rd_indcollation[keyno], + collation, PointerGetDatum(bdesc), PointerGetDatum(bval), values[keyno], @@ -483,7 +486,8 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) * this index ... */ Assert((key->sk_flags & SK_ISNULL) || - (key->sk_collation == + !key->sk_collation || + (key->sk_collation->collid == TupleDescAttr(bdesc->bd_tupdesc, keyattno - 1)->attcollation)); @@ -644,7 +648,7 @@ brinbuildCallback(Relation index, * Update dtuple state, if and as necessary. */ FunctionCall4Coll(addValue, - attr->attcollation, + pg_newlocale_from_collation(attr->attcollation), PointerGetDatum(state->bs_bdesc), PointerGetDatum(col), values[i], isnull[i]); @@ -1444,7 +1448,7 @@ union_tuples(BrinDesc *bdesc, BrinMemTuple *a, BrinTuple *b) unionFn = index_getprocinfo(bdesc->bd_index, keyno + 1, BRIN_PROCNUM_UNION); FunctionCall3Coll(unionFn, - bdesc->bd_index->rd_indcollation[keyno], + index_getcollinfo(bdesc->bd_index, keyno + 1), PointerGetDatum(bdesc), PointerGetDatum(col_a), PointerGetDatum(col_b)); diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 6ce355c6a9..a091d4a216 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -140,7 +140,6 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); Datum newval = PG_GETARG_DATUM(2); bool isnull = PG_GETARG_BOOL(3); - Oid colloid = PG_GET_COLLATION(); FmgrInfo *finfo; Datum result; bool new = false; @@ -190,7 +189,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) * "contains empty" flag in the element (unless already set). */ finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY); - if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval))) + if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, PG_GET_COLLATION(), newval))) { if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY])) { @@ -207,7 +206,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) /* Check if the new value is already contained. */ finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS); if (finfo != NULL && - DatumGetBool(FunctionCall2Coll(finfo, colloid, + DatumGetBool(FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[INCLUSION_UNION], newval))) PG_RETURN_BOOL(false); @@ -222,7 +221,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) */ finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE); if (finfo != NULL && - !DatumGetBool(FunctionCall2Coll(finfo, colloid, + !DatumGetBool(FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[INCLUSION_UNION], newval))) { @@ -233,7 +232,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) /* Finally, merge the new value to the existing union. */ finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE); Assert(finfo != NULL); - result = FunctionCall2Coll(finfo, colloid, + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[INCLUSION_UNION], newval); if (!attr->attbyval) pfree(DatumGetPointer(column->bv_values[INCLUSION_UNION])); @@ -253,8 +252,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); ScanKey key = (ScanKey) PG_GETARG_POINTER(2); - Oid colloid = PG_GET_COLLATION(), - subtype; + Oid subtype; Datum unionval; AttrNumber attno; Datum query; @@ -317,49 +315,49 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTLeftStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverRightStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverLeftStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTRightStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverRightStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTLeftStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTRightStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverLeftStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTBelowStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverAboveStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverBelowStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTAboveStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverAboveStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTBelowStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); case RTAboveStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverBelowStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); /* @@ -378,7 +376,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTSubEqualStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, key->sk_strategy); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_DATUM(result); /* @@ -398,7 +396,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTSuperEqualStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverlapStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); if (DatumGetBool(result)) PG_RETURN_BOOL(true); @@ -417,13 +415,13 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTAdjacentStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverlapStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); if (DatumGetBool(result)) PG_RETURN_BOOL(true); finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTAdjacentStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_DATUM(result); /* @@ -452,7 +450,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTLessEqualStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTRightStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); if (!DatumGetBool(result)) PG_RETURN_BOOL(true); @@ -462,7 +460,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTEqualStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTContainsStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); if (DatumGetBool(result)) PG_RETURN_BOOL(true); @@ -471,7 +469,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) case RTGreaterEqualStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTLeftStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); if (!DatumGetBool(result)) PG_RETURN_BOOL(true); @@ -481,7 +479,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) /* no need to check for empty elements */ finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTLeftStrategyNumber); - result = FunctionCall2Coll(finfo, colloid, unionval, query); + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), unionval, query); PG_RETURN_BOOL(!DatumGetBool(result)); default: @@ -503,7 +501,6 @@ brin_inclusion_union(PG_FUNCTION_ARGS) BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1); BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2); - Oid colloid = PG_GET_COLLATION(); AttrNumber attno; Form_pg_attribute attr; FmgrInfo *finfo; @@ -560,7 +557,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS) /* Check if A and B are mergeable; if not, mark A unmergeable. */ finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE); if (finfo != NULL && - !DatumGetBool(FunctionCall2Coll(finfo, colloid, + !DatumGetBool(FunctionCall2Coll(finfo, PG_GET_COLLATION(), col_a->bv_values[INCLUSION_UNION], col_b->bv_values[INCLUSION_UNION]))) { @@ -571,7 +568,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS) /* Finally, merge B to A. */ finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE); Assert(finfo != NULL); - result = FunctionCall2Coll(finfo, colloid, + result = FunctionCall2Coll(finfo, PG_GET_COLLATION(), col_a->bv_values[INCLUSION_UNION], col_b->bv_values[INCLUSION_UNION]); if (!attr->attbyval) diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 0f6aa33a45..98d0dfe4ee 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -69,7 +69,6 @@ brin_minmax_add_value(PG_FUNCTION_ARGS) BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); Datum newval = PG_GETARG_DATUM(2); bool isnull = PG_GETARG_DATUM(3); - Oid colloid = PG_GET_COLLATION(); FmgrInfo *cmpFn; Datum compar; bool updated = false; @@ -111,7 +110,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS) */ cmpFn = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid, BTLessStrategyNumber); - compar = FunctionCall2Coll(cmpFn, colloid, newval, column->bv_values[0]); + compar = FunctionCall2Coll(cmpFn, PG_GET_COLLATION(), newval, column->bv_values[0]); if (DatumGetBool(compar)) { if (!attr->attbyval) @@ -125,7 +124,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS) */ cmpFn = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid, BTGreaterStrategyNumber); - compar = FunctionCall2Coll(cmpFn, colloid, newval, column->bv_values[1]); + compar = FunctionCall2Coll(cmpFn, PG_GET_COLLATION(), newval, column->bv_values[1]); if (DatumGetBool(compar)) { if (!attr->attbyval) @@ -148,8 +147,7 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); ScanKey key = (ScanKey) PG_GETARG_POINTER(2); - Oid colloid = PG_GET_COLLATION(), - subtype; + Oid subtype; AttrNumber attno; Datum value; Datum matches; @@ -194,7 +192,7 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) case BTLessEqualStrategyNumber: finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype, key->sk_strategy); - matches = FunctionCall2Coll(finfo, colloid, column->bv_values[0], + matches = FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[0], value); break; case BTEqualStrategyNumber: @@ -206,21 +204,21 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) */ finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype, BTLessEqualStrategyNumber); - matches = FunctionCall2Coll(finfo, colloid, column->bv_values[0], + matches = FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[0], value); if (!DatumGetBool(matches)) break; /* max() >= scankey */ finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype, BTGreaterEqualStrategyNumber); - matches = FunctionCall2Coll(finfo, colloid, column->bv_values[1], + matches = FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[1], value); break; case BTGreaterEqualStrategyNumber: case BTGreaterStrategyNumber: finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype, key->sk_strategy); - matches = FunctionCall2Coll(finfo, colloid, column->bv_values[1], + matches = FunctionCall2Coll(finfo, PG_GET_COLLATION(), column->bv_values[1], value); break; default: @@ -243,7 +241,6 @@ brin_minmax_union(PG_FUNCTION_ARGS) BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1); BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2); - Oid colloid = PG_GET_COLLATION(); AttrNumber attno; Form_pg_attribute attr; FmgrInfo *finfo; @@ -281,7 +278,7 @@ brin_minmax_union(PG_FUNCTION_ARGS) /* Adjust minimum, if B's min is less than A's min */ finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid, BTLessStrategyNumber); - needsadj = FunctionCall2Coll(finfo, colloid, col_b->bv_values[0], + needsadj = FunctionCall2Coll(finfo, PG_GET_COLLATION(), col_b->bv_values[0], col_a->bv_values[0]); if (needsadj) { @@ -294,7 +291,7 @@ brin_minmax_union(PG_FUNCTION_ARGS) /* Adjust maximum, if B's max is greater than A's max */ finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid, BTGreaterStrategyNumber); - needsadj = FunctionCall2Coll(finfo, colloid, col_b->bv_values[1], + needsadj = FunctionCall2Coll(finfo, PG_GET_COLLATION(), col_b->bv_values[1], col_a->bv_values[1]); if (needsadj) { diff --git a/src/backend/access/common/scankey.c b/src/backend/access/common/scankey.c index 781516c56a..f8b25839c4 100644 --- a/src/backend/access/common/scankey.c +++ b/src/backend/access/common/scankey.c @@ -16,6 +16,7 @@ #include "access/skey.h" #include "catalog/pg_collation.h" +#include "utils/pg_locale.h" /* @@ -42,7 +43,7 @@ ScanKeyEntryInitialize(ScanKey entry, entry->sk_attno = attributeNumber; entry->sk_strategy = strategy; entry->sk_subtype = subtype; - entry->sk_collation = collation; + entry->sk_collation = pg_newlocale_from_collation(collation); entry->sk_argument = argument; if (RegProcedureIsValid(procedure)) { @@ -83,7 +84,7 @@ ScanKeyInit(ScanKey entry, entry->sk_attno = attributeNumber; entry->sk_strategy = strategy; entry->sk_subtype = InvalidOid; - entry->sk_collation = DEFAULT_COLLATION_OID; + entry->sk_collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); entry->sk_argument = argument; fmgr_info(procedure, &entry->sk_func); } @@ -103,7 +104,7 @@ ScanKeyEntryInitializeWithInfo(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, - Oid collation, + fmLocalePtr collation, FmgrInfo *finfo, Datum argument) { diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index d7696a1ad0..0bca9e0e44 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -26,6 +26,7 @@ #include "storage/predicate.h" #include "utils/builtins.h" #include "utils/index_selfuncs.h" +#include "utils/pg_locale.h" #include "utils/typcache.h" @@ -204,9 +205,9 @@ initGinState(GinState *state, Relation index) * type has a nondefault collation.) */ if (OidIsValid(index->rd_indcollation[i])) - state->supportCollation[i] = index->rd_indcollation[i]; + state->supportCollation[i] = index_getcollinfo(index, i + 1); else - state->supportCollation[i] = DEFAULT_COLLATION_OID; + state->supportCollation[i] = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); } } @@ -440,7 +441,7 @@ typedef struct typedef struct { FmgrInfo *cmpDatumFunc; - Oid collation; + fmLocalePtr collation; bool haveDups; } cmpEntriesArg; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 8a42effdf7..45562a0c33 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -24,6 +24,7 @@ #include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" @@ -1521,9 +1522,9 @@ initGISTstate(Relation index) * any cases where a GiST storage type has a nondefault collation.) */ if (OidIsValid(index->rd_indcollation[i])) - giststate->supportCollation[i] = index->rd_indcollation[i]; + giststate->supportCollation[i] = index_getcollinfo(index, i + 1); else - giststate->supportCollation[i] = DEFAULT_COLLATION_OID; + giststate->supportCollation[i] = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); } MemoryContextSwitchTo(oldCxt); diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 7c9b2cfc9e..735afc8d3a 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -18,6 +18,7 @@ #include "access/reloptions.h" #include "access/relscan.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "storage/buf_internals.h" @@ -88,7 +89,7 @@ _hash_datum2hashkey(Relation rel, Datum key) procinfo = index_getprocinfo(rel, 1, HASHSTANDARD_PROC); collation = rel->rd_indcollation[0]; - return DatumGetUInt32(FunctionCall1Coll(procinfo, collation, key)); + return DatumGetUInt32(FunctionCall1Coll(procinfo, pg_newlocale_from_collation(collation), key)); } /* @@ -115,7 +116,7 @@ _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype) RelationGetRelationName(rel)); collation = rel->rd_indcollation[0]; - return DatumGetUInt32(OidFunctionCall1Coll(hash_proc, collation, key)); + return DatumGetUInt32(OidFunctionCall1Coll(hash_proc, pg_newlocale_from_collation(collation), key)); } /* diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index eade540ef5..19a905b80b 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -79,6 +79,7 @@ #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/predicate.h" +#include "utils/pg_locale.h" #include "utils/snapmgr.h" #include "utils/tqual.h" @@ -899,6 +900,27 @@ index_getprocinfo(Relation irel, return locinfo; } +/* + * Get index collation lookup info from relcache. + */ +pg_locale_t +index_getcollinfo(Relation irel, + AttrNumber attnum) +{ + Assert(irel->rd_indcollinfo != NULL); + + if (irel->rd_indcollation[attnum - 1] == InvalidOid) + return NULL; + + /* Initialize the lookup info if first time through */ + if (!irel->rd_indcollinfo[attnum - 1]) + { + irel->rd_indcollinfo[attnum - 1] = pg_newlocale_from_collation(irel->rd_indcollation[attnum - 1]); + } + + return irel->rd_indcollinfo[attnum - 1]; +} + /* ---------------- * index_store_float8_orderby_distances * diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 16223d01ec..2fd9bab69a 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -21,6 +21,7 @@ #include "pgstat.h" #include "storage/predicate.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/tqual.h" @@ -955,7 +956,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) cur->sk_attno, InvalidStrategy, cur->sk_subtype, - cur->sk_collation, + cur->sk_collation ? cur->sk_collation->collid : InvalidOid, cmp_proc, cur->sk_argument); } diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 205457ef99..f622aa2cc4 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -24,13 +24,14 @@ #include "utils/array.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" typedef struct BTSortArrayContext { FmgrInfo flinfo; - Oid collation; + fmLocalePtr collation; bool reverse; } BTSortArrayContext; @@ -103,7 +104,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup) (AttrNumber) (i + 1), InvalidStrategy, InvalidOid, - rel->rd_indcollation[i], + index_getcollinfo(rel, i + 1), procinfo, arg); } @@ -151,7 +152,7 @@ _bt_mkscankey_nodata(Relation rel) (AttrNumber) (i + 1), InvalidStrategy, InvalidOid, - rel->rd_indcollation[i], + index_getcollinfo(rel, i + 1), procinfo, (Datum) 0); } @@ -1246,7 +1247,7 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption) { skey->sk_strategy = BTEqualStrategyNumber; skey->sk_subtype = InvalidOid; - skey->sk_collation = InvalidOid; + skey->sk_collation = 0; } else if (skey->sk_flags & SK_SEARCHNOTNULL) { @@ -1255,7 +1256,7 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption) else skey->sk_strategy = BTLessStrategyNumber; skey->sk_subtype = InvalidOid; - skey->sk_collation = InvalidOid; + skey->sk_collation = 0; } else { diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c index 098e09c574..f17ee1e216 100644 --- a/src/backend/access/spgist/spgdoinsert.c +++ b/src/backend/access/spgist/spgdoinsert.c @@ -827,7 +827,7 @@ doPickSplit(Relation index, SpGistState *state, */ procinfo = index_getprocinfo(index, 1, SPGIST_PICKSPLIT_PROC); FunctionCall2Coll(procinfo, - index->rd_indcollation[0], + index_getcollinfo(index, 1), PointerGetDatum(&in), PointerGetDatum(&out)); @@ -1923,7 +1923,7 @@ spgdoinsert(Relation index, SpGistState *state, compressProcinfo = index_getprocinfo(index, 1, SPGIST_COMPRESS_PROC); leafDatum = FunctionCall1Coll(compressProcinfo, - index->rd_indcollation[0], + index_getcollinfo(index, 1), datum); } else @@ -2125,7 +2125,7 @@ spgdoinsert(Relation index, SpGistState *state, { /* use user-defined choose method */ FunctionCall2Coll(procinfo, - index->rd_indcollation[0], + index_getcollinfo(index, 1), PointerGetDatum(&in), PointerGetDatum(&out)); } diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c index c883ae95e4..d467e6b923 100644 --- a/src/backend/access/spgist/spgscan.c +++ b/src/backend/access/spgist/spgscan.c @@ -329,7 +329,7 @@ spgbeginscan(Relation rel, int keysz, int orderbysz) index_getprocinfo(rel, 1, SPGIST_LEAF_CONSISTENT_PROC), CurrentMemoryContext); - so->indexCollation = rel->rd_indcollation[0]; + so->indexCollation = index_getcollinfo(rel, 1); scan->opaque = so; diff --git a/src/backend/access/spgist/spgtextproc.c b/src/backend/access/spgist/spgtextproc.c index 153c57b540..e354594c60 100644 --- a/src/backend/access/spgist/spgtextproc.c +++ b/src/backend/access/spgist/spgtextproc.c @@ -425,7 +425,7 @@ spg_text_inner_consistent(PG_FUNCTION_ARGS) { spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); - bool collate_is_c = lc_collate_is_c(PG_GET_COLLATION()); + bool collate_is_c = PG_GET_COLLATION() && PG_GET_COLLATION()->collate_is_c; text *reconstructedValue; text *reconstrText; int maxReconstrLen; diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 9919e6f0d7..c232e8f76b 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -129,7 +129,7 @@ spgGetCache(Relation index) procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC); FunctionCall2Coll(procinfo, - index->rd_indcollation[0], + index_getcollinfo(index, 1), PointerGetDatum(&in), PointerGetDatum(&cache->config)); diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index b8445dc372..c4fe4de11c 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -55,6 +55,7 @@ #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/pg_rusage.h" #include "utils/sampling.h" #include "utils/sortsupport.h" @@ -1914,6 +1915,7 @@ compute_distinct_stats(VacAttrStatsP stats, bool is_varwidth = (!stats->attrtype->typbyval && stats->attrtype->typlen < 0); FmgrInfo f_cmpeq; + pg_locale_t collation; typedef struct { Datum value; @@ -1935,6 +1937,8 @@ compute_distinct_stats(VacAttrStatsP stats, track_cnt = 0; fmgr_info(mystats->eqfunc, &f_cmpeq); + /* We always use the default collation for statistics */ + collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); for (i = 0; i < samplerows; i++) { @@ -1993,9 +1997,8 @@ compute_distinct_stats(VacAttrStatsP stats, firstcount1 = track_cnt; for (j = 0; j < track_cnt; j++) { - /* We always use the default collation for statistics */ if (DatumGetBool(FunctionCall2Coll(&f_cmpeq, - DEFAULT_COLLATION_OID, + collation, value, track[j].value))) { match = true; @@ -2274,7 +2277,7 @@ compute_scalar_stats(VacAttrStatsP stats, memset(&ssup, 0, sizeof(ssup)); ssup.ssup_cxt = CurrentMemoryContext; /* We always use the default collation for statistics */ - ssup.ssup_collation = DEFAULT_COLLATION_OID; + ssup.ssup_collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); ssup.ssup_nulls_first = false; /* diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index 8fb51e8c3d..ed77b6e406 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -214,12 +214,10 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e return InvalidObjectAddress; /* - * Check that the locales can be loaded. NB: pg_newlocale_from_collation - * is only supposed to be called on non-C-equivalent locales. + * Check that the locales can be loaded. */ CommandCounterIncrement(); - if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid)) - (void) pg_newlocale_from_collation(newoid); + (void) pg_newlocale_from_collation(newoid); ObjectAddressSet(address, CollationRelationId, newoid); diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 87e4dd8245..f60443ca6d 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -58,6 +58,7 @@ #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/snapmgr.h" #include "utils/tqual.h" @@ -882,7 +883,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control, * psql, which has been found to be necessary due to old habits. */ t_sql = DirectFunctionCall4Coll(textregexreplace, - C_COLLATION_OID, + pg_newlocale_from_collation(C_COLLATION_OID), t_sql, CStringGetTextDatum("^\\\\echo.*$"), CStringGetTextDatum(""), diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index ebece4d1d7..116aa2935d 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -68,6 +68,7 @@ #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/syscache.h" #include "utils/typcache.h" @@ -2298,7 +2299,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver InvokeFunctionExecuteHook(fexpr->funcid); fmgr_info(fexpr->funcid, &flinfo); fmgr_info_set_expr((Node *) fexpr, &flinfo); - InitFunctionCallInfoData(fcinfo, &flinfo, nargs, fexpr->inputcollid, (Node *) callcontext, NULL); + InitFunctionCallInfoData(fcinfo, &flinfo, nargs, pg_newlocale_from_collation(fexpr->inputcollid), (Node *) callcontext, NULL); /* * Evaluate procedure arguments inside a suitable execution context. Note diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index d9087cac15..c7627f0276 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -46,6 +46,7 @@ #include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/typcache.h" @@ -970,7 +971,7 @@ ExecInitExprRec(Expr *node, ExprState *state, fmgr_info(opexpr->opfuncid, finfo); fmgr_info_set_expr((Node *) node, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, - opexpr->inputcollid, NULL, NULL); + pg_newlocale_from_collation(opexpr->inputcollid), NULL, NULL); /* Evaluate scalar directly into left function argument */ ExecInitExprRec(scalararg, state, @@ -1739,7 +1740,7 @@ ExecInitExprRec(Expr *node, ExprState *state, fmgr_info(proc, finfo); fmgr_info_set_expr((Node *) node, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, - inputcollid, NULL, NULL); + pg_newlocale_from_collation(inputcollid), NULL, NULL); /* * If we enforced permissions checks on index support @@ -1882,7 +1883,7 @@ ExecInitExprRec(Expr *node, ExprState *state, fmgr_info(typentry->cmp_proc, finfo); fmgr_info_set_expr((Node *) node, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, - minmaxexpr->inputcollid, NULL, NULL); + pg_newlocale_from_collation(minmaxexpr->inputcollid), NULL, NULL); scratch.opcode = EEOP_MINMAX; /* allocate space to store arguments */ @@ -2197,7 +2198,7 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, /* Initialize function call parameter structure too */ InitFunctionCallInfoData(*fcinfo, flinfo, - nargs, inputcollid, NULL, NULL); + nargs, pg_newlocale_from_collation(inputcollid), NULL, NULL); /* Keep extra copies of this info to save an indirection at runtime */ scratch->d.func.fn_addr = flinfo->fn_addr; diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 8b35bb458d..54e046f004 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -892,7 +892,7 @@ index_recheck_constraint(Relation index, Oid *constr_procs, return false; if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i], - index->rd_indcollation[i], + index_getcollinfo(index, i + 1), existing_values[i], new_values[i]))) return false; diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index bf73f05af2..7a61cebf19 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -30,6 +30,7 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/typcache.h" @@ -706,7 +707,7 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node, /* Initialize the function call parameter struct as well */ InitFunctionCallInfoData(sexpr->fcinfo_data, &(sexpr->func), list_length(sexpr->args), - input_collation, NULL, NULL); + pg_newlocale_from_collation(input_collation), NULL, NULL); /* If function returns set, check if that's allowed by caller */ if (sexpr->func.fn_retset && !allowSRF) diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index fc7c6051c5..d5ff7e12e8 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -31,6 +31,7 @@ #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/snapmgr.h" #include "utils/syscache.h" @@ -154,7 +155,7 @@ static Node *sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo, static List *init_execution_state(List *queryTree_list, SQLFunctionCachePtr fcache, bool lazyEvalOK); -static void init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK); +static void init_sql_fcache(FmgrInfo *finfo, pg_locale_t collation, bool lazyEvalOK); static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache); static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache); static void postquel_end(execution_state *es); @@ -591,9 +592,10 @@ init_execution_state(List *queryTree_list, * Initialize the SQLFunctionCache for a SQL function */ static void -init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK) +init_sql_fcache(FmgrInfo *finfo, pg_locale_t collation, bool lazyEvalOK) { Oid foid = finfo->fn_oid; + Oid collid = collation ? collation->collid : InvalidOid; MemoryContext fcontext; MemoryContext oldcontext; Oid rettype; @@ -676,7 +678,7 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK) */ fcache->pinfo = prepare_sql_fn_parse_info(procedureTuple, finfo->fn_expr, - collation); + collid); /* * And of course we need the function body text. diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index daf56cd3d1..951f45a730 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -234,6 +234,7 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/syscache.h" #include "utils/tuplesort.h" #include "utils/datum.h" @@ -2889,7 +2890,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, /* Begin filling in the pertrans data */ pertrans->aggref = aggref; pertrans->aggshared = false; - pertrans->aggCollation = aggref->inputcollid; + pertrans->aggCollation = pg_newlocale_from_collation(aggref->inputcollid); pertrans->transfn_oid = aggtransfn; pertrans->serialfn_oid = aggserialfn; pertrans->deserialfn_oid = aggdeserialfn; diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index 51d910bd5e..e98f97588c 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -25,6 +25,7 @@ #include "miscadmin.h" #include "optimizer/planmain.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" /* @@ -157,7 +158,7 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) SortSupport sortKey = gm_state->gm_sortkeys + i; sortKey->ssup_cxt = CurrentMemoryContext; - sortKey->ssup_collation = node->collations[i]; + sortKey->ssup_collation = pg_newlocale_from_collation(node->collations[i]); sortKey->ssup_nulls_first = node->nullsFirst[i]; sortKey->ssup_attno = node->sortColIdx[i]; diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index f209173a85..ddf01219f5 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -42,6 +42,7 @@ #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" /* @@ -1060,7 +1061,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) /* Initialize sort support */ orderbysort->ssup_cxt = CurrentMemoryContext; - orderbysort->ssup_collation = orderbyColl; + orderbysort->ssup_collation = pg_newlocale_from_collation(orderbyColl); /* See cmp_orderbyvals() comments on NULLS LAST */ orderbysort->ssup_nulls_first = false; /* ssup_attno is unused here and elsewhere */ diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 188e76b60c..a6c51a335d 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -43,6 +43,7 @@ #include "executor/nodeMergeAppend.h" #include "lib/binaryheap.h" #include "miscadmin.h" +#include "utils/pg_locale.h" /* * We have one slot for each item in the heap array. We use SlotNumber @@ -202,7 +203,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) SortSupport sortKey = mergestate->ms_sortkeys + i; sortKey->ssup_cxt = CurrentMemoryContext; - sortKey->ssup_collation = node->collations[i]; + sortKey->ssup_collation = pg_newlocale_from_collation(node->collations[i]); sortKey->ssup_nulls_first = node->nullsFirst[i]; sortKey->ssup_attno = node->sortColIdx[i]; diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 1c90291d12..292be0a49c 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -98,6 +98,7 @@ #include "miscadmin.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" /* @@ -212,7 +213,7 @@ MJExamineQuals(List *mergeclauses, /* Set up sort support data */ clause->ssup.ssup_cxt = CurrentMemoryContext; - clause->ssup.ssup_collation = collation; + clause->ssup.ssup_collation = pg_newlocale_from_collation(collation); if (opstrategy == BTLessStrategyNumber) clause->ssup.ssup_reverse = false; else if (opstrategy == BTGreaterStrategyNumber) diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 298e370745..cd4bd47cad 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -49,6 +49,7 @@ #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/regproc.h" #include "utils/syscache.h" #include "windowapi.h" @@ -83,7 +84,7 @@ typedef struct WindowStatePerFuncData FmgrInfo flinfo; /* fmgr lookup data for window function */ - Oid winCollation; /* collation derived for window function */ + fmLocalePtr winCollation; /* collation derived for window function */ /* * We need the len and byval info for the result of each function in order @@ -2448,7 +2449,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) econtext->ecxt_per_query_memory); fmgr_info_set_expr((Node *) wfunc, &perfuncstate->flinfo); - perfuncstate->winCollation = wfunc->inputcollid; + perfuncstate->winCollation = pg_newlocale_from_collation(wfunc->inputcollid); get_typlenbyval(wfunc->wintype, &perfuncstate->resulttypeLen, @@ -2511,7 +2512,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) fmgr_info(node->startInRangeFunc, &winstate->startInRangeFunc); if (OidIsValid(node->endInRangeFunc)) fmgr_info(node->endInRangeFunc, &winstate->endInRangeFunc); - winstate->inRangeColl = node->inRangeColl; + winstate->inRangeColl = pg_newlocale_from_collation(node->inRangeColl); winstate->inRangeAsc = node->inRangeAsc; winstate->inRangeNullsFirst = node->inRangeNullsFirst; diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 0129dd24d0..85751bc8c9 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -42,6 +42,7 @@ #include "utils/varlena.h" #include "utils/guc.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/memutils.h" #ifdef USE_LDAP @@ -2652,6 +2653,13 @@ parse_ident_line(TokenizedLine *tok_line) List *tokens; HbaToken *token; IdentLine *parsedline; + /* We can't do catalog access yet, so fake what we need of a C locale. */ + struct pg_locale_struct c_coll = { + .collid = C_COLLATION_OID, + .provider = COLLPROVIDER_LIBC, + .collate_is_c = true, + .ctype_is_c = true, + }; Assert(tok_line->fields != NIL); field = list_head(tok_line->fields); @@ -2695,7 +2703,7 @@ parse_ident_line(TokenizedLine *tok_line) wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1, wstr, strlen(parsedline->ident_user + 1)); - r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID); + r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, &c_coll); if (r) { char errstr[100]; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 5f46415394..e1511b7e60 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -3409,7 +3409,7 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation, bool isIndexable = false; Node *rightop; Oid expr_op; - Oid expr_coll; + pg_locale_t expr_coll; Const *patt; Const *prefix = NULL; Pattern_Prefix_Status pstatus = Pattern_Prefix_None; @@ -3425,7 +3425,7 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation, /* we know these will succeed */ rightop = get_rightop(clause); expr_op = ((OpExpr *) clause)->opno; - expr_coll = ((OpExpr *) clause)->inputcollid; + expr_coll = pg_newlocale_from_collation(((OpExpr *) clause)->inputcollid); /* again, required for all current special ops: */ if (!IsA(rightop, Const) || @@ -3523,7 +3523,7 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation, (opfamily == TEXT_SPGIST_FAM_OID) || (opfamily == TEXT_BTREE_FAM_OID && (pstatus == Pattern_Prefix_Exact || - lc_collate_is_c(idxcollation))); + pg_newlocale_from_collation(idxcollation)->collate_is_c)); break; case OID_BPCHAR_LIKE_OP: @@ -3534,7 +3534,7 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation, (opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) || (opfamily == BPCHAR_BTREE_FAM_OID && (pstatus == Pattern_Prefix_Exact || - lc_collate_is_c(idxcollation))); + pg_newlocale_from_collation(idxcollation)->collate_is_c)); break; case OID_NAME_LIKE_OP: @@ -3743,7 +3743,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation) Node *leftop = get_leftop(clause); Node *rightop = get_rightop(clause); Oid expr_op = ((OpExpr *) clause)->opno; - Oid expr_coll = ((OpExpr *) clause)->inputcollid; + pg_locale_t expr_coll = pg_newlocale_from_collation(((OpExpr *) clause)->inputcollid); Const *patt = (Const *) rightop; Const *prefix = NULL; Pattern_Prefix_Status pstatus; @@ -4201,7 +4201,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation, if (oproid == InvalidOid) elog(ERROR, "no < operator for opfamily %u", opfamily); fmgr_info(get_opcode(oproid), <proc); - greaterstr = make_greater_string(prefix_const, <proc, collation); + greaterstr = make_greater_string(prefix_const, <proc, pg_newlocale_from_collation(collation)); if (greaterstr) { expr = make_opclause(oproid, BOOLOID, false, diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index a570ac0aab..ef2e7def10 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -46,6 +46,7 @@ #include "storage/bufmgr.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/partcache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -1753,7 +1754,7 @@ restriction_selectivity(PlannerInfo *root, return (Selectivity) 0.5; result = DatumGetFloat8(OidFunctionCall4Coll(oprrest, - inputcollid, + pg_newlocale_from_collation(inputcollid), PointerGetDatum(root), ObjectIdGetDatum(operatorid), PointerGetDatum(args), @@ -1791,7 +1792,7 @@ join_selectivity(PlannerInfo *root, return (Selectivity) 0.5; result = DatumGetFloat8(OidFunctionCall5Coll(oprjoin, - inputcollid, + pg_newlocale_from_collation(inputcollid), PointerGetDatum(root), ObjectIdGetDatum(operatorid), PointerGetDatum(args), @@ -1948,7 +1949,7 @@ find_partition_scheme(PlannerInfo *root, Relation relation) memcmp(partkey->partopcintype, part_scheme->partopcintype, sizeof(Oid) * partnatts) != 0 || memcmp(partkey->partcollation, part_scheme->partcollation, - sizeof(Oid) * partnatts) != 0) + sizeof(pg_locale_t) * partnatts) != 0) continue; /* @@ -1995,9 +1996,9 @@ find_partition_scheme(PlannerInfo *root, Relation relation) memcpy(part_scheme->partopcintype, partkey->partopcintype, sizeof(Oid) * partnatts); - part_scheme->partcollation = (Oid *) palloc(sizeof(Oid) * partnatts); + part_scheme->partcollation = (pg_locale_t *) palloc(sizeof(pg_locale_t) * partnatts); memcpy(part_scheme->partcollation, partkey->partcollation, - sizeof(Oid) * partnatts); + sizeof(pg_locale_t) * partnatts); part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts); memcpy(part_scheme->parttyplen, partkey->parttyplen, @@ -2059,7 +2060,7 @@ set_baserel_partition_key_exprs(Relation relation, partexpr = (Expr *) makeVar(varno, attno, partkey->parttypid[cnt], partkey->parttypmod[cnt], - partkey->parttypcoll[cnt], 0); + partkey->parttypcollid[cnt], 0); } else { diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index eeaab2f4c9..de3edbb51f 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -31,6 +31,7 @@ #include "utils/hashutils.h" #include "utils/lsyscache.h" #include "utils/partcache.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/snapmgr.h" #include "utils/ruleutils.h" @@ -81,11 +82,11 @@ static PartitionRangeBound *make_one_partition_rbound(PartitionKey key, int inde static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2); static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, - Oid *partcollation, Datum *datums1, + fmLocalePtr *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2); static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, - Oid *partcollation, + fmLocalePtr *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal); static int get_partition_bound_num_indexes(PartitionBoundInfo b); @@ -1381,7 +1382,7 @@ make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower) */ static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, - Oid *partcollation, + fmLocalePtr *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2) { @@ -1444,7 +1445,7 @@ partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, * */ int32 -partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation, +partition_rbound_datum_cmp(FmgrInfo *partsupfunc, fmLocalePtr *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums) { @@ -1495,7 +1496,7 @@ partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2) * to the input value. */ int -partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, +partition_list_bsearch(FmgrInfo *partsupfunc, fmLocalePtr *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal) { @@ -1539,7 +1540,7 @@ partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, */ static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, - Oid *partcollation, + fmLocalePtr *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal) { @@ -1584,7 +1585,7 @@ partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, * to the input tuple. */ int -partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, +partition_range_datum_bsearch(FmgrInfo *partsupfunc, fmLocalePtr *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal) { @@ -1801,12 +1802,15 @@ make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2) { Oid operoid; + Oid partcollid; bool need_relabel = false; Expr *result = NULL; /* Get the correct btree operator for this partitioning column */ operoid = get_partition_operator(key, keynum, strategy, &need_relabel); + partcollid = key->partcollation[keynum] ? key->partcollation[keynum]->collid : InvalidOid; + /* * Chosen operator may be such that the non-Const operand needs to be * coerced, so apply the same; see the comment in @@ -1814,11 +1818,11 @@ make_partition_op_expr(PartitionKey key, int keynum, */ if (!IsA(arg1, Const) && (need_relabel || - key->partcollation[keynum] != key->parttypcoll[keynum])) + partcollid != key->parttypcollid[keynum])) arg1 = (Expr *) makeRelabelType(arg1, key->partopcintype[keynum], -1, - key->partcollation[keynum], + partcollid, COERCE_EXPLICIT_CAST); /* Generate the actual expression */ @@ -1842,7 +1846,7 @@ make_partition_op_expr(PartitionKey key, int keynum, arrexpr = makeNode(ArrayExpr); arrexpr->array_typeid = get_array_type(key->parttypid[keynum]); - arrexpr->array_collid = key->parttypcoll[keynum]; + arrexpr->array_collid = key->parttypcollid[keynum]; arrexpr->element_typeid = key->parttypid[keynum]; arrexpr->elements = elems; arrexpr->multidims = false; @@ -1853,7 +1857,7 @@ make_partition_op_expr(PartitionKey key, int keynum, saopexpr->opno = operoid; saopexpr->opfuncid = get_opcode(operoid); saopexpr->useOr = true; - saopexpr->inputcollid = key->partcollation[keynum]; + saopexpr->inputcollid = partcollid; saopexpr->args = list_make2(arg1, arrexpr); saopexpr->location = -1; @@ -1874,7 +1878,7 @@ make_partition_op_expr(PartitionKey key, int keynum, false, arg1, elem, InvalidOid, - key->partcollation[keynum]); + partcollid); elemops = lappend(elemops, elemop); } @@ -1889,7 +1893,7 @@ make_partition_op_expr(PartitionKey key, int keynum, false, arg1, arg2, InvalidOid, - key->partcollation[keynum]); + partcollid); break; default: @@ -1961,7 +1965,7 @@ get_qual_for_hash(Relation parent, PartitionBoundSpec *spec) key->partattrs[i], key->parttypid[i], key->parttypmod[i], - key->parttypcoll[i], + key->parttypcollid[i], 0); } else @@ -2016,7 +2020,7 @@ get_qual_for_list(Relation parent, PartitionBoundSpec *spec) key->partattrs[0], key->parttypid[0], key->parttypmod[0], - key->parttypcoll[0], + key->parttypcollid[0], 0); else keyCol = (Expr *) copyObject(linitial(key->partexprs)); @@ -2059,7 +2063,7 @@ get_qual_for_list(Relation parent, PartitionBoundSpec *spec) */ val = makeConst(key->parttypid[0], key->parttypmod[0], - key->parttypcoll[0], + key->parttypcollid[0], key->parttyplen[0], datumCopy(*boundinfo->datums[i], key->parttypbyval[0], @@ -2581,7 +2585,7 @@ get_range_key_properties(PartitionKey key, int keynum, key->partattrs[keynum], key->parttypid[keynum], key->parttypmod[keynum], - key->parttypcoll[keynum], + key->parttypcollid[keynum], 0); } else @@ -2629,7 +2633,7 @@ get_range_nulltest(PartitionKey key) key->partattrs[i], key->parttypid[i], key->parttypmod[i], - key->parttypcoll[i], + key->parttypcollid[i], 0); } else diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 35c87535d3..44e8471817 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -54,6 +54,7 @@ #include "partitioning/partbounds.h" #include "rewrite/rewriteManip.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" /* @@ -1496,7 +1497,7 @@ gen_prune_steps_from_opexps(PartitionScheme part_scheme, * See also IndexCollMatchesExprColl. */ #define PartCollMatchesExprColl(partcoll, exprcoll) \ - ((partcoll) == InvalidOid || (partcoll) == (exprcoll)) + ((partcoll) == 0 || (partcoll)->collid == (exprcoll)) /* * match_clause_to_partition_key @@ -1537,8 +1538,8 @@ match_clause_to_partition_key(RelOptInfo *rel, List **clause_steps) { PartitionScheme part_scheme = rel->part_scheme; - Oid partopfamily = part_scheme->partopfamily[partkeyidx], - partcoll = part_scheme->partcollation[partkeyidx]; + Oid partopfamily = part_scheme->partopfamily[partkeyidx]; + pg_locale_t partcoll = part_scheme->partcollation[partkeyidx]; Expr *expr; /* @@ -2228,7 +2229,7 @@ get_matching_list_bounds(PartitionPruneContext *context, maxoff; bool is_equal; bool inclusive = false; - Oid *partcollation = context->partcollation; + pg_locale_t *partcollation = context->partcollation; Assert(context->strategy == PARTITION_STRATEGY_LIST); Assert(context->partnatts == 1); @@ -2429,7 +2430,7 @@ get_matching_range_bounds(PartitionPruneContext *context, { PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); PartitionBoundInfo boundinfo = context->boundinfo; - Oid *partcollation = context->partcollation; + pg_locale_t *partcollation = context->partcollation; int partnatts = context->partnatts; int *partindices = boundinfo->indexes; int off, diff --git a/src/backend/regex/regc_pg_locale.c b/src/backend/regex/regc_pg_locale.c index acbed2eeed..751b76a282 100644 --- a/src/backend/regex/regc_pg_locale.c +++ b/src/backend/regex/regc_pg_locale.c @@ -74,7 +74,6 @@ typedef enum static PG_Locale_Strategy pg_regex_strategy; static pg_locale_t pg_regex_locale; -static Oid pg_regex_collation; /* * Hard-wired character properties for C locale @@ -229,61 +228,48 @@ static const unsigned char pg_char_properties[128] = { * to store the results in static variables. */ void -pg_set_regex_collation(Oid collation) +pg_set_regex_collation(pg_locale_t collation) { - if (lc_ctype_is_c(collation)) + if (!collation) + { + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for regular expression"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + + pg_regex_locale = collation; + + if (collation->ctype_is_c) { /* C/POSIX collations use this path regardless of database encoding */ pg_regex_strategy = PG_REGEX_LOCALE_C; - pg_regex_locale = 0; - pg_regex_collation = C_COLLATION_OID; } else { - if (collation == DEFAULT_COLLATION_OID) - pg_regex_locale = 0; - else if (OidIsValid(collation)) - { - /* - * NB: pg_newlocale_from_collation will fail if not HAVE_LOCALE_T; - * the case of pg_regex_locale != 0 but not HAVE_LOCALE_T does not - * have to be considered below. - */ - pg_regex_locale = pg_newlocale_from_collation(collation); - } - else - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for regular expression"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - #ifdef USE_ICU - if (pg_regex_locale && pg_regex_locale->provider == COLLPROVIDER_ICU) + if (pg_regex_locale->provider == COLLPROVIDER_ICU) pg_regex_strategy = PG_REGEX_LOCALE_ICU; else #endif if (GetDatabaseEncoding() == PG_UTF8) { - if (pg_regex_locale) + if (pg_regex_locale->provider == COLLPROVIDER_LIBC) pg_regex_strategy = PG_REGEX_LOCALE_WIDE_L; else pg_regex_strategy = PG_REGEX_LOCALE_WIDE; } else { - if (pg_regex_locale) + if (pg_regex_locale->provider == COLLPROVIDER_LIBC) pg_regex_strategy = PG_REGEX_LOCALE_1BYTE_L; else pg_regex_strategy = PG_REGEX_LOCALE_1BYTE; } - - pg_regex_collation = collation; } } @@ -718,7 +704,7 @@ typedef int (*pg_wc_probefunc) (pg_wchar c); typedef struct pg_ctype_cache { pg_wc_probefunc probefunc; /* pg_wc_isalpha or a sibling */ - Oid collation; /* collation this entry is for */ + Oid collid; /* collation this entry is for */ struct cvec cv; /* cache entry contents */ struct pg_ctype_cache *next; /* chain link */ } pg_ctype_cache; @@ -787,7 +773,7 @@ pg_ctype_get_cache(pg_wc_probefunc probefunc, int cclasscode) for (pcc = pg_ctype_cache_list; pcc != NULL; pcc = pcc->next) { if (pcc->probefunc == probefunc && - pcc->collation == pg_regex_collation) + pcc->collid == pg_regex_locale->collid) return &pcc->cv; } @@ -798,7 +784,7 @@ pg_ctype_get_cache(pg_wc_probefunc probefunc, int cclasscode) if (pcc == NULL) return NULL; pcc->probefunc = probefunc; - pcc->collation = pg_regex_collation; + pcc->collid = pg_regex_locale->collid; pcc->cv.nchrs = 0; pcc->cv.chrspace = 128; pcc->cv.chrs = (chr *) malloc(pcc->cv.chrspace * sizeof(chr)); diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c index eb1f3d57a8..d18ac8c9b8 100644 --- a/src/backend/regex/regcomp.c +++ b/src/backend/regex/regcomp.c @@ -315,7 +315,7 @@ pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, - Oid collation) + pg_locale_t collation) { struct vars var; struct vars *v = &var; diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index 9b75711ebd..cc3ae50a35 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -822,7 +822,7 @@ libpqrcv_create_slot(WalReceiverConn *conn, const char *slotname, slotname, pchomp(PQerrorMessage(conn->streamConn))))); } - *lsn = DatumGetLSN(DirectFunctionCall1Coll(pg_lsn_in, InvalidOid, + *lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in, CStringGetDatum(PQgetvalue(res, 0, 1)))); if (!PQgetisnull(res, 0, 2)) snapshot = pstrdup(PQgetvalue(res, 0, 2)); diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c index 5dcee95250..54053156b6 100644 --- a/src/backend/statistics/extended_stats.c +++ b/src/backend/statistics/extended_stats.c @@ -30,6 +30,7 @@ #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -372,7 +373,7 @@ multi_sort_add_dimension(MultiSortSupport mss, int sortdim, Oid oper) SortSupport ssup = &mss->ssup[sortdim]; ssup->ssup_cxt = CurrentMemoryContext; - ssup->ssup_collation = DEFAULT_COLLATION_OID; + ssup->ssup_collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); ssup->ssup_nulls_first = false; ssup->ssup_cxt = CurrentMemoryContext; diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c index 6f5b635413..c1ac473e40 100644 --- a/src/backend/tsearch/spell.c +++ b/src/backend/tsearch/spell.c @@ -729,7 +729,7 @@ NIAddAffix(IspellDict *Conf, const char *flag, char flagflags, const char *mask, err = pg_regcomp(&(Affix->reg.regex), wmask, wmasklen, REG_ADVANCED | REG_NOSUB, - DEFAULT_COLLATION_OID); + pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); if (err) { char errstr[100]; diff --git a/src/backend/tsearch/ts_locale.c b/src/backend/tsearch/ts_locale.c index 62deece7a9..a803446441 100644 --- a/src/backend/tsearch/ts_locale.c +++ b/src/backend/tsearch/ts_locale.c @@ -37,13 +37,12 @@ t_isdigit(const char *ptr) { int clen = pg_mblen(ptr); wchar_t character[WC_BUF_LEN]; - Oid collation = DEFAULT_COLLATION_OID; /* TODO */ - pg_locale_t mylocale = 0; /* TODO */ + pg_locale_t collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); /* TODO */ - if (clen == 1 || lc_ctype_is_c(collation)) + if (clen == 1 || collation->ctype_is_c) return isdigit(TOUCHAR(ptr)); - char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale); + char2wchar(character, WC_BUF_LEN, ptr, clen, collation); return iswdigit((wint_t) character[0]); } @@ -53,13 +52,12 @@ t_isspace(const char *ptr) { int clen = pg_mblen(ptr); wchar_t character[WC_BUF_LEN]; - Oid collation = DEFAULT_COLLATION_OID; /* TODO */ - pg_locale_t mylocale = 0; /* TODO */ + pg_locale_t collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); /* TODO */ - if (clen == 1 || lc_ctype_is_c(collation)) + if (clen == 1 || collation->ctype_is_c) return isspace(TOUCHAR(ptr)); - char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale); + char2wchar(character, WC_BUF_LEN, ptr, clen, collation); return iswspace((wint_t) character[0]); } @@ -69,13 +67,12 @@ t_isalpha(const char *ptr) { int clen = pg_mblen(ptr); wchar_t character[WC_BUF_LEN]; - Oid collation = DEFAULT_COLLATION_OID; /* TODO */ - pg_locale_t mylocale = 0; /* TODO */ + pg_locale_t collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); /* TODO */ - if (clen == 1 || lc_ctype_is_c(collation)) + if (clen == 1 || collation->ctype_is_c) return isalpha(TOUCHAR(ptr)); - char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale); + char2wchar(character, WC_BUF_LEN, ptr, clen, collation); return iswalpha((wint_t) character[0]); } @@ -85,13 +82,12 @@ t_isprint(const char *ptr) { int clen = pg_mblen(ptr); wchar_t character[WC_BUF_LEN]; - Oid collation = DEFAULT_COLLATION_OID; /* TODO */ - pg_locale_t mylocale = 0; /* TODO */ + pg_locale_t collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); /* TODO */ - if (clen == 1 || lc_ctype_is_c(collation)) + if (clen == 1 || collation->ctype_is_c) return isprint(TOUCHAR(ptr)); - char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale); + char2wchar(character, WC_BUF_LEN, ptr, clen, collation); return iswprint((wint_t) character[0]); } @@ -252,8 +248,7 @@ char * lowerstr_with_len(const char *str, int len) { char *out; - Oid collation = DEFAULT_COLLATION_OID; /* TODO */ - pg_locale_t mylocale = 0; /* TODO */ + pg_locale_t collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); /* TODO */ if (len == 0) return pstrdup(""); @@ -264,7 +259,7 @@ lowerstr_with_len(const char *str, int len) * Also, for a C locale there is no need to process as multibyte. From * backend/utils/adt/oracle_compat.c Teodor */ - if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c(collation)) + if (pg_database_encoding_max_length() > 1 && !collation->ctype_is_c) { wchar_t *wstr, *wptr; @@ -277,7 +272,7 @@ lowerstr_with_len(const char *str, int len) */ wptr = wstr = (wchar_t *) palloc(sizeof(wchar_t) * (len + 1)); - wlen = char2wchar(wstr, len + 1, str, len, mylocale); + wlen = char2wchar(wstr, len + 1, str, len, collation); Assert(wlen <= len); while (*wptr) @@ -292,7 +287,7 @@ lowerstr_with_len(const char *str, int len) len = pg_database_encoding_max_length() * wlen + 1; out = (char *) palloc(len); - wlen = wchar2char(out, wstr, len, mylocale); + wlen = wchar2char(out, wstr, len, collation); pfree(wstr); diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c index d7cd2e5839..36a5dcf4e1 100644 --- a/src/backend/tsearch/wparser_def.c +++ b/src/backend/tsearch/wparser_def.c @@ -297,11 +297,10 @@ TParserInit(char *str, int len) */ if (prs->charmaxlen > 1) { - Oid collation = DEFAULT_COLLATION_OID; /* TODO */ - pg_locale_t mylocale = 0; /* TODO */ + pg_locale_t collation = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); /* TODO */ prs->usewide = true; - if (lc_ctype_is_c(collation)) + if (collation->ctype_is_c) { /* * char2wchar doesn't work for C-locale and sizeof(pg_wchar) could @@ -314,7 +313,7 @@ TParserInit(char *str, int len) { prs->wstr = (wchar_t *) palloc(sizeof(wchar_t) * (prs->lenstr + 1)); char2wchar(prs->wstr, prs->lenstr + 1, prs->str, prs->lenstr, - mylocale); + collation); } } else diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c index 339525b53b..40090b0a8a 100644 --- a/src/backend/utils/adt/array_selfuncs.c +++ b/src/backend/utils/adt/array_selfuncs.c @@ -24,6 +24,7 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/selfuncs.h" #include "utils/typcache.h" @@ -1171,7 +1172,7 @@ element_compare(const void *key1, const void *key2, void *arg) FmgrInfo *cmpfunc = (FmgrInfo *) arg; Datum c; - c = FunctionCall2Coll(cmpfunc, DEFAULT_COLLATION_OID, d1, d2); + c = FunctionCall2Coll(cmpfunc, pg_newlocale_from_collation(DEFAULT_COLLATION_OID), d1, d2); return DatumGetInt32(c); } diff --git a/src/backend/utils/adt/array_typanalyze.c b/src/backend/utils/adt/array_typanalyze.c index 92e38b870f..76f57eb4bf 100644 --- a/src/backend/utils/adt/array_typanalyze.c +++ b/src/backend/utils/adt/array_typanalyze.c @@ -21,6 +21,7 @@ #include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/typcache.h" @@ -712,7 +713,7 @@ element_hash(const void *key, Size keysize) Datum d = *((const Datum *) key); Datum h; - h = FunctionCall1Coll(array_extra_data->hash, DEFAULT_COLLATION_OID, d); + h = FunctionCall1Coll(array_extra_data->hash, pg_newlocale_from_collation(DEFAULT_COLLATION_OID), d); return DatumGetUInt32(h); } @@ -741,7 +742,7 @@ element_compare(const void *key1, const void *key2) Datum d2 = *((const Datum *) key2); Datum c; - c = FunctionCall2Coll(array_extra_data->cmp, DEFAULT_COLLATION_OID, d1, d2); + c = FunctionCall2Coll(array_extra_data->cmp, pg_newlocale_from_collation(DEFAULT_COLLATION_OID), d1, d2); return DatumGetInt32(c); } diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index cb7a6b6d01..bcc3fb3b5c 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -633,7 +633,7 @@ static Datum array_position_common(FunctionCallInfo fcinfo) { ArrayType *array; - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); Oid element_type; Datum searched_element, value; @@ -784,7 +784,7 @@ Datum array_positions(PG_FUNCTION_ARGS) { ArrayType *array; - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); Oid element_type; Datum searched_element, value; diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index ce1ded888f..bf8de273f1 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -144,16 +144,16 @@ static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs, static ArrayType *array_replace_internal(ArrayType *array, Datum search, bool search_isnull, Datum replace, bool replace_isnull, - bool remove, Oid collation, + bool remove, fmLocalePtr collation, FunctionCallInfo fcinfo); static int width_bucket_array_float8(Datum operand, ArrayType *thresholds); static int width_bucket_array_fixed(Datum operand, ArrayType *thresholds, - Oid collation, + fmLocalePtr collation, TypeCacheEntry *typentry); static int width_bucket_array_variable(Datum operand, ArrayType *thresholds, - Oid collation, + fmLocalePtr collation, TypeCacheEntry *typentry); @@ -3573,7 +3573,7 @@ array_eq(PG_FUNCTION_ARGS) { AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0); AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1); - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); int ndims1 = AARR_NDIM(array1); int ndims2 = AARR_NDIM(array2); int *dims1 = AARR_DIMS(array1); @@ -3744,7 +3744,7 @@ array_cmp(FunctionCallInfo fcinfo) { AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0); AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1); - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); int ndims1 = AARR_NDIM(array1); int ndims2 = AARR_NDIM(array2); int *dims1 = AARR_DIMS(array1); @@ -4097,7 +4097,7 @@ hash_array_extended(PG_FUNCTION_ARGS) * When matchall is false, return true if any members of array1 are in array2. */ static bool -array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, +array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, fmLocalePtr collation, bool matchall, void **fn_extra) { bool result = matchall; @@ -4244,7 +4244,7 @@ arrayoverlap(PG_FUNCTION_ARGS) { AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0); AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1); - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); bool result; result = array_contain_compare(array1, array2, collation, false, @@ -4262,7 +4262,7 @@ arraycontains(PG_FUNCTION_ARGS) { AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0); AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1); - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); bool result; result = array_contain_compare(array2, array1, collation, true, @@ -4280,7 +4280,7 @@ arraycontained(PG_FUNCTION_ARGS) { AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0); AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1); - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); bool result; result = array_contain_compare(array1, array2, collation, true, @@ -6039,7 +6039,7 @@ static ArrayType * array_replace_internal(ArrayType *array, Datum search, bool search_isnull, Datum replace, bool replace_isnull, - bool remove, Oid collation, + bool remove, fmLocalePtr collation, FunctionCallInfo fcinfo) { ArrayType *result; @@ -6349,7 +6349,7 @@ width_bucket_array(PG_FUNCTION_ARGS) { Datum operand = PG_GETARG_DATUM(0); ArrayType *thresholds = PG_GETARG_ARRAYTYPE_P(1); - Oid collation = PG_GET_COLLATION(); + fmLocalePtr collation = PG_GET_COLLATION(); Oid element_type = ARR_ELEMTYPE(thresholds); int result; @@ -6454,7 +6454,7 @@ width_bucket_array_float8(Datum operand, ArrayType *thresholds) static int width_bucket_array_fixed(Datum operand, ArrayType *thresholds, - Oid collation, + fmLocalePtr collation, TypeCacheEntry *typentry) { char *thresholds_data; @@ -6507,7 +6507,7 @@ width_bucket_array_fixed(Datum operand, static int width_bucket_array_variable(Datum operand, ArrayType *thresholds, - Oid collation, + fmLocalePtr collation, TypeCacheEntry *typentry) { char *thresholds_data; diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 2923afe7b6..39f05b6abf 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -976,7 +976,7 @@ static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, int ver, NUMDesc *Num); static void DCH_to_char(FormatNode *node, bool is_interval, - TmToChar *in, char *out, Oid collid); + TmToChar *in, char *out, pg_locale_t collation); static void DCH_from_char(FormatNode *node, char *in, TmFromChar *out); #ifdef DEBUG_TO_FROM_CHAR @@ -1005,7 +1005,7 @@ static void NUM_numpart_from_char(NUMProc *Np, int id, int input_len); static void NUM_numpart_to_char(NUMProc *Np, int id); static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, - int sign, bool is_to_char, Oid collid); + int sign, bool is_to_char, pg_locale_t collation); static DCHCacheEntry *DCH_cache_getnew(const char *str); static DCHCacheEntry *DCH_cache_search(const char *str); static DCHCacheEntry *DCH_cache_fetch(const char *str); @@ -1540,40 +1540,34 @@ u_strToTitle_default_BI(UChar *dest, int32_t destCapacity, * to this function. The result is a palloc'd, null-terminated string. */ char * -str_tolower(const char *buff, size_t nbytes, Oid collid) +str_tolower(const char *buff, size_t nbytes, pg_locale_t collation) { char *result; if (!buff) return NULL; + if (!collation) + { + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for lower() function"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + /* C/POSIX collations use this path regardless of database encoding */ - if (lc_ctype_is_c(collid)) + if (collation->ctype_is_c) { result = asc_tolower(buff, nbytes); } else { - pg_locale_t mylocale = 0; - - if (collid != DEFAULT_COLLATION_OID) - { - if (!OidIsValid(collid)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for lower() function"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - mylocale = pg_newlocale_from_collation(collid); - } - #ifdef USE_ICU - if (mylocale && mylocale->provider == COLLPROVIDER_ICU) + if (collation->provider == COLLPROVIDER_ICU) { int32_t len_uchar; int32_t len_conv; @@ -1581,7 +1575,7 @@ str_tolower(const char *buff, size_t nbytes, Oid collid) UChar *buff_conv; len_uchar = icu_to_uchar(&buff_uchar, buff, nbytes); - len_conv = icu_convert_case(u_strToLower, mylocale, + len_conv = icu_convert_case(u_strToLower, collation, &buff_conv, buff_uchar, len_uchar); icu_from_uchar(&result, buff_conv, len_conv); pfree(buff_uchar); @@ -1604,13 +1598,13 @@ str_tolower(const char *buff, size_t nbytes, Oid collid) /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); - char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); + char2wchar(workspace, nbytes + 1, buff, nbytes, collation); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T - if (mylocale) - workspace[curr_char] = towlower_l(workspace[curr_char], mylocale->info.lt); + if (collation->provider == COLLPROVIDER_LIBC) + workspace[curr_char] = towlower_l(workspace[curr_char], collation->info.lt); else #endif workspace[curr_char] = towlower(workspace[curr_char]); @@ -1623,7 +1617,7 @@ str_tolower(const char *buff, size_t nbytes, Oid collid) result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); - wchar2char(result, workspace, result_size, mylocale); + wchar2char(result, workspace, result_size, collation); pfree(workspace); } else @@ -1642,8 +1636,8 @@ str_tolower(const char *buff, size_t nbytes, Oid collid) for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T - if (mylocale) - *p = tolower_l((unsigned char) *p, mylocale->info.lt); + if (collation->provider == COLLPROVIDER_LIBC) + *p = tolower_l((unsigned char) *p, collation->info.lt); else #endif *p = pg_tolower((unsigned char) *p); @@ -1662,40 +1656,34 @@ str_tolower(const char *buff, size_t nbytes, Oid collid) * to this function. The result is a palloc'd, null-terminated string. */ char * -str_toupper(const char *buff, size_t nbytes, Oid collid) +str_toupper(const char *buff, size_t nbytes, pg_locale_t collation) { char *result; if (!buff) return NULL; + if (!collation) + { + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for upper() function"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + /* C/POSIX collations use this path regardless of database encoding */ - if (lc_ctype_is_c(collid)) + if (collation->ctype_is_c) { result = asc_toupper(buff, nbytes); } else { - pg_locale_t mylocale = 0; - - if (collid != DEFAULT_COLLATION_OID) - { - if (!OidIsValid(collid)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for upper() function"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - mylocale = pg_newlocale_from_collation(collid); - } - #ifdef USE_ICU - if (mylocale && mylocale->provider == COLLPROVIDER_ICU) + if (collation->provider == COLLPROVIDER_ICU) { int32_t len_uchar, len_conv; @@ -1703,7 +1691,7 @@ str_toupper(const char *buff, size_t nbytes, Oid collid) UChar *buff_conv; len_uchar = icu_to_uchar(&buff_uchar, buff, nbytes); - len_conv = icu_convert_case(u_strToUpper, mylocale, + len_conv = icu_convert_case(u_strToUpper, collation, &buff_conv, buff_uchar, len_uchar); icu_from_uchar(&result, buff_conv, len_conv); pfree(buff_uchar); @@ -1726,13 +1714,13 @@ str_toupper(const char *buff, size_t nbytes, Oid collid) /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); - char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); + char2wchar(workspace, nbytes + 1, buff, nbytes, collation); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T - if (mylocale) - workspace[curr_char] = towupper_l(workspace[curr_char], mylocale->info.lt); + if (collation->provider == COLLPROVIDER_LIBC) + workspace[curr_char] = towupper_l(workspace[curr_char], collation->info.lt); else #endif workspace[curr_char] = towupper(workspace[curr_char]); @@ -1745,7 +1733,7 @@ str_toupper(const char *buff, size_t nbytes, Oid collid) result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); - wchar2char(result, workspace, result_size, mylocale); + wchar2char(result, workspace, result_size, collation); pfree(workspace); } else @@ -1764,8 +1752,8 @@ str_toupper(const char *buff, size_t nbytes, Oid collid) for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T - if (mylocale) - *p = toupper_l((unsigned char) *p, mylocale->info.lt); + if (collation->provider == COLLPROVIDER_LIBC) + *p = toupper_l((unsigned char) *p, collation->info.lt); else #endif *p = pg_toupper((unsigned char) *p); @@ -1784,7 +1772,7 @@ str_toupper(const char *buff, size_t nbytes, Oid collid) * to this function. The result is a palloc'd, null-terminated string. */ char * -str_initcap(const char *buff, size_t nbytes, Oid collid) +str_initcap(const char *buff, size_t nbytes, pg_locale_t collation) { char *result; int wasalnum = false; @@ -1792,33 +1780,27 @@ str_initcap(const char *buff, size_t nbytes, Oid collid) if (!buff) return NULL; + if (!collation) + { + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for initcap() function"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + /* C/POSIX collations use this path regardless of database encoding */ - if (lc_ctype_is_c(collid)) + if (collation->ctype_is_c) { result = asc_initcap(buff, nbytes); } else { - pg_locale_t mylocale = 0; - - if (collid != DEFAULT_COLLATION_OID) - { - if (!OidIsValid(collid)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for initcap() function"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - mylocale = pg_newlocale_from_collation(collid); - } - #ifdef USE_ICU - if (mylocale && mylocale->provider == COLLPROVIDER_ICU) + if (collation->provider == COLLPROVIDER_ICU) { int32_t len_uchar, len_conv; @@ -1826,7 +1808,7 @@ str_initcap(const char *buff, size_t nbytes, Oid collid) UChar *buff_conv; len_uchar = icu_to_uchar(&buff_uchar, buff, nbytes); - len_conv = icu_convert_case(u_strToTitle_default_BI, mylocale, + len_conv = icu_convert_case(u_strToTitle_default_BI, collation, &buff_conv, buff_uchar, len_uchar); icu_from_uchar(&result, buff_conv, len_conv); pfree(buff_uchar); @@ -1849,18 +1831,18 @@ str_initcap(const char *buff, size_t nbytes, Oid collid) /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); - char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); + char2wchar(workspace, nbytes + 1, buff, nbytes, collation); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T - if (mylocale) + if (collation->provider == COLLPROVIDER_LIBC) { if (wasalnum) - workspace[curr_char] = towlower_l(workspace[curr_char], mylocale->info.lt); + workspace[curr_char] = towlower_l(workspace[curr_char], collation->info.lt); else - workspace[curr_char] = towupper_l(workspace[curr_char], mylocale->info.lt); - wasalnum = iswalnum_l(workspace[curr_char], mylocale->info.lt); + workspace[curr_char] = towupper_l(workspace[curr_char], collation->info.lt); + wasalnum = iswalnum_l(workspace[curr_char], collation->info.lt); } else #endif @@ -1880,7 +1862,7 @@ str_initcap(const char *buff, size_t nbytes, Oid collid) result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); - wchar2char(result, workspace, result_size, mylocale); + wchar2char(result, workspace, result_size, collation); pfree(workspace); } else @@ -1899,13 +1881,13 @@ str_initcap(const char *buff, size_t nbytes, Oid collid) for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T - if (mylocale) + if (collation->provider == COLLPROVIDER_LIBC) { if (wasalnum) - *p = tolower_l((unsigned char) *p, mylocale->info.lt); + *p = tolower_l((unsigned char) *p, collation->info.lt); else - *p = toupper_l((unsigned char) *p, mylocale->info.lt); - wasalnum = isalnum_l((unsigned char) *p, mylocale->info.lt); + *p = toupper_l((unsigned char) *p, collation->info.lt); + wasalnum = isalnum_l((unsigned char) *p, collation->info.lt); } else #endif @@ -2008,21 +1990,21 @@ asc_initcap(const char *buff, size_t nbytes) /* convenience routines for when the input is null-terminated */ static char * -str_tolower_z(const char *buff, Oid collid) +str_tolower_z(const char *buff, pg_locale_t collation) { - return str_tolower(buff, strlen(buff), collid); + return str_tolower(buff, strlen(buff), collation); } static char * -str_toupper_z(const char *buff, Oid collid) +str_toupper_z(const char *buff, pg_locale_t collation) { - return str_toupper(buff, strlen(buff), collid); + return str_toupper(buff, strlen(buff), collation); } static char * -str_initcap_z(const char *buff, Oid collid) +str_initcap_z(const char *buff, pg_locale_t collation) { - return str_initcap(buff, strlen(buff), collid); + return str_initcap(buff, strlen(buff), collation); } static char * @@ -2433,7 +2415,7 @@ from_char_seq_search(int *dest, char **src, const char *const *array, int type, * ---------- */ static void -DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid) +DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, pg_locale_t collation) { FormatNode *n; char *s; @@ -2611,7 +2593,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid); + char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2631,7 +2613,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid); + char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2651,7 +2633,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid); + char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2671,7 +2653,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid); + char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2690,7 +2672,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid); + char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2709,7 +2691,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid); + char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2733,7 +2715,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) { - char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid); + char *str = str_toupper_z(localized_full_days[tm->tm_wday], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2751,7 +2733,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) { - char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid); + char *str = str_initcap_z(localized_full_days[tm->tm_wday], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2769,7 +2751,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) { - char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid); + char *str = str_tolower_z(localized_full_days[tm->tm_wday], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2787,7 +2769,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) { - char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid); + char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2804,7 +2786,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) { - char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid); + char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -2821,7 +2803,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) { - char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid); + char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collation); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); @@ -3503,7 +3485,7 @@ DCH_cache_fetch(const char *str) * for formatting. */ static text * -datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) +datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, pg_locale_t collation) { FormatNode *format; char *fmt_str, @@ -3549,7 +3531,7 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) } /* The real work is here */ - DCH_to_char(format, is_interval, tmtc, result, collid); + DCH_to_char(format, is_interval, tmtc, result, collation); if (!incache) pfree(format); @@ -4830,7 +4812,7 @@ NUM_eat_non_data_chars(NUMProc *Np, int n, int input_len) static char * NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, - int sign, bool is_to_char, Oid collid) + int sign, bool is_to_char, pg_locale_t collation) { FormatNode *n; NUMProc _Np, diff --git a/src/backend/utils/adt/jsonb_gin.c b/src/backend/utils/adt/jsonb_gin.c index c8a27451d2..ba5b24377e 100644 --- a/src/backend/utils/adt/jsonb_gin.c +++ b/src/backend/utils/adt/jsonb_gin.c @@ -20,6 +20,7 @@ #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/jsonb.h" +#include "utils/pg_locale.h" #include "utils/varlena.h" typedef struct PathHashStack @@ -55,7 +56,7 @@ gin_compare_jsonb(PG_FUNCTION_ARGS) len2 = VARSIZE_ANY_EXHDR(arg2); /* Compare text as bttextcmp does, but always using C collation */ - result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID); + result = varstr_cmp(a1p, len1, a2p, len2, pg_newlocale_from_collation(C_COLLATION_OID)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index 713631b04f..de589351e8 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -19,6 +19,7 @@ #include "utils/builtins.h" #include "utils/jsonb.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/varlena.h" /* @@ -1341,7 +1342,7 @@ compareJsonbScalarValue(JsonbValue *aScalar, JsonbValue *bScalar) aScalar->val.string.len, bScalar->val.string.val, bScalar->val.string.len, - DEFAULT_COLLATION_OID); + pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); case jbvNumeric: return DatumGetInt32(DirectFunctionCall2(numeric_cmp, PointerGetDatum(aScalar->val.numeric), diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c index ff716c5f58..ef733226bd 100644 --- a/src/backend/utils/adt/like.c +++ b/src/backend/utils/adt/like.c @@ -32,21 +32,21 @@ static int SB_MatchText(char *t, int tlen, char *p, int plen, - pg_locale_t locale, bool locale_is_c); + pg_locale_t locale); static text *SB_do_like_escape(text *, text *); static int MB_MatchText(char *t, int tlen, char *p, int plen, - pg_locale_t locale, bool locale_is_c); + pg_locale_t locale); static text *MB_do_like_escape(text *, text *); static int UTF8_MatchText(char *t, int tlen, char *p, int plen, - pg_locale_t locale, bool locale_is_c); + pg_locale_t locale); static int SB_IMatchText(char *t, int tlen, char *p, int plen, - pg_locale_t locale, bool locale_is_c); + pg_locale_t locale); static int GenericMatchText(char *s, int slen, char *p, int plen); -static int Generic_Text_IC_like(text *str, text *pat, Oid collation); +static int Generic_Text_IC_like(text *str, text *pat, pg_locale_t collation); /*-------------------- * Support routine for MatchText. Compares given multibyte streams @@ -90,12 +90,12 @@ wchareq(char *p1, char *p2) * fold-on-the-fly processing, however. */ static char -SB_lower_char(unsigned char c, pg_locale_t locale, bool locale_is_c) +SB_lower_char(unsigned char c, pg_locale_t locale) { - if (locale_is_c) + if (locale->ctype_is_c) return pg_ascii_tolower(c); #ifdef HAVE_LOCALE_T - else if (locale) + else if (locale->provider == COLLPROVIDER_LIBC) return tolower_l(c, locale->info.lt); #endif else @@ -132,7 +132,7 @@ SB_lower_char(unsigned char c, pg_locale_t locale, bool locale_is_c) #include "like_match.c" /* setup to compile like_match.c for single byte case insensitive matches */ -#define MATCH_LOWER(t) SB_lower_char((unsigned char) (t), locale, locale_is_c) +#define MATCH_LOWER(t) SB_lower_char((unsigned char) (t), locale) #define NextChar(p, plen) NextByte((p), (plen)) #define MatchText SB_IMatchText @@ -151,39 +151,31 @@ static inline int GenericMatchText(char *s, int slen, char *p, int plen) { if (pg_database_encoding_max_length() == 1) - return SB_MatchText(s, slen, p, plen, 0, true); + return SB_MatchText(s, slen, p, plen, 0); else if (GetDatabaseEncoding() == PG_UTF8) - return UTF8_MatchText(s, slen, p, plen, 0, true); + return UTF8_MatchText(s, slen, p, plen, 0); else - return MB_MatchText(s, slen, p, plen, 0, true); + return MB_MatchText(s, slen, p, plen, 0); } static inline int -Generic_Text_IC_like(text *str, text *pat, Oid collation) +Generic_Text_IC_like(text *str, text *pat, pg_locale_t collation) { char *s, *p; int slen, plen; - pg_locale_t locale = 0; - bool locale_is_c = false; - if (lc_ctype_is_c(collation)) - locale_is_c = true; - else if (collation != DEFAULT_COLLATION_OID) + if (!collation) { - if (!OidIsValid(collation)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for ILIKE"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - locale = pg_newlocale_from_collation(collation); + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for ILIKE"), + errhint("Use the COLLATE clause to set the collation explicitly."))); } /* @@ -194,7 +186,7 @@ Generic_Text_IC_like(text *str, text *pat, Oid collation) * way. */ - if (pg_database_encoding_max_length() > 1 || (locale && locale->provider == COLLPROVIDER_ICU)) + if (pg_database_encoding_max_length() > 1 || (collation->provider == COLLPROVIDER_ICU)) { /* lower's result is never packed, so OK to use old macros here */ pat = DatumGetTextPP(DirectFunctionCall1Coll(lower, collation, @@ -206,9 +198,9 @@ Generic_Text_IC_like(text *str, text *pat, Oid collation) s = VARDATA_ANY(str); slen = VARSIZE_ANY_EXHDR(str); if (GetDatabaseEncoding() == PG_UTF8) - return UTF8_MatchText(s, slen, p, plen, 0, true); + return UTF8_MatchText(s, slen, p, plen, 0); else - return MB_MatchText(s, slen, p, plen, 0, true); + return MB_MatchText(s, slen, p, plen, 0); } else { @@ -216,7 +208,7 @@ Generic_Text_IC_like(text *str, text *pat, Oid collation) plen = VARSIZE_ANY_EXHDR(pat); s = VARDATA_ANY(str); slen = VARSIZE_ANY_EXHDR(str); - return SB_IMatchText(s, slen, p, plen, locale, locale_is_c); + return SB_IMatchText(s, slen, p, plen, collation); } } @@ -324,7 +316,7 @@ bytealike(PG_FUNCTION_ARGS) p = VARDATA_ANY(pat); plen = VARSIZE_ANY_EXHDR(pat); - result = (SB_MatchText(s, slen, p, plen, 0, true) == LIKE_TRUE); + result = (SB_MatchText(s, slen, p, plen, 0) == LIKE_TRUE); PG_RETURN_BOOL(result); } @@ -345,7 +337,7 @@ byteanlike(PG_FUNCTION_ARGS) p = VARDATA_ANY(pat); plen = VARSIZE_ANY_EXHDR(pat); - result = (SB_MatchText(s, slen, p, plen, 0, true) != LIKE_TRUE); + result = (SB_MatchText(s, slen, p, plen, 0) != LIKE_TRUE); PG_RETURN_BOOL(result); } diff --git a/src/backend/utils/adt/like_match.c b/src/backend/utils/adt/like_match.c index 18428569a8..8316481abb 100644 --- a/src/backend/utils/adt/like_match.c +++ b/src/backend/utils/adt/like_match.c @@ -77,7 +77,7 @@ static int MatchText(char *t, int tlen, char *p, int plen, - pg_locale_t locale, bool locale_is_c) + pg_locale_t locale) { /* Fast path for match-everything pattern */ if (plen == 1 && *p == '%') @@ -175,7 +175,7 @@ MatchText(char *t, int tlen, char *p, int plen, if (GETCHAR(*t) == firstpat) { int matched = MatchText(t, tlen, p, plen, - locale, locale_is_c); + locale); if (matched != LIKE_FALSE) return matched; /* TRUE or ABORT */ diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index b8f86973dc..ad8da6e335 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -37,6 +37,7 @@ #include "utils/ruleutils.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" +#include "utils/pg_locale.h" #include "utils/timestamp.h" @@ -476,7 +477,7 @@ Datum pg_collation_for(PG_FUNCTION_ARGS) { Oid typeid; - Oid collid; + pg_locale_t collation; typeid = get_fn_expr_argtype(fcinfo->flinfo, 0); if (!typeid) @@ -487,10 +488,10 @@ pg_collation_for(PG_FUNCTION_ARGS) errmsg("collations are not supported by type %s", format_type_be(typeid)))); - collid = PG_GET_COLLATION(); - if (!collid) + collation = PG_GET_COLLATION(); + if (!collation) PG_RETURN_NULL(); - PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid))); + PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collation->collid))); } diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index a3dc3be5a8..a80791af72 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -119,9 +119,6 @@ static char lc_time_envbuf[LC_ENV_BUFSIZE]; typedef struct { Oid collid; /* hash key: pg_collation OID */ - bool collate_is_c; /* is collation's LC_COLLATE C? */ - bool ctype_is_c; /* is collation's LC_CTYPE C? */ - bool flags_valid; /* true if above flags are valid */ pg_locale_t locale; /* locale_t struct, or 0 if not valid */ } collation_cache_entry; @@ -1060,13 +1057,12 @@ check_strxfrm_bug(void) */ static collation_cache_entry * -lookup_collation_cache(Oid collation, bool set_flags) +lookup_collation_cache(Oid collation) { collation_cache_entry *cache_entry; bool found; Assert(OidIsValid(collation)); - Assert(collation != DEFAULT_COLLATION_OID); if (collation_cache == NULL) { @@ -1087,141 +1083,13 @@ lookup_collation_cache(Oid collation, bool set_flags) * Make sure cache entry is marked invalid, in case we fail before * setting things. */ - cache_entry->flags_valid = false; cache_entry->locale = 0; } - if (set_flags && !cache_entry->flags_valid) - { - /* Attempt to set the flags */ - HeapTuple tp; - Form_pg_collation collform; - const char *collcollate; - const char *collctype; - - tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation)); - if (!HeapTupleIsValid(tp)) - elog(ERROR, "cache lookup failed for collation %u", collation); - collform = (Form_pg_collation) GETSTRUCT(tp); - - collcollate = NameStr(collform->collcollate); - collctype = NameStr(collform->collctype); - - cache_entry->collate_is_c = ((strcmp(collcollate, "C") == 0) || - (strcmp(collcollate, "POSIX") == 0)); - cache_entry->ctype_is_c = ((strcmp(collctype, "C") == 0) || - (strcmp(collctype, "POSIX") == 0)); - - cache_entry->flags_valid = true; - - ReleaseSysCache(tp); - } - return cache_entry; } -/* - * Detect whether collation's LC_COLLATE property is C - */ -bool -lc_collate_is_c(Oid collation) -{ - /* - * If we're asked about "collation 0", return false, so that the code will - * go into the non-C path and report that the collation is bogus. - */ - if (!OidIsValid(collation)) - return false; - - /* - * If we're asked about the default collation, we have to inquire of the C - * library. Cache the result so we only have to compute it once. - */ - if (collation == DEFAULT_COLLATION_OID) - { - static int result = -1; - char *localeptr; - - if (result >= 0) - return (bool) result; - localeptr = setlocale(LC_COLLATE, NULL); - if (!localeptr) - elog(ERROR, "invalid LC_COLLATE setting"); - - if (strcmp(localeptr, "C") == 0) - result = true; - else if (strcmp(localeptr, "POSIX") == 0) - result = true; - else - result = false; - return (bool) result; - } - - /* - * If we're asked about the built-in C/POSIX collations, we know that. - */ - if (collation == C_COLLATION_OID || - collation == POSIX_COLLATION_OID) - return true; - - /* - * Otherwise, we have to consult pg_collation, but we cache that. - */ - return (lookup_collation_cache(collation, true))->collate_is_c; -} - -/* - * Detect whether collation's LC_CTYPE property is C - */ -bool -lc_ctype_is_c(Oid collation) -{ - /* - * If we're asked about "collation 0", return false, so that the code will - * go into the non-C path and report that the collation is bogus. - */ - if (!OidIsValid(collation)) - return false; - - /* - * If we're asked about the default collation, we have to inquire of the C - * library. Cache the result so we only have to compute it once. - */ - if (collation == DEFAULT_COLLATION_OID) - { - static int result = -1; - char *localeptr; - - if (result >= 0) - return (bool) result; - localeptr = setlocale(LC_CTYPE, NULL); - if (!localeptr) - elog(ERROR, "invalid LC_CTYPE setting"); - - if (strcmp(localeptr, "C") == 0) - result = true; - else if (strcmp(localeptr, "POSIX") == 0) - result = true; - else - result = false; - return (bool) result; - } - - /* - * If we're asked about the built-in C/POSIX collations, we know that. - */ - if (collation == C_COLLATION_OID || - collation == POSIX_COLLATION_OID) - return true; - - /* - * Otherwise, we have to consult pg_collation, but we cache that. - */ - return (lookup_collation_cache(collation, true))->ctype_is_c; -} - - /* simple subroutine for reporting errors from newlocale() */ #ifdef HAVE_LOCALE_T static void @@ -1259,14 +1127,6 @@ report_newlocale_failure(const char *localename) * Create a locale_t from a collation OID. Results are cached for the * lifetime of the backend. Thus, do not free the result with freelocale(). * - * As a special optimization, the default/database collation returns 0. - * Callers should then revert to the non-locale_t-enabled code path. - * In fact, they shouldn't call this function at all when they are dealing - * with the default locale. That can save quite a bit in hotspots. - * Also, callers should avoid calling this before going down a C/POSIX - * fastpath, because such a fastpath should work even on platforms without - * locale_t support in the C library. - * * For simplicity, we always generate COLLATE + CTYPE even though we * might only need one of them. Since this is called only once per session, * it shouldn't cost much. @@ -1276,14 +1136,46 @@ pg_newlocale_from_collation(Oid collid) { collation_cache_entry *cache_entry; - /* Callers must pass a valid OID */ - Assert(OidIsValid(collid)); + if (!OidIsValid(collid)) + return 0; - /* Return 0 for "default" collation, just in case caller forgets */ + /* + * For efficiency, cache and return information about the default + * collation separately. (Also, for bootstrapping, we need to be able to + * deal with this without catalog access.) + */ if (collid == DEFAULT_COLLATION_OID) - return (pg_locale_t) 0; + { + static struct pg_locale_struct result = { + .collid = DEFAULT_COLLATION_OID, + .provider = COLLPROVIDER_DEFAULT, + }; + static bool result_valid = false; + + if (!result_valid) + { + char *localeptr; + + localeptr = setlocale(LC_COLLATE, NULL); + if (!localeptr) + elog(ERROR, "invalid LC_COLLATE setting"); + + result.collate_is_c = ((strcmp(localeptr, "C") == 0) || + (strcmp(localeptr, "POSIX") == 0)); + + localeptr = setlocale(LC_CTYPE, NULL); + if (!localeptr) + elog(ERROR, "invalid LC_CTYPE setting"); - cache_entry = lookup_collation_cache(collid, false); + result.ctype_is_c = ((strcmp(localeptr, "C") == 0) || + (strcmp(localeptr, "POSIX") == 0)); + + result_valid = true; + } + return &result; + } + + cache_entry = lookup_collation_cache(collid); if (cache_entry->locale == 0) { @@ -1297,6 +1189,10 @@ pg_newlocale_from_collation(Oid collid) Datum collversion; bool isnull; + /* We'll fill in the result struct locally before allocating memory */ + memset(&result, 0, sizeof(result)); + result.collid = collid; + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for collation %u", collid); @@ -1305,8 +1201,6 @@ pg_newlocale_from_collation(Oid collid) collcollate = NameStr(collform->collcollate); collctype = NameStr(collform->collctype); - /* We'll fill in the result struct locally before allocating memory */ - memset(&result, 0, sizeof(result)); result.provider = collform->collprovider; if (collform->collprovider == COLLPROVIDER_LIBC) @@ -1355,6 +1249,20 @@ pg_newlocale_from_collation(Oid collid) } result.info.lt = loc; + + if (collid == C_COLLATION_OID || + collid == POSIX_COLLATION_OID) + { + result.collate_is_c = true; + result.ctype_is_c = true; + } + else + { + result.collate_is_c = ((strcmp(collcollate, "C") == 0) || + (strcmp(collcollate, "POSIX") == 0)); + result.ctype_is_c = ((strcmp(collctype, "C") == 0) || + (strcmp(collctype, "POSIX") == 0)); + } #else /* not HAVE_LOCALE_T */ /* platform that doesn't support locale_t */ ereport(ERROR, @@ -1607,7 +1515,7 @@ wchar2char(char *to, const wchar_t *from, size_t tolen, pg_locale_t locale) { size_t result; - Assert(!locale || locale->provider == COLLPROVIDER_LIBC); + Assert(locale->provider == COLLPROVIDER_DEFAULT || locale->provider == COLLPROVIDER_LIBC); if (tolen == 0) return 0; @@ -1635,7 +1543,7 @@ wchar2char(char *to, const wchar_t *from, size_t tolen, pg_locale_t locale) } else #endif /* WIN32 */ - if (locale == (pg_locale_t) 0) + if (locale->provider == COLLPROVIDER_DEFAULT) { /* Use wcstombs directly for the default locale */ result = wcstombs(to, from, tolen); @@ -1679,7 +1587,7 @@ char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen, { size_t result; - Assert(!locale || locale->provider == COLLPROVIDER_LIBC); + Assert(locale->provider == COLLPROVIDER_DEFAULT || locale->provider == COLLPROVIDER_LIBC); if (tolen == 0) return 0; @@ -1712,7 +1620,7 @@ char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen, /* mbstowcs requires ending '\0' */ char *str = pnstrdup(from, fromlen); - if (locale == (pg_locale_t) 0) + if (locale->provider == COLLPROVIDER_DEFAULT) { /* Use mbstowcs directly for the default locale */ result = mbstowcs(to, str, tolen); diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c index 171fcc8a44..70c7202fe2 100644 --- a/src/backend/utils/adt/regexp.c +++ b/src/backend/utils/adt/regexp.c @@ -102,7 +102,7 @@ typedef struct cached_re_str char *cre_pat; /* original RE (not null terminated!) */ int cre_pat_len; /* length of original RE, in bytes */ int cre_flags; /* compile flags: extended,icase etc */ - Oid cre_collation; /* collation to use */ + fmLocalePtr cre_collation; /* collation to use */ regex_t cre_re; /* the compiled regular expression */ } cached_re_str; @@ -113,7 +113,7 @@ static cached_re_str re_array[MAX_CACHED_RES]; /* cached re's */ /* Local functions */ static regexp_matches_ctx *setup_regexp_matches(text *orig_str, text *pattern, pg_re_flags *flags, - Oid collation, + fmLocalePtr collation, bool use_subpatterns, bool ignore_degenerate, bool fetching_unmatched); @@ -134,7 +134,7 @@ static Datum build_regexp_split_result(regexp_matches_ctx *splitctx); * an array of pg_wchar, which is what Spencer's regex package wants. */ static regex_t * -RE_compile_and_cache(text *text_re, int cflags, Oid collation) +RE_compile_and_cache(text *text_re, int cflags, fmLocalePtr collation) { int text_re_len = VARSIZE_ANY_EXHDR(text_re); char *text_re_val = VARDATA_ANY(text_re); @@ -341,7 +341,7 @@ RE_execute(regex_t *re, char *dat, int dat_len, */ static bool RE_compile_and_execute(text *text_re, char *dat, int dat_len, - int cflags, Oid collation, + int cflags, fmLocalePtr collation, int nmatch, regmatch_t *pmatch) { regex_t *re; @@ -966,7 +966,7 @@ regexp_matches_no_flags(PG_FUNCTION_ARGS) */ static regexp_matches_ctx * setup_regexp_matches(text *orig_str, text *pattern, pg_re_flags *re_flags, - Oid collation, + fmLocalePtr collation, bool use_subpatterns, bool ignore_degenerate, bool fetching_unmatched) @@ -1377,7 +1377,7 @@ build_regexp_split_result(regexp_matches_ctx *splitctx) * If it is an exact match, not just a prefix, *exact is returned as true. */ char * -regexp_fixed_prefix(text *text_re, bool case_insensitive, Oid collation, +regexp_fixed_prefix(text *text_re, bool case_insensitive, fmLocalePtr collation, bool *exact) { char *result; diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 5f729342f8..49baa551a5 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -24,6 +24,7 @@ #include "miscadmin.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/pg_locale.h" #include "utils/typcache.h" @@ -960,7 +961,7 @@ record_cmp(FunctionCallInfo fcinfo) /* Compare the pair of elements */ InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2, - collation, NULL, NULL); + pg_newlocale_from_collation(collation), NULL, NULL); locfcinfo.arg[0] = values1[i1]; locfcinfo.arg[1] = values2[i2]; locfcinfo.argnull[0] = false; @@ -1194,7 +1195,7 @@ record_eq(PG_FUNCTION_ARGS) /* Compare the pair of elements */ InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2, - collation, NULL, NULL); + pg_newlocale_from_collation(collation), NULL, NULL); locfcinfo.arg[0] = values1[i1]; locfcinfo.arg[1] = values2[i2]; locfcinfo.argnull[0] = false; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index ffca0fe5bb..e12e8905c3 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -370,12 +370,12 @@ var_eq_const(VariableStatData *vardata, Oid operator, /* be careful to apply operator right way 'round */ if (varonleft) match = DatumGetBool(FunctionCall2Coll(&eqproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot.values[i], constval)); else match = DatumGetBool(FunctionCall2Coll(&eqproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), constval, sslot.values[i])); if (match) @@ -666,11 +666,11 @@ mcv_selectivity(VariableStatData *vardata, FmgrInfo *opproc, { if (varonleft ? DatumGetBool(FunctionCall2Coll(opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot.values[i], constval)) : DatumGetBool(FunctionCall2Coll(opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), constval, sslot.values[i]))) mcv_selec += sslot.numbers[i]; @@ -744,11 +744,11 @@ histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc, { if (varonleft ? DatumGetBool(FunctionCall2Coll(opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot.values[i], constval)) : DatumGetBool(FunctionCall2Coll(opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), constval, sslot.values[i]))) nmatch++; @@ -873,7 +873,7 @@ ineq_histogram_selectivity(PlannerInfo *root, &sslot.values[probe]); ltcmp = DatumGetBool(FunctionCall2Coll(opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot.values[probe], constval)); if (isgt) @@ -1203,7 +1203,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate) Oid operator = PG_GETARG_OID(1); List *args = (List *) PG_GETARG_POINTER(2); int varRelid = PG_GETARG_INT32(3); - Oid collation = PG_GET_COLLATION(); + pg_locale_t collation = PG_GET_COLLATION(); VariableStatData vardata; Node *other; bool varonleft; @@ -1883,6 +1883,7 @@ scalararraysel(PlannerInfo *root, TypeCacheEntry *typentry; RegProcedure oprsel; FmgrInfo oprselproc; + pg_locale_t collation; Selectivity s1; Selectivity s1disjoint; @@ -1945,6 +1946,8 @@ scalararraysel(PlannerInfo *root, return (Selectivity) 0.5; fmgr_info(oprsel, &oprselproc); + collation = pg_newlocale_from_collation(clause->inputcollid); + /* * In the array-containment check above, we must only believe that an * operator is equality or inequality if it is the default btree equality @@ -2024,7 +2027,7 @@ scalararraysel(PlannerInfo *root, elmbyval)); if (is_join_clause) s2 = DatumGetFloat8(FunctionCall5Coll(&oprselproc, - clause->inputcollid, + collation, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), @@ -2032,7 +2035,7 @@ scalararraysel(PlannerInfo *root, PointerGetDatum(sjinfo))); else s2 = DatumGetFloat8(FunctionCall4Coll(&oprselproc, - clause->inputcollid, + collation, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), @@ -2091,7 +2094,7 @@ scalararraysel(PlannerInfo *root, args = list_make2(leftop, elem); if (is_join_clause) s2 = DatumGetFloat8(FunctionCall5Coll(&oprselproc, - clause->inputcollid, + collation, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), @@ -2099,7 +2102,7 @@ scalararraysel(PlannerInfo *root, PointerGetDatum(sjinfo))); else s2 = DatumGetFloat8(FunctionCall4Coll(&oprselproc, - clause->inputcollid, + collation, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), @@ -2143,7 +2146,7 @@ scalararraysel(PlannerInfo *root, args = list_make2(leftop, dummyexpr); if (is_join_clause) s2 = DatumGetFloat8(FunctionCall5Coll(&oprselproc, - clause->inputcollid, + collation, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), @@ -2151,7 +2154,7 @@ scalararraysel(PlannerInfo *root, PointerGetDatum(sjinfo))); else s2 = DatumGetFloat8(FunctionCall4Coll(&oprselproc, - clause->inputcollid, + collation, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), @@ -2499,7 +2502,7 @@ eqjoinsel_inner(Oid opfuncoid, if (hasmatch2[j]) continue; if (DatumGetBool(FunctionCall2Coll(&eqproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot1->values[i], sslot2->values[j]))) { @@ -2711,7 +2714,7 @@ eqjoinsel_semi(Oid opfuncoid, if (hasmatch2[j]) continue; if (DatumGetBool(FunctionCall2Coll(&eqproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot1->values[i], sslot2->values[j]))) { @@ -4432,7 +4435,7 @@ convert_string_datum(Datum value, Oid typid, bool *failure) return NULL; } - if (!lc_collate_is_c(DEFAULT_COLLATION_OID)) + if (!pg_newlocale_from_collation(DEFAULT_COLLATION_OID)->collate_is_c) { char *xfrmstr; size_t xfrmlen; @@ -5407,14 +5410,14 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop, continue; } if (DatumGetBool(FunctionCall2Coll(&opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), sslot.values[i], tmin))) { tmin = sslot.values[i]; tmin_is_mcv = true; } if (DatumGetBool(FunctionCall2Coll(&opproc, - DEFAULT_COLLATION_OID, + pg_newlocale_from_collation(DEFAULT_COLLATION_OID), tmax, sslot.values[i]))) { tmax = sslot.values[i]; @@ -5737,16 +5740,16 @@ find_join_input_rel(PlannerInfo *root, Relids relids) */ static int pattern_char_isalpha(char c, bool is_multibyte, - pg_locale_t locale, bool locale_is_c) + pg_locale_t locale) { - if (locale_is_c) + if (locale->ctype_is_c) return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); else if (is_multibyte && IS_HIGHBIT_SET(c)) return true; - else if (locale && locale->provider == COLLPROVIDER_ICU) + else if (locale->provider == COLLPROVIDER_ICU) return IS_HIGHBIT_SET(c) ? true : false; #ifdef HAVE_LOCALE_T - else if (locale && locale->provider == COLLPROVIDER_LIBC) + else if (locale->provider == COLLPROVIDER_LIBC) return isalpha_l((unsigned char) c, locale->info.lt); #endif else @@ -5767,7 +5770,7 @@ pattern_char_isalpha(char c, bool is_multibyte, */ static Pattern_Prefix_Status -like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, +like_fixed_prefix(Const *patt_const, bool case_insensitive, pg_locale_t collation, Const **prefix_const, Selectivity *rest_selec) { char *match; @@ -5777,8 +5780,6 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, int pos, match_pos; bool is_multibyte = (pg_database_encoding_max_length() > 1); - pg_locale_t locale = 0; - bool locale_is_c = false; /* the right-hand const is type text or bytea */ Assert(typeid == BYTEAOID || typeid == TEXTOID); @@ -5790,23 +5791,16 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("case insensitive matching not supported on type bytea"))); - /* If case-insensitive, we need locale info */ - if (lc_ctype_is_c(collation)) - locale_is_c = true; - else if (collation != DEFAULT_COLLATION_OID) + if (!collation) { - if (!OidIsValid(collation)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for ILIKE"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - locale = pg_newlocale_from_collation(collation); + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for ILIKE"), + errhint("Use the COLLATE clause to set the collation explicitly."))); } } @@ -5844,7 +5838,7 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, /* Stop if case-varying character (it's sort of a wildcard) */ if (case_insensitive && - pattern_char_isalpha(patt[pos], is_multibyte, locale, locale_is_c)) + pattern_char_isalpha(patt[pos], is_multibyte, collation)) break; match[match_pos++] = patt[pos]; @@ -5875,7 +5869,7 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, } static Pattern_Prefix_Status -regex_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, +regex_fixed_prefix(Const *patt_const, bool case_insensitive, pg_locale_t collation, Const **prefix_const, Selectivity *rest_selec) { Oid typeid = patt_const->consttype; @@ -5943,7 +5937,7 @@ regex_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation, } Pattern_Prefix_Status -pattern_fixed_prefix(Const *patt, Pattern_Type ptype, Oid collation, +pattern_fixed_prefix(Const *patt, Pattern_Type ptype, pg_locale_t collation, Const **prefix, Selectivity *rest_selec) { Pattern_Prefix_Status result; @@ -6045,7 +6039,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata, elog(ERROR, "no < operator for opfamily %u", opfamily); fmgr_info(get_opcode(cmpopr), &opproc); greaterstrcon = make_greater_string(prefixcon, &opproc, - DEFAULT_COLLATION_OID); + pg_newlocale_from_collation(DEFAULT_COLLATION_OID)); if (greaterstrcon) { Selectivity topsel; @@ -6323,7 +6317,7 @@ byte_increment(unsigned char *ptr, int len) * not 256^K, which is what an exhaustive search would approach). */ Const * -make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation) +make_greater_string(const Const *str_const, FmgrInfo *ltproc, pg_locale_t collation) { Oid datatype = str_const->consttype; char *workstr; @@ -6359,13 +6353,13 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation) { workstr = TextDatumGetCString(str_const->constvalue); len = strlen(workstr); - if (lc_collate_is_c(collation) || len == 0) + if (collation->collate_is_c || len == 0) cmpstr = str_const->constvalue; else { /* If first time through, determine the suffix to use */ static char suffixchar = 0; - static Oid suffixcollation = 0; + static pg_locale_t suffixcollation = 0; if (!suffixchar || suffixcollation != collation) { @@ -7475,7 +7469,7 @@ gincost_pattern(IndexOptInfo *index, int indexcol, collation = DEFAULT_COLLATION_OID; OidFunctionCall7Coll(extractProcOid, - collation, + pg_newlocale_from_collation(collation), query, PointerGetDatum(&nentries), UInt16GetDatum(strategy_op), diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index 8f07b1e272..daf004cfe4 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -22,6 +22,7 @@ #include "nodes/nodeFuncs.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/pg_locale.h" #include "utils/varlena.h" #include "mb/pg_wchar.h" @@ -870,13 +871,12 @@ Datum bpchar_sortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); - Oid collid = ssup->ssup_collation; MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); /* Use generic string SortSupport */ - varstr_sortsupport(ssup, collid, true); + varstr_sortsupport(ssup, ssup->ssup_collation, true); MemoryContextSwitchTo(oldcontext); @@ -1085,7 +1085,7 @@ btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); /* Use generic string SortSupport, forcing "C" collation */ - varstr_sortsupport(ssup, C_COLLATION_OID, true); + varstr_sortsupport(ssup, pg_newlocale_from_collation(C_COLLATION_OID), true); MemoryContextSwitchTo(oldcontext); diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 0fd3b15748..f57e5511c5 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -68,7 +68,6 @@ typedef struct int last_len2; /* Length of last buf2 string/strxfrm() blob */ int last_returned; /* Last comparison result (cache) */ bool cache_blob; /* Does buf2 contain strxfrm() blob, etc? */ - bool collate_c; bool bpchar; /* Sorting bpchar, not varchar/text/bytea? */ hyperLogLogState abbr_card; /* Abbreviated key cardinality state */ hyperLogLogState full_card; /* Full key cardinality state */ @@ -108,7 +107,7 @@ static int text_position(text *t1, text *t2); static void text_position_setup(text *t1, text *t2, TextPositionState *state); static int text_position_next(int start_pos, TextPositionState *state); static void text_position_cleanup(TextPositionState *state); -static int text_cmp(text *arg1, text *arg2, Oid collid); +static int text_cmp(text *arg1, text *arg2, pg_locale_t locale); static bytea *bytea_catenate(bytea *t1, bytea *t2); static bytea *bytea_substring(Datum str, int S, @@ -1378,17 +1377,29 @@ text_position_cleanup(TextPositionState *state) * whether arg1 is less than, equal to, or greater than arg2. */ int -varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid) +varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, pg_locale_t collation) { int result; + if (!collation) + { + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for string comparison"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + /* * Unfortunately, there is no strncoll(), so in the non-C locale case we * have to do some memory copying. This turns out to be significantly * slower, so we optimize the case where LC_COLLATE is C. We also try to * optimize relatively-short strings by avoiding palloc/pfree overhead. */ - if (lc_collate_is_c(collid)) + if (collation->collate_is_c) { result = memcmp(arg1, arg2, Min(len1, len2)); if ((result == 0) && (len1 != len2)) @@ -1400,23 +1411,6 @@ varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid) char a2buf[TEXTBUFLEN]; char *a1p, *a2p; - pg_locale_t mylocale = 0; - - if (collid != DEFAULT_COLLATION_OID) - { - if (!OidIsValid(collid)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for string comparison"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - mylocale = pg_newlocale_from_collation(collid); - } /* * memcmp() can't tell us which of two unequal strings sorts first, @@ -1433,7 +1427,8 @@ varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid) #ifdef WIN32 /* Win32 does not have UTF-8, so we need to map to UTF-16 */ if (GetDatabaseEncoding() == PG_UTF8 - && (!mylocale || mylocale->provider == COLLPROVIDER_LIBC)) + && (collation->provider == COLLPROVIDER_DEFAULT || + collation->provider == COLLPROVIDER_LIBC)) { int a1len; int a2len; @@ -1489,8 +1484,8 @@ varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid) errno = 0; #ifdef HAVE_LOCALE_T - if (mylocale) - result = wcscoll_l((LPWSTR) a1p, (LPWSTR) a2p, mylocale->info.lt); + if (collation->provider == COLLPROVIDER_LIBC) + result = wcscoll_l((LPWSTR) a1p, (LPWSTR) a2p, collation->info.lt); else #endif result = wcscoll((LPWSTR) a1p, (LPWSTR) a2p); @@ -1535,57 +1530,54 @@ varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid) memcpy(a2p, arg2, len2); a2p[len2] = '\0'; - if (mylocale) + if (collation->provider == COLLPROVIDER_ICU) { - if (mylocale->provider == COLLPROVIDER_ICU) - { #ifdef USE_ICU #ifdef HAVE_UCOL_STRCOLLUTF8 - if (GetDatabaseEncoding() == PG_UTF8) - { - UErrorCode status; + if (GetDatabaseEncoding() == PG_UTF8) + { + UErrorCode status; - status = U_ZERO_ERROR; - result = ucol_strcollUTF8(mylocale->info.icu.ucol, - arg1, len1, - arg2, len2, - &status); - if (U_FAILURE(status)) - ereport(ERROR, - (errmsg("collation failed: %s", u_errorName(status)))); - } - else + status = U_ZERO_ERROR; + result = ucol_strcollUTF8(collation->info.icu.ucol, + arg1, len1, + arg2, len2, + &status); + if (U_FAILURE(status)) + ereport(ERROR, + (errmsg("collation failed: %s", u_errorName(status)))); + } + else #endif - { - int32_t ulen1, - ulen2; - UChar *uchar1, - *uchar2; + { + int32_t ulen1, + ulen2; + UChar *uchar1, + *uchar2; - ulen1 = icu_to_uchar(&uchar1, arg1, len1); - ulen2 = icu_to_uchar(&uchar2, arg2, len2); + ulen1 = icu_to_uchar(&uchar1, arg1, len1); + ulen2 = icu_to_uchar(&uchar2, arg2, len2); - result = ucol_strcoll(mylocale->info.icu.ucol, - uchar1, ulen1, - uchar2, ulen2); + result = ucol_strcoll(collation->info.icu.ucol, + uchar1, ulen1, + uchar2, ulen2); - pfree(uchar1); - pfree(uchar2); - } + pfree(uchar1); + pfree(uchar2); + } #else /* not USE_ICU */ - /* shouldn't happen */ - elog(ERROR, "unsupported collprovider: %c", mylocale->provider); + /* shouldn't happen */ + elog(ERROR, "unsupported collprovider: %c", collation->provider); #endif /* not USE_ICU */ - } - else - { + } + else if (collation->provider == COLLPROVIDER_LIBC) + { #ifdef HAVE_LOCALE_T - result = strcoll_l(a1p, a2p, mylocale->info.lt); + result = strcoll_l(a1p, a2p, collation->info.lt); #else - /* shouldn't happen */ - elog(ERROR, "unsupported collprovider: %c", mylocale->provider); + /* shouldn't happen */ + elog(ERROR, "unsupported collprovider: %c", collation->provider); #endif - } } else result = strcoll(a1p, a2p); @@ -1613,7 +1605,7 @@ varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid) * Returns -1, 0 or 1 */ static int -text_cmp(text *arg1, text *arg2, Oid collid) +text_cmp(text *arg1, text *arg2, pg_locale_t collation) { char *a1p, *a2p; @@ -1626,7 +1618,7 @@ text_cmp(text *arg1, text *arg2, Oid collid) len1 = VARSIZE_ANY_EXHDR(arg1); len2 = VARSIZE_ANY_EXHDR(arg2); - return varstr_cmp(a1p, len1, a2p, len2, collid); + return varstr_cmp(a1p, len1, a2p, len2, collation); } /* @@ -1808,13 +1800,12 @@ Datum bttextsortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); - Oid collid = ssup->ssup_collation; MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); /* Use generic string SortSupport */ - varstr_sortsupport(ssup, collid, false); + varstr_sortsupport(ssup, ssup->ssup_collation, false); MemoryContextSwitchTo(oldcontext); @@ -1832,12 +1823,22 @@ bttextsortsupport(PG_FUNCTION_ARGS) * this will not work with any other collation, though. */ void -varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) +varstr_sortsupport(SortSupport ssup, pg_locale_t collation, bool bpchar) { bool abbreviate = ssup->abbreviate; - bool collate_c = false; VarStringSortSupport *sss; - pg_locale_t locale = 0; + + if (!collation) + { + /* + * This typically means that the parser could not resolve a + * conflict of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for string comparison"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } /* * If possible, set ssup->comparator to a function which can be used to @@ -1851,37 +1852,18 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) * make things quite a bit faster with varstrfastcmp_c or bpcharfastcmp_c, * both of which use memcmp() rather than strcoll(). */ - if (lc_collate_is_c(collid)) + if (collation->collate_is_c) { if (!bpchar) ssup->comparator = varstrfastcmp_c; else ssup->comparator = bpcharfastcmp_c; - - collate_c = true; } else { /* - * We need a collation-sensitive comparison. To make things faster, - * we'll figure out the collation based on the locale id and cache the - * result. + * We need a collation-sensitive comparison. */ - if (collid != DEFAULT_COLLATION_OID) - { - if (!OidIsValid(collid)) - { - /* - * This typically means that the parser could not resolve a - * conflict of implicit collations, so report it that way. - */ - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for string comparison"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - locale = pg_newlocale_from_collation(collid); - } /* * There is a further exception on Windows. When the database @@ -1893,7 +1875,7 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) */ #ifdef WIN32 if (GetDatabaseEncoding() == PG_UTF8 && - !(locale && locale->provider == COLLPROVIDER_ICU)) + collation->provider != COLLPROVIDER_ICU) return; #endif @@ -1922,7 +1904,7 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) * platforms. */ #ifndef TRUST_STRXFRM - if (!collate_c && !(locale && locale->provider == COLLPROVIDER_ICU)) + if (!(collation->collate_is_c || collation->provider == COLLPROVIDER_ICU)) abbreviate = false; #endif @@ -1933,7 +1915,7 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) * scratch space (and to detect requirement for BpChar semantics from * caller), and the abbreviation case requires additional state. */ - if (abbreviate || !collate_c) + if (abbreviate || !collation->collate_is_c) { sss = palloc(sizeof(VarStringSortSupport)); sss->buf1 = palloc(TEXTBUFLEN); @@ -1945,7 +1927,7 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) sss->last_len2 = -1; /* Initialize */ sss->last_returned = 0; - sss->locale = locale; + sss->locale = collation; /* * To avoid somehow confusing a strxfrm() blob and an original string, @@ -1962,7 +1944,6 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) * Arbitrarily initialize cache_blob to true. */ sss->cache_blob = true; - sss->collate_c = collate_c; sss->bpchar = bpchar; ssup->ssup_extra = sss; @@ -2156,57 +2137,54 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport ssup) goto done; } - if (sss->locale) + if (sss->locale->provider == COLLPROVIDER_ICU) { - if (sss->locale->provider == COLLPROVIDER_ICU) - { #ifdef USE_ICU #ifdef HAVE_UCOL_STRCOLLUTF8 - if (GetDatabaseEncoding() == PG_UTF8) - { - UErrorCode status; - - status = U_ZERO_ERROR; - result = ucol_strcollUTF8(sss->locale->info.icu.ucol, - a1p, len1, - a2p, len2, - &status); - if (U_FAILURE(status)) - ereport(ERROR, - (errmsg("collation failed: %s", u_errorName(status)))); - } - else + if (GetDatabaseEncoding() == PG_UTF8) + { + UErrorCode status; + + status = U_ZERO_ERROR; + result = ucol_strcollUTF8(sss->locale->info.icu.ucol, + a1p, len1, + a2p, len2, + &status); + if (U_FAILURE(status)) + ereport(ERROR, + (errmsg("collation failed: %s", u_errorName(status)))); + } + else #endif - { - int32_t ulen1, - ulen2; - UChar *uchar1, - *uchar2; + { + int32_t ulen1, + ulen2; + UChar *uchar1, + *uchar2; - ulen1 = icu_to_uchar(&uchar1, a1p, len1); - ulen2 = icu_to_uchar(&uchar2, a2p, len2); + ulen1 = icu_to_uchar(&uchar1, a1p, len1); + ulen2 = icu_to_uchar(&uchar2, a2p, len2); - result = ucol_strcoll(sss->locale->info.icu.ucol, - uchar1, ulen1, - uchar2, ulen2); + result = ucol_strcoll(sss->locale->info.icu.ucol, + uchar1, ulen1, + uchar2, ulen2); - pfree(uchar1); - pfree(uchar2); - } + pfree(uchar1); + pfree(uchar2); + } #else /* not USE_ICU */ - /* shouldn't happen */ - elog(ERROR, "unsupported collprovider: %c", sss->locale->provider); + /* shouldn't happen */ + elog(ERROR, "unsupported collprovider: %c", sss->locale->provider); #endif /* not USE_ICU */ - } - else - { + } + else if (sss->locale->provider == COLLPROVIDER_LIBC) + { #ifdef HAVE_LOCALE_T - result = strcoll_l(sss->buf1, sss->buf2, sss->locale->info.lt); + result = strcoll_l(sss->buf1, sss->buf2, sss->locale->info.lt); #else - /* shouldn't happen */ - elog(ERROR, "unsupported collprovider: %c", sss->locale->provider); + /* shouldn't happen */ + elog(ERROR, "unsupported collprovider: %c", sss->locale->provider); #endif - } } else result = strcoll(sss->buf1, sss->buf2); @@ -2309,7 +2287,7 @@ varstr_abbrev_convert(Datum original, SortSupport ssup) * -- then an authoritative tie-breaker will happen, and do the right * thing: explicitly consider string length. */ - if (sss->collate_c) + if (sss->locale->collate_is_c) memcpy(pres, authoritative_data, Min(len, sizeof(Datum))); else { @@ -2758,7 +2736,7 @@ bttext_pattern_sortsupport(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); /* Use generic string SortSupport, forcing "C" collation */ - varstr_sortsupport(ssup, C_COLLATION_OID, false); + varstr_sortsupport(ssup, pg_newlocale_from_collation(C_COLLATION_OID), false); MemoryContextSwitchTo(oldcontext); @@ -3798,7 +3776,7 @@ bytea_sortsupport(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); /* Use generic string SortSupport, forcing "C" collation */ - varstr_sortsupport(ssup, C_COLLATION_OID, false); + varstr_sortsupport(ssup, pg_newlocale_from_collation(C_COLLATION_OID), false); MemoryContextSwitchTo(oldcontext); diff --git a/src/backend/utils/cache/partcache.c b/src/backend/utils/cache/partcache.c index 6db2c6f783..aae0141e20 100644 --- a/src/backend/utils/cache/partcache.c +++ b/src/backend/utils/cache/partcache.c @@ -33,6 +33,7 @@ #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/partcache.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -150,7 +151,7 @@ RelationBuildPartitionKey(Relation relation) key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid)); key->partsupfunc = (FmgrInfo *) palloc0(key->partnatts * sizeof(FmgrInfo)); - key->partcollation = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + key->partcollation = (fmLocalePtr *) palloc0(key->partnatts * sizeof(fmLocalePtr)); /* Gather type and collation info as well */ key->parttypid = (Oid *) palloc0(key->partnatts * sizeof(Oid)); @@ -158,7 +159,7 @@ RelationBuildPartitionKey(Relation relation) key->parttyplen = (int16 *) palloc0(key->partnatts * sizeof(int16)); key->parttypbyval = (bool *) palloc0(key->partnatts * sizeof(bool)); key->parttypalign = (char *) palloc0(key->partnatts * sizeof(char)); - key->parttypcoll = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + key->parttypcollid = (Oid *) palloc0(key->partnatts * sizeof(Oid)); MemoryContextSwitchTo(oldcxt); /* determine support function number to search for */ @@ -203,7 +204,7 @@ RelationBuildPartitionKey(Relation relation) fmgr_info_cxt(funcid, &key->partsupfunc[i], partkeycxt); /* Collation */ - key->partcollation[i] = collation->values[i]; + key->partcollation[i] = pg_newlocale_from_collation(collation->values[i]); /* Collect type information */ if (attno != 0) @@ -212,7 +213,7 @@ RelationBuildPartitionKey(Relation relation) key->parttypid[i] = att->atttypid; key->parttypmod[i] = att->atttypmod; - key->parttypcoll[i] = att->attcollation; + key->parttypcollid[i] = att->attcollation; } else { @@ -221,7 +222,7 @@ RelationBuildPartitionKey(Relation relation) key->parttypid[i] = exprType(lfirst(partexprs_item)); key->parttypmod[i] = exprTypmod(lfirst(partexprs_item)); - key->parttypcoll[i] = exprCollation(lfirst(partexprs_item)); + key->parttypcollid[i] = exprCollation(lfirst(partexprs_item)); partexprs_item = lnext(partexprs_item); } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index c3071db1cd..69cfefe699 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1432,6 +1432,8 @@ RelationInitIndexAccessInfo(Relation relation) relation->rd_indcollation = (Oid *) MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid)); + relation->rd_indcollinfo = (fmLocalePtr *) + MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(fmLocalePtr)); relation->rd_indoption = (int16 *) MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16)); @@ -5542,6 +5544,10 @@ load_relcache_init_file(bool shared) rel->rd_indcollation = indcollation; + /* set up zeroed collation-info vector */ + rel->rd_indcollinfo = (fmLocalePtr *) + MemoryContextAllocZero(indexcxt, relform->relnatts * sizeof(fmLocalePtr)); + /* finally, read the vector of indoption values */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; @@ -5573,6 +5579,7 @@ load_relcache_init_file(bool shared) Assert(rel->rd_supportinfo == NULL); Assert(rel->rd_indoption == NULL); Assert(rel->rd_indcollation == NULL); + Assert(rel->rd_indcollinfo == NULL); } /* diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 09f9d5fdcb..d0e759de1f 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -66,6 +66,7 @@ #include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/rel.h" #include "utils/snapmgr.h" #include "utils/syscache.h" @@ -836,7 +837,7 @@ load_rangetype_info(TypeCacheEntry *typentry) pg_range = (Form_pg_range) GETSTRUCT(tup); subtypeOid = pg_range->rngsubtype; - typentry->rng_collation = pg_range->rngcollation; + typentry->rng_collation = pg_newlocale_from_collation(pg_range->rngcollation); opclassOid = pg_range->rngsubopc; canonicalOid = pg_range->rngcanonical; subdiffOid = pg_range->rngsubdiff; diff --git a/src/backend/utils/fmgr/README b/src/backend/utils/fmgr/README index 5a2331ff15..1801b5ca50 100644 --- a/src/backend/utils/fmgr/README +++ b/src/backend/utils/fmgr/README @@ -64,7 +64,7 @@ typedef struct FmgrInfo *flinfo; /* ptr to lookup info used for this call */ Node *context; /* pass info about context of call */ Node *resultinfo; /* pass or return extra info about result */ - Oid fncollation; /* collation for function to use */ + pg_locale_t fncollation; /* collation for function to use */ bool isnull; /* function must set true if result is NULL */ short nargs; /* # arguments actually passed */ Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */ @@ -92,7 +92,7 @@ function that returns a set, as discussed below.) Like the context field, resultinfo is a hook for expansion; fmgr itself doesn't constrain the use of the field. -fncollation is the input collation derived by the parser, or InvalidOid +fncollation is the input collation derived by the parser, or NULL when there are no inputs of collatable types or they don't share a common collation. This is effectively a hidden additional argument, which collation-sensitive functions can use to determine their behavior. diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 73ff48c196..ab3c93e0bf 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -790,7 +790,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) * look at FmgrInfo, since there won't be any. */ Datum -DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1) +DirectFunctionCall1Coll(PGFunction func, fmLocalePtr collation, Datum arg1) { FunctionCallInfoData fcinfo; Datum result; @@ -810,7 +810,7 @@ DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1) } Datum -DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2) +DirectFunctionCall2Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2) { FunctionCallInfoData fcinfo; Datum result; @@ -832,7 +832,7 @@ DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2) } Datum -DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall3Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3) { FunctionCallInfoData fcinfo; @@ -857,7 +857,7 @@ DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, } Datum -DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall4Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4) { FunctionCallInfoData fcinfo; @@ -884,7 +884,7 @@ DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, } Datum -DirectFunctionCall5Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall5Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5) { FunctionCallInfoData fcinfo; @@ -913,7 +913,7 @@ DirectFunctionCall5Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, } Datum -DirectFunctionCall6Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall6Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6) { @@ -945,7 +945,7 @@ DirectFunctionCall6Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, } Datum -DirectFunctionCall7Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall7Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7) { @@ -979,7 +979,7 @@ DirectFunctionCall7Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, } Datum -DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall8Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8) { @@ -1015,7 +1015,7 @@ DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, } Datum -DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, +DirectFunctionCall9Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9) @@ -1063,7 +1063,7 @@ DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, */ Datum -CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1) +CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1) { FunctionCallInfoData fcinfo; Datum result; @@ -1083,7 +1083,7 @@ CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum } Datum -CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2) +CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2) { FunctionCallInfoData fcinfo; Datum result; @@ -1110,7 +1110,7 @@ CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum * are allowed to be NULL. */ Datum -FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1) +FunctionCall1Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1) { FunctionCallInfoData fcinfo; Datum result; @@ -1130,7 +1130,7 @@ FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1) } Datum -FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2) +FunctionCall2Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2) { FunctionCallInfoData fcinfo; Datum result; @@ -1152,7 +1152,7 @@ FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2) } Datum -FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall3Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3) { FunctionCallInfoData fcinfo; @@ -1177,7 +1177,7 @@ FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, } Datum -FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall4Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4) { FunctionCallInfoData fcinfo; @@ -1204,7 +1204,7 @@ FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, } Datum -FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall5Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5) { FunctionCallInfoData fcinfo; @@ -1233,7 +1233,7 @@ FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, } Datum -FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall6Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6) { @@ -1265,7 +1265,7 @@ FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, } Datum -FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall7Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7) { @@ -1299,7 +1299,7 @@ FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, } Datum -FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall8Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8) { @@ -1335,7 +1335,7 @@ FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, } Datum -FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, +FunctionCall9Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9) @@ -1382,7 +1382,7 @@ FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, * do the fmgr_info() once and then use FunctionCallN(). */ Datum -OidFunctionCall0Coll(Oid functionId, Oid collation) +OidFunctionCall0Coll(Oid functionId, fmLocalePtr collation) { FmgrInfo flinfo; FunctionCallInfoData fcinfo; @@ -1402,7 +1402,7 @@ OidFunctionCall0Coll(Oid functionId, Oid collation) } Datum -OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1) +OidFunctionCall1Coll(Oid functionId, fmLocalePtr collation, Datum arg1) { FmgrInfo flinfo; FunctionCallInfoData fcinfo; @@ -1425,7 +1425,7 @@ OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1) } Datum -OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2) +OidFunctionCall2Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2) { FmgrInfo flinfo; FunctionCallInfoData fcinfo; @@ -1450,7 +1450,7 @@ OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2) } Datum -OidFunctionCall3Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall3Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3) { FmgrInfo flinfo; @@ -1478,7 +1478,7 @@ OidFunctionCall3Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, } Datum -OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall4Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4) { FmgrInfo flinfo; @@ -1508,7 +1508,7 @@ OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, } Datum -OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall5Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5) { FmgrInfo flinfo; @@ -1540,7 +1540,7 @@ OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, } Datum -OidFunctionCall6Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall6Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6) { @@ -1575,7 +1575,7 @@ OidFunctionCall6Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, } Datum -OidFunctionCall7Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall7Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7) { @@ -1612,7 +1612,7 @@ OidFunctionCall7Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, } Datum -OidFunctionCall8Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall8Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8) { @@ -1651,7 +1651,7 @@ OidFunctionCall8Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, } Datum -OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, +OidFunctionCall9Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9) diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index ee7fd83c02..0a13d73466 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -109,6 +109,7 @@ #include "utils/logtape.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/pg_rusage.h" #include "utils/rel.h" #include "utils/sortsupport.h" @@ -853,7 +854,7 @@ tuplesort_begin_heap(TupleDesc tupDesc, AssertArg(sortOperators[i] != 0); sortKey->ssup_cxt = CurrentMemoryContext; - sortKey->ssup_collation = sortCollations[i]; + sortKey->ssup_collation = pg_newlocale_from_collation(sortCollations[i]); sortKey->ssup_nulls_first = nullsFirstFlags[i]; sortKey->ssup_attno = attNums[i]; /* Convey if abbreviation optimization is applicable in principle */ @@ -1141,7 +1142,7 @@ tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, state->sortKeys = (SortSupport) palloc0(sizeof(SortSupportData)); state->sortKeys->ssup_cxt = CurrentMemoryContext; - state->sortKeys->ssup_collation = sortCollation; + state->sortKeys->ssup_collation = pg_newlocale_from_collation(sortCollation); state->sortKeys->ssup_nulls_first = nullsFirstFlag; /* diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 534fac7bf2..10b1fd643a 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -174,6 +174,7 @@ extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum); extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum); +extern fmLocalePtr index_getcollinfo(Relation irel, AttrNumber attnum); extern void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, double *distances, bool recheckOrderBy); diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 81bf8734ce..90c55465c6 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -79,7 +79,7 @@ typedef struct GinState /* canPartialMatch[i] is true if comparePartialFn[i] is valid */ bool canPartialMatch[INDEX_MAX_KEYS]; /* Collations to pass to the support functions */ - Oid supportCollation[INDEX_MAX_KEYS]; + fmLocalePtr supportCollation[INDEX_MAX_KEYS]; } GinState; @@ -285,7 +285,7 @@ typedef struct GinScanKeyData GinTernaryValue (*triConsistentFn) (GinScanKey key); FmgrInfo *consistentFmgrInfo; FmgrInfo *triConsistentFmgrInfo; - Oid collation; + fmLocalePtr collation; /* other data needed for calling consistentFn */ Datum query; diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 36ed7244ba..9ca7718680 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -93,7 +93,7 @@ typedef struct GISTSTATE FmgrInfo fetchFn[INDEX_MAX_KEYS]; /* Collations to pass to the support functions */ - Oid supportCollation[INDEX_MAX_KEYS]; + fmLocalePtr supportCollation[INDEX_MAX_KEYS]; } GISTSTATE; diff --git a/src/include/access/skey.h b/src/include/access/skey.h index ab3bb2c8eb..c5e76cf97a 100644 --- a/src/include/access/skey.h +++ b/src/include/access/skey.h @@ -67,7 +67,7 @@ typedef struct ScanKeyData AttrNumber sk_attno; /* table or index column number */ StrategyNumber sk_strategy; /* operator strategy number */ Oid sk_subtype; /* strategy subtype */ - Oid sk_collation; /* collation to use, if needed */ + fmLocalePtr sk_collation; /* collation to use, if needed */ FmgrInfo sk_func; /* lookup info for function to call */ Datum sk_argument; /* data to compare */ } ScanKeyData; @@ -144,7 +144,7 @@ extern void ScanKeyEntryInitializeWithInfo(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, - Oid collation, + fmLocalePtr collation, FmgrInfo *finfo, Datum argument); diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index d23862ea71..8033111e79 100644 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -171,7 +171,7 @@ typedef struct SpGistScanOpaqueData int numberOfOrderBys; /* number of ordering operators */ ScanKey orderByData; /* array of ordering op descriptors */ Oid *orderByTypes; /* array of ordering op return types */ - Oid indexCollation; /* collation of index column */ + fmLocalePtr indexCollation; /* collation of index column */ /* Opclass defined functions: */ FmgrInfo innerConsistentFn; diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h index 8fb8c8fe80..4df25fdaff 100644 --- a/src/include/executor/nodeAgg.h +++ b/src/include/executor/nodeAgg.h @@ -86,7 +86,7 @@ typedef struct AggStatePerTransData FmgrInfo deserialfn; /* Input collation derived for aggregate */ - Oid aggCollation; + fmLocalePtr aggCollation; /* number of sorting columns */ int numSortCols; diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 101f513ba6..1cd50a3f7d 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -22,6 +22,9 @@ typedef struct Node *fmNodePtr; typedef struct Aggref *fmAggrefPtr; +/* Likewise, avoid including pg_locale.h here */ +typedef struct pg_locale_struct *fmLocalePtr; + /* Likewise, avoid including execnodes.h here */ typedef void (*fmExprContextCallbackFunction) (Datum arg); @@ -79,7 +82,7 @@ typedef struct FunctionCallInfoData FmgrInfo *flinfo; /* ptr to lookup info used for this call */ fmNodePtr context; /* pass info about context of call */ fmNodePtr resultinfo; /* pass or return extra info about result */ - Oid fncollation; /* collation for function to use */ + fmLocalePtr fncollation; /* collation for function to use */ #define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4 bool isnull; /* function must set true if result is NULL */ short nargs; /* # arguments actually passed */ @@ -466,32 +469,32 @@ extern int no_such_variable * directly-computed parameter list. Note that neither arguments nor result * are allowed to be NULL. */ -extern Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall1Coll(PGFunction func, fmLocalePtr collation, Datum arg1); -extern Datum DirectFunctionCall2Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall2Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2); -extern Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall3Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3); -extern Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall4Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4); -extern Datum DirectFunctionCall5Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall5Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5); -extern Datum DirectFunctionCall6Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall6Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6); -extern Datum DirectFunctionCall7Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall7Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7); -extern Datum DirectFunctionCall8Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall8Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8); -extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation, +extern Datum DirectFunctionCall9Coll(PGFunction func, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8, @@ -506,40 +509,40 @@ extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation, * used fn_extra, unless its use is known to be compatible with the callee's. */ extern Datum CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, - Oid collation, Datum arg1); + fmLocalePtr collation, Datum arg1); extern Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, - Oid collation, Datum arg1, Datum arg2); + fmLocalePtr collation, Datum arg1, Datum arg2); /* These are for invocation of a previously-looked-up function with a * directly-computed parameter list. Note that neither arguments nor result * are allowed to be NULL. */ -extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall1Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1); -extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall2Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2); -extern Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall3Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3); -extern Datum FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall4Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4); -extern Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall5Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5); -extern Datum FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall6Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6); -extern Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall7Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7); -extern Datum FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall8Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8); -extern Datum FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, +extern Datum FunctionCall9Coll(FmgrInfo *flinfo, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8, @@ -551,98 +554,98 @@ extern Datum FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, * FunctionCallN(). If the same function is to be invoked repeatedly, do the * fmgr_info() once and then use FunctionCallN(). */ -extern Datum OidFunctionCall0Coll(Oid functionId, Oid collation); -extern Datum OidFunctionCall1Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall0Coll(Oid functionId, fmLocalePtr collation); +extern Datum OidFunctionCall1Coll(Oid functionId, fmLocalePtr collation, Datum arg1); -extern Datum OidFunctionCall2Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall2Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2); -extern Datum OidFunctionCall3Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall3Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3); -extern Datum OidFunctionCall4Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall4Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4); -extern Datum OidFunctionCall5Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall5Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5); -extern Datum OidFunctionCall6Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall6Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6); -extern Datum OidFunctionCall7Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall7Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7); -extern Datum OidFunctionCall8Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall8Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8); -extern Datum OidFunctionCall9Coll(Oid functionId, Oid collation, +extern Datum OidFunctionCall9Coll(Oid functionId, fmLocalePtr collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9); /* These macros allow the collation argument to be omitted (with a default of - * InvalidOid, ie, no collation). They exist mostly for backwards + * no collation). They exist mostly for backwards * compatibility of source code. */ #define DirectFunctionCall1(func, arg1) \ - DirectFunctionCall1Coll(func, InvalidOid, arg1) + DirectFunctionCall1Coll(func, 0, arg1) #define DirectFunctionCall2(func, arg1, arg2) \ - DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2) + DirectFunctionCall2Coll(func, 0, arg1, arg2) #define DirectFunctionCall3(func, arg1, arg2, arg3) \ - DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3) + DirectFunctionCall3Coll(func, 0, arg1, arg2, arg3) #define DirectFunctionCall4(func, arg1, arg2, arg3, arg4) \ - DirectFunctionCall4Coll(func, InvalidOid, arg1, arg2, arg3, arg4) + DirectFunctionCall4Coll(func, 0, arg1, arg2, arg3, arg4) #define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5) \ - DirectFunctionCall5Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5) + DirectFunctionCall5Coll(func, 0, arg1, arg2, arg3, arg4, arg5) #define DirectFunctionCall6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ - DirectFunctionCall6Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6) + DirectFunctionCall6Coll(func, 0, arg1, arg2, arg3, arg4, arg5, arg6) #define DirectFunctionCall7(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ - DirectFunctionCall7Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + DirectFunctionCall7Coll(func, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define DirectFunctionCall8(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ - DirectFunctionCall8Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + DirectFunctionCall8Coll(func, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) #define DirectFunctionCall9(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ - DirectFunctionCall9Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + DirectFunctionCall9Coll(func, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) #define FunctionCall1(flinfo, arg1) \ - FunctionCall1Coll(flinfo, InvalidOid, arg1) + FunctionCall1Coll(flinfo, 0, arg1) #define FunctionCall2(flinfo, arg1, arg2) \ - FunctionCall2Coll(flinfo, InvalidOid, arg1, arg2) + FunctionCall2Coll(flinfo, 0, arg1, arg2) #define FunctionCall3(flinfo, arg1, arg2, arg3) \ - FunctionCall3Coll(flinfo, InvalidOid, arg1, arg2, arg3) + FunctionCall3Coll(flinfo, 0, arg1, arg2, arg3) #define FunctionCall4(flinfo, arg1, arg2, arg3, arg4) \ - FunctionCall4Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4) + FunctionCall4Coll(flinfo, 0, arg1, arg2, arg3, arg4) #define FunctionCall5(flinfo, arg1, arg2, arg3, arg4, arg5) \ - FunctionCall5Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5) + FunctionCall5Coll(flinfo, 0, arg1, arg2, arg3, arg4, arg5) #define FunctionCall6(flinfo, arg1, arg2, arg3, arg4, arg5, arg6) \ - FunctionCall6Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6) + FunctionCall6Coll(flinfo, 0, arg1, arg2, arg3, arg4, arg5, arg6) #define FunctionCall7(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ - FunctionCall7Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + FunctionCall7Coll(flinfo, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define FunctionCall8(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ - FunctionCall8Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + FunctionCall8Coll(flinfo, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) #define FunctionCall9(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ - FunctionCall9Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + FunctionCall9Coll(flinfo, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) #define OidFunctionCall0(functionId) \ - OidFunctionCall0Coll(functionId, InvalidOid) + OidFunctionCall0Coll(functionId, 0) #define OidFunctionCall1(functionId, arg1) \ - OidFunctionCall1Coll(functionId, InvalidOid, arg1) + OidFunctionCall1Coll(functionId, 0, arg1) #define OidFunctionCall2(functionId, arg1, arg2) \ - OidFunctionCall2Coll(functionId, InvalidOid, arg1, arg2) + OidFunctionCall2Coll(functionId, 0, arg1, arg2) #define OidFunctionCall3(functionId, arg1, arg2, arg3) \ - OidFunctionCall3Coll(functionId, InvalidOid, arg1, arg2, arg3) + OidFunctionCall3Coll(functionId, 0, arg1, arg2, arg3) #define OidFunctionCall4(functionId, arg1, arg2, arg3, arg4) \ - OidFunctionCall4Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4) + OidFunctionCall4Coll(functionId, 0, arg1, arg2, arg3, arg4) #define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5) \ - OidFunctionCall5Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5) + OidFunctionCall5Coll(functionId, 0, arg1, arg2, arg3, arg4, arg5) #define OidFunctionCall6(functionId, arg1, arg2, arg3, arg4, arg5, arg6) \ - OidFunctionCall6Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6) + OidFunctionCall6Coll(functionId, 0, arg1, arg2, arg3, arg4, arg5, arg6) #define OidFunctionCall7(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ - OidFunctionCall7Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + OidFunctionCall7Coll(functionId, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define OidFunctionCall8(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ - OidFunctionCall8Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + OidFunctionCall8Coll(functionId, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) #define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ - OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + OidFunctionCall9Coll(functionId, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) /* Special cases for convenient invocation of datatype I/O functions. */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 5ed0f40f69..525d1c44bd 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2062,7 +2062,7 @@ typedef struct WindowAggState /* these fields are used with RANGE offset PRECEDING/FOLLOWING: */ FmgrInfo startInRangeFunc; /* in_range function for startOffset */ FmgrInfo endInRangeFunc; /* in_range function for endOffset */ - Oid inRangeColl; /* collation for in_range tests */ + fmLocalePtr inRangeColl; /* collation for in_range tests */ bool inRangeAsc; /* use ASC sort order for in_range tests? */ bool inRangeNullsFirst; /* nulls sort first for in_range tests? */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 6fd24203dd..25c0192661 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -375,7 +375,6 @@ typedef struct PartitionSchemeData int16 partnatts; /* number of partition attributes */ Oid *partopfamily; /* OIDs of operator families */ Oid *partopcintype; /* OIDs of opclass declared input data types */ - Oid *partcollation; /* OIDs of partitioning collations */ /* Cached information about partition key data types. */ int16 *parttyplen; @@ -383,6 +382,7 @@ typedef struct PartitionSchemeData /* Cached information about partition comparison functions. */ FmgrInfo *partsupfunc; + fmLocalePtr *partcollation; /* partitioning collations */ } PartitionSchemeData; typedef struct PartitionSchemeData *PartitionScheme; diff --git a/src/include/partitioning/partbounds.h b/src/include/partitioning/partbounds.h index 36fb584e23..2f95fa00a2 100644 --- a/src/include/partitioning/partbounds.h +++ b/src/include/partitioning/partbounds.h @@ -94,15 +94,15 @@ extern void check_default_partition_contents(Relation parent, PartitionBoundSpec *new_spec); extern int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, - Oid *partcollation, + fmLocalePtr *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums); extern int partition_list_bsearch(FmgrInfo *partsupfunc, - Oid *partcollation, + fmLocalePtr *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal); extern int partition_range_datum_bsearch(FmgrInfo *partsupfunc, - Oid *partcollation, + fmLocalePtr *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal); extern int partition_hash_bsearch(PartitionBoundInfo boundinfo, diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index e07aaaf798..341db8e2e4 100644 --- a/src/include/partitioning/partprune.h +++ b/src/include/partitioning/partprune.h @@ -52,7 +52,7 @@ typedef struct PartitionPruneContext int partnatts; int nparts; PartitionBoundInfo boundinfo; - Oid *partcollation; + fmLocalePtr *partcollation; FmgrInfo *partsupfunc; FmgrInfo *stepcmpfuncs; MemoryContext ppccontext; diff --git a/src/include/regex/regex.h b/src/include/regex/regex.h index 27fdc09040..543b0b864d 100644 --- a/src/include/regex/regex.h +++ b/src/include/regex/regex.h @@ -36,6 +36,7 @@ * Add your own defines, if needed, here. */ #include "mb/pg_wchar.h" +#include "utils/pg_locale.h" /* * interface types etc. @@ -73,7 +74,7 @@ typedef struct #define REG_USHORTEST 020000 int re_csize; /* sizeof(character) */ char *re_endp; /* backward compatibility kludge */ - Oid re_collation; /* Collation that defines LC_CTYPE behavior */ + pg_locale_t re_collation; /* Collation that defines LC_CTYPE behavior */ /* the rest is opaque pointers to hidden innards */ char *re_guts; /* `char *' is more portable than `void *' */ char *re_fns; @@ -167,7 +168,7 @@ typedef struct /* * the prototypes for exported functions */ -extern int pg_regcomp(regex_t *, const pg_wchar *, size_t, int, Oid); +extern int pg_regcomp(regex_t *, const pg_wchar *, size_t, int, pg_locale_t); extern int pg_regexec(regex_t *, const pg_wchar *, size_t, size_t, rm_detail_t *, size_t, regmatch_t[], int); extern int pg_regprefix(regex_t *, pg_wchar **, size_t *); extern void pg_regfree(regex_t *); diff --git a/src/include/regex/regguts.h b/src/include/regex/regguts.h index 5d0e7a961c..6849c99e41 100644 --- a/src/include/regex/regguts.h +++ b/src/include/regex/regguts.h @@ -478,5 +478,5 @@ struct guts /* prototypes for functions that are exported from regcomp.c to regexec.c */ -extern void pg_set_regex_collation(Oid collation); +extern void pg_set_regex_collation(pg_locale_t collation); extern color pg_reg_getcolor(struct colormap *cm, chr c); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 61785a2433..a991294c0f 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -59,7 +59,7 @@ extern int oid_cmp(const void *p1, const void *p2); /* regexp.c */ extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive, - Oid collation, bool *exact); + fmLocalePtr collation, bool *exact); /* ruleutils.c */ extern bool quote_all_identifiers; diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index a9f5548b46..272cc60054 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -20,9 +20,9 @@ #include "fmgr.h" -extern char *str_tolower(const char *buff, size_t nbytes, Oid collid); -extern char *str_toupper(const char *buff, size_t nbytes, Oid collid); -extern char *str_initcap(const char *buff, size_t nbytes, Oid collid); +extern char *str_tolower(const char *buff, size_t nbytes, fmLocalePtr collation); +extern char *str_toupper(const char *buff, size_t nbytes, fmLocalePtr collation); +extern char *str_initcap(const char *buff, size_t nbytes, fmLocalePtr collation); extern char *asc_tolower(const char *buff, size_t nbytes); extern char *asc_toupper(const char *buff, size_t nbytes); diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h index 2939032f0a..3095df36a8 100644 --- a/src/include/utils/partcache.h +++ b/src/include/utils/partcache.h @@ -35,7 +35,7 @@ typedef struct PartitionKeyData FmgrInfo *partsupfunc; /* lookup info for support funcs */ /* Partitioning collation per attribute */ - Oid *partcollation; + fmLocalePtr *partcollation; /* Type information per attribute */ Oid *parttypid; @@ -43,7 +43,7 @@ typedef struct PartitionKeyData int16 *parttyplen; bool *parttypbyval; char *parttypalign; - Oid *parttypcoll; + Oid *parttypcollid; } PartitionKeyData; extern void RelationBuildPartitionKey(Relation relation); diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h index 88a3134862..026906b1b5 100644 --- a/src/include/utils/pg_locale.h +++ b/src/include/utils/pg_locale.h @@ -61,9 +61,6 @@ extern bool check_locale(int category, const char *locale, char **canonname); extern char *pg_perm_setlocale(int category, const char *locale); extern void check_strxfrm_bug(void); -extern bool lc_collate_is_c(Oid collation); -extern bool lc_ctype_is_c(Oid collation); - /* * Return the POSIX lconv struct (contains number/money formatting * information) with locale information for all categories. @@ -81,6 +78,7 @@ extern void cache_locale_time(void); */ struct pg_locale_struct { + Oid collid; char provider; union { @@ -96,6 +94,8 @@ struct pg_locale_struct #endif int dummy; /* in case we have neither LOCALE_T nor ICU */ } info; + bool collate_is_c; + bool ctype_is_c; }; typedef struct pg_locale_struct *pg_locale_t; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 2217081dcc..d5b2547e94 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -162,6 +162,7 @@ typedef struct RelationData uint16 *rd_exclstrats; /* exclusion ops' strategy numbers, if any */ void *rd_amcache; /* available for use by index AM */ Oid *rd_indcollation; /* OIDs of index collations */ + fmLocalePtr *rd_indcollinfo; /* lookup info for index collations */ /* * foreign-table support diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index 95e44280c4..5b5894c8b3 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -179,11 +179,11 @@ extern double histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc, extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt, Pattern_Type ptype, - Oid collation, + fmLocalePtr collation, Const **prefix, Selectivity *rest_selec); extern Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc, - Oid collation); + fmLocalePtr collation); extern Selectivity boolvarsel(PlannerInfo *root, Node *arg, int varRelid); extern Selectivity booltestsel(PlannerInfo *root, BoolTestType booltesttype, diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h index 818e0b1843..be56e25a45 100644 --- a/src/include/utils/sortsupport.h +++ b/src/include/utils/sortsupport.h @@ -64,7 +64,7 @@ typedef struct SortSupportData * and should not be changed later. */ MemoryContext ssup_cxt; /* Context containing sort info */ - Oid ssup_collation; /* Collation to use, or InvalidOid */ + fmLocalePtr ssup_collation; /* Collation to use, or 0 */ /* * Additional sorting parameters; but unlike ssup_collation, these can be diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h index 217d064da5..9994cbd6b6 100644 --- a/src/include/utils/typcache.h +++ b/src/include/utils/typcache.h @@ -92,7 +92,7 @@ typedef struct TypeCacheEntry * btree comparison function. */ struct TypeCacheEntry *rngelemtype; /* range's element type */ - Oid rng_collation; /* collation for comparisons, if any */ + fmLocalePtr rng_collation; /* collation for comparisons, if any */ FmgrInfo rng_cmp_proc_finfo; /* comparison function */ FmgrInfo rng_canonical_finfo; /* canonicalization function, if any */ FmgrInfo rng_subdiff_finfo; /* difference function, if any */ diff --git a/src/include/utils/varlena.h b/src/include/utils/varlena.h index c776931bc4..64f0350c71 100644 --- a/src/include/utils/varlena.h +++ b/src/include/utils/varlena.h @@ -16,8 +16,8 @@ #include "nodes/pg_list.h" #include "utils/sortsupport.h" -extern int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid); -extern void varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar); +extern int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, fmLocalePtr collation); +extern void varstr_sortsupport(SortSupport ssup, fmLocalePtr collation, bool bpchar); extern int varstr_levenshtein(const char *source, int slen, const char *target, int tlen, int ins_c, int del_c, int sub_c, diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 8bacc74cce..594340b29a 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -28,6 +28,7 @@ #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/pg_locale.h" #include "utils/regproc.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -350,7 +351,8 @@ do_compile(FunctionCallInfo fcinfo, function->fn_oid = fcinfo->flinfo->fn_oid; function->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data); function->fn_tid = procTup->t_self; - function->fn_input_collation = fcinfo->fncollation; + if (fcinfo->fncollation) + function->fn_input_collation = fcinfo->fncollation->collid; function->fn_cxt = func_cxt; function->out_param_varno = -1; /* set up for no OUT param */ function->resolve_option = plpgsql_variable_conflict; @@ -2350,7 +2352,8 @@ compute_function_hashkey(FunctionCallInfo fcinfo, } /* get input collation, if known */ - hashkey->inputCollation = fcinfo->fncollation; + if (fcinfo->fncollation) + hashkey->inputCollation = fcinfo->fncollation->collid; if (procStruct->pronargs > 0) { base-commit: 001bb9f3ed05e7c370151f7aad3a83447c52c157 -- 2.20.0