v2-0005-Add-get_icu_library_hook.patch
text/x-patch
Filename: v2-0005-Add-get_icu_library_hook.patch
Type: text/x-patch
Part: 4
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0005
Subject: Add get_icu_library_hook.
| File | + | − |
|---|---|---|
| src/backend/commands/collationcmds.c | 3 | 3 |
| src/backend/utils/adt/pg_locale.c | 49 | 7 |
| src/include/utils/pg_locale_internal.h | 9 | 1 |
From 7dca88aa9f51e7674151bb90506b5305f9107bac Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Mon, 5 Dec 2022 16:14:18 -0800
Subject: [PATCH v2 5/6] Add get_icu_library_hook.
Controls how ICU library symbols are loaded.
---
src/backend/commands/collationcmds.c | 6 +--
src/backend/utils/adt/pg_locale.c | 56 ++++++++++++++++++++++----
src/include/utils/pg_locale_internal.h | 10 ++++-
3 files changed, 61 insertions(+), 11 deletions(-)
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 16b1bcbdc0..f439e832da 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -560,7 +560,7 @@ get_icu_language_tag(const char *localename)
{
char buf[ULOC_FULLNAME_CAPACITY];
UErrorCode status;
- pg_icu_library *iculib = get_builtin_icu_library();
+ pg_icu_library *iculib = get_icu_library(NULL, NULL, NULL);
status = U_ZERO_ERROR;
iculib->toLanguageTag(localename, buf, sizeof(buf), true, &status);
@@ -586,7 +586,7 @@ get_icu_locale_comment(const char *localename)
int32 len_uchar;
int32 i;
char *result;
- pg_icu_library *iculib = get_builtin_icu_library();
+ pg_icu_library *iculib = get_icu_library(NULL, NULL, NULL);
status = U_ZERO_ERROR;
len_uchar = iculib->getDisplayName(localename, "en",
@@ -811,7 +811,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
#ifdef USE_ICU
{
int i;
- pg_icu_library *iculib = get_builtin_icu_library();
+ pg_icu_library *iculib = get_icu_library(NULL, NULL, NULL);
/*
* Start the loop at -1 to sneak in the root locale without too much
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 4daff8b7b5..b75a825df6 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -109,6 +109,34 @@ char *localized_full_days[7 + 1];
char *localized_abbrev_months[12 + 1];
char *localized_full_months[12 + 1];
+/*
+ * get_icu_library_hook can be set to control how the pg_icu_library is
+ * constructed inside a pg_locale_t structure, and therefore which specific
+ * ICU symbols are called.
+ *
+ * Without the hook, Postgres constructs the pg_icu_library from the version
+ * of ICU that Postgres is linked against at build time.
+ *
+ * The hook can instead load the ICU symbols from a different version of the
+ * ICU library on the system, which can avoid problems when the collation
+ * subtly changes across different versions of ICU.
+ *
+ * If the hook returns true, it indicates that it has successfully filled in
+ * the pg_icu_library structure that was passed in. If it returns false,
+ * Postgres will fill in the structure itself. The version of the collation
+ * returned does not need to match exactly the version that was passed in;
+ * though if not, Postgres will issue a WARNING.
+ *
+ * XXX: For now, the only information the hook has access to is the ICU
+ * collation name, ICU ctype, and the ICU version string that was obtained at
+ * the time the collation was created (or when it was last refreshed). We
+ * should consider what other information can be provided to allow for greater
+ * control which library is loaded.
+ */
+#ifdef USE_ICU
+get_icu_library_hook_type get_icu_library_hook = NULL;
+#endif
+
/* indicates whether locale information cache is valid */
static bool CurrentLocaleConvValid = false;
static bool CurrentLCTimeValid = false;
@@ -1463,18 +1491,15 @@ report_newlocale_failure(const char *localename)
#endif /* HAVE_LOCALE_T */
#ifdef USE_ICU
-pg_icu_library *
-get_builtin_icu_library()
+static bool
+get_builtin_icu_library(pg_icu_library *lib)
{
- pg_icu_library *lib;
-
/*
* These assignments will fail to compile if an incompatible API change is
* made to some future version of ICU, at which point we might need to
* consider special treatment for different major version ranges, with
* intermediate trampoline functions.
*/
- lib = palloc0(sizeof(*lib));
lib->getICUVersion = u_getVersion;
lib->getUnicodeVersion = u_getUnicodeVersion;
lib->getCLDRVersion = ulocdata_getCLDRVersion;
@@ -1512,8 +1537,25 @@ get_builtin_icu_library()
StaticAssertStmt(U_MAX_VERSION_LENGTH == 4,
"ucol_getVersion output buffer size changed incompatibly");
+ return true;
+}
+
+pg_icu_library *
+get_icu_library(const char *collate, const char *ctype, const char *version)
+{
+ pg_icu_library *lib = palloc0(sizeof(*lib));
+ bool filled = false;
+
+ if (get_icu_library_hook != NULL)
+ filled = get_icu_library_hook(lib, collate, ctype, version);
+
+ if(!filled)
+ filled = get_builtin_icu_library(lib);
+
+ Assert(filled);
return lib;
}
+
#endif
/*
@@ -1607,7 +1649,7 @@ pg_newlocale(char provider, bool isdefault, bool deterministic,
{
UCollator *collator;
UErrorCode status;
- pg_icu_library *iculib = get_builtin_icu_library();
+ pg_icu_library *iculib = get_icu_library(collate, ctype, version);
/* collator may be leaked if we encounter an error */
@@ -1926,7 +1968,7 @@ get_collation_actual_version(char collprovider, const char *collcollate)
UErrorCode status;
UVersionInfo versioninfo;
char buf[U_MAX_VERSION_STRING_LENGTH];
- pg_icu_library *iculib = get_builtin_icu_library();
+ pg_icu_library *iculib = get_icu_library(NULL, NULL, NULL);
status = U_ZERO_ERROR;
collator = iculib->openCollator(collcollate, &status);
diff --git a/src/include/utils/pg_locale_internal.h b/src/include/utils/pg_locale_internal.h
index 54445d8b87..1be0205391 100644
--- a/src/include/utils/pg_locale_internal.h
+++ b/src/include/utils/pg_locale_internal.h
@@ -162,10 +162,18 @@ struct pg_locale_struct
};
#ifdef USE_ICU
+
+typedef bool (*get_icu_library_hook_type)(
+ pg_icu_library *lib, const char *collate, const char *ctype,
+ const char *version);
+
+extern PGDLLIMPORT get_icu_library_hook_type get_icu_library_hook;
+
#define PG_ICU_LIB(x) ((x)->info.icu.lib)
#define PG_ICU_COL(x) ((x)->info.icu.ucol)
-extern pg_icu_library *get_builtin_icu_library(void);
+extern pg_icu_library *get_icu_library(const char *collate, const char *ctype,
+ const char *version);
extern int32_t icu_to_uchar(pg_icu_library *lib, UChar **buff_uchar,
const char *buff, size_t nbytes);
extern int32_t icu_from_uchar(pg_icu_library *lib, char **result,
--
2.34.1