summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeff Davis2025-01-08 21:54:07 +0000
committerJeff Davis2025-01-08 21:54:07 +0000
commit4f5cef2607c1f8804d4b54250642aaf586745b0e (patch)
treed2f80304780e9cd564539c912f5d786a01a1b29b /src
parent3c49d462dbcfaff7bb77b1fec2c73c1079d25433 (diff)
Move code for collation version into provider-specific files.
Author: Andreas Karlsson Discussion: https://postgr.es/m/4548a168-62cd-457b-8d06-9ba7b985c477%40proxel.se
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/pg_locale.c103
-rw-r--r--src/backend/utils/adt/pg_locale_builtin.c24
-rw-r--r--src/backend/utils/adt/pg_locale_icu.c17
-rw-r--r--src/backend/utils/adt/pg_locale_libc.c74
4 files changed, 123 insertions, 95 deletions
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index d65b9b3bd25..dc8248fb269 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -69,10 +69,6 @@
#include "utils/pg_locale.h"
#include "utils/syscache.h"
-#ifdef __GLIBC__
-#include <gnu/libc-version.h>
-#endif
-
#ifdef WIN32
#include <shlwapi.h>
#endif
@@ -91,6 +87,7 @@
/* pg_locale_builtin.c */
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 */
#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,
const char *src, ssize_t srclen,
pg_locale_t locale);
+extern char *get_collation_actual_version_icu(const char *collcollate);
#endif
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,
const char *src, ssize_t srclen,
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,
ssize_t srclen, pg_locale_t locale);
@@ -1391,100 +1390,14 @@ get_collation_actual_version(char collprovider, const char *collcollate)
{
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 (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)));
- }
-
+ collversion = get_collation_actual_version_builtin(collcollate);
#ifdef USE_ICU
- if (collprovider == COLLPROVIDER_ICU)
- {
- 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
+ else if (collprovider == COLLPROVIDER_ICU)
+ collversion = get_collation_actual_version_icu(collcollate);
#endif
- if (collprovider == COLLPROVIDER_LIBC &&
- 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
- }
+ else if (collprovider == COLLPROVIDER_LIBC)
+ collversion = get_collation_actual_version_libc(collcollate);
return collversion;
}
diff --git a/src/backend/utils/adt/pg_locale_builtin.c b/src/backend/utils/adt/pg_locale_builtin.c
index 53a38b1e93f..5161915e6b1 100644
--- a/src/backend/utils/adt/pg_locale_builtin.c
+++ b/src/backend/utils/adt/pg_locale_builtin.c
@@ -24,6 +24,7 @@
extern pg_locale_t create_pg_locale_builtin(Oid collid,
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,
ssize_t srclen, pg_locale_t locale);
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;
}
+
+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 */
+}
diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c
index d5b5f59fe89..6e1fb78bbf3 100644
--- a/src/backend/utils/adt/pg_locale_icu.c
+++ b/src/backend/utils/adt/pg_locale_icu.c
@@ -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,
const char *src, ssize_t srclen,
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,
const UChar *src, int32_t srcLength,
@@ -528,6 +529,22 @@ strnxfrm_prefix_icu(char *dest, size_t destsize,
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.
*
diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c
index 85dce4508ee..81120061b50 100644
--- a/src/backend/utils/adt/pg_locale_libc.c
+++ b/src/backend/utils/adt/pg_locale_libc.c
@@ -25,6 +25,14 @@
#include "utils/pg_locale.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
* 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,
const char *src, ssize_t srclen,
pg_locale_t locale);
+extern char *get_collation_actual_version_libc(const char *collcollate);
static locale_t make_libc_collator(const char *collate,
const char *ctype);
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;
}
+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
*