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

Reply via email to