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: