8000 Move code for collation version into provider-specific files. · postgres/postgres@4f5cef2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4f5cef2

Browse files
committed
Move code for collation version into provider-specific files.
Author: Andreas Karlsson Discussion: https://postgr.es/m/4548a168-62cd-457b-8d06-9ba7b985c477%40proxel.se
1 parent 3c49d46 commit 4f5cef2

File tree

4 files changed

+123
-95
lines changed

4 files changed

+123
-95
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 8 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@
6969
#include "utils/pg_locale.h"
7070
#include "utils/syscache.h"
7171

72-
#ifdef __GLIBC__
73-
#include <gnu/libc-version.h>
74-
#endif
75-
7672
#ifdef WIN32
7773
#include <shlwapi.h>
7874
#endif
@@ -91,6 +87,7 @@
9187

9288
/* pg_locale_builtin.c */
9389
extern pg_locale_t create_pg_locale_builtin(Oid collid, MemoryContext context);
90+
extern char *get_collation_actual_version_builtin(const char *collcollate);
9491

9592
/* pg_locale_icu.c */
9693
#ifdef USE_ICU
@@ -104,6 +101,7 @@ extern size_t strnxfrm_icu(char *dest, size_t destsize,
104101
extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
105102
const char *src, ssize_t srclen,
106103
pg_locale_t locale);
104+
extern char *get_collation_actual_version_icu(const char *collcollate);
107105
#endif
108106
extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
109107

@@ -115,6 +113,7 @@ extern int strncoll_libc(const char *arg1, ssize_t len1,
115113
extern size_t strnxfrm_libc(char *dest, size_t destsize,
116114
const char *src, ssize_t srclen,
117115
pg_locale_t locale);
116+
extern char *get_collation_actual_version_libc(const char *collcollate);
118117

119118
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
120119
ssize_t srclen, pg_locale_t locale);
@@ -1391,100 +1390,14 @@ get_collation_actual_version(char collprovider, const char *collcollate)
13911390
{
13921391
char *collversion = NULL;
13931392

1394-
/*
1395-
* The only two supported locales (C and C.UTF-8) are both based on memcmp
1396-
* and are not expected to change, but track the version anyway.
1397-
*
1398-
* Note that the character semantics may change for some locales, but the
1399-
* collation version only tracks changes to sort order.
1400-
*/
14011393
if (collprovider == COLLPROVIDER_BUILTIN)
1402-
{
1403-
if (strcmp(collcollate, "C") == 0)
1404-
return "1";
1405-
else if (strcmp(collcollate, "C.UTF-8") == 0)
1406-
return "1";
1407-
else
1408-
ereport(ERROR,
1409-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1410-
errmsg("invalid locale name \"%s\" for builtin provider",
1411-
collcollate)));
1412-
}
1413-
1394+
collversion = get_collation_actual_version_builtin(collcollate);
14141395
#ifdef USE_ICU
1415-
if (collprovider == COLLPROVIDER_ICU)
1416-
{
1417-
UCollator *collator;
1418-
UVersionInfo versioninfo;
1419-
char buf[U_MAX_VERSION_STRING_LENGTH];
1420-
1421-
collator = pg_ucol_open(collcollate);
1422-
1423-
ucol_getVersion(collator, versioninfo);
1424-
ucol_close(collator);
1425-
1426-
u_versionToString(versioninfo, buf);
1427-
collversion = pstrdup(buf);
1428-
}
1429-
else
1396+
else if (collprovider == COLLPROVIDER_ICU)
1397+
collversion = get_collation_actual_version_icu(collcollate);
14301398
#endif
1431-
if (collprovider == COLLPROVIDER_LIBC &&
1432-
pg_strcasecmp("C", collcollate) != 0 &&
1433-
pg_strncasecmp("C.", collcollate, 2) != 0 &&
1434-
pg_strcasecmp("POSIX", collcollate) != 0)
1435-
{
1436-
#if defined(__GLIBC__)
1437-
/* Use the glibc version because we don't have anything better. */
1438-
collversion = pstrdup(gnu_get_libc_version());
1439-
#elif defined(LC_VERSION_MASK)
1440-
locale_t loc;
1441-
1442-
/* Look up FreeBSD collation version. */
1443-
loc = newlocale(LC_COLLATE_MASK, collcollate, NULL);
1444-
if (loc)
1445-
{
1446-
collversion =
1447-
pstrdup(querylocale(LC_COLLATE_MASK | LC_VERSION_MASK, loc));
1448-
freelocale(loc);
1449-
}
1450-
else
1451-
ereport(ERROR,
1452-
(errmsg("could not load locale \"%s\"", collcollate)));
1453-
#elif defined(WIN32)
1454-
/*
1455-
* If we are targeting Windows Vista and above, we can ask for a name
1456-
* given a collation name (earlier versions required a location code
1457-
* that we don't have).
1458-
*/
1459-
NLSVERSIONINFOEX version = {sizeof(NLSVERSIONINFOEX)};
1460-
WCHAR wide_collcollate[LOCALE_NAME_MAX_LENGTH];
1461-
1462-
MultiByteToWideChar(CP_ACP, 0, collcollate, -1, wide_collcollate,
1463-
LOCALE_NAME_MAX_LENGTH);
1464-
if (!GetNLSVersionEx(COMPARE_STRING, wide_collcollate, &version))
1465-
{
1466-
/*
1467-
* GetNLSVersionEx() wants a language tag such as "en-US", not a
1468-
* locale name like "English_United States.1252". Until those
1469-
* values can be prevented from entering the system, or 100%
1470-
* reliably converted to the more useful tag format, tolerate the
1471-
* resulting error and report that we have no version data.
1472-
*/
1473-
if (GetLastError() == ERROR_INVALID_PARAMETER)
1474-
return NULL;
1475-
1476-
ereport(ERROR,
1477-
(errmsg("could not get collation version for locale \"%s\": error code %lu",
1478-
collcollate,
1479-
GetLastError())));
1480-
}
1481-
collversion = psprintf("%lu.%lu,%lu.%lu",
1482-
(version.dwNLSVersion >> 8) & 0xFFFF,
1483-
version.dwNLSVersion & 0xFF,
1484-
(version.dwDefinedVersion >> 8) & 0xFFFF,
1485-
version.dwDefinedVersion & 0xFF);
1486-
#endif
1487-
}
1399+
else if (collprovider == COLLPROVIDER_LIBC)
1400+
collversion = get_collation_actual_version_libc(collcollate);
14881401

