aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/Makefile1
-rw-r--r--src/backend/utils/adt/meson.build1
-rw-r--r--src/backend/utils/adt/pg_locale.c162
-rw-r--r--src/backend/utils/adt/pg_locale_builtin.c70
-rw-r--r--src/backend/utils/adt/pg_locale_icu.c97
-rw-r--r--src/backend/utils/adt/pg_locale_libc.c74
6 files changed, 259 insertions, 146 deletions
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 85e5eaf32eb..35e8c01aab9 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -79,6 +79,7 @@ OBJS = \
orderedsetaggs.o \
partitionfuncs.o \
pg_locale.o \
+ pg_locale_builtin.o \
pg_locale_icu.o \
pg_locale_libc.o \
pg_lsn.o \
diff --git a/src/backend/utils/adt/meson.build b/src/backend/utils/adt/meson.build
index f73f294b8f5..e86d6dc8e0a 100644
--- a/src/backend/utils/adt/meson.build
+++ b/src/backend/utils/adt/meson.build
@@ -66,6 +66,7 @@ backend_sources += files(
'orderedsetaggs.c',
'partitionfuncs.c',
'pg_locale.c',
+ 'pg_locale_builtin.c',
'pg_locale_icu.c',
'pg_locale_libc.c',
'pg_lsn.c',
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 91cee7714b1..4cb56126e97 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -89,11 +89,12 @@
#define MAX_L10N_DATA 80
+/* pg_locale_builtin.c */
+extern pg_locale_t create_pg_locale_builtin(Oid collid, MemoryContext context);
+
/* pg_locale_icu.c */
#ifdef USE_ICU
extern UCollator *pg_ucol_open(const char *loc_str);
-extern UCollator *make_icu_collator(const char *iculocstr,
- const char *icurules);
extern int strncoll_icu(const char *arg1, ssize_t len1,
const char *arg2, ssize_t len2,
pg_locale_t locale);
@@ -104,10 +105,10 @@ extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
const char *src, ssize_t srclen,
pg_locale_t locale);
#endif
+extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
/* pg_locale_libc.c */
-extern locale_t make_libc_collator(const char *collate,
- const char *ctype);
+extern pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context);
extern int strncoll_libc(const char *arg1, ssize_t len1,
const char *arg2, ssize_t len2,
pg_locale_t locale);
@@ -138,7 +139,7 @@ char *localized_full_months[12 + 1];
/* is the databases's LC_CTYPE the C locale? */
bool database_ctype_is_c = false;
-static struct pg_locale_struct default_locale;
+static pg_locale_t default_locale = NULL;
/* indicates whether locale information cache is valid */
static bool CurrentLocaleConvValid = false;
@@ -1194,7 +1195,6 @@ IsoLocaleName(const char *winlocname)
#endif /* WIN32 && LC_MESSAGES */
-
/*
* Create a new pg_locale_t struct for the given collation oid.
*/
@@ -1207,80 +1207,23 @@ create_pg_locale(Oid collid, MemoryContext context)
Datum datum;
bool isnull;
- result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
-
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for collation %u", collid);
collform = (Form_pg_collation) GETSTRUCT(tp);
- result->provider = collform->collprovider;
- result->deterministic = collform->collisdeterministic;
- result->is_default = false;
-
if (collform->collprovider == COLLPROVIDER_BUILTIN)
- {
- const char *locstr;
-
- datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
- locstr = TextDatumGetCString(datum);
-
- result->collate_is_c = true;
- result->ctype_is_c = (strcmp(locstr, "C") == 0);
-
- builtin_validate_locale(GetDatabaseEncoding(), locstr);
-
- result->info.builtin.locale = MemoryContextStrdup(context,
- locstr);
- }
+ result = create_pg_locale_builtin(collid, context);
else if (collform->collprovider == COLLPROVIDER_ICU)
- {
-#ifdef USE_ICU
- const char *iculocstr;
- const char *icurules;
-
- datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
- iculocstr = TextDatumGetCString(datum);
-
- result->collate_is_c = false;
- result->ctype_is_c = false;
-
- datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
- if (!isnull)
- icurules = TextDatumGetCString(datum);
- else
- icurules = NULL;
-
- result->info.icu.locale = MemoryContextStrdup(context, iculocstr);
- result->info.icu.ucol = make_icu_collator(iculocstr, icurules);
-#else
- /* could get here if a collation was created by a build with ICU */
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("ICU is not supported in this build")));
-#endif
- }
+ result = create_pg_locale_icu(collid, context);
else if (collform->collprovider == COLLPROVIDER_LIBC)
- {
- const char *collcollate;
- const char *collctype;
-
- datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collcollate);
- collcollate = TextDatumGetCString(datum);
- datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collctype);
- collctype = TextDatumGetCString(datum);
-
- result->collate_is_c = (strcmp(collcollate, "C") == 0) ||
- (strcmp(collcollate, "POSIX") == 0);
- result->ctype_is_c = (strcmp(collctype, "C") == 0) ||
- (strcmp(collctype, "POSIX") == 0);
-
- result->info.lt = make_libc_collator(collcollate, collctype);
- }
+ result = create_pg_locale_libc(collid, context);
else
/* shouldn't happen */
PGLOCALE_SUPPORT_ERROR(collform->collprovider);
+ result->is_default = false;
+
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
&isnull);
if (!isnull)
@@ -1336,7 +1279,9 @@ init_database_collation(void)
{
HeapTuple tup;
Form_pg_database dbform;
- Datum datum;
+ pg_locale_t result;
+
+ Assert(default_locale == NULL);
/* Fetch our pg_database row normally, via syscache */
tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
@@ -1345,81 +1290,22 @@ init_database_collation(void)
dbform = (Form_pg_database) GETSTRUCT(tup);
if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
- {
- char *datlocale;
-
- datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_datlocale);
- datlocale = TextDatumGetCString(datum);
-
- builtin_validate_locale(dbform->encoding, datlocale);
-
- default_locale.collate_is_c = true;
- default_locale.ctype_is_c = (strcmp(datlocale, "C") == 0);
-
- default_locale.info.builtin.locale = MemoryContextStrdup(TopMemoryContext,
- datlocale);
- }
+ result = create_pg_locale_builtin(DEFAULT_COLLATION_OID,
+ TopMemoryContext);
else if (dbform->datlocprovider == COLLPROVIDER_ICU)
- {
-#ifdef USE_ICU
- char *datlocale;
- char *icurules;
- bool isnull;
-
- datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_datlocale);
- datlocale = TextDatumGetCString(datum);
-
- default_locale.collate_is_c = false;
- default_locale.ctype_is_c = false;
-
- datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_daticurules, &isnull);
- if (!isnull)
- icurules = TextDatumGetCString(datum);
- else
- icurules = NULL;
-
- default_locale.info.icu.locale = MemoryContextStrdup(TopMemoryContext, datlocale);
- default_locale.info.icu.ucol = make_icu_collator(datlocale, icurules);
-#else
- /* could get here if a collation was created by a build with ICU */
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("ICU is not supported in this build")));
-#endif
- }
+ result = create_pg_locale_icu(DEFAULT_COLLATION_OID,
+ TopMemoryContext);
else if (dbform->datlocprovider == COLLPROVIDER_LIBC)
- {
- const char *datcollate;
- const char *datctype;
-
- datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_datcollate);
- datcollate = TextDatumGetCString(datum);
- datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_datctype);
- datctype = TextDatumGetCString(datum);
-
- default_locale.collate_is_c = (strcmp(datcollate, "C") == 0) ||
- (strcmp(datcollate, "POSIX") == 0);
- default_locale.ctype_is_c = (strcmp(datctype, "C") == 0) ||
- (strcmp(datctype, "POSIX") == 0);
-
- default_locale.info.lt = make_libc_collator(datcollate, datctype);
- }
+ result = create_pg_locale_libc(DEFAULT_COLLATION_OID,
+ TopMemoryContext);
else
/* shouldn't happen */
PGLOCALE_SUPPORT_ERROR(dbform->datlocprovider);
-
- default_locale.provider = dbform->datlocprovider;
- default_locale.is_default = true;
-
- /*
- * Default locale is currently always deterministic. Nondeterministic
- * locales currently don't support pattern matching, which would break a
- * lot of things if applied globally.
- */
- default_locale.deterministic = true;
-
+ result->is_default = true;
ReleaseSysCache(tup);
+
+ default_locale = result;
}
/*
@@ -1437,7 +1323,7 @@ pg_newlocale_from_collation(Oid collid)
bool found;
if (collid == DEFAULT_COLLATION_OID)
- return &default_locale;
+ return default_locale;
if (!OidIsValid(collid))
elog(ERROR, "cache lookup failed for collation %u", collid);
diff --git a/src/backend/utils/adt/pg_locale_builtin.c b/src/backend/utils/adt/pg_locale_builtin.c
new file mode 100644
index 00000000000..4246971a4d8
--- /dev/null
+++ b/src/backend/utils/adt/pg_locale_builtin.c
@@ -0,0 +1,70 @@
+/*-----------------------------------------------------------------------
+ *
+ * PostgreSQL locale utilities for builtin provider
+ *
+ * Portions Copyright (c) 2002-2024, PostgreSQL Global Development Group
+ *
+ * src/backend/utils/adt/pg_locale_builtin.c
+ *
+ *-----------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "catalog/pg_database.h"
+#include "catalog/pg_collation.h"
+#include "mb/pg_wchar.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/memutils.h"
+#include "utils/pg_locale.h"
+#include "utils/syscache.h"
+
+extern pg_locale_t create_pg_locale_builtin(Oid collid,
+ MemoryContext context);
+
+pg_locale_t
+create_pg_locale_builtin(Oid collid, MemoryContext context)
+{
+ const char *locstr;
+ pg_locale_t result;
+
+ if (collid == DEFAULT_COLLATION_OID)
+ {
+ HeapTuple tp;
+ Datum datum;
+
+ tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
+ datum = SysCacheGetAttrNotNull(DATABASEOID, tp,
+ Anum_pg_database_datlocale);
+ locstr = TextDatumGetCString(datum);
+ ReleaseSysCache(tp);
+ }
+ else
+ {
+ HeapTuple tp;
+ Datum datum;
+
+ tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for collation %u", collid);
+ datum = SysCacheGetAttrNotNull(COLLOID, tp,
+ Anum_pg_collation_colllocale);
+ locstr = TextDatumGetCString(datum);
+ ReleaseSysCache(tp);
+ }
+
+ builtin_validate_locale(GetDatabaseEncoding(), locstr);
+
+ result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
+
+ result->info.builtin.locale = MemoryContextStrdup(context, locstr);
+ result->provider = COLLPROVIDER_BUILTIN;
+ result->deterministic = true;
+ result->collate_is_c = true;
+ result->ctype_is_c = (strcmp(locstr, "C") == 0);
+
+ return result;
+}
diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c
index 2a87e25dfb1..73eb430d750 100644
--- a/src/backend/utils/adt/pg_locale_icu.c
+++ b/src/backend/utils/adt/pg_locale_icu.c
@@ -12,14 +12,20 @@
#include "postgres.h"
#ifdef USE_ICU
-
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
+#endif
+#include "access/htup_details.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_collation.h"
#include "mb/pg_wchar.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
#include "utils/formatting.h"
+#include "utils/memutils.h"
#include "utils/pg_locale.h"
+#include "utils/syscache.h"
/*
* Size of stack buffer to use for string transformations, used to avoid heap
@@ -29,9 +35,11 @@
*/
#define TEXTBUFLEN 1024
+extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
+
+#ifdef USE_ICU
+
extern UCollator *pg_ucol_open(const char *loc_str);
-extern UCollator *make_icu_collator(const char *iculocstr,
- const char *icurules);
extern int strncoll_icu(const char *arg1, ssize_t len1,
const char *arg2, ssize_t len2,
pg_locale_t locale);
@@ -49,6 +57,8 @@ extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
*/
static UConverter *icu_converter = NULL;
+static UCollator *make_icu_collator(const char *iculocstr,
+ const char *icurules);
static int strncoll_icu_no_utf8(const char *arg1, ssize_t len1,
const char *arg2, ssize_t len2,
pg_locale_t locale);
@@ -63,6 +73,85 @@ static int32_t uchar_convert(UConverter *converter,
const char *src, int32_t srclen);
static void icu_set_collation_attributes(UCollator *collator, const char *loc,
UErrorCode *status);
+#endif
+
+pg_locale_t
+create_pg_locale_icu(Oid collid, MemoryContext context)
+{
+#ifdef USE_ICU
+ bool deterministic;
+ const char *iculocstr;
+ const char *icurules = NULL;
+ UCollator *collator;
+ pg_locale_t result;
+
+ if (collid == DEFAULT_COLLATION_OID)
+ {
+ HeapTuple tp;
+ Datum datum;
+ bool isnull;
+
+ tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
+
+ /* default database collation is always deterministic */
+ deterministic = true;
+ datum = SysCacheGetAttrNotNull(DATABASEOID, tp,
+ Anum_pg_database_datlocale);
+ iculocstr = TextDatumGetCString(datum);
+ datum = SysCacheGetAttr(DATABASEOID, tp,
+ Anum_pg_database_daticurules, &isnull);
+ if (!isnull)
+ icurules = TextDatumGetCString(datum);
+
+ ReleaseSysCache(tp);
+ }
+ else
+ {
+ Form_pg_collation collform;
+ HeapTuple tp;
+ Datum datum;
+ bool isnull;
+
+ tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for collation %u", collid);
+ collform = (Form_pg_collation) GETSTRUCT(tp);
+ deterministic = collform->collisdeterministic;
+ datum = SysCacheGetAttrNotNull(COLLOID, tp,
+ Anum_pg_collation_colllocale);
+ iculocstr = TextDatumGetCString(datum);
+ datum = SysCacheGetAttr(COLLOID, tp,
+ Anum_pg_collation_collicurules, &isnull);
+ if (!isnull)
+ icurules = TextDatumGetCString(datum);
+
+ ReleaseSysCache(tp);
+ }
+
+ collator = make_icu_collator(iculocstr, icurules);
+
+ result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
+ result->info.icu.locale = MemoryContextStrdup(context, iculocstr);
+ result->info.icu.ucol = collator;
+ result->provider = COLLPROVIDER_ICU;
+ result->deterministic = deterministic;
+ result->collate_is_c = false;
+ result->ctype_is_c = false;
+
+ return result;
+#else
+ /* could get here if a collation was created by a build with ICU */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("ICU is not supported in this build")));
+
+ return NULL;
+#endif
+}
+
+#ifdef USE_ICU
/*
* Wrapper around ucol_open() to handle API differences for older ICU
@@ -160,7 +249,7 @@ pg_ucol_open(const char *loc_str)
*
* Ensure that no path leaks a UCollator.
*/
-UCollator *
+static UCollator *
make_icu_collator(const char *iculocstr, const char *icurules)
{
if (!icurules)
diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c
index 83f310fc71c..374ac37ba0a 100644
--- a/src/backend/utils/adt/pg_locale_libc.c
+++ b/src/backend/utils/adt/pg_locale_libc.c
@@ -11,10 +11,16 @@
#include "postgres.h"
+#include "access/htup_details.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_collation.h"
#include "mb/pg_wchar.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
#include "utils/formatting.h"
+#include "utils/memutils.h"
#include "utils/pg_locale.h"
+#include "utils/syscache.h"
/*
* Size of stack buffer to use for string transformations, used to avoid heap
@@ -24,15 +30,16 @@
*/
#define TEXTBUFLEN 1024
-extern locale_t make_libc_collator(const char *collate,
- const char *ctype);
+extern pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context);
+
extern int strncoll_libc(const char *arg1, ssize_t len1,
const char *arg2, ssize_t len2,
pg_locale_t locale);
extern size_t strnxfrm_libc(char *dest, size_t destsize,
const char *src, ssize_t srclen,
pg_locale_t locale);
-
+static locale_t make_libc_collator(const char *collate,
+ const char *ctype);
static void report_newlocale_failure(const char *localename);
#ifdef WIN32
@@ -41,6 +48,65 @@ static int strncoll_libc_win32_utf8(const char *arg1, ssize_t len1,
pg_locale_t locale);
#endif
+pg_locale_t
+create_pg_locale_libc(Oid collid, MemoryContext context)
+{
+ const char *collate;
+ const char *ctype;
+ locale_t loc;
+ pg_locale_t result;
+
+ if (collid == DEFAULT_COLLATION_OID)
+ {
+ HeapTuple tp;
+ Datum datum;
+
+ tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
+ datum = SysCacheGetAttrNotNull(DATABASEOID, tp,
+ Anum_pg_database_datcollate);
+ collate = TextDatumGetCString(datum);
+ datum = SysCacheGetAttrNotNull(DATABASEOID, tp,
+ Anum_pg_database_datctype);
+ ctype = TextDatumGetCString(datum);
+
+ ReleaseSysCache(tp);
+ }
+ else
+ {
+ HeapTuple tp;
+ Datum datum;
+
+ tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for collation %u", collid);
+
+ datum = SysCacheGetAttrNotNull(COLLOID, tp,
+ Anum_pg_collation_collcollate);
+ collate = TextDatumGetCString(datum);
+ datum = SysCacheGetAttrNotNull(COLLOID, tp,
+ Anum_pg_collation_collctype);
+ ctype = TextDatumGetCString(datum);
+
+ ReleaseSysCache(tp);
+ }
+
+
+ loc = make_libc_collator(collate, ctype);
+
+ result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
+ result->provider = COLLPROVIDER_LIBC;
+ result->deterministic = true;
+ result->collate_is_c = (strcmp(collate, "C") == 0) ||
+ (strcmp(collate, "POSIX") == 0);
+ result->ctype_is_c = (strcmp(ctype, "C") == 0) ||
+ (strcmp(ctype, "POSIX") == 0);
+ result->info.lt = loc;
+
+ return result;
+}
+
/*
* Create a locale_t with the given collation and ctype.
*
@@ -49,7 +115,7 @@ static int strncoll_libc_win32_utf8(const char *arg1, ssize_t len1,
*
* Ensure that no path leaks a locale_t.
*/
-locale_t
+static locale_t
make_libc_collator(const char *collate, const char *ctype)
{
locale_t loc = 0;