Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
On Wed, Jul 19, 2006 at 01:35:16PM -0400, Tom Lane wrote: 1) I think the most straightforward way to load an instrumentation plugin is to define a new custom GUC variable (using the custom_variable_classes mechanism). This seems a bit messy and special-purpose. I see no good reason to tie it to plpgsql; we'll just need another one for every other language. IMHO what we want is something with similar properties to preload_libraries, but processed on a per-backend basis instead of once at postmaster start. (You could almost just tell people to select the plugin they want by LOADing it, but that is hard to use if you're trying to debug a non-interactive application. A GUC variable can be set for an app without much cooperation from the app.) snip We should also think about a deregistration function. This would allow you to turn debugging on and off within an interactive session. The GUC variable is really only for coercing non-interactive applications into being debuggable --- I don't see it as being important for interactive debugging, as compared to just select plugin_init(); ... This isn't the only example of where it would be handy to be able to tell a certain backend or group of backends to do something, so you could gain more insight into what some application is doing. Turning on query logging is another example that comes to mind. Is there some way we could allow one backend to tell another backend to change certain aspects of its behavior? One idea is to have a function that can send commands to another backend via some form of IPC. That backend would then execute the commands the next time it would normally accept commands from it's client connection. Of course this creates a pretty big foot-gun, so we might want to greatly restrict what kind of commands could be executed this way. Another possibility would be allowing users to specify certain GUC settings for backends that match certain criteria when they're spawned, such as what IP the client is connecting from, or what user it's authenticating as. -- Jim C. Nasby, Sr. Engineering Consultant [EMAIL PROTECTED] Pervasive Software http://pervasive.comwork: 512-231-6117 vcard: http://jim.nasby.net/pervasive.vcf cell: 512-569-9461 ---(end of broadcast)--- TIP 1: if posting/reading through Usenet, please send an appropriate subscribe-nomail command to [EMAIL PROTECTED] so that your message can get through to the mailing list cleanly
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
Jim C. Nasby [EMAIL PROTECTED] writes: Another possibility would be allowing users to specify certain GUC settings for backends that match certain criteria when they're spawned, such as what IP the client is connecting from, or what user it's authenticating as. ALTER USER SET ... regards, tom lane ---(end of broadcast)--- TIP 6: explain analyze is your friend
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
Sorry to poke - but I'd like to get a patch submitted next week. Any more comments? Thanks. -- Korry Thanks for the quick feedback. 1) I think the most straightforward way to load an instrumentation plugin is to define a new custom GUC variable (using the custom_variable_classes mechanism). This seems a bit messy and special-purpose. Agreed, I'm not crazy about using a custom_variable_class variable either. I see no good reason to tie it to plpgsql; we'll just need another one for every other language. Hmmm... but the plugins themselves would be language-specific. I can't imagine that a plugin (say a profiler) for PL/python would work for PL/pgSQL. It seems to me that, even if we come up with a common mechanism, we'll still need a separate GUC variable *name* for each PL. Or am I not understanding something? Can you post an example of what you are thinking (what would such a GUC variable look like)? IMHO what we want is something with similar properties to preload_libraries, but processed on a per-backend basis instead of once at postmaster start. (You could almost just tell people to select the plugin they want by LOADing it, but that is hard to use if you're trying to debug a non-interactive application. A GUC variable can be set for an app without much cooperation from the app.) Agreed. When the plugin's shared library gets loaded, one way or the other, it should construct the function-pointer struct and then pass it to a function defined by plpgsql (this lets us hide/postpone the decision about whether there can be more than one active plugin). But there's a timing issue there. If you ask the plugin to call a call-handler function, then you can't load the plugin at backend startup because the PL/pgSQL call-handler isn't loaded until it's required. Since both the plugin and the call-handler are dynamically loaded, I think one of them has to load the other. We already have a mechanism for loading call-handlers on demand - it seems kind of messy to introduce another mechanism for loading plugins (that in turn load the call-handlers). The PL/pgSQL call-handler has a convenient initialization function that could read the GUC variable and load the referenced plugin (that's what I'm doing right now). What I'm thinking is that the plpgsql_init() function would look something like this (my changes in red); PLpgSQL_plugin pluginHooks; typedef void (*plugin_loader_func)(PLpgSQL_plugin *hooks); void plpgsql_init(void) { static char * pluginName; plugin_load_func plugin_loader(); /* Do initialization only once */ if (!plpgsql_firstcall) return; plpgsql_HashTableInit(); RegisterXactCallback(plpgsql_xact_cb, NULL); plpgsql_firstcall = false; /* Load any instrumentation plugins */ DefineCustomStringVariable( "plpgsql.plugin", "Name of instrumentation plugin to use when PL/pgSQL function is invoked", NULL, pluginName, PGC_USERSET, NULL, NULL ); EmitWarningsOnPlaceholders("plpgsql"); if (pluginName ) { plugin_loader = (plugin_loader_func *)load_external_function(pluginName, "plugin_loader", false, NULL ); if (plugin_loader) (*plugin_loader)(pluginHooks); } } (Ignore the custom variable stuff for now) Each plugin would export a plugin_loader() function - that function, given a pointer to a PLpgSQL_plugin structure, would fill in that structure with the required function pointers. One issue that needs to be thought about with either this proposal or your original is what permissions are needed to set the GUC variable. I don't think we dare allow non-superusers to specify LOADing of arbitrary shared libraries, so there has to be some filter function. Perhaps a better way is that the GUC variable specifies a (list of) initialization functions to call at backend start, and then the superuserness is involved with installing the init functions into pg_proc, and the GUC variable itself needs no special permissions. Again, a plugin's init function would just register its function-pointer struct with plpgsql. You're right, privileges are an issue. Is it safe enough if we force all plugins to reside in $libdir? Each plugin could enforce additional security as needed that way, but you'd have to hold enough privileges to get your plugin into $libdir to begin with so you can't write your own nasty plugin to gain more privileges than you ought to have. We should also think about a deregistration function. This would allow you to turn debugging on and off within an interactive session. The GUC variable is really only for coercing non-interactive applications into being debuggable --- I don't see it as being important for interactive debugging, as compared to just "select plugin_init();" ... Ok. 3) Any comments on the PLpgSQL_plugin structure? Should it include (as it's first member) a
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
Hi Korry, On Jul 21, 2006, at 12:51 PM, korry wrote: Sorry to poke - but I'd like to get a patch submitted next week. Any more comments? Thanks. I'm unqualified to comment on the server side design, but I was wondering if there was consensus on how the client interface to the debugger would work. From previous threads I saw DBGP mentioned (http://xdebug.org/docs-dbgp.php), but I don't recall seeing any final commitment to it. Thanks, John John DeSoi, Ph.D. http://pgedit.com/ Power Tools for PostgreSQL ---(end of broadcast)--- TIP 6: explain analyze is your friend
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
I'm unqualified to comment on the server side design, but I was wondering if there was consensus on how the client interface to the debugger would work. From previous threads I saw DBGP mentioned (http://xdebug.org/docs-dbgp.php), but I don't recall seeing any final commitment to it. The patch that I'll be submitting for 8.2 will implement a way to instrument PL/pgSQL (and that idea can be extended to other PL languages). 'Instrumentation' can mean different things - it may be a debugger, a profiler, a coverage analyzer, a tracer, ... EnterpriseDB has developed a few plugins that we'll be contributing soon (a debugger, a profiler, and a tracer). The debugger is by far the largest plugin that we've developed and we implemented it before we had the idea to use a modular architecture (we're still in the process of converting the debugger to modular form, at the moment it's pretty heavily integrated into the PL/pgSQL interpreter). As soon as we get a patch in for the plugin architecture, we'll open-source at least one or two of the plugins so others can use them and/or write more (the debugger will take a little longer). That means that we (i.e. the community) haven't made a firm commitment to the debugger client protocol. I can tell you a little about the protocol that we are currently using, but it may change by the time we're ready to open-source the debugger. I gave a presentation at the anniversary summit that described the overall architecture and also showed the client/server protocol - the slides and audio should be available at the conference web site real soon now. The most important part, from your perspective (assuming that you might want to add a debugger to pgEdit), is the method that a debugger client application uses to interact with the debugger server. That's done through a collection of server-side functions that you can call from any libpq application. For example, to set a breakpoint, you would: SELECT * FROM pldbg_set_breakpoint( sessionHandle, functionOID, lineNumber, processID ); to step/over: SELECT * FROM pldbg_step_over( sessionHandle ); to step/into: SELECT * FROM pldbg_step_into( sessionHandle ); to get a copy of all local variables: SELECT * FROM pldbg_get_variables( sessionHandle, stackFrame ); and so on. There are a few functions that you can call to attach your debugger client to a target server and to set global breakpoints. I'll be posting more information as we get closer to releasing this stuff. -- Korry ---(end of broadcast)--- TIP 4: Have you searched our list archives? http://archives.postgresql.org
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
korry [EMAIL PROTECTED] writes: I see no good reason to tie it to plpgsql; we'll just need another one for every other language. Hmmm... but the plugins themselves would be language-specific. You miss my point. The plugins will be language-specific but the mechanism for selecting/loading them shouldn't be. When the plugin's shared library gets loaded, one way or the other, it should construct the function-pointer struct and then pass it to a function defined by plpgsql (this lets us hide/postpone the decision about whether there can be more than one active plugin). But there's a timing issue there. If you ask the plugin to call a call-handler function, then you can't load the plugin at backend startup because the PL/pgSQL call-handler isn't loaded until it's required. Since both the plugin and the call-handler are dynamically loaded, I think one of them has to load the other. Right, but if you set up the mechanism such that each individual PL is responsible for loading plugins, then we'll have to duplicate all that code each time we instrument another PL. I want to do as much as possible of the work in the core code so that we don't end up with duplicate code to maintain. That being the case, I don't see anything wrong with having the selection mechanism pull in the selected plugin(s) and then those force loading of the language handlers so that they can call the plugin installation function. Sure, sometimes this would result in loading a plugin and handler that don't get used in the current session, but given that people would only load plugins they intend to use, I don't see that as a significant objection. I'm thinking that the cleanest way to handle this would be to add another column to pg_language containing the OID of the plugin receptor function for each PL. Then the plugin just calls that function passing its constructed function-pointer struct. This eliminates the need for hard-wired assumptions about function names and so forth, and also lets you use the existing fmgr functionality to pull in the PL's handler library. OTOH this requires extending the syntax of CREATE LANGUAGE and so on. That is all doable (it's basically the same kind of work that got done when we added validator functions for PLs) but it might be more work than we think the plugin idea is worth. To do it without a pg_language column, we'd need code in each plugin to identify the language shared library (by looking in pg_language), force loading of same (using existing fmgr code), and look up and call a plugin receptor function given an expected C-code name for it (again, most of this already exists in fmgr). It's not a huge amount of code, probably, but again duplicating it in each plugin seems unappealing. I suppose we could make fmgr export a general function to find a plugin receptor function given the PL name and the expected C symbol. Comments anyone? regards, tom lane ---(end of broadcast)--- TIP 4: Have you searched our list archives? http://archives.postgresql.org
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
When the plugin's shared library gets loaded, one way or the other, it should construct the function-pointer struct and then pass it to a function defined by plpgsql (this lets us hide/postpone the decision about whether there can be more than one active plugin). But there's a timing issue there. If you ask the plugin to call a call-handler function, then you can't load the plugin at backend startup because the PL/pgSQL call-handler isn't loaded until it's required. Since both the plugin and the call-handler are dynamically loaded, I think one of them has to load the other. Right, but if you set up the mechanism such that each individual PL is responsible for loading plugins, then we'll have to duplicate all that code each time we instrument another PL. I want to do as much as possible of the work in the core code so that we don't end up with duplicate code to maintain. I think I'm missing something important here. At minimum, you need a way to identify a plugin (or a list of plugins), and, if we generalize the mechanism, a way to identify the language that that plugin is associated with (like, this profiler works with PL/tcl, this debugger works with PL/Java, ...). Once you have that, you've got two choices: 1) The plugin loads the language or 2) The language loads the plugin You are suggesting option 1. That means that we must: a) come up with a way to identify the set of plugins desired (probably some GUC variables?) b) Extend the pg_language structure c) Extend the CREATE LANGUAGE statement d) come up with a way for the backend to load the plugins (the backend already knows how to load a language-handler) e) add loader code to each plugin (there should be more plugins than languages eventually) f) add loader code to each language (at least each language that wants to support a plugin) On the other hand, if the language loads the plugin, we must: a) come up with a way to identify the set of plugins desired (probably some GUC variables?) b) add loader code to each plugin c) add loader code to each language (that wants to support a plugin) In either case, the loader code in the language-handlers and the loader code in the plugins could be simple calls to common functions that are defined in the core, avoiding a lot of duplicate code. For example, each language handler (in it's initialization code) could include a call such as: pl_load_plugins( "pl/pgsql", functionPointers ); or pl_load_plugins( "pl/java", functionPointers ); pl_load_plugins() would reside in the core, it would find the list of plugins, load each one, find the plugin's initialization function, and call that function with functionPointers (the initializer would fill in the functionPointers structure). So what am I missing? What's the advantage to having the plugin load the language? To do it without a pg_language column, we'd need code in each plugin to identify the language shared library (by looking in pg_language), force loading of same (using existing fmgr code), and look up and call a plugin receptor function given an expected C-code name for it (again, most of this already exists in fmgr). It's not a huge amount of code, probably, but again duplicating it in each plugin seems unappealing. I suppose we could make fmgr export a general function to find a plugin receptor function given the PL name and the expected C symbol. That's what I was thinking too. But we could avoid hard-coded names using a syntax similar to preload_libraries (each entry in preload_libraries can contain the name of an optional initialization function). If you specify libraryName:functionName, we would assume that functionName was the loader function, if you just specify libraryName, we could look for a hard-coded default. (Oh, and any more comments on security? Is it enough to require that all plugins live in $libdir?) -- Korry
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
Hi korry-san. From: korry I'm unqualified to comment on the server side design, but I was wondering if there was consensus on how the client interface to the debugger would work. From previous threads I saw DBGP mentioned (http://xdebug.org/docs-dbgp.php), but I don't recall seeing any final commitment to it. The patch that I'll be submitting for 8.2 will implement a way to instrument PL/pgSQL (and that idea can be extended to other PL languages). 'Instrumentation' can mean different things - it may be a debugger, a profiler, a coverage analyzer, a tracer, ... I can regard it as very great. probably, It is expected that workstation (edb-debugger) is realizable with an addition of some language parser.:-) EnterpriseDB has developed a few plugins that we'll be contributing soon (a debugger, a profiler, and a tracer). The debugger is by far the largest plugin that we've developed and we implemented it before we had the idea to use a modular architecture (we're still in the process of converting the debugger to modular form, at the moment it's pretty heavily integrated into the PL/pgSQL interpreter). As soon as we get a patch in for the plugin architecture, we'll open-source at least one or two of the plugins so others can use them and/or write more (the debugger will take a little longer). That means that we (i.e. the community) haven't made a firm commitment to the debugger client protocol. I can tell you a little about the protocol that we are currently using, but it may change by the time we're ready to open-source the debugger. I gave a presentation at the anniversary summit that described the overall architecture and also showed the client/server protocol - the slides and audio should be available at the conference web site real soon now. Great.! Your session was very wonderful. People who were not able to hear it will be seen. The most important part, from your perspective (assuming that you might want to add a debugger to pgEdit), is the method that a debugger client application uses to interact with the debugger server. That's done through a collection of server-side functions that you can call from any libpq application. For example, to set a breakpoint, you would: SELECT * FROM pldbg_set_breakpoint( sessionHandle, functionOID, lineNumber, processID ); to step/over: SELECT * FROM pldbg_step_over( sessionHandle ); to step/into: SELECT * FROM pldbg_step_into( sessionHandle ); to get a copy of all local variables: SELECT * FROM pldbg_get_variables( sessionHandle, stackFrame ); and so on. There are a few functions that you can call to attach your debugger client to a target server and to set global breakpoints. I'll be posting more information as we get closer to releasing this stuff. This regards me as a very great contribution.! As for me, the feeling of workstation (edb-debugger) was pleased very much. I consider it so that often to pgAdmin. Then, I am looking forward to the evolution.:-) Thanks!! Regards, Hiroshi Saito ---(end of broadcast)--- TIP 2: Don't 'kill -9' the postmaster
[HACKERS] Loading the PL/pgSQL debugger (and other plugins)
I'm working on a patch that implements the PL/pgSQL instrumentation stuff (i.e. the PL/pgSQL debugger) that I discussed at the Anniversary Summit and I need some opinions (this seems like a good place to look for opinions :-) A quick review: the PL/pgSQL debugger is designed as an optional plugin that loads into the PL/pgSQL interpreter on-demand. You can use the plugin idea to implement other kinds of instrumentation (I demo'ed a tracer and a profiler at the conference, along with a debugger). A plugin architecture greatly reduces the (source code) footprint that would normally be required to implement a full-featured debugger. A plugin is basically a structure that contains a few function pointers. If those function pointers are NULL, the PL/pgSQL interpreter works exactly the way it does today. If any of those function pointers are non-NULL, the PL/pgSQL interpreter calls the target function (which points to a chunk of code inside of the plugin) and the plugin does whatever it needs to do. Right now, the plugin structure looks like this: typedef struct { void (*init)( estate, func, error_callback, assign_expr, expr ); 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 ); } PLpgSQL_plugin; I've truncated the argument list (in this e-mail) for the (*init)() function since it's rather long (error_callback and assign_expr are both function pointers). When the PL/pgSQL intrepreter loads the plugin, it calls the plugin-init() function. When the PL/pgSQL intrepreter starts running a new function, it calls the plugin-func_beg() function. When the PL/pgSQL intrepreter completes a function, it calls the plugin-func_end() function. When the PL/pgSQL interpreter is about to execute a line of PL/pgSQL code, it calls plugin-stmt_beg() When the PL/pgSQL interpreter has finished executing a line of PL/pgSQL code, it calls plugin-stmt_end() So here is where I need a few opinions: 1) I think the most straightforward way to load an instrumentation plugin is to define a new custom GUC variable (using the custom_variable_classes mechanism). When the PL/pgSQL call-handler loads, it can check that config. variable (something like plpgsql.plugin = '$libdir/plugin_profiler' or plpgsql.plugin = '$libdir/plugin_debugger') and load the plugin if non-NULL. That seems a little obtuse to me since custom variables don't appear in the prototype postgresql.conf file. Would it be better to add a real GUC variable instead of a custom variable? 2) Given that plpgsql.plugin points to the name of a shared-object file (or DLL or whatever you prefer to call it), we need to find *something* inside of the file. The most obvious choice would be to look for a variable (a structure or structure pointer) with a fixed name. That would mean, for example, that a plugin would define an externally visible PLpgSQL_plugin structure named plugin_hooks and the PL/pgSQL interpreter would look for that symbol inside of the plugin. Alternatively, we could look for a function inside of the plugin (something like 'plugin_loader') and then call that function with a pointer to a PLpgSQL_plugin structure. I prefer the function-pointer approach since we already have a reliable mechanism in place for finding a function inside of a shared-object (the same mechanism works for finding a variable instead of a function pointer, but I doubt that that has been tested in all platforms). 3) Any comments on the PLpgSQL_plugin structure? Should it include (as it's first member) a structure version number so we can add to/change the structure as needed? 4) Do we need to support multiple active plugins? Would you ever need to load the debugger at the same time you've loaded the profiler (no)? Would you ever need to load the tracer at the same time you need the debugger (probably not)? If we need to support multiple plugins, should be just introduce a meta-plugin that knows how to handle a list of other plugins? (Messy, but certainly gets the job done without worrying about it right now). 5) I'll also be adding a void pointer to the PLpgSQL_execstate structure (think of a PLpgSQL_execstate as a stack frame). The new pointer is reserved for use by the plugin. It may be handy to add a void pointer to each PLpgSQL_stmt as well - is that acceptable? (That would mean an extra 4-bytes per-line of compiled PL/pgSQL code, even if you don't have a plugin loaded). Any other comments? Obviously, you'll have a chance to critique the patch when I get it sent in. Thanks for your help. -- Korry ---(end of broadcast)--- TIP 4: Have you searched our list archives?
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
korry [EMAIL PROTECTED] writes: I'm working on a patch that implements the PL/pgSQL instrumentation stuff (i.e. the PL/pgSQL debugger) that I discussed at the Anniversary Summit and I need some opinions (this seems like a good place to look for opinions :-) Opinions R US ;-) 1) I think the most straightforward way to load an instrumentation plugin is to define a new custom GUC variable (using the custom_variable_classes mechanism). This seems a bit messy and special-purpose. I see no good reason to tie it to plpgsql; we'll just need another one for every other language. IMHO what we want is something with similar properties to preload_libraries, but processed on a per-backend basis instead of once at postmaster start. (You could almost just tell people to select the plugin they want by LOADing it, but that is hard to use if you're trying to debug a non-interactive application. A GUC variable can be set for an app without much cooperation from the app.) When the plugin's shared library gets loaded, one way or the other, it should construct the function-pointer struct and then pass it to a function defined by plpgsql (this lets us hide/postpone the decision about whether there can be more than one active plugin). One issue that needs to be thought about with either this proposal or your original is what permissions are needed to set the GUC variable. I don't think we dare allow non-superusers to specify LOADing of arbitrary shared libraries, so there has to be some filter function. Perhaps a better way is that the GUC variable specifies a (list of) initialization functions to call at backend start, and then the superuserness is involved with installing the init functions into pg_proc, and the GUC variable itself needs no special permissions. Again, a plugin's init function would just register its function-pointer struct with plpgsql. We should also think about a deregistration function. This would allow you to turn debugging on and off within an interactive session. The GUC variable is really only for coercing non-interactive applications into being debuggable --- I don't see it as being important for interactive debugging, as compared to just select plugin_init(); ... 3) Any comments on the PLpgSQL_plugin structure? Should it include (as it's first member) a structure version number so we can add to/change the structure as needed? Given our current plans for enforcing recompiles at major version changes (via magic-block checking), I'm not sure I see a need for this. 4) Do we need to support multiple active plugins? Probably, but let's fix the API to hide this, so we don't have to commit now. regards, tom lane ---(end of broadcast)--- TIP 5: don't forget to increase your free space map settings
Re: [HACKERS] Loading the PL/pgSQL debugger (and other plugins)
Thanks for the quick feedback. 1) I think the most straightforward way to load an instrumentation plugin is to define a new custom GUC variable (using the custom_variable_classes mechanism). This seems a bit messy and special-purpose. Agreed, I'm not crazy about using a custom_variable_class variable either. I see no good reason to tie it to plpgsql; we'll just need another one for every other language. Hmmm... but the plugins themselves would be language-specific. I can't imagine that a plugin (say a profiler) for PL/python would work for PL/pgSQL. It seems to me that, even if we come up with a common mechanism, we'll still need a separate GUC variable *name* for each PL. Or am I not understanding something? Can you post an example of what you are thinking (what would such a GUC variable look like)? IMHO what we want is something with similar properties to preload_libraries, but processed on a per-backend basis instead of once at postmaster start. (You could almost just tell people to select the plugin they want by LOADing it, but that is hard to use if you're trying to debug a non-interactive application. A GUC variable can be set for an app without much cooperation from the app.) Agreed. When the plugin's shared library gets loaded, one way or the other, it should construct the function-pointer struct and then pass it to a function defined by plpgsql (this lets us hide/postpone the decision about whether there can be more than one active plugin). But there's a timing issue there. If you ask the plugin to call a call-handler function, then you can't load the plugin at backend startup because the PL/pgSQL call-handler isn't loaded until it's required. Since both the plugin and the call-handler are dynamically loaded, I think one of them has to load the other. We already have a mechanism for loading call-handlers on demand - it seems kind of messy to introduce another mechanism for loading plugins (that in turn load the call-handlers). The PL/pgSQL call-handler has a convenient initialization function that could read the GUC variable and load the referenced plugin (that's what I'm doing right now). What I'm thinking is that the plpgsql_init() function would look something like this (my changes in red); PLpgSQL_plugin pluginHooks; typedef void (*plugin_loader_func)(PLpgSQL_plugin *hooks); void plpgsql_init(void) { static char * pluginName; plugin_load_func plugin_loader(); /* Do initialization only once */ if (!plpgsql_firstcall) return; plpgsql_HashTableInit(); RegisterXactCallback(plpgsql_xact_cb, NULL); plpgsql_firstcall = false; /* Load any instrumentation plugins */ DefineCustomStringVariable( "plpgsql.plugin", "Name of instrumentation plugin to use when PL/pgSQL function is invoked", NULL, pluginName, PGC_USERSET, NULL, NULL ); EmitWarningsOnPlaceholders("plpgsql"); if (pluginName ) { plugin_loader = (plugin_loader_func *)load_external_function(pluginName, "plugin_loader", false, NULL ); if (plugin_loader) (*plugin_loader)(pluginHooks); } } (Ignore the custom variable stuff for now) Each plugin would export a plugin_loader() function - that function, given a pointer to a PLpgSQL_plugin structure, would fill in that structure with the required function pointers. One issue that needs to be thought about with either this proposal or your original is what permissions are needed to set the GUC variable. I don't think we dare allow non-superusers to specify LOADing of arbitrary shared libraries, so there has to be some filter function. Perhaps a better way is that the GUC variable specifies a (list of) initialization functions to call at backend start, and then the superuserness is involved with installing the init functions into pg_proc, and the GUC variable itself needs no special permissions. Again, a plugin's init function would just register its function-pointer struct with plpgsql. You're right, privileges are an issue. Is it safe enough if we force all plugins to reside in $libdir? Each plugin could enforce additional security as needed that way, but you'd have to hold enough privileges to get your plugin into $libdir to begin with so you can't write your own nasty plugin to gain more privileges than you ought to have. We should also think about a deregistration function. This would allow you to turn debugging on and off within an interactive session. The GUC variable is really only for coercing non-interactive applications into being debuggable --- I don't see it as being important for interactive debugging, as compared to just "select plugin_init();" ... Ok. 3) Any comments on the PLpgSQL_plugin structure? Should it include (as it's first member) a structure version number so we can add to/change the structure as needed? Given our current plans for enforcing recompiles at major version changes (via magic-block checking), I'm