Re: [rfc] new CREATE FUNCTION (and more) - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [rfc] new CREATE FUNCTION (and more)
Date
Msg-id 11336.974430656@sss.pgh.pa.us
Whole thread Raw
In response to Re: [rfc] new CREATE FUNCTION (and more)  (Philip Warner <pjw@rhyme.com.au>)
Responses Re: [rfc] new CREATE FUNCTION (and more)  (Philip Warner <pjw@rhyme.com.au>)
List pgsql-hackers
Philip Warner <pjw@rhyme.com.au> writes:
> For possible future compatibility, can you also do something like:
>     PG_FUNCTION_API_V2;
>     PG_FUNCTION_V2(foo);
>     PG_FUNCTION_V2(bar);
>     ...

> Where
> PG_FUNCTION_API_V2 expands to:
>     int pg_fmgr_api_version(void) { return 2; }
> And PG_FUNCTION_V2(foo) either does nothing or expands to:
>     int pg_fmgr_api2_version_foo(void) { return 2; }

I'm not following the point here.  Why two different macros?  It doesn't
look to me like the first one does anything.  The per-routine macro
calls should be capable of doing everything that needs to be done.

Per your comments and Marko's about future extension, it seems that
a single-word result might start to get a little cramped before long.
I like Marko's design:
struct pg_function_info_header {    int api_ver;};

The api_ver field is sufficient for now, but for values > 2 there
might be additional fields defined.

We can either have this struct be an initialized global variable,
or have a called function that returns a pointer to it, depending on
the question of which way seems easier to implement/more portable.
The macro can hide the details of how it's done.

> The first call will tell PG that (because it is version 2), it should
> expect the next set of entry points. Since we will not be allowing mixed
> versions in this version of the API (I think),

Yes, we will, because there is a case in the regression tests that
will break anything that doesn't cope with mixed versions ;-).
I deliberately left some of the routines in regress.c old-style ...

> This way we make it more independant of future API versions by not
> requiring a specific special entry point for each function. Then can do
> things like use the same entry point for multiple functions, possibly act
> as stubs pointing to other libraries (by loading & returning another
> library entry point) etc etc. 

Hmm.  This stub idea might be a sufficient reason to say that we want to
do a function call rather than look for a global variable.  However,
I am unpersuaded by the idea that a one-liner function per useful entry
point is an intolerable amount of overhead.  Let's keep it simple here.

>     PG_FUNCTION_V3(foo, false, true, foo_entry_point)
> expand to:
>     void pg_fmgr_api_version_foo(fmgr_info *i) 
>        { i->iscacheable=false; 
i-> isstrict=true;
i-> entrypoint=foo_entry_point; }

I prefer something like
const inforec * pg_api_foo(void){    static inforec foo_info = { ... };    return &foo_info;}

since this avoids prejudging anything.  (In your example, how does
the version function *know* how big the record it's been handed is?
Loading a version-N library into a Postgres version < N might bomb
hard because the info function scribbles on fields that aren't there.
Handing back a pointer to something that the main code then treats
as read-only seems much safer.)  The above implementation with a
preset static inforec is of course only one way it could be done
without breaking the ABI for the info function...

> Perhaps in PG_FUNCTION_API_V4 we can implement some kind of interface for
> listing supported entry points for module loading...

I think that should be seen as a separate feature, rather than
mixing it up with support information about any individual function.
        regards, tom lane


pgsql-hackers by date:

Previous
From: Philip Warner
Date:
Subject: Re: [rfc] new CREATE FUNCTION (and more)
Next
From: Philip Warner
Date:
Subject: Re: [rfc] new CREATE FUNCTION (and more)