Thread: Mysterious Bus Error with get_fn_expr_argtype()
Howdy, I'm trying to write a simple function that will return a string with the type name of a value. Unfortunately, it keeps dying on me. I don't even get any useful debugging information with --enable-cassert, just this: LOG: server process (PID 96946) was terminated by signal 10: Bus error LOG: terminating any other active server processes LOG: all server processes terminated; reinitializing I stuck in a few calls to elog(), and it looks like this is the line that's choking: typeoid = get_fn_expr_argtype(fcinfo->flinfo, 0); But that's copied directly from enum.c. So I'm pretty mystified. Any help would be greatly appreciated. Here's the complete code: #include "postgres.h" #include "fmgr.h" #include "utils/builtins.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif extern Datum type_of (PG_FUNCTION_ARGS); Datum type_of(PG_FUNCTION_ARGS) { Oid typeoid; Datum result; char *typename; typeoid = get_fn_expr_argtype(fcinfo->flinfo, 0); if (typeoid == InvalidOid) { ereport( ERROR, ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine data type of argumentto type_of()") ) ); } typename = format_type_be(typeoid); result = DirectFunctionCall1(textin, CStringGetDatum(typename));PG_RETURN_DATUM(result); } And I load the function like so: CREATE OR REPLACE FUNCTION type_of(anyelement) RETURNS text AS '$libdir/type_of' LANGUAGE C STRICT IMMUTABLE; Thanks, DAvid
"David E. Wheeler" <david@kineticode.com> writes: > Here's the complete code: Looks like you forgot PG_FUNCTION_INFO_V1(), so what's being passed to this isn't an fcinfo ... regards, tom lane
On Sep 1, 2008, at 16:55, Tom Lane wrote: > "David E. Wheeler" <david@kineticode.com> writes: >> Here's the complete code: > > Looks like you forgot PG_FUNCTION_INFO_V1(), so what's being passed to > this isn't an fcinfo ... Bah! I knew I had to be missing something really fundamental. Thanks Tom. BTW, anyone have any interest in this function in core? Its purpose is to return a string identifying the data type of its argument. It's useful for dynamically building queries to pass to PL/pgSQL's EXECUTE statement when you don't know the data types of values you're putting into the statement. Thanks, David
On Tue, Sep 2, 2008 at 2:03 PM, David E. Wheeler <david@kineticode.com> wrote: > BTW, anyone have any interest in this function in core? Its purpose is to > return a string identifying the data type of its argument. It's useful for > dynamically building queries to pass to PL/pgSQL's EXECUTE statement when > you don't know the data types of values you're putting into the statement. > +1. I've been using a variation on this theme (it returns the type OID, not a text value) for a couple of years. I find it very helpful for troubleshooting queries where I need to track the cast/coercion behaviour. For the record, my version of the function is simply: PG_FUNCTION_INFO_V1(gettype); Datum gettype(PG_FUNCTION_ARGS) { PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0)); } CREATE OR REPLACE FUNCTION gettype(anyelement) RETURNS oid AS'libname', 'gettype'LANGUAGE C IMMUTABLE STRICT; Cheers, BJ
"Neil Conway" <neilc@samurai.com> writes: > On Mon, Sep 1, 2008 at 9:35 PM, Brendan Jurd <direvus@gmail.com> wrote: >> +1. I've been using a variation on this theme (it returns the type >> OID, not a text value) for a couple of years. > Returning regtype seems like the natural choice. I was just about to say the same. Another thought is that you might as well declare the input type as "any" --- using "anyelement" just causes the parser to waste a few cycles checking for argument/result type conflicts that can't exist here. I don't like gettype() as the function name: it's not particularly readable and it seems to infringe on application namespace. It should be pg_something ... maybe pg_typeof() ? Oh, another thing: it shouldn't be STRICT. Nulls have perfectly good types. regards, tom lane
On Tue, Sep 2, 2008 at 2:57 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote: > "Neil Conway" <neilc@samurai.com> writes: > >> Returning regtype seems like the natural choice. > > I was just about to say the same. Yes. In fact, the way I typically use the function is to write gettype(whatever)::regtype. I was too lazy to modify the function to return regtype, and with "::regtype" weighing in at a mere 9 keystrokes there wasn't much motivation =) > Another thought is that you might as > well declare the input type as "any" --- using "anyelement" just causes > the parser to waste a few cycles checking for argument/result type > conflicts that can't exist here. Good tip. > I don't like gettype() as the function name: it's not particularly > readable and it seems to infringe on application namespace. It should > be pg_something ... maybe pg_typeof() ? > Sure, pg_typeof() sounds good. I only used gettype() because it was a familiar name (PHP has an analogous builtin function called gettype()). > Oh, another thing: it shouldn't be STRICT. Nulls have perfectly good > types. > Agreed. Barring any further comments/objections, I'll go ahead and prepare a patch to add this to core. Cheers, BJ
On Sep 1, 2008, at 22:31, Brendan Jurd wrote: >> Oh, another thing: it shouldn't be STRICT. Nulls have perfectly good >> types. > > Agreed. > > Barring any further comments/objections, I'll go ahead and prepare a > patch to add this to core. So it will return a text representation or an Oid? Best, David
On Tue, Sep 02, 2008 at 08:58:04AM -0700, David E. Wheeler wrote: > >Barring any further comments/objections, I'll go ahead and prepare a > >patch to add this to core. > > So it will return a text representation or an Oid? Hopefully regtype. The function doesn't need changing, but then users can get a text representation of the type easily then. Have a nice day, -- Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/ > Please line up in a tree and maintain the heap invariant while > boarding. Thank you for flying nlogn airlines.
On Sep 2, 2008, at 08:58, David E. Wheeler wrote: > On Sep 1, 2008, at 22:31, Brendan Jurd wrote: > >>> Oh, another thing: it shouldn't be STRICT. Nulls have perfectly >>> good >>> types. >> >> Agreed. >> >> Barring any further comments/objections, I'll go ahead and prepare a >> patch to add this to core. > > So it will return a text representation or an Oid? Looks like regtype displays as an integer. So how about pg_regtypeof() and pg_typeof()? PG_FUNCTION_INFO_V1(pg_regtypeof); Datum pg_regtypeof(PG_FUNCTION_ARGS) { PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0)); } PG_FUNCTION_INFO_V1(pg_typeof); Datum pg_typeof(PG_FUNCTION_ARGS) { Oid typeoid; typeoid = get_fn_expr_argtype(fcinfo->flinfo, 0); if (typeoid == InvalidOid) { ereport( ERROR, ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine data type of argumentto pg_typeof()") ) ); } PG_RETURN_DATUM(CStringGetDatum(format_type_be(typeoid))); } Best, David
On Sep 2, 2008, at 10:43, David E. Wheeler wrote: > Looks like regtype displays as an integer. So how about > pg_regtypeof() and pg_typeof()? Sorry, make that: PG_FUNCTION_INFO_V1(pg_regtypeof); Datum pg_regtypeof(PG_FUNCTION_ARGS) { PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0)); } PG_FUNCTION_INFO_V1(pg_typeof); Datum pg_typeof(PG_FUNCTION_ARGS) { Oid typeoid; typeoid = get_fn_expr_argtype(fcinfo->flinfo, 0); if (typeoid == InvalidOid) { ereport( ERROR, ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine data type of argumentto pg_typeof()") ) ); } PG_RETURN_DATUM(DirectFunctionCall1(textin, CStringGetDatum(format_type_be(typeoid)))); } Best, David
"David E. Wheeler" <david@kineticode.com> writes: > Looks like regtype displays as an integer. Better try that again. regression=# select 1043::regtype; regtype -------------------character varying (1 row) regression=# I see no need for two functions here. regards, tom lane
On Sep 2, 2008, at 11:06, Tom Lane wrote: > Better try that again. > > regression=# select 1043::regtype; > regtype > ------------------- > character varying > (1 row) > > regression=# > > I see no need for two functions here. Oh. I tried: try=# select 1::regtype; regtype --------- 1 I had assumed that 1 would be some type, but apparently not. Oops. Best, David