From cda659465d1834549c131c22ff50329b159b7e00 Mon Sep 17 00:00:00 2001 From: Yurii Rashkovskii Date: Wed, 17 Jul 2024 17:01:00 -0700 Subject: [PATCH] [EARLY WIP] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PG_FUNCTION_INFO_V1 did quite well for Postgres over the years. However, it has issues: The safety of our extensions often relies on being defensive about the types of arguments the functions receive. A Postgres user with sufficient privileges can create a function with any parameters/return signature calling our native function. Unless that function inspects FunctionCallInfo deeply (which comes at a non-zero cost), all bets are off in this case, and a crash or other malfunction can occur. Sometimes, it would be meaningful to select a different function implementation based on some load-time parameters – either based on the host system or on something coming from the database. In the case of more optimal generated code specific to CPUs, function multiversioning can alleviate this (subject to limitations of multiversioning, but for all other cases, there's no straightforward way to pick the right function when we load it. `PG_FUNCTION_INFO_V2` defines `pg_finfo_FUNCTION_NAME` symbol. Some languages make it much harder to construct names like this. This also makes it much harder to list all exported names (we need to find symbols!) This is less critical than the ones above, but it is still a concern. --- This change introduces a way to list all functions ahead of time, with their parameters. --- src/include/fmgr.h | 53 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/include/fmgr.h b/src/include/fmgr.h index ccb4070a25140..382efed343a6a 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -378,9 +378,18 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum); /*------------------------------------------------------------------------- * Support for detecting call convention of dynamically-loaded functions * - * Dynamically loaded functions currently can only use the version-1 ("new - * style") calling convention. Version-0 ("old style") is not supported - * anymore. Version 1 is the call convention defined in this header file, and + * Dynamically loaded functions currently can use the version-2 ("new + * style") or version-1 calling convention. Version-0 ("old style") is not + * supported anymore + * + * Version 2 is the call convention defined in this header file, and must + * be accompanied by the following construct: + * + * PG_FUNCTIONS_V2( + * + * ); + * + * Version 1 is the call convention defined in this header file, and * must be accompanied by the macro call * * PG_FUNCTION_INFO_V1(function_name); @@ -401,7 +410,8 @@ typedef struct typedef const Pg_finfo_record *(*PGFInfoFunction) (void); /* - * Macro to build an info function associated with the given function name. + * Macro to build an info function associated with the given function name + * for version-1 calling convention. * * As a convenience, also provide an "extern" declaration for the given * function name, so that writers of C functions need not write that too. @@ -423,6 +433,41 @@ CppConcat(pg_finfo_,funcname) (void) \ } \ extern int no_such_variable +typedef struct { + const char *name; +} Pg_FunctionInfo_v2; + +typedef struct { + int api_version; + union { + Pg_FunctionInfo_v2 *v2; + } info; +} Pg_FunctionInfo; + +typedef struct { + int api_version; + int total_entries; + Pg_FunctionInfo_v2 entries[FLEXIBLE_ARRAY_MEMBER]; +} Pg_functions_info_v2; + +extern PGDLLEXPORT const Pg_functions_info_v2 * pg_finfo_functions_v2(void); + +/* Expected signature of an info function */ +typedef const Pg_functions_info_v2 *(*PGFunctionsInfo) (void); + +#define PG_FUNCTIONS_V2(members) \ +const Pg_functions_info_v2 * \ +pg_finfo_functions_v2(void) \ +{ \ + static const Pg_functions_info_v2 info = { \ + .entries = {members}, \ + .api_version = 2, \ + .total_entries = sizeof((Pg_FunctionInfo_v2[]){members}) / sizeof(Pg_FunctionInfo_v2) \ + }; \ + return &info; \ +} \ +extern int no_such_variable + /* * Declare _PG_init/_PG_fini centrally. Historically each shared library had