Thread: test datatype for ANY
Hi there, 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; IF "param is of BOOLEAN TYPE" THEN -- do something with BOOLEAN END IF; RETURN; END; $$ LANGUAGE plpgsql; Thanks, Nosy
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/
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
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/
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
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/
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