v6-0001-WIN32-pg_import_system_collations.patch
application/octet-stream
Filename: v6-0001-WIN32-pg_import_system_collations.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v6-0001
Subject: WIN32 pg_import_system_collations
| File | + | − |
|---|---|---|
| src/backend/commands/collationcmds.c | 154 | 50 |
From 7fb63f46bf762b699ceb291c8f1f68a3bee17c18 Mon Sep 17 00:00:00 2001
From: Juan Jose Santamaria Flecha <juanjo.santamaria@gmail.com>
Date: Tue, 12 Jul 2022 09:23:06 -0400
Subject: [PATCH] WIN32 pg_import_system_collations
---
src/backend/commands/collationcmds.c | 204 ++++++++++++++++++++++++++---------
1 file changed, 154 insertions(+), 50 deletions(-)
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index fcfc02d..240fa50 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -575,6 +575,135 @@ get_icu_locale_comment(const char *localename)
#endif /* USE_ICU */
+/* will we use EnumSystemLocalesEx in pg_import_system_collations? */
+#ifdef WIN32
+#define ENUM_SYSTEM_LOCALE
+#endif
+
+
+#if defined(READ_LOCALE_A_OUTPUT) || defined(ENUM_SYSTEM_LOCALE)
+/*
+ * Create a collation if the input locale is valid for so.
+ * Also keeps track of the number of valid locales and collations created.
+ */
+static int
+CollationFromLocale(char *isolocale, char *localebuf, int *nvalid,
+ int *ncreated, int nspid)
+{
+ int enc;
+ Oid collid;
+
+ /*
+ * Some systems have locale names that don't consist entirely of
+ * ASCII letters (such as "bokmål" or "français").
+ * This is pretty silly, since we need the locale itself to
+ * interpret the non-ASCII characters. We can't do much with
+ * those, so we filter them out.
+ */
+ if (!pg_is_ascii(localebuf))
+ {
+ elog(DEBUG1, "skipping locale with non-ASCII name: \"%s\"", localebuf);
+ return -1;
+ }
+
+ enc = pg_get_encoding_from_locale(localebuf, false);
+ if (enc < 0)
+ {
+ elog(DEBUG1, "skipping locale with unrecognized encoding: \"%s\"",
+ localebuf);
+ return -1;
+ }
+ if (!PG_VALID_BE_ENCODING(enc))
+ {
+ elog(DEBUG1, "skipping locale with client-only encoding: \"%s\"", localebuf);
+ return -1;
+ }
+ if (enc == PG_SQL_ASCII)
+ return -1; /* C/POSIX are already in the catalog */
+
+ /* count valid locales found in operating system */
+ *nvalid += 1;
+
+ /*
+ * Create a collation named the same as the locale, but quietly
+ * doing nothing if it already exists. This is the behavior we
+ * need even at initdb time, because some versions of "locale -a"
+ * can report the same locale name more than once. And it's
+ * convenient for later import runs, too, since you just about
+ * always want to add on new locales without a lot of chatter
+ * about existing ones.
+ */
+ collid = CollationCreate(isolocale, nspid, GetUserId(),
+ COLLPROVIDER_LIBC, true, enc,
+ localebuf, localebuf, NULL,
+ get_collation_actual_version(COLLPROVIDER_LIBC, localebuf),
+ true, true);
+ if (OidIsValid(collid))
+ {
+ *ncreated += 1;
+
+ /* Must do CCI between inserts to handle duplicates correctly */
+ CommandCounterIncrement();
+ }
+
+ return enc;
+}
+#endif /* defined(READ_LOCALE_A_OUTPUT) || defined(ENUM_SYSTEM_LOCALE) */
+
+
+#ifdef ENUM_SYSTEM_LOCALE
+/* Parameter to be passed to the callback function win32_read_locale() */
+typedef struct
+{
+ int *ncreated;
+ int *nvalid;
+ Oid nspid;
+} CollParam;
+
+/*
+ * Callback function for EnumSystemLocalesEx() in pg_import_system_collations()
+ * Creates a collation for every valid locale.
+ */
+static BOOL CALLBACK
+win32_read_locale(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
+{
+ CollParam *param = (CollParam *) lparam;
+ char localebuf[NAMEDATALEN];
+ char isolocale[NAMEDATALEN];
+ int result;
+ char *hyphen;
+
+ (void) dwFlags;
+
+ result = WideCharToMultiByte(CP_ACP, 0, pStr, -1, localebuf, NAMEDATALEN,
+ NULL, NULL);
+
+ if (result == 0)
+ {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ elog(DEBUG1, "skipping locale with too-long name: \"%s\"", localebuf);
+ return (TRUE);
+ }
+ if (localebuf[0] == '\0')
+ return (TRUE);
+
+ /*
+ * Windows will use hyphens between language and territory, where POSIX
+ * uses an underscore. Simply make it POSIX looking.
+ */
+ strcpy(isolocale, localebuf);
+ hyphen = strchr(isolocale, '-');
+ if (hyphen)
+ *hyphen = '_';
+
+ CollationFromLocale(isolocale, localebuf, param->nvalid, param->ncreated,
+ param->nspid);
+
+ return (TRUE);
+}
+#endif /* ENUM_SYSTEM_LOCALE */
+
+
/*
* pg_import_system_collations: add known system collations to pg_collation
*/
@@ -633,58 +762,9 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
}
localebuf[len - 1] = '\0';
- /*
- * Some systems have locale names that don't consist entirely of
- * ASCII letters (such as "bokmål" or "français").
- * This is pretty silly, since we need the locale itself to
- * interpret the non-ASCII characters. We can't do much with
- * those, so we filter them out.
- */
- if (!pg_is_ascii(localebuf))
- {
- elog(DEBUG1, "skipping locale with non-ASCII name: \"%s\"", localebuf);
- continue;
- }
-
- enc = pg_get_encoding_from_locale(localebuf, false);
+ enc = CollationFromLocale(localebuf, localebuf, &nvalid, &ncreated, nspid);
if (enc < 0)
- {
- elog(DEBUG1, "skipping locale with unrecognized encoding: \"%s\"",
- localebuf);
- continue;
- }
- if (!PG_VALID_BE_ENCODING(enc))
- {
- elog(DEBUG1, "skipping locale with client-only encoding: \"%s\"", localebuf);
continue;
- }
- if (enc == PG_SQL_ASCII)
- continue; /* C/POSIX are already in the catalog */
-
- /* count valid locales found in operating system */
- nvalid++;
-
- /*
- * Create a collation named the same as the locale, but quietly
- * doing nothing if it already exists. This is the behavior we
- * need even at initdb time, because some versions of "locale -a"
- * can report the same locale name more than once. And it's
- * convenient for later import runs, too, since you just about
- * always want to add on new locales without a lot of chatter
- * about existing ones.
- */
- collid = CollationCreate(localebuf, nspid, GetUserId(),
- COLLPROVIDER_LIBC, true, enc,
- localebuf, localebuf, NULL,
- get_collation_actual_version(COLLPROVIDER_LIBC, localebuf),
- true, true);
- if (OidIsValid(collid))
- {
- ncreated++;
-
- /* Must do CCI between inserts to handle duplicates correctly */
- CommandCounterIncrement();
- }
/*
* Generate aliases such as "en_US" in addition to "en_US.utf8"
@@ -816,5 +896,29 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
}
#endif /* USE_ICU */
+ /* Load collations known to WIN32 */
+#ifdef ENUM_SYSTEM_LOCALE
+ {
+ int nvalid = 0;
+ CollParam param;
+ param.ncreated = &ncreated;
+ param.nvalid = &nvalid;
+ param.nspid = nspid;
+
+ /*
+ * Enumerate the locales that are either installed on or supported
+ * by the OS.
+ */
+ if (!EnumSystemLocalesEx(win32_read_locale, LOCALE_ALL,
+ (LPARAM) ¶m, NULL))
+ _dosmaperr(GetLastError());
+
+ /* Give a warning if EnumSystemLocalesEx seems to be malfunctioning */
+ if (nvalid == 0)
+ ereport(WARNING,
+ (errmsg("no usable system locales were found")));
+ }
+#endif /* ENUM_SYSTEM_LOCALE */
+
PG_RETURN_INT32(ncreated);
}
--
2.11.0