#include "utils/pg_locale.h"
#include "utils/syscache.h"
-#ifdef __GLIBC__
-#include <gnu/libc-version.h>
-#endif
-
#ifdef WIN32
#include <shlwapi.h>
#endif
/* 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
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);
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);
{
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;
}
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,
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 */
+}
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,
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.
*
#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
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);
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
*