mirror of
https://github.com/postgres/postgres.git
synced 2025-05-06 19:59:18 +03:00
Perform provider-specific initialization in new functions.
Reviewed-by: Andreas Karlsson Discussion: https://postgr.es/m/4548a168-62cd-457b-8d06-9ba7b985c477@proxel.se
This commit is contained in:
parent
8817e8d3a4
commit
1ba0782ce9
@ -79,6 +79,7 @@ OBJS = \
|
|||||||
orderedsetaggs.o \
|
orderedsetaggs.o \
|
||||||
partitionfuncs.o \
|
partitionfuncs.o \
|
||||||
pg_locale.o \
|
pg_locale.o \
|
||||||
|
pg_locale_builtin.o \
|
||||||
pg_locale_icu.o \
|
pg_locale_icu.o \
|
||||||
pg_locale_libc.o \
|
pg_locale_libc.o \
|
||||||
pg_lsn.o \
|
pg_lsn.o \
|
||||||
|
@ -66,6 +66,7 @@ backend_sources += files(
|
|||||||
'orderedsetaggs.c',
|
'orderedsetaggs.c',
|
||||||
'partitionfuncs.c',
|
'partitionfuncs.c',
|
||||||
'pg_locale.c',
|
'pg_locale.c',
|
||||||
|
'pg_locale_builtin.c',
|
||||||
'pg_locale_icu.c',
|
'pg_locale_icu.c',
|
||||||
'pg_locale_libc.c',
|
'pg_locale_libc.c',
|
||||||
'pg_lsn.c',
|
'pg_lsn.c',
|
||||||
|
@ -89,11 +89,12 @@
|
|||||||
|
|
||||||
#define MAX_L10N_DATA 80
|
#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 */
|
/* pg_locale_icu.c */
|
||||||
#ifdef USE_ICU
|
#ifdef USE_ICU
|
||||||
extern UCollator *pg_ucol_open(const char *loc_str);
|
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,
|
extern int strncoll_icu(const char *arg1, ssize_t len1,
|
||||||
const char *arg2, ssize_t len2,
|
const char *arg2, ssize_t len2,
|
||||||
pg_locale_t locale);
|
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,
|
const char *src, ssize_t srclen,
|
||||||
pg_locale_t locale);
|
pg_locale_t locale);
|
||||||
#endif
|
#endif
|
||||||
|
extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
|
||||||
|
|
||||||
/* pg_locale_libc.c */
|
/* pg_locale_libc.c */
|
||||||
extern locale_t make_libc_collator(const char *collate,
|
extern pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context);
|
||||||
const char *ctype);
|
|
||||||
extern int strncoll_libc(const char *arg1, ssize_t len1,
|
extern int strncoll_libc(const char *arg1, ssize_t len1,
|
||||||
const char *arg2, ssize_t len2,
|
const char *arg2, ssize_t len2,
|
||||||
pg_locale_t locale);
|
pg_locale_t locale);
|
||||||
@ -138,7 +139,7 @@ char *localized_full_months[12 + 1];
|
|||||||
/* is the databases's LC_CTYPE the C locale? */
|
/* is the databases's LC_CTYPE the C locale? */
|
||||||
bool database_ctype_is_c = false;
|
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 */
|
/* indicates whether locale information cache is valid */
|
||||||
static bool CurrentLocaleConvValid = false;
|
static bool CurrentLocaleConvValid = false;
|
||||||
@ -1194,7 +1195,6 @@ IsoLocaleName(const char *winlocname)
|
|||||||
|
|
||||||
#endif /* WIN32 && LC_MESSAGES */
|
#endif /* WIN32 && LC_MESSAGES */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new pg_locale_t struct for the given collation oid.
|
* 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;
|
Datum datum;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
|
|
||||||
|
|
||||||
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
|
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
|
||||||
if (!HeapTupleIsValid(tp))
|
if (!HeapTupleIsValid(tp))
|
||||||
elog(ERROR, "cache lookup failed for collation %u", collid);
|
elog(ERROR, "cache lookup failed for collation %u", collid);
|
||||||
collform = (Form_pg_collation) GETSTRUCT(tp);
|
collform = (Form_pg_collation) GETSTRUCT(tp);
|
||||||
|
|
||||||
result->provider = collform->collprovider;
|
|
||||||
result->deterministic = collform->collisdeterministic;
|
|
||||||
result->is_default = false;
|
|
||||||
|
|
||||||
if (collform->collprovider == COLLPROVIDER_BUILTIN)
|
if (collform->collprovider == COLLPROVIDER_BUILTIN)
|
||||||
{
|
result = create_pg_locale_builtin(collid, context);
|
||||||
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);
|
|
||||||
}
|
|
||||||
else if (collform->collprovider == COLLPROVIDER_ICU)
|
else if (collform->collprovider == COLLPROVIDER_ICU)
|
||||||
{
|
result = create_pg_locale_icu(collid, context);
|
||||||
#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
|
|
||||||
}
|
|
||||||
else if (collform->collprovider == COLLPROVIDER_LIBC)
|
else if (collform->collprovider == COLLPROVIDER_LIBC)
|
||||||
{
|
result = create_pg_locale_libc(collid, context);
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
/* shouldn't happen */
|
/* shouldn't happen */
|
||||||
PGLOCALE_SUPPORT_ERROR(collform->collprovider);
|
PGLOCALE_SUPPORT_ERROR(collform->collprovider);
|
||||||
|
|
||||||
|
result->is_default = false;
|
||||||
|
|
||||||
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
|
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
|
||||||
&isnull);
|
&isnull);
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
@ -1336,7 +1279,9 @@ init_database_collation(void)
|
|||||||
{
|
{
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Form_pg_database dbform;
|
Form_pg_database dbform;
|
||||||
Datum datum;
|
pg_locale_t result;
|
||||||
|
|
||||||
|
Assert(default_locale == NULL);
|
||||||
|
|
||||||
/* Fetch our pg_database row normally, via syscache */
|
/* Fetch our pg_database row normally, via syscache */
|
||||||
tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
|
tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
|
||||||
@ -1345,81 +1290,22 @@ init_database_collation(void)
|
|||||||
dbform = (Form_pg_database) GETSTRUCT(tup);
|
dbform = (Form_pg_database) GETSTRUCT(tup);
|
||||||
|
|
||||||
if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
|
if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
|
||||||
{
|
result = create_pg_locale_builtin(DEFAULT_COLLATION_OID,
|
||||||
char *datlocale;
|
TopMemoryContext);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else if (dbform->datlocprovider == COLLPROVIDER_ICU)
|
else if (dbform->datlocprovider == COLLPROVIDER_ICU)
|
||||||
{
|
result = create_pg_locale_icu(DEFAULT_COLLATION_OID,
|
||||||
#ifdef USE_ICU
|
TopMemoryContext);
|
||||||
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
|
|
||||||
}
|
|
||||||
else if (dbform->datlocprovider == COLLPROVIDER_LIBC)
|
else if (dbform->datlocprovider == COLLPROVIDER_LIBC)
|
||||||
{
|
result = create_pg_locale_libc(DEFAULT_COLLATION_OID,
|
||||||
const char *datcollate;
|
TopMemoryContext);
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
/* shouldn't happen */
|
/* shouldn't happen */
|
||||||
PGLOCALE_SUPPORT_ERROR(dbform->datlocprovider);
|
PGLOCALE_SUPPORT_ERROR(dbform->datlocprovider);
|
||||||
|
|
||||||
|
result->is_default = true;
|
||||||
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;
|
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
|
||||||
|
default_locale = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1437,7 +1323,7 @@ pg_newlocale_from_collation(Oid collid)
|
|||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
if (collid == DEFAULT_COLLATION_OID)
|
if (collid == DEFAULT_COLLATION_OID)
|
||||||
return &default_locale;
|
return default_locale;
|
||||||
|
|
||||||
if (!OidIsValid(collid))
|
if (!OidIsValid(collid))
|
||||||
elog(ERROR, "cache lookup failed for collation %u", collid);
|
elog(ERROR, "cache lookup failed for collation %u", collid);
|
||||||
|
70
src/backend/utils/adt/pg_locale_builtin.c
Normal file
70
src/backend/utils/adt/pg_locale_builtin.c
Normal file
@ -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;
|
||||||
|
}
|
@ -12,14 +12,20 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#ifdef USE_ICU
|
#ifdef USE_ICU
|
||||||
|
|
||||||
#include <unicode/ucnv.h>
|
#include <unicode/ucnv.h>
|
||||||
#include <unicode/ustring.h>
|
#include <unicode/ustring.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "access/htup_details.h"
|
||||||
|
#include "catalog/pg_database.h"
|
||||||
#include "catalog/pg_collation.h"
|
#include "catalog/pg_collation.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
#include "utils/formatting.h"
|
#include "utils/formatting.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/pg_locale.h"
|
#include "utils/pg_locale.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of stack buffer to use for string transformations, used to avoid heap
|
* Size of stack buffer to use for string transformations, used to avoid heap
|
||||||
@ -29,9 +35,11 @@
|
|||||||
*/
|
*/
|
||||||
#define TEXTBUFLEN 1024
|
#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 *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,
|
extern int strncoll_icu(const char *arg1, ssize_t len1,
|
||||||
const char *arg2, ssize_t len2,
|
const char *arg2, ssize_t len2,
|
||||||
pg_locale_t locale);
|
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 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,
|
static int strncoll_icu_no_utf8(const char *arg1, ssize_t len1,
|
||||||
const char *arg2, ssize_t len2,
|
const char *arg2, ssize_t len2,
|
||||||
pg_locale_t locale);
|
pg_locale_t locale);
|
||||||
@ -63,6 +73,85 @@ static int32_t uchar_convert(UConverter *converter,
|
|||||||
const char *src, int32_t srclen);
|
const char *src, int32_t srclen);
|
||||||
static void icu_set_collation_attributes(UCollator *collator, const char *loc,
|
static void icu_set_collation_attributes(UCollator *collator, const char *loc,
|
||||||
UErrorCode *status);
|
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
|
* 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.
|
* Ensure that no path leaks a UCollator.
|
||||||
*/
|
*/
|
||||||
UCollator *
|
static UCollator *
|
||||||
make_icu_collator(const char *iculocstr, const char *icurules)
|
make_icu_collator(const char *iculocstr, const char *icurules)
|
||||||
{
|
{
|
||||||
if (!icurules)
|
if (!icurules)
|
||||||
|
@ -11,10 +11,16 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/htup_details.h"
|
||||||
|
#include "catalog/pg_database.h"
|
||||||
#include "catalog/pg_collation.h"
|
#include "catalog/pg_collation.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
#include "utils/formatting.h"
|
#include "utils/formatting.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/pg_locale.h"
|
#include "utils/pg_locale.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of stack buffer to use for string transformations, used to avoid heap
|
* Size of stack buffer to use for string transformations, used to avoid heap
|
||||||
@ -24,15 +30,16 @@
|
|||||||
*/
|
*/
|
||||||
#define TEXTBUFLEN 1024
|
#define TEXTBUFLEN 1024
|
||||||
|
|
||||||
extern locale_t make_libc_collator(const char *collate,
|
extern pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context);
|
||||||
const char *ctype);
|
|
||||||
extern int strncoll_libc(const char *arg1, ssize_t len1,
|
extern int strncoll_libc(const char *arg1, ssize_t len1,
|
||||||
const char *arg2, ssize_t len2,
|
const char *arg2, ssize_t len2,
|
||||||
pg_locale_t locale);
|
pg_locale_t locale);
|
||||||
extern size_t strnxfrm_libc(char *dest, size_t destsize,
|
extern size_t strnxfrm_libc(char *dest, size_t destsize,
|
||||||
const char *src, ssize_t srclen,
|
const char *src, ssize_t srclen,
|
||||||
pg_locale_t locale);
|
pg_locale_t locale);
|
||||||
|
static locale_t make_libc_collator(const char *collate,
|
||||||
|
const char *ctype);
|
||||||
static void report_newlocale_failure(const char *localename);
|
static void report_newlocale_failure(const char *localename);
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -41,6 +48,65 @@ static int strncoll_libc_win32_utf8(const char *arg1, ssize_t len1,
|
|||||||
pg_locale_t locale);
|
pg_locale_t locale);
|
||||||
#endif
|
#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.
|
* 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.
|
* Ensure that no path leaks a locale_t.
|
||||||
*/
|
*/
|
||||||
locale_t
|
static locale_t
|
||||||
make_libc_collator(const char *collate, const char *ctype)
|
make_libc_collator(const char *collate, const char *ctype)
|
||||||
{
|
{
|
||||||
locale_t loc = 0;
|
locale_t loc = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user