v9-0011-Introduce-hooks-for-creating-custom-pg_locale_t.patch
text/x-patch
Filename: v9-0011-Introduce-hooks-for-creating-custom-pg_locale_t.patch
Type: text/x-patch
Part: 10
Patch
Format: format-patch
Series: patch v9-0011
Subject: Introduce hooks for creating custom pg_locale_t.
| File | + | − |
|---|---|---|
| src/backend/utils/adt/pg_locale.c | 53 | 22 |
| src/include/utils/pg_locale.h | 24 | 0 |
| src/tools/pgindent/typedefs.list | 2 | 0 |
From a4d74d22b450359d303a5f08c8a965fb4215bcc5 Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Wed, 25 Sep 2024 16:10:28 -0700
Subject: [PATCH v9 11/11] Introduce hooks for creating custom pg_locale_t.
Now that collation, case mapping, and ctype behavior is controlled
with a method table, we can hook the behavior.
The hooks can provide their own arbitrary method table, which may be
based on a different version of ICU than what Postgres was built with,
or entirely unrelated to ICU/libc.
---
src/backend/utils/adt/pg_locale.c | 75 ++++++++++++++++++++++---------
src/include/utils/pg_locale.h | 24 ++++++++++
src/tools/pgindent/typedefs.list | 2 +
3 files changed, 79 insertions(+), 22 deletions(-)
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 71cd8647d35..79135eb493a 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -103,6 +103,9 @@ extern char *get_collation_actual_version_icu(const char *collcollate);
/* pg_locale_libc.c */
extern pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context);
+create_pg_locale_hook_type create_pg_locale_hook = NULL;
+collation_version_hook_type collation_version_hook = NULL;
+
/* GUC settings */
char *locale_messages;
char *locale_monetary;
@@ -1190,7 +1193,7 @@ create_pg_locale(Oid collid, MemoryContext context)
{
HeapTuple tp;
Form_pg_collation collform;
- pg_locale_t result;
+ pg_locale_t result = NULL;
Datum datum;
bool isnull;
@@ -1199,15 +1202,21 @@ create_pg_locale(Oid collid, MemoryContext context)
elog(ERROR, "cache lookup failed for collation %u", collid);
collform = (Form_pg_collation) GETSTRUCT(tp);
- if (collform->collprovider == COLLPROVIDER_BUILTIN)
- result = create_pg_locale_builtin(collid, context);
- else if (collform->collprovider == COLLPROVIDER_ICU)
- result = create_pg_locale_icu(collid, context);
- else if (collform->collprovider == COLLPROVIDER_LIBC)
- result = create_pg_locale_libc(collid, context);
- else
- /* shouldn't happen */
- PGLOCALE_SUPPORT_ERROR(collform->collprovider);
+ if (create_pg_locale_hook != NULL)
+ result = create_pg_locale_hook(collid, context);
+
+ if (result == NULL)
+ {
+ if (collform->collprovider == COLLPROVIDER_BUILTIN)
+ result = create_pg_locale_builtin(collid, context);
+ else if (collform->collprovider == COLLPROVIDER_ICU)
+ result = create_pg_locale_icu(collid, context);
+ else if (collform->collprovider == COLLPROVIDER_LIBC)
+ result = create_pg_locale_libc(collid, context);
+ else
+ /* shouldn't happen */
+ PGLOCALE_SUPPORT_ERROR(collform->collprovider);
+ }
Assert((result->collate_is_c && result->collate == NULL) ||
(!result->collate_is_c && result->collate != NULL));
@@ -1270,7 +1279,7 @@ init_database_collation(void)
{
HeapTuple tup;
Form_pg_database dbform;
- pg_locale_t result;
+ pg_locale_t result = NULL;
Assert(default_locale == NULL);
@@ -1280,18 +1289,25 @@ init_database_collation(void)
elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
dbform = (Form_pg_database) GETSTRUCT(tup);
- if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
- result = create_pg_locale_builtin(DEFAULT_COLLATION_OID,
- TopMemoryContext);
- else if (dbform->datlocprovider == COLLPROVIDER_ICU)
- result = create_pg_locale_icu(DEFAULT_COLLATION_OID,
- TopMemoryContext);
- else if (dbform->datlocprovider == COLLPROVIDER_LIBC)
- result = create_pg_locale_libc(DEFAULT_COLLATION_OID,
+ if (create_pg_locale_hook != NULL)
+ result = create_pg_locale_hook(DEFAULT_COLLATION_OID,
TopMemoryContext);
- else
- /* shouldn't happen */
- PGLOCALE_SUPPORT_ERROR(dbform->datlocprovider);
+
+ if (result == NULL)
+ {
+ if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
+ result = create_pg_locale_builtin(DEFAULT_COLLATION_OID,
+ TopMemoryContext);
+ else if (dbform->datlocprovider == COLLPROVIDER_ICU)
+ result = create_pg_locale_icu(DEFAULT_COLLATION_OID,
+ TopMemoryContext);
+ else if (dbform->datlocprovider == COLLPROVIDER_LIBC)
+ result = create_pg_locale_libc(DEFAULT_COLLATION_OID,
+ TopMemoryContext);
+ else
+ /* shouldn't happen */
+ PGLOCALE_SUPPORT_ERROR(dbform->datlocprovider);
+ }
ReleaseSysCache(tup);
@@ -1360,6 +1376,21 @@ get_collation_actual_version(char collprovider, const char *collcollate)
{
char *collversion = NULL;
+ if (collation_version_hook != NULL)
+ {
+ char *version;
+
+ if (collation_version_hook(collprovider, collcollate, &version))
+ return version;
+ }
+
+ /*
+ * 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)
collversion = get_collation_actual_version_builtin(collcollate);
#ifdef USE_ICU
diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h
index 1225f22131c..d7c8c927075 100644
--- a/src/include/utils/pg_locale.h
+++ b/src/include/utils/pg_locale.h
@@ -155,6 +155,30 @@ struct pg_locale_struct
typedef struct pg_locale_struct *pg_locale_t;
+/*
+ * Hooks to enable custom locale providers.
+ */
+
+/*
+ * Hook create_pg_locale(). Return result (allocated in the given context) to
+ * override; or return NULL to return control to create_pg_locale(). When
+ * creating the default database collation, collid is DEFAULT_COLLATION_OID.
+ */
+typedef pg_locale_t (*create_pg_locale_hook_type) (Oid collid,
+ MemoryContext context);
+
+/*
+ * Hook get_collation_actual_version(). Set *version out parameter and return
+ * true to override; or return false to return control to
+ * get_collation_actual_version().
+ */
+typedef bool (*collation_version_hook_type) (char collprovider,
+ const char *collcollate,
+ char **version);
+
+extern PGDLLIMPORT create_pg_locale_hook_type create_pg_locale_hook;
+extern PGDLLIMPORT collation_version_hook_type collation_version_hook;
+
extern void init_database_collation(void);
extern pg_locale_t pg_newlocale_from_collation(Oid collid);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 94b041ec9e9..e39fe343d21 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3376,6 +3376,7 @@ cmpEntriesArg
codes_t
collation_cache_entry
collation_cache_hash
+collation_version_hook_type
color
colormaprange
compare_context
@@ -3392,6 +3393,7 @@ core_yyscan_t
corrupt_items
cost_qual_eval_context
cp_hash_func
+create_pg_locale_hook_type
create_upper_paths_hook_type
createdb_failure_params
crosstab_HashEnt
--
2.45.2