Thread: Polymorphic "setof record" function?
Hi list, I have written a function that returns a setof record. The function has a table name as a parameter and the resulting records have the same structure as this table. Is there any easy way to specify this when I call the function? If the table has many columns then it's annoying to specify all of them. I need something like: select * from myfunc('mytable') as x(like mytable) or select * from myfunc('mytable') as x(mytable%TYPE) Is there any solution for PostgreSQL 8.2? Regards, Christian -- Deriva GmbH Tel.: +49 551 489500-42 Financial IT and Consulting Fax: +49 551 489500-91 Hans-Böckler-Straße 2 http://www.deriva.de D-37079 Göttingen Deriva CA Certificate: http://www.deriva.de/deriva-ca.cer
2009/1/13 Christian Schröder <cs@deriva.de>: > Hi list, > I have written a function that returns a setof record. The function has a > table name as a parameter and the resulting records have the same structure > as this table. Is there any easy way to specify this when I call the > function? If the table has many columns then it's annoying to specify all of > them. > I need something like: > select * from myfunc('mytable') as x(like mytable) > or > select * from myfunc('mytable') as x(mytable%TYPE) > > Is there any solution for PostgreSQL 8.2? > Can make the function with text parametter (table name) and search in the catalog for the table?. Then you will have the table to get %TYPE... > Regards, > Christian > > -- > Deriva GmbH Tel.: +49 551 489500-42 > Financial IT and Consulting Fax: +49 551 489500-91 > Hans-Böckler-Straße 2 http://www.deriva.de > D-37079 Göttingen > > Deriva CA Certificate: http://www.deriva.de/deriva-ca.cer > > > > -- > Sent via pgsql-general mailing list (pgsql-general@postgresql.org) > To make changes to your subscription: > http://www.postgresql.org/mailpref/pgsql-general > -- Emanuel Calvo Franco ArPUG / AOSUG Member Postgresql Support & Admin
On Tue, Jan 13, 2009 at 02:50:49PM +0100, Christian Schrrrder wrote: > I have written a function that returns a setof record. The function has > a table name as a parameter and the resulting records have the same > structure as this table. Is there any easy way to specify this when I > call the function? If the table has many columns then it's annoying to > specify all of them. I'm struggling to understand PG as well. I'd expect to be able to use the normal :: cast operator, but it doesn't seem to function as expected. I came up with the following code: CREATE TEMP TABLE foo ( cola INTEGER, colb TEXT ); INSERT INTO foo (cola, colb) VALUES (1, 'hi'), (2, 'bye'), (3, 'hello'), (4, 'testing'); SELECT (x::foo).cola FROM (SELECT x::record FROM foo x LIMIT 10) x; CREATE FUNCTION bar() RETURNS SETOF RECORD LANGUAGE SQL AS $$ SELECT * FROM foo LIMIT 10; $$; SELECT (x::foo).cola FROM ( SELECT bar()) AS xxx(x); I get "cannot cast type record to foo" from the final query, which I don't understand at all. It suggests that casting something to a value of type RECORD sometimes keeps the real type information around, and sometimes not. Why? Sam
On 1/13/09, Christian Schröder <cs@deriva.de> wrote: > Hi list, > I have written a function that returns a setof record. The function has a > table name as a parameter and the resulting records have the same structure > as this table. Is there any easy way to specify this when I call the > function? If the table has many columns then it's annoying to specify all of > them. > I need something like: > select * from myfunc('mytable') as x(like mytable) > or > select * from myfunc('mytable') as x(mytable%TYPE) > > Is there any solution for PostgreSQL 8.2? Unfortunately to the best of my knowledge there is no way to do this. I think what you want is to have sql functions that specialize on type in the way that templates do in C++. This is _not_ the same as polymorhphic functions(anyelement, etc), because you would _end_up_with_as_separate_plan_per_type_ (and other reasons). Polymorphic functions are more similar to how inheritance in c++ works...you operate on the 'base' type. The type inferring operator (%type) is only part of the problem, you need to be able to create functions that it is known to the planner that it's template style: IMHO, this is a better abstraction than our current anyX pseudotypes, outside of the anyarray tricks. merlin
On Wed, 14 Jan 2009 11:46:29 -0500 "Merlin Moncure" <mmoncure@gmail.com> wrote: > On 1/13/09, Christian Schröder <cs@deriva.de> wrote: > > Hi list, > > I have written a function that returns a setof record. The > > function has a table name as a parameter and the resulting > > records have the same structure as this table. Is there any easy > > way to specify this when I call the function? If the table has > > many columns then it's annoying to specify all of them. > > I need something like: > > select * from myfunc('mytable') as x(like mytable) > > or > > select * from myfunc('mytable') as x(mytable%TYPE) > > > > Is there any solution for PostgreSQL 8.2? > Unfortunately to the best of my knowledge there is no way to do > this. I think what you want is to have sql functions that > specialize on type in the way that templates do in C++. > This is _not_ the same as polymorhphic functions(anyelement, etc), > because you would _end_up_with_as_separate_plan_per_type_ (and > other reasons). Polymorphic functions are more similar to how > inheritance in c++ works...you operate on the 'base' type. > The type inferring operator (%type) is only part of the problem, > you need to be able to create functions that it is known to the > planner that it's template style: > > IMHO, this is a better abstraction than our current anyX > pseudotypes, outside of the anyarray tricks. I still haven't got the time to use them, but wouldn't refcursor help? Unfortunately I didn't find very enlightening examples of refcursors use around. -- Ivan Sergio Borgonovo http://www.webthatworks.it
Merlin Moncure wrote: > On 1/13/09, Christian Schröder <cs@deriva.de> wrote: > >> Hi list, >> I have written a function that returns a setof record. The function has a >> table name as a parameter and the resulting records have the same structure >> as this table. Is there any easy way to specify this when I call the >> function? If the table has many columns then it's annoying to specify all of >> them. >> I need something like: >> select * from myfunc('mytable') as x(like mytable) >> or >> select * from myfunc('mytable') as x(mytable%TYPE) >> >> Is there any solution for PostgreSQL 8.2? >> > > Unfortunately to the best of my knowledge there is no way to do this. > I think what you want is to have sql functions that specialize on > type in the way that templates do in C++. > That would certainly be the best solution, but I would also be happy with some syntactic sugar: The function may still be declared as returning a set of records, so that I would still have to declare their actual return type in the query. However, I would like to have an easy way to express: "the record will have the same structure as table x". Regards, Christian -- Deriva GmbH Tel.: +49 551 489500-42 Financial IT and Consulting Fax: +49 551 489500-91 Hans-Böckler-Straße 2 http://www.deriva.de D-37079 Göttingen Deriva CA Certificate: http://www.deriva.de/deriva-ca.cer
On Thu, Jan 15, 2009 at 4:57 AM, Christian Schröder <cs@deriva.de> wrote: > Merlin Moncure wrote: >>> them. >>> I need something like: >>> select * from myfunc('mytable') as x(like mytable) >>> or >>> select * from myfunc('mytable') as x(mytable%TYPE) >>> >>> Is there any solution for PostgreSQL 8.2? >>> >> >> Unfortunately to the best of my knowledge there is no way to do this. >> I think what you want is to have sql functions that specialize on >> type in the way that templates do in C++. >> > > That would certainly be the best solution, but I would also be happy with > some syntactic sugar: The function may still be declared as returning a set > of records, so that I would still have to declare their actual return type > in the query. However, I would like to have an easy way to express: "the > record will have the same structure as table x". There is a circuitous way to do this that sometimes works. Declare your function to return text and do this inside the function body (for example): create or replace function func() returns text as $$ select foo::text from foo limit 5; $$ language sql; select func::foo from (select func()) q; Couple of notes here: *) obviously, the idea here is to use dynamic-sql to return different table types based on inputs *) can only upcast to one table per function call (but can return varying record types based if left in text) *) record::text casts I think were introduced in 8.3. There is a more complex way to do it in 8.2 that is probably not worth the effort. *) record::text casts are not really reflexive. null fields are an issue or example. merlin