Re: test datatype for ANY

Started by Michael Fuhrabout 21 years ago6 messagesgeneral
Jump to latest
#1Michael Fuhr
mike@fuhr.org

On Fri, Feb 11, 2005 at 08:40:53PM +0000, NosyMan wrote:

How can I test the type of a parameter passed to a function via ANY data type?
I want something like this:

CREATE OR REPLACE FUNCTION myfunction(_param ANY) RETURNS INTEGER AS $$
BEGIN
IF "_param IS OF INTEGER TYPE" THEN
-- do something with INTEGER
END IF;

PostgreSQL has an undocumented IS OF construct:

http://archives.postgresql.org/pgsql-general/2005-01/msg00398.php

Example:

IF param IS OF (integer) THEN
-- do integer stuff
ELSIF param IS OF (boolean) THEN
-- do boolean stuff
END IF;

Since IS OF is undocumented, I'd be careful about using it. I don't
know what plans the developers have for it, but I doubt they'll
feel sorry for you if your code breaks because they removed it or
changed its behavior.

See also the coltype() function I posted as part of the same thread
that mentioned IS OF:

http://archives.postgresql.org/pgsql-general/2005-01/msg00390.php

Using coltype(), the above code would look like this:

IF coltype(param) = 'integer'::regtype THEN
-- do integer stuff
ELSIF coltype(param) = 'boolean'::regtype THEN
-- do boolean stuff
END IF;

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Fuhr (#1)

Michael Fuhr <mike@fuhr.org> writes:

On Fri, Feb 11, 2005 at 08:40:53PM +0000, NosyMan wrote:

I want something like this:

CREATE OR REPLACE FUNCTION myfunction(_param ANY) RETURNS INTEGER AS $$

PostgreSQL has an undocumented IS OF construct:

... which won't help since IS OF is a parse-time test, and he needs a
run-time one. However, he'll never get that far anyway since plpgsql
doesn't allow ANY parameters. AFAIK the *only* way you could write such
a function is in C (using get_fn_expr_argtype()).

There are some limited cases you could handle in plpgsql using the
polymorphic-functions stuff (ie, ANYELEMENT not ANY) but it still has
no concept of a run-time type test.

regards, tom lane

#3Michael Fuhr
mike@fuhr.org
In reply to: Tom Lane (#2)

On Fri, Feb 11, 2005 at 02:32:31PM -0500, Tom Lane wrote:

There are some limited cases you could handle in plpgsql using the
polymorphic-functions stuff (ie, ANYELEMENT not ANY) but it still has
no concept of a run-time type test.

Eh? What am I misunderstanding then? The following done in 8.0.1:

CREATE FUNCTION argtype(param anyelement) RETURNS text AS $$
BEGIN
IF param IS OF (integer) THEN
RETURN 'integer';
ELSIF param IS OF (numeric) THEN
RETURN 'numeric';
ELSIF param IS OF (boolean) THEN
RETURN 'boolean';
ELSIF param IS OF (text) THEN
RETURN 'text';
ELSIF param IS OF (date) THEN
RETURN 'date';
END IF;

RETURN 'something else';
END;
$$ LANGUAGE plpgsql IMMUTABLE;

SELECT argtype(1);
argtype
---------
integer

SELECT argtype(1.2);
argtype
---------
numeric

SELECT argtype('test'::text);
argtype
---------
text

SELECT argtype(true);
argtype
---------
boolean

CREATE TABLE foo (id integer, foodate date);
INSERT INTO foo VALUES (1, current_date);
SELECT argtype(id) AS idtype, argtype(foodate) AS foodatetype FROM foo;
idtype | foodatetype
---------+-------------
integer | date

SELECT argtype(x) FROM (SELECT foodate FROM foo) AS s(x);
argtype
---------
date

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Fuhr (#3)

Michael Fuhr <mike@fuhr.org> writes:

On Fri, Feb 11, 2005 at 02:32:31PM -0500, Tom Lane wrote:

There are some limited cases you could handle in plpgsql using the
polymorphic-functions stuff (ie, ANYELEMENT not ANY) but it still has
no concept of a run-time type test.

Eh? What am I misunderstanding then? The following done in 8.0.1:

CREATE FUNCTION argtype(param anyelement) RETURNS text AS $$
BEGIN
IF param IS OF (integer) THEN
RETURN 'integer';
ELSIF param IS OF (numeric) THEN
RETURN 'numeric';
ELSIF param IS OF (boolean) THEN
RETURN 'boolean';
ELSIF param IS OF (text) THEN
RETURN 'text';
ELSIF param IS OF (date) THEN
RETURN 'date';
END IF;

RETURN 'something else';
END;
$$ LANGUAGE plpgsql IMMUTABLE;

[ thinks about that for awhile... ] Oh, I see. The reason this appears
to work is that plpgsql compiles a separate version of the function for
each actual parameter datatype that is used in a given session. So in
your example, you get a separate version for integer, numeric, etc.
Within each such version IS OF yields constants, but it "works right"
anyway.

I'm not sure if you can actually tell the difference between this
behavior and a true runtime test; except maybe that the backend would
get a bit bloated if you tried it on hundreds of different types in one
session.

regards, tom lane

#5Michael Fuhr
mike@fuhr.org
In reply to: Tom Lane (#4)

On Fri, Feb 11, 2005 at 03:37:01PM -0500, Tom Lane wrote:

[ thinks about that for awhile... ] Oh, I see. The reason this appears
to work is that plpgsql compiles a separate version of the function for
each actual parameter datatype that is used in a given session. So in
your example, you get a separate version for integer, numeric, etc.

Is that the general case for polymorphic functions?

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Fuhr (#5)

Michael Fuhr <mike@fuhr.org> writes:

On Fri, Feb 11, 2005 at 03:37:01PM -0500, Tom Lane wrote:

[ thinks about that for awhile... ] Oh, I see. The reason this appears
to work is that plpgsql compiles a separate version of the function for
each actual parameter datatype that is used in a given session. So in
your example, you get a separate version for integer, numeric, etc.

Is that the general case for polymorphic functions?

AFAIR all the PLs that support polymorphism do it that way. It's not
the only way it could be done, but it was the easiest way to bolt
polymorphism onto the existing code, which generally assumed that
every data value in the function has a fixed datatype.

regards, tom lane