14891402
return collversion;
14901403
}

src/backend/utils/adt/pg_locale_builtin.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
extern pg_locale_t create_pg_locale_builtin(Oid collid,
2626
MemoryContext context);
27+
extern char *get_collation_actual_version_builtin(const char *collcollate);
2728
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
2829
ssize_t srclen, pg_locale_t locale);
2930
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)
148149

149150
return result;
150151
}
152+
153+
char *
154+
get_collation_actual_version_builtin(const char *collcollate)
155+
{
156+
/*
157+
* The only two supported locales (C and C.UTF-8) are both based on memcmp
158+
* and are not expected to change, but track the version anyway.
159+
*
160+
* Note that the character semantics may change for some locales, but the
161+
* collation version only tracks changes to sort order.
162+
*/
163+
if (strcmp(collcollate, "C") == 0)
164+
return "1";
165+
else if (strcmp(collcollate, "C.UTF-8") == 0)
166+
return "1";
167+
else
168+
ereport(ERROR,
169+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
170+
errmsg("invalid locale name \"%s\" for builtin provider",
171+
collcollate)));
172+
173+
return NULL; /* keep compiler quiet */
174+
}

src/backend/utils/adt/pg_locale_icu.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ extern size_t strnxfrm_icu(char *dest, size_t destsize,
6767
extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
6868
const char *src, ssize_t srclen,
6969
pg_locale_t locale);
70+
extern char *get_collation_actual_version_icu(const char *collcollate);
7071

