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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy