Hello Updated version
I still not happy with plugin_info - it is only per plugin now and should be per plugin and per function. Regards Pavel 2014/1/12 Pavel Stehule <pavel.steh...@gmail.com> > > > > 2014/1/12 Marko Tiikkaja <ma...@joh.to> > >> On 1/12/14, 5:33 PM, I wrote: >> >>> On 1/9/14, 11:41 PM, Pavel Stehule wrote: >>> >>>> There are two basic questions: >>>> >>>> b) will we support same API still - a reference on plugin_info in exec >>>> state is a issue - described in patch. >>>> >>> >>> Pardon my ignorance, but why does the plugin_info have to be in the >>> executor state? If we're going to change the API, can't we pass it >>> directly to the callback function? >>> >> >> Oh, I think I'm being stupid -- we'd only have to do what *if* we don't >> want to change the API? Then my vote is for breaking the API. >> > > yes. It is my vote too. > > It is trouble - but support same API is really ugly - on second hand - > there are only few plpgsql plugins - and every plugin needs recompilation > for new mayor version and fixing will be easy. > > Regards > > Pavel Stehule > > >> >> >> Regards, >> Marko Tiikkaja >> > >
commit 56c89d4c41e4962d46fd83c6045b5827b51d9dfc Author: Pavel Stehule <pavel.steh...@gmail.com> Date: Sun Jan 12 20:47:56 2014 +0100 cleaned version, break original plpgsql plugin API diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile index 852b0c7..37d17a8 100644 --- a/src/pl/plpgsql/src/Makefile +++ b/src/pl/plpgsql/src/Makefile @@ -19,7 +19,7 @@ rpath = OBJS = pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o pl_scanner.o -DATA = plpgsql.control plpgsql--1.0.sql plpgsql--unpackaged--1.0.sql +DATA = plpgsql.control plpgsql--1.1.sql plpgsql--1.0--1.1.sql plpgsql--unpackaged--1.0.sql all: all-lib diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 3749fac..2b6b405 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -86,6 +86,22 @@ typedef struct SimpleEcontextStackEntry static EState *shared_simple_eval_estate = NULL; static SimpleEcontextStackEntry *simple_econtext_stack = NULL; +/* + * List of pointers and info of registered plugins. + */ +typedef struct PluginPtrEntry +{ + PLpgSQL_plugin *plugin_ptr; + void *plugin_info; /* reserved for use by optional plugin */ + struct PluginPtrEntry *next; +} PluginPtrEntry; + +/* + * Allocated in TopMemoryContext + */ +static PluginPtrEntry *plugins = NULL; +static int used_plugin_hook_types = 0; + /************************************************************ * Local function forward declarations ************************************************************/ @@ -236,6 +252,15 @@ static char *format_expr_params(PLpgSQL_execstate *estate, static char *format_preparedparamsdata(PLpgSQL_execstate *estate, const PreparedParamsData *ppd); +/* Bits for used plugin callback types */ +#define PLUGIN_HOOK_TYPE_FUNC_SETUP (1 << 0) +#define PLUGIN_HOOK_TYPE_FUNC_BEG (1 << 2) +#define PLUGIN_HOOK_TYPE_FUNC_END (1 << 3) +#define PLUGIN_HOOK_TYPE_STMT_BEG (1 << 4) +#define PLUGIN_HOOK_TYPE_STMT_END (1 << 5) + +#define EXEC_PLUGIN_HOOK_TYPE(type) \ + ((used_plugin_hook_types & (PLUGIN_HOOK_TYPE_ ## type)) == (PLUGIN_HOOK_TYPE_ ## type)) /* ---------- * plpgsql_exec_function Called by the call handler for @@ -331,10 +356,22 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, exec_set_found(&estate, false); /* - * Let the instrumentation plugin peek at this function + * Let the instrumentation plugins peek at this function */ - if (*plugin_ptr && (*plugin_ptr)->func_beg) - ((*plugin_ptr)->func_beg) (&estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_BEG)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->func_beg) + (pl_ptr->func_beg) (&estate, func, &pe->plugin_info); + } + } /* * Now call the toplevel block of statements @@ -479,10 +516,22 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, estate.err_text = gettext_noop("during function exit"); /* - * Let the instrumentation plugin peek at this function + * Let the instrumentation plugins peek at this function */ - if (*plugin_ptr && (*plugin_ptr)->func_end) - ((*plugin_ptr)->func_end) (&estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_END)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->func_end) + (pl_ptr->func_end) (&estate, func, &pe->plugin_info); + } + } /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); @@ -699,10 +748,22 @@ plpgsql_exec_trigger(PLpgSQL_function *func, exec_set_found(&estate, false); /* - * Let the instrumentation plugin peek at this function + * Let the instrumentation plugins peek at this function */ - if (*plugin_ptr && (*plugin_ptr)->func_beg) - ((*plugin_ptr)->func_beg) (&estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_BEG)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->func_beg) + (pl_ptr->func_beg) (&estate, func, &pe->plugin_info); + } + } /* * Now call the toplevel block of statements @@ -768,10 +829,22 @@ plpgsql_exec_trigger(PLpgSQL_function *func, } /* - * Let the instrumentation plugin peek at this function + * Let the instrumentation plugins peek at this function */ - if (*plugin_ptr && (*plugin_ptr)->func_end) - ((*plugin_ptr)->func_end) (&estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_END)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->func_end) + (pl_ptr->func_end) (&estate, func, &pe->plugin_info); + } + } /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); @@ -831,10 +904,22 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata) var->freeval = true; /* - * Let the instrumentation plugin peek at this function + * Let the instrumentation plugins peek at this function */ - if (*plugin_ptr && (*plugin_ptr)->func_beg) - ((*plugin_ptr)->func_beg) (&estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_BEG)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->func_beg) + (pl_ptr->func_beg) (&estate, func, &pe->plugin_info); + } + } /* * Now call the toplevel block of statements @@ -865,10 +950,22 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata) estate.err_text = gettext_noop("during function exit"); /* - * Let the instrumentation plugin peek at this function + * Let the instrumentation plugins peek at this function */ - if (*plugin_ptr && (*plugin_ptr)->func_end) - ((*plugin_ptr)->func_end) (&estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_END)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->func_end) + (pl_ptr->func_end) (&estate, func, &pe->plugin_info); + } + } /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); @@ -1389,9 +1486,21 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) save_estmt = estate->err_stmt; estate->err_stmt = stmt; - /* Let the plugin know that we are about to execute this statement */ - if (*plugin_ptr && (*plugin_ptr)->stmt_beg) - ((*plugin_ptr)->stmt_beg) (estate, stmt); + /* Let the plugins know that we are about to execute this statement */ + if (EXEC_PLUGIN_HOOK_TYPE(STMT_BEG)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->stmt_beg) + (pl_ptr->stmt_beg) (&estate, stmt, &pe->plugin_info); + } + } CHECK_FOR_INTERRUPTS(); @@ -1495,8 +1604,20 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) } /* Let the plugin know that we have finished executing this statement */ - if (*plugin_ptr && (*plugin_ptr)->stmt_end) - ((*plugin_ptr)->stmt_end) (estate, stmt); + if (EXEC_PLUGIN_HOOK_TYPE(STMT_END)) + { + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + if (pl_ptr->stmt_end) + (pl_ptr->stmt_end) (&estate, stmt, &pe->plugin_info); + } + } estate->err_stmt = save_estmt; @@ -3160,8 +3281,6 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, estate->err_stmt = NULL; estate->err_text = NULL; - estate->plugin_info = NULL; - /* * Create an EState and ExprContext for evaluation of simple expressions. */ @@ -3173,13 +3292,26 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, * pointers so it can call back into PL/pgSQL for doing things like * variable assignments and stack traces */ - if (*plugin_ptr) + if (plugins) { - (*plugin_ptr)->error_callback = plpgsql_exec_error_callback; - (*plugin_ptr)->assign_expr = exec_assign_expr; + PluginPtrEntry *pe; + + Assert(plugins != NULL); + + for (pe = plugins; pe != NULL; pe = pe->next) + { + PLpgSQL_plugin *pl_ptr = pe->plugin_ptr; + + pl_ptr->error_callback = plpgsql_exec_error_callback; + pl_ptr->assign_expr = exec_assign_expr; - if ((*plugin_ptr)->func_setup) - ((*plugin_ptr)->func_setup) (estate, func); + if (EXEC_PLUGIN_HOOK_TYPE(FUNC_SETUP)) + { + Assert(pl_ptr->func_setup); + + (pl_ptr->func_setup) (estate, func, &pe->plugin_info); + } + } } } @@ -6632,3 +6764,30 @@ format_preparedparamsdata(PLpgSQL_execstate *estate, return paramstr.data; } + +/* + * Register a next plugin info + */ +void +plpgsql_register_plugin_internal(PLpgSQL_plugin *plugin_ptr) +{ + PluginPtrEntry *new_entry; + MemoryContext old_cxt; + + old_cxt = MemoryContextSwitchTo(TopMemoryContext); + new_entry = palloc0(sizeof(PluginPtrEntry)); + MemoryContextSwitchTo(old_cxt); + + /* + * a order of plugins should not be important, so place new plugin as + * first item of plugin list. There are no necessary search end of list. + */ + new_entry->next = plugins; + plugins = new_entry; + + used_plugin_hook_types |= (plugin_ptr->func_setup ? PLUGIN_HOOK_TYPE_FUNC_SETUP : 0); + used_plugin_hook_types |= (plugin_ptr->func_beg ? PLUGIN_HOOK_TYPE_FUNC_BEG : 0); + used_plugin_hook_types |= (plugin_ptr->func_end ? PLUGIN_HOOK_TYPE_FUNC_END : 0); + used_plugin_hook_types |= (plugin_ptr->stmt_beg ? PLUGIN_HOOK_TYPE_STMT_BEG : 0); + used_plugin_hook_types |= (plugin_ptr->stmt_end ? PLUGIN_HOOK_TYPE_STMT_END : 0); +} diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index f02203a..db6851e 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -39,10 +39,6 @@ int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR; bool plpgsql_print_strict_params = false; -/* Hook for plugins */ -PLpgSQL_plugin **plugin_ptr = NULL; - - /* * _PG_init() - library load-time initialization * @@ -82,9 +78,6 @@ _PG_init(void) RegisterXactCallback(plpgsql_xact_cb, NULL); RegisterSubXactCallback(plpgsql_subxact_cb, NULL); - /* Set up a rendezvous point with optional instrumentation plugin */ - plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin"); - inited = true; } @@ -384,3 +377,21 @@ plpgsql_validator(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* ---------- + * + * register any plpgsql plugin + * + * ---------- + */ +PG_FUNCTION_INFO_V1(plpgsql_register_plugin); + +Datum +plpgsql_register_plugin(PG_FUNCTION_ARGS) +{ + PLpgSQL_plugin *plugin_ptr = (PLpgSQL_plugin *) PG_GETARG_POINTER(0); + + plpgsql_register_plugin_internal(plugin_ptr); + + PG_RETURN_VOID(); +} diff --git a/src/pl/plpgsql/src/plpgsql--1.0--1.1.sql b/src/pl/plpgsql/src/plpgsql--1.0--1.1.sql new file mode 100644 index 0000000..c7e9a62 --- /dev/null +++ b/src/pl/plpgsql/src/plpgsql--1.0--1.1.sql @@ -0,0 +1,6 @@ +/* src/pl/plpgsql/src/plpgsql--1.0--1.1.sql */ + +CREATE FUNCTION plpgsql_register_plugin(internal) +RETURNS void +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; diff --git a/src/pl/plpgsql/src/plpgsql--1.0.sql b/src/pl/plpgsql/src/plpgsql--1.0.sql deleted file mode 100644 index 5eeea56..0000000 --- a/src/pl/plpgsql/src/plpgsql--1.0.sql +++ /dev/null @@ -1,11 +0,0 @@ -/* src/pl/plpgsql/src/plpgsql--1.0.sql */ - -/* - * Currently, all the interesting stuff is done by CREATE LANGUAGE. - * Later we will probably "dumb down" that command and put more of the - * knowledge into this script. - */ - -CREATE PROCEDURAL LANGUAGE plpgsql; - -COMMENT ON PROCEDURAL LANGUAGE plpgsql IS 'PL/pgSQL procedural language'; diff --git a/src/pl/plpgsql/src/plpgsql--1.1.sql b/src/pl/plpgsql/src/plpgsql--1.1.sql new file mode 100644 index 0000000..74aa4b9 --- /dev/null +++ b/src/pl/plpgsql/src/plpgsql--1.1.sql @@ -0,0 +1,16 @@ +/* src/pl/plpgsql/src/plpgsql--1.1.sql */ + +/* + * Currently, all the interesting stuff is done by CREATE LANGUAGE. + * Later we will probably "dumb down" that command and put more of the + * knowledge into this script. + */ + +CREATE PROCEDURAL LANGUAGE plpgsql; + +COMMENT ON PROCEDURAL LANGUAGE plpgsql IS 'PL/pgSQL procedural language'; + +CREATE FUNCTION plpgsql_register_plugin(internal) +RETURNS void +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; diff --git a/src/pl/plpgsql/src/plpgsql.control b/src/pl/plpgsql/src/plpgsql.control index b320227..4c75c93 100644 --- a/src/pl/plpgsql/src/plpgsql.control +++ b/src/pl/plpgsql/src/plpgsql.control @@ -1,6 +1,6 @@ # plpgsql extension comment = 'PL/pgSQL procedural language' -default_version = '1.0' +default_version = '1.1' module_pathname = '$libdir/plpgsql' relocatable = false schema = pg_catalog diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index f3d1283..b0c80c1 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -791,8 +791,6 @@ typedef struct PLpgSQL_execstate /* status information for error context reporting */ PLpgSQL_stmt *err_stmt; /* current stmt */ const char *err_text; /* additional state info */ - - void *plugin_info; /* reserved for use by optional plugin */ } PLpgSQL_execstate; @@ -830,11 +828,16 @@ typedef struct PLpgSQL_execstate typedef struct { /* Function pointers set up by the plugin */ - void (*func_setup) (PLpgSQL_execstate *estate, PLpgSQL_function *func); - void (*func_beg) (PLpgSQL_execstate *estate, PLpgSQL_function *func); - void (*func_end) (PLpgSQL_execstate *estate, PLpgSQL_function *func); - void (*stmt_beg) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt); - void (*stmt_end) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt); + void (*func_setup) (PLpgSQL_execstate *estate, PLpgSQL_function *func, + void **plugin_info;); + void (*func_beg) (PLpgSQL_execstate *estate, PLpgSQL_function *func, + void **plugin_info;); + void (*func_end) (PLpgSQL_execstate *estate, PLpgSQL_function *func, + void **plugin_info;); + void (*stmt_beg) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt, + void **plugin_info;); + void (*stmt_end) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt, + void **plugin_info;); /* Function pointers set by PL/pgSQL itself */ void (*error_callback) (void *arg); @@ -894,8 +897,6 @@ extern char *plpgsql_error_funcname; extern PLpgSQL_function *plpgsql_curr_compile; extern MemoryContext compile_tmp_cxt; -extern PLpgSQL_plugin **plugin_ptr; - /********************************************************************** * Function declarations **********************************************************************/ @@ -941,6 +942,7 @@ extern void _PG_init(void); extern Datum plpgsql_call_handler(PG_FUNCTION_ARGS); extern Datum plpgsql_inline_handler(PG_FUNCTION_ARGS); extern Datum plpgsql_validator(PG_FUNCTION_ARGS); +extern Datum plpgsql_register_plugin(PG_FUNCTION_ARGS); /* ---------- * Functions in pl_exec.c @@ -961,6 +963,7 @@ extern Oid exec_get_datum_type(PLpgSQL_execstate *estate, extern void exec_get_datum_type_info(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typmod, Oid *collation); +extern void plpgsql_register_plugin_internal(PLpgSQL_plugin *plugin_ptr); /* ---------- * Functions for namespace handling in pl_funcs.c
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers