Re: [rfc] new CREATE FUNCTION (and more)

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Philip Warner <pjw(at)rhyme(dot)com(dot)au>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: [rfc] new CREATE FUNCTION (and more)
Date: 2000-11-17 03:10:56
Message-ID: 11336.974430656@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Philip Warner <pjw(at)rhyme(dot)com(dot)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

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Philip Warner 2000-11-17 03:49:56 Re: [rfc] new CREATE FUNCTION (and more)
Previous Message Philip Warner 2000-11-17 02:36:02 Re: [rfc] new CREATE FUNCTION (and more)