mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Move code for collation version into provider-specific files.
Author: Andreas Karlsson Discussion: https://postgr.es/m/4548a168-62cd-457b-8d06-9ba7b985c477%40proxel.se
This commit is contained in:
@@ -69,10 +69,6 @@
|
|||||||
#include "utils/pg_locale.h"
|
#include "utils/pg_locale.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
#ifdef __GLIBC__
|
|
||||||
#include <gnu/libc-version.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -91,6 +87,7 @@
|
|||||||
|
|
||||||
/* pg_locale_builtin.c */
|
/* pg_locale_builtin.c */
|
||||||
extern pg_locale_t create_pg_locale_builtin(Oid collid, MemoryContext context);
|
extern pg_locale_t create_pg_locale_builtin(Oid collid, MemoryContext context);
|
||||||
|
extern char *get_collation_actual_version_builtin(const char *collcollate);
|
||||||
|
|
||||||
/* pg_locale_icu.c */
|
/* pg_locale_icu.c */
|
||||||
#ifdef USE_ICU
|
#ifdef USE_ICU
|
||||||
@@ -104,6 +101,7 @@ extern size_t strnxfrm_icu(char *dest, size_t destsize,
|
|||||||
extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
|
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);
|
||||||
|
extern char *get_collation_actual_version_icu(const char *collcollate);
|
||||||
#endif
|
#endif
|
||||||
extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
|
extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
|
||||||
|
|
||||||
@@ -115,6 +113,7 @@ extern int strncoll_libc(const char *arg1, ssize_t len1,
|
|||||||
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);
|
||||||
|
extern char *get_collation_actual_version_libc(const char *collcollate);
|
||||||
|
|
||||||
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
|
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
|
||||||
ssize_t srclen, pg_locale_t locale);
|
ssize_t srclen, pg_locale_t locale);
|
||||||
@@ -1391,100 +1390,14 @@ get_collation_actual_version(char collprovider, const char *collcollate)
|
|||||||
{
|
{
|
||||||
char *collversion = NULL;
|
char *collversion = NULL;
|
||||||
|
|
||||||
/*
|
|
||||||
* The only two supported locales (C and C.UTF-8) are both based on memcmp
|
|
||||||
* and are not expected to change, but track the version anyway.
|
|
||||||
*
|
|
||||||
* Note that the character semantics may change for some locales, but the
|
|
||||||
* collation version only tracks changes to sort order.
|
|
||||||
*/
|
|
||||||
if (collprovider == COLLPROVIDER_BUILTIN)
|
if (collprovider == COLLPROVIDER_BUILTIN)
|
||||||
{
|
collversion = get_collation_actual_version_builtin(collcollate);
|
||||||
if (strcmp(collcollate, "C") == 0)
|
|
||||||
return "1";
|
|
||||||
else if (strcmp(collcollate, "C.UTF-8") == 0)
|
|
||||||
return "1";
|
|
||||||
else
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
||||||
errmsg("invalid locale name \"%s\" for builtin provider",
|
|
||||||
collcollate)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_ICU
|
#ifdef USE_ICU
|
||||||
if (collprovider == COLLPROVIDER_ICU)
|
else if (collprovider == COLLPROVIDER_ICU)
|
||||||
{
|
collversion = get_collation_actual_version_icu(collcollate);
|
||||||
UCollator *collator;
|
|
||||||
UVersionInfo versioninfo;
|
|
||||||
char buf[U_MAX_VERSION_STRING_LENGTH];
|
|
||||||
|
|
||||||
collator = pg_ucol_open(collcollate);
|
|
||||||
|
|
||||||
ucol_getVersion(collator, versioninfo);
|
|
||||||
ucol_close(collator);
|
|
||||||
|
|
||||||
u_versionToString(versioninfo, buf);
|
|
||||||
collversion = pstrdup(buf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
if (collprovider == COLLPROVIDER_LIBC &&
|
else if (collprovider == COLLPROVIDER_LIBC)
|
||||||
pg_strcasecmp("C", collcollate) != 0 &&
|
collversion = get_collation_actual_version_libc(collcollate);
|
||||||
pg_strncasecmp("C.", collcollate, 2) != 0 &&
|
|
||||||
pg_strcasecmp("POSIX", collcollate) != 0)
|
|
||||||
{
|
|
||||||
#if defined(__GLIBC__)
|
|
||||||
/* Use the glibc version because we don't have anything better. */
|
|
||||||
collversion = pstrdup(gnu_get_libc_version());
|
|
||||||
#elif defined(LC_VERSION_MASK)
|
|
||||||
locale_t loc;
|
|
||||||
|
|
||||||
/* Look up FreeBSD collation version. */
|
|
||||||
loc = newlocale(LC_COLLATE_MASK, collcollate, NULL);
|
|
||||||
if (loc)
|
|
||||||
{
|
|
||||||
collversion =
|
|
||||||
pstrdup(querylocale(LC_COLLATE_MASK | LC_VERSION_MASK, loc));
|
|
||||||
freelocale(loc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ereport(ERROR,
|
|
||||||
(errmsg("could not load locale \"%s\"", collcollate)));
|
|
||||||
#elif defined(WIN32)
|
|
||||||
/*
|
|
||||||
* If we are targeting Windows Vista and above, we can ask for a name
|
|
||||||
* given a collation name (earlier versions required a location code
|
|
||||||
* that we don't have).
|
|
||||||
*/
|
|
||||||
NLSVERSIONINFOEX version = {sizeof(NLSVERSIONINFOEX)};
|
|
||||||
WCHAR wide_collcollate[LOCALE_NAME_MAX_LENGTH];
|
|
||||||
|
|
||||||
MultiByteToWideChar(CP_ACP, 0, collcollate, -1, wide_collcollate,
|
|
||||||
LOCALE_NAME_MAX_LENGTH);
|
|
||||||
if (!GetNLSVersionEx(COMPARE_STRING, wide_collcollate, &version))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* GetNLSVersionEx() wants a language tag such as "en-US", not a
|
|
||||||
* locale name like "English_United States.1252". Until those
|
|
||||||
* values can be prevented from entering the system, or 100%
|
|
||||||
* reliably converted to the more useful tag format, tolerate the
|
|
||||||
* resulting error and report that we have no version data.
|
|
||||||
*/
|
|
||||||
if (GetLastError() == ERROR_INVALID_PARAMETER)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ereport(ERROR,
|
|
||||||
(errmsg("could not get collation version for locale \"%s\": error code %lu",
|
|
||||||
collcollate,
|
|
||||||
GetLastError())));
|
|
||||||
}
|
|
||||||
collversion = psprintf("%lu.%lu,%lu.%lu",
|
|
||||||
(version.dwNLSVersion >> 8) & 0xFFFF,
|
|
||||||
version.dwNLSVersion & 0xFF,
|
|
||||||
(version.dwDefinedVersion >> 8) & 0xFFFF,
|
|
||||||
version.dwDefinedVersion & 0xFF);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return collversion;
|
return collversion;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
extern pg_locale_t create_pg_locale_builtin(Oid collid,
|
extern pg_locale_t create_pg_locale_builtin(Oid collid,
|
||||||
MemoryContext context);
|
MemoryContext context);
|
||||||
|
extern char *get_collation_actual_version_builtin(const char *collcollate);
|
||||||
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
|
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
|
||||||
ssize_t srclen, pg_locale_t locale);
|
ssize_t srclen, pg_locale_t locale);
|
||||||
extern size_t strtitle_builtin(char *dst, size_t dstsize, const char *src,
|
extern size_t strtitle_builtin(char *dst, size_t dstsize, const char *src,
|
||||||
@@ -148,3 +149,26 @@ create_pg_locale_builtin(Oid collid, MemoryContext context)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_collation_actual_version_builtin(const char *collcollate)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The only two supported locales (C and C.UTF-8) are both based on memcmp
|
||||||
|
* and are not expected to change, but track the version anyway.
|
||||||
|
*
|
||||||
|
* Note that the character semantics may change for some locales, but the
|
||||||
|
* collation version only tracks changes to sort order.
|
||||||
|
*/
|
||||||
|
if (strcmp(collcollate, "C") == 0)
|
||||||
|
return "1";
|
||||||
|
else if (strcmp(collcollate, "C.UTF-8") == 0)
|
||||||
|
return "1";
|
||||||
|
else
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
|
errmsg("invalid locale name \"%s\" for builtin provider",
|
||||||
|
collcollate)));
|
||||||
|
|
||||||
|
return NULL; /* keep compiler quiet */
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ extern size_t strnxfrm_icu(char *dest, size_t destsize,
|
|||||||
extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
|
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);
|
||||||
|
extern char *get_collation_actual_version_icu(const char *collcollate);
|
||||||
|
|
||||||
typedef int32_t (*ICU_Convert_Func) (UChar *dest, int32_t destCapacity,
|
typedef int32_t (*ICU_Convert_Func) (UChar *dest, int32_t destCapacity,
|
||||||
const UChar *src, int32_t srcLength,
|
const UChar *src, int32_t srcLength,
|
||||||
@@ -528,6 +529,22 @@ strnxfrm_prefix_icu(char *dest, size_t destsize,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_collation_actual_version_icu(const char *collcollate)
|
||||||
|
{
|
||||||
|
UCollator *collator;
|
||||||
|
UVersionInfo versioninfo;
|
||||||
|
char buf[U_MAX_VERSION_STRING_LENGTH];
|
||||||
|
|
||||||
|
collator = pg_ucol_open(collcollate);
|
||||||
|
|
||||||
|
ucol_getVersion(collator, versioninfo);
|
||||||
|
ucol_close(collator);
|
||||||
|
|
||||||
|
u_versionToString(versioninfo, buf);
|
||||||
|
return pstrdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a string in the database encoding into a string of UChars.
|
* Convert a string in the database encoding into a string of UChars.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,6 +25,14 @@
|
|||||||
#include "utils/pg_locale.h"
|
#include "utils/pg_locale.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
#include <gnu/libc-version.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
* allocations in typical cases. This should be large enough that most strings
|
* allocations in typical cases. This should be large enough that most strings
|
||||||
@@ -48,6 +56,7 @@ extern int strncoll_libc(const char *arg1, ssize_t len1,
|
|||||||
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);
|
||||||
|
extern char *get_collation_actual_version_libc(const char *collcollate);
|
||||||
static locale_t make_libc_collator(const char *collate,
|
static locale_t make_libc_collator(const char *collate,
|
||||||
const char *ctype);
|
const char *ctype);
|
||||||
static void report_newlocale_failure(const char *localename);
|
static void report_newlocale_failure(const char *localename);
|
||||||
@@ -610,6 +619,71 @@ strnxfrm_libc(char *dest, size_t destsize, const char *src, ssize_t srclen,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_collation_actual_version_libc(const char *collcollate)
|
||||||
|
{
|
||||||
|
char *collversion = NULL;
|
||||||
|
|
||||||
|
if (pg_strcasecmp("C", collcollate) != 0 &&
|
||||||
|
pg_strncasecmp("C.", collcollate, 2) != 0 &&
|
||||||
|
pg_strcasecmp("POSIX", collcollate) != 0)
|
||||||
|
{
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
/* Use the glibc version because we don't have anything better. */
|
||||||
|
collversion = pstrdup(gnu_get_libc_version());
|
||||||
|
#elif defined(LC_VERSION_MASK)
|
||||||
|
locale_t loc;
|
||||||
|
|
||||||
|
/* Look up FreeBSD collation version. */
|
||||||
|
loc = newlocale(LC_COLLATE_MASK, collcollate, NULL);
|
||||||
|
if (loc)
|
||||||
|
{
|
||||||
|
collversion =
|
||||||
|
pstrdup(querylocale(LC_COLLATE_MASK | LC_VERSION_MASK, loc));
|
||||||
|
freelocale(loc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("could not load locale \"%s\"", collcollate)));
|
||||||
|
#elif defined(WIN32)
|
||||||
|
/*
|
||||||
|
* If we are targeting Windows Vista and above, we can ask for a name
|
||||||
|
* given a collation name (earlier versions required a location code
|
||||||
|
* that we don't have).
|
||||||
|
*/
|
||||||
|
NLSVERSIONINFOEX version = {sizeof(NLSVERSIONINFOEX)};
|
||||||
|
WCHAR wide_collcollate[LOCALE_NAME_MAX_LENGTH];
|
||||||
|
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, collcollate, -1, wide_collcollate,
|
||||||
|
LOCALE_NAME_MAX_LENGTH);
|
||||||
|
if (!GetNLSVersionEx(COMPARE_STRING, wide_collcollate, &version))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* GetNLSVersionEx() wants a language tag such as "en-US", not a
|
||||||
|
* locale name like "English_United States.1252". Until those
|
||||||
|
* values can be prevented from entering the system, or 100%
|
||||||
|
* reliably converted to the more useful tag format, tolerate the
|
||||||
|
* resulting error and report that we have no version data.
|
||||||
|
*/
|
||||||
|
if (GetLastError() == ERROR_INVALID_PARAMETER)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("could not get collation version for locale \"%s\": error code %lu",
|
||||||
|
collcollate,
|
||||||
|
GetLastError())));
|
||||||
|
}
|
||||||
|
collversion = psprintf("%lu.%lu,%lu.%lu",
|
||||||
|
(version.dwNLSVersion >> 8) & 0xFFFF,
|
||||||
|
version.dwNLSVersion & 0xFF,
|
||||||
|
(version.dwDefinedVersion >> 8) & 0xFFFF,
|
||||||
|
version.dwDefinedVersion & 0xFF);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return collversion;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* strncoll_libc_win32_utf8
|
* strncoll_libc_win32_utf8
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user