Re: returning a recordset from PLpg/SQL - Mailing list pgsql-sql

From Joe Conway
Subject Re: returning a recordset from PLpg/SQL
Date
Msg-id 404384D0.4000108@joeconway.com
Whole thread Raw
In response to Re: returning a recordset from PLpg/SQL  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: returning a recordset from PLpg/SQL
List pgsql-sql
Tom Lane wrote:
> Stephan Szabo <sszabo@megazone.bigpanda.com> writes:
>>On Tue, 2 Mar 2004, Terence Kearns wrote:
>>>Well I haven't yet done anything because I couldn't get anything to
>>>compile which returned SETOF RECORD..
> 
>>As a starting point, SETOF "RECORD" is different from SETOF RECORD given
>>PostgreSQL's fold case to lower case for unquoted names.
> 
> Also, you can hardly expect a function to return a rowtype that doesn't
> even exist until the function executes --- how the heck is the parser
> supposed to make sense of the calling query?  So the "execute create
> type" part of this is nonsense, I'm afraid.  The SETOF RECORD mechanism
> will let you return a rowtype that is not known fully at the time the
> function is written, but the rowtype does have to be known when the
> calling query is parsed.
> 
> You might be able to replace the CREATE TYPE with an anonymous record
> type in the calling query:
> 
>     select ...
>     from details_for_profile(...) as x(doc_id int4,
>                                        doc_title varchar(256),
>                                        ...);

A small improvement is to do a two-step process. From your app, you 
first SELECT a function call that returns an SQL statement as a text 
string, specific to att_data_type. Then you execute that as a second 
step. For example:
--8<--------------------------

create table hdr(hid int primary key, context text);
insert into hdr values(1, 'test1');
insert into hdr values(2, 'test2');

create table att(aid int primary key, attname text, atttype text);
insert into att values (1, 'test_date', 'timestamp');
insert into att values (2, 'height', 'float8');
insert into att values (3, 'width', 'float8');
insert into att values (4, 'color', 'text');

create table det( did int primary key, hid int references hdr, aid int references att, val text
);
insert into det values(1,1,1,'15-mar-2004');
insert into det values(2,1,2,'3.14159');
insert into det values(3,1,3,'2.8');
insert into det values(4,1,4,'blue');
insert into det values(5,2,1,'16-mar-2004');
insert into det values(6,2,2,'2.34');
insert into det values(7,2,3,'3.28');
insert into det values(8,2,4,'red');

create or replace function exec_sql(int) returns setof record as '
DECLARE  lookup_row record;  v_atttype text := '''';  rec record;
BEGIN  FOR lookup_row IN SELECT * FROM att WHERE aid = $1  LOOP    v_atttype := lookup_row.atttype;  END LOOP;
  FOR rec IN execute ''SELECT h.hid, h.context, d.val::'' || v_atttype ||             '' FROM hdr h, att a, det d '' ||
           '' WHERE d.hid = h.hid and d.aid = a.aid and a.aid = '' || $1  LOOP    RETURN NEXT rec;  END LOOP;  RETURN;
 
END;
' language plpgsql;

create or replace function write_sql(int) returns text as '
DECLARE  v_attname text := '''';  v_atttype text := '''';  v_result text;  lookup_row record;
BEGIN  FOR lookup_row IN SELECT * FROM att WHERE aid = $1  LOOP    v_attname := lookup_row.attname;    v_atttype :=
lookup_row.atttype; END LOOP;  v_result := ''select hid, context, '' || v_attname ||              '' from exec_sql(''
||$1 || '') as t(hid int, context 
 
text, '' ||              v_attname || '' '' || v_atttype || '')'';  return v_result;
END;
' language plpgsql;

regression=# select write_sql(1);                                            write_sql
-------------------------------------------------------------------------------------------------- select hid, context,
test_datefrom exec_sql(1) as t(hid int, context 
 
text, test_date timestamp)
(1 row)

regression=# select hid, context, test_date from exec_sql(1) as t(hid 
int, context text, test_date timestamp); hid | context |      test_date
-----+---------+---------------------   1 | test1   | 2004-03-15 00:00:00   2 | test2   | 2004-03-16 00:00:00
(2 rows)

regression=# select write_sql(2);                                        write_sql
----------------------------------------------------------------------------------------- select hid, context, height
fromexec_sql(2) as t(hid int, context 
 
text, height float8)
(1 row)

regression=# select hid, context, height from exec_sql(2) as t(hid int, 
context text, height float8); hid | context | height
-----+---------+---------   1 | test1   | 3.14159   2 | test2   |    2.34
(2 rows)

regression=# select write_sql(3);                                       write_sql
--------------------------------------------------------------------------------------- select hid, context, width from
exec_sql(3)as t(hid int, context 
 
text, width float8)
(1 row)

regression=# select hid, context, width from exec_sql(3) as t(hid int, 
context text, width float8); hid | context | width
-----+---------+-------   1 | test1   |   2.8   2 | test2   |  3.28
(2 rows)

regression=# select write_sql(4);                                      write_sql
------------------------------------------------------------------------------------- select hid, context, color from
exec_sql(4)as t(hid int, context 
 
text, color text)
(1 row)

regression=# select hid, context, color from exec_sql(4) as t(hid int, 
context text, color text); hid | context | color
-----+---------+-------   1 | test1   | blue   2 | test2   | red
(2 rows)

--8<--------------------------

Hopefully this is close enough to what you are trying to do that it will 
give you some ideas.

HTH,

Joe



pgsql-sql by date:

Previous
From: Steve Crawford
Date:
Subject: Re: User defined types -- Social Security number...
Next
From: Michael Chaney
Date:
Subject: Re: User defined types -- Social Security number...