7172
typedef int32_t (*ICU_Convert_Func) (UChar *dest, int32_t destCapacity,
7273
const UChar *src, int32_t srcLength,
@@ -528,6 +529,22 @@ strnxfrm_prefix_icu(char *dest, size_t destsize,
528529
return result;
529530
}
530531

532+
char *
533+
get_collation_actual_version_icu(const char *collcollate)
534+
{
535+
UCollator *collator;
536+
UVersionInfo versioninfo;
537+
char buf[U_MAX_VERSION_STRING_LENGTH];
538+
539+
collator = pg_ucol_open(collcollate);
540+
541+
ucol_getVersion(collator, versioninfo);
542+
ucol_close(collator);
543+
544+
u_versionToString(versioninfo, buf);
545+
return pstrdup(buf);
546+
}
547+
531548
/*
532549
* Convert a string in the database encoding into a string of UChars.
533550
*

src/backend/utils/adt/pg_locale_libc.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
#include "utils/pg_locale.h"
2626
#include "utils/syscache.h"
2727

28+
#ifdef __GLIBC__
29+
#include <gnu/libc-version.h>
30+
#endif
31+
32+
#ifdef WIN32
33+
#include <shlwapi.h>
34+
#endif
35+
2836
/*
2937
* Size of stack buffer to use for string transformations, used to avoid heap
3038
* 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,
4856
extern size_t strnxfrm_libc(char *dest, size_t destsize,
4957
const char *src, ssize_t srclen,
5058
pg_locale_t locale);
59+
extern char *get_collation_actual_version_libc(const char *collcollate);
5160
static locale_t make_libc_collator(const char *collate,
5261
const char *ctype);
5362
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,
610619
return result;
611620
}
612621

622+
char *
623+
get_collation_actual_version_libc(const char *collcollate)
624+
{
625+
char *collversion = NULL;
626+
627+
if (pg_strcasecmp("C", collcollate) != 0 &&
628+
pg_strncasecmp("C.", collcollate, 2) != 0 &&
629+
pg_strcasecmp("POSIX", collcollate) != 0)
630+
{
631+
#if defined(__GLIBC__)
632+
/* Use the glibc version because we don't have anything better. */
633+
collversion = pstrdup(gnu_get_libc_version());
634+
#elif defined(LC_VERSION_MASK)
635+
locale_t loc;
636+
637+
/* Look up FreeBSD collation version. */
638+
loc = newlocale(LC_COLLATE_MASK, collcollate, NULL);
639+
if (loc)
640+
{
641+
collversion =
642+
pstrdup(querylocale(LC_COLLATE_MASK | LC_VERSION_MASK, loc));
643+
freelocale(loc);
644+
}
645+
else
646+
ereport(ERROR,
647+
(errmsg("could not load locale \"%s\"", collcollate)));
648+
#elif defined(WIN32)
649+
/*
650+
* If we are targeting Windows Vista and above, we can ask for a name
651+
* given a collation name (earlier versions required a location code
652+
* that we don't have).
653+
*/
654+
NLSVERSIONINFOEX version = {sizeof(NLSVERSIONINFOEX)};
655+
WCHAR wide_collcollate[LOCALE_NAME_MAX_LENGTH];
656+
657+
MultiByteToWideChar(CP_ACP, 0, collcollate, -1, wide_collcollate,
658+
LOCALE_NAME_MAX_LENGTH);
659+
if (!GetNLSVersionEx(COMPARE_STRING, wide_collcollate, &version))
660+
{
661+
/*
662+
* GetNLSVersionEx() wants a language tag such as "en-US", not a
663+
* locale name like "English_United States.1252". Until those
664+
* values can be prevented from entering the system, or 100%
665+
* reliably converted to the more useful tag format, tolerate the
666+
* resulting error and report that we have no version data.
667+
*/
668+
if (GetLastError() == ERROR_INVALID_PARAMETER)
669+
return NULL;
670+
671+
ereport(ERROR,
672+
(errmsg("could not get collation version for locale \"%s\": error code %lu",
673+
collcollate,
674+
GetLastError())));
675+
}
676+
collversion = psprintf("%lu.%lu,%lu.%lu",
677+
(version.dwNLSVersion >> 8) & 0xFFFF,
678+
version.dwNLSVersion & 0xFF,
679+
(version.dwDefinedVersion >> 8) & 0xFFFF,
680+
version.dwDefinedVersion & 0xFF);
681+
#endif
682+
}
683+
684+
return collversion;
685+
}
686+
613687
/*
614688
* strncoll_libc_win32_utf8
615689
*

0 commit comments

Comments
 (0)
0