Mysterious Bus Error with get_fn_expr_argtype()

Started by David E. Wheelerover 17 years ago12 messages
#1David E. Wheeler
david@kineticode.com

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 argument to
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

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: David E. Wheeler (#1)
Re: Mysterious Bus Error with get_fn_expr_argtype()

"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

#3David E. Wheeler
david@kineticode.com
In reply to: Tom Lane (#2)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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

#4Brendan Jurd
direvus@gmail.com
In reply to: David E. Wheeler (#3)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: David E. Wheeler (#1)
Re: Mysterious Bus Error with get_fn_expr_argtype()

"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

#6Brendan Jurd
direvus@gmail.com
In reply to: Tom Lane (#5)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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

#7David E. Wheeler
david@kineticode.com
In reply to: Brendan Jurd (#6)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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

#8Martijn van Oosterhout
kleptog@svana.org
In reply to: David E. Wheeler (#7)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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/

Show quoted text

Please line up in a tree and maintain the heap invariant while
boarding. Thank you for flying nlogn airlines.

#9David E. Wheeler
david@kineticode.com
In reply to: David E. Wheeler (#7)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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 argument to
pg_typeof()")
)
);
}

PG_RETURN_DATUM(CStringGetDatum(format_type_be(typeoid)));
}

Best,

David

#10David E. Wheeler
david@kineticode.com
In reply to: David E. Wheeler (#9)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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 argument to
pg_typeof()")
)
);
}

PG_RETURN_DATUM(DirectFunctionCall1(textin,
CStringGetDatum(format_type_be(typeoid))));
}

Best,

David

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: David E. Wheeler (#9)
Re: Mysterious Bus Error with get_fn_expr_argtype()

"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

#12David E. Wheeler
david@kineticode.com
In reply to: Tom Lane (#11)
Re: Mysterious Bus Error with get_fn_expr_argtype()

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