Philip Warner <[EMAIL PROTECTED]> 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