Thread: returning composite types.

returning composite types.

From
Franco Bruno Borghesi
Date:
Hi guys.

I'm working with functions in my database, using plpgsql, but I reached a
point where I realize I'm missing a concept: how do I return composite types
from a function? I'll give you an example:

CREATE TYPE mytype AS(  val1 INTEGER,  val2 INTEGER,  val3 INTEGER,  val4 INTEGER
);

If I want my function to return a "mytype" type, should I declare it as:
CREATE FUNCTION myFunction() RETURNS mytype AS ...
or maybe
CREATE FUNCTION myFunction() RETURNS SETOF mytype AS ...

and in any case, inside the function, how should I declare the variable
holding the return value?:

DECLARE  result mytype;
BEGIN
...  RETURN result;
END;

or maybe

DECLARE  result mytype%ROWTYPE;
BEGIN
...  RETURN result;
END;

I've read the documentation and the examples in it, but I still don't
understand what the right way is. If you could give an example of a function
filling "mytipe" and returning it, it would really help me.

Thanks in advance.

Re: returning composite types.

From
"Jordan S. Jones"
Date:
Here is how I have been doing mine:<br /><br /><blockquote><tt>CREATE FUNCTION "myFunction" () RETURNS SETOF mytype<br
/>AS<br /> '<br /> DECLARE<br />     r      mytype%ROWTYPE;<br /> BEGIN<br />     FOR r IN [SELECT STATEMENT]<br />    
LOOP<br/>        RETURN NEXT r;<br />     END LOOP;<br />     RETURN;<br /> END;<br /> '<br /> LANGUAGE 'plpgsql';<br
/></tt></blockquote>Hope this Helps..<br /><br /> Jordan S. Jones<br /><br /><br /> Franco Bruno Borghesi wrote:<br
/><blockquotecite="mid200303282020.25997.franco@akyasociados.com.ar" type="cite"><pre wrap="">Hi guys.
 

I'm working with functions in my database, using plpgsql, but I reached a 
point where I realize I'm missing a concept: how do I return composite types 
from a function? I'll give you an example:

CREATE TYPE mytype AS(  val1 INTEGER,  val2 INTEGER,  val3 INTEGER,  val4 INTEGER   
);

If I want my function to return a "mytype" type, should I declare it as:
CREATE FUNCTION myFunction() RETURNS mytype AS ...
or maybe
CREATE FUNCTION myFunction() RETURNS SETOF mytype AS ...

and in any case, inside the function, how should I declare the variable 
holding the return value?:

DECLARE  result mytype;
BEGIN
...  RETURN result;   
END;   

or maybe      

DECLARE  result mytype%ROWTYPE;
BEGIN
...  RETURN result;   
END;   

I've read the documentation and the examples in it, but I still don't 
understand what the right way is. If you could give an example of a function 
filling "mytipe" and returning it, it would really help me.

Thanks in advance.  </pre></blockquote>

Re: returning composite types.

From
Franco Bruno Borghesi
Date:
ok, soy you're telling me that the only way to return a composite type is
using a set of them, even if I know my function will allways return 1 record.

And tell me: can I assign values to this record without using the "for" as you
did? maybe a SELECT INTO, or something.

I'll tell you what I'm trying to do, maybe that will help: I have 4 functions,
that do specific tasks, and they are called in a chained mode. I want the
first function in the chain to call the other functions, and return all the
results in a composite type, like this:

CREATE TYPE mytype AS( val1 INTEGER, val2 INTEGER, val3 INTEGER, val4 INTEGER
);

CREATE FUNCTION f1() RETURNS SETOF mytype AS '
DECLARE  result mytype%ROWTYPE;
BEGIN  result.val1=/*something*/;  SELECT * INTO result FROM f2(result);     RETURN NEXT result;  RETURN;
END;
' LANGUAGE 'plpgsql';

CREATE FUNCTION f2(mytype) RETURNS SETOF mytype AS '
DECLARE  result ALIAS FOR $1;
BEGIN  result.val2=2;  IF (result.val1>50) THEN     SELECT * INTO result FROM f3(result);           ELSE     SELECT *
INTOresult FROM f4(result);  END IF;        RETURN NEXT result;  RETURN; 
END;
' LANGUAGE 'plpgsql';

CREATE FUNCTION f3(mytype) RETURNS SETOF mytype AS '
DECLARE  result ALIAS FOR $1;
BEGIN  /*do something with result*/  RETURN NEXT result;  RETURN;
END;
' LANGUAGE 'plpgsql';
CREATE FUNCTION f4(mytype) RETURNS SETOF mytype AS '
DECLARE  result ALIAS FOR $1;
BEGIN  /*do something with result*/  RETURN NEXT result;  RETURN;
END;
' LANGUAGE 'plpgsql';

In a programming language I would pass mytype by reference, and I was trying
to something like that here in plpgsql.


On Friday 28 March 2003 21:32, Jordan S. Jones wrote:
> Here is how I have been doing mine:
>
>     CREATE FUNCTION "myFunction" () RETURNS SETOF mytype
>     AS
>     '
>     DECLARE
>         r      mytype%ROWTYPE;
>     BEGIN
>         FOR r IN [SELECT STATEMENT]
>         LOOP
>            RETURN NEXT r;
>         END LOOP;
>         RETURN;
>     END;
>     '
>     LANGUAGE 'plpgsql';
>
> Hope this Helps..
>
> Jordan S. Jones
>
> Franco Bruno Borghesi wrote:
> >Hi guys.
> >
> >I'm working with functions in my database, using plpgsql, but I reached a
> >point where I realize I'm missing a concept: how do I return composite
> > types from a function? I'll give you an example:
> >
> >CREATE TYPE mytype AS(
> >   val1 INTEGER,
> >   val2 INTEGER,
> >   val3 INTEGER,
> >   val4 INTEGER
> >);
> >
> >If I want my function to return a "mytype" type, should I declare it as:
> >CREATE FUNCTION myFunction() RETURNS mytype AS ...
> >or maybe
> >CREATE FUNCTION myFunction() RETURNS SETOF mytype AS ...
> >
> >and in any case, inside the function, how should I declare the variable
> >holding the return value?:
> >
> >DECLARE
> >   result mytype;
> >BEGIN
> >...
> >   RETURN result;
> >END;
> >
> >or maybe
> >
> >DECLARE
> >   result mytype%ROWTYPE;
> >BEGIN
> >...
> >   RETURN result;
> >END;
> >
> >I've read the documentation and the examples in it, but I still don't
> >understand what the right way is. If you could give an example of a
> > function filling "mytipe" and returning it, it would really help me.
> >
> >Thanks in advance.

Re: returning composite types.

From
Joe Conway
Date:
Franco Bruno Borghesi wrote:
> ok, soy you're telling me that the only way to return a composite type is 
> using a set of them, even if I know my function will allways return 1 record.

Try this:

create type foo as (f1 int, f2 text);
create or replace function retfoo(int, text) returns foo as ' declare  result foo%ROWTYPE; begin  select into result
$1,$2;  return result; end;
 
' language 'plpgsql';

regression=# select * from retfoo(2,'b'); f1 | f2
----+----  2 | b
(1 row)

Joe



Re: returning composite types.

From
Franco Bruno Borghesi
Date:
yes, i was trying to do something like that, but it breaks always in the same
place, first I thought that it was because of the way I was assigning values
to the fields of my row, but now I'm beginning to think that the reason is
the way I pass the row to f2.

Here is the error:
franco=# SELECT f1();
WARNING:  Error occurred while executing PL/pgSQL function f1
WARNING:  line 5 at select into variables
ERROR:  Attribute "result" not found

CREATE TYPE mytype AS (val1 INTEGER, val2 INTEGER, val3 INTEGER);

CREATE OR REPLACE FUNCTION f1() RETURNS mytype AS '
DECLARE     result mytype%ROWTYPE;
BEGIN  result.val1:=1;     SELECT val2, val3 INTO result.val2, result.val3 FROM f2(result);  RETURN result;
END;
' LANGUAGE 'plpgsql';

CREATE OR REPLACE FUNCTION f2(mytype) RETURNS mytype AS '
DECLARE     arg ALIAS FOR $1;  result mytype%ROWTYPE;
BEGIN  arg.val2:=2;  arg.val3:=3;  SELECT arg.val1, arg.val2, arg.val3 INTO result.val1, result.val2,
result.val3;  RETURN result;
END;
' LANGUAGE 'plpgsql';

what do you guys think?

On Saturday 29 March 2003 13:49, Joe Conway wrote:
> Franco Bruno Borghesi wrote:
> > ok, soy you're telling me that the only way to return a composite type is
> > using a set of them, even if I know my function will allways return 1
> > record.
>
> Try this:
>
> create type foo as (f1 int, f2 text);
> create or replace function retfoo(int, text) returns foo as '
>   declare
>    result foo%ROWTYPE;
>   begin
>    select into result $1, $2;
>    return result;
>   end;
> ' language 'plpgsql';
>
> regression=# select * from retfoo(2,'b');
>   f1 | f2
> ----+----
>    2 | b
> (1 row)
>
> Joe

Re: returning composite types.

From
Joe Conway
Date:
Franco Bruno Borghesi wrote:
> yes, i was trying to do something like that, but it breaks always in the same 
> place, first I thought that it was because of the way I was assigning values 
> to the fields of my row, but now I'm beginning to think that the reason is 
> the way I pass the row to f2. 
> 
> Here is the error:
> franco=# SELECT f1();
> WARNING:  Error occurred while executing PL/pgSQL function f1
> WARNING:  line 5 at select into variables
> ERROR:  Attribute "result" not found
> 
> CREATE TYPE mytype AS (val1 INTEGER, val2 INTEGER, val3 INTEGER);
> 
> CREATE OR REPLACE FUNCTION f1() RETURNS mytype AS '
> DECLARE   
>    result mytype%ROWTYPE;
> BEGIN
>    result.val1:=1;   
>    SELECT val2, val3 INTO result.val2, result.val3 FROM f2(result);

It looks like plpgsql doesn't support composite type variables as 
arguments to functions that are called from within a function. The error 
is saying it cannot find an attribute named result -- that's because 
there is no *attribute* called result, there is a rowtype variable.

I'm not sure right off what is involved in fixing this, but you can 
always pass the individual attributes to f2:

CREATE TYPE mytype AS (val1 INTEGER, val2 INTEGER, val3 INTEGER);

CREATE OR REPLACE FUNCTION f2(int,int,int) RETURNS mytype AS '
DECLARE   arg1 ALIAS FOR $1;   arg2 ALIAS FOR $2;   arg3 ALIAS FOR $3;   newval2 int;   newval3 int;   result
mytype%ROWTYPE;
BEGIN   newval2 := coalesce(arg2,2) * arg1;   newval3 := coalesce(arg3,3) * arg1;   SELECT INTO result.val1,
result.val2,result.val3     arg1, newval2, newval3;   RETURN result;
 
END;
' LANGUAGE 'plpgsql';

CREATE OR REPLACE FUNCTION f1(int) RETURNS mytype AS '
DECLARE   result mytype%ROWTYPE;
BEGIN   result.val1:=$1;   SELECT INTO result.val2, result.val3 val2, val3     FROM f2(result.val1, result.val2,
result.val3);  RETURN result;
 
END;
' LANGUAGE 'plpgsql';

regression=# select * from f1(2); val1 | val2 | val3
------+------+------    2 |    4 |    6
(1 row)

HTH,

Joe



Re: returning composite types.

From
Franco Bruno Borghesi
Date:
so what you're saying is that it's not a syntactical error, it's just an
unsupported feature.

Ok then, I will just call my functions sending the values from my composite
type individually.

thanks guys!

On Saturday 29 March 2003 15:25, Joe Conway wrote:
> Franco Bruno Borghesi wrote:
> > yes, i was trying to do something like that, but it breaks always in the
> > same place, first I thought that it was because of the way I was
> > assigning values to the fields of my row, but now I'm beginning to think
> > that the reason is the way I pass the row to f2.
> >
> > Here is the error:
> > franco=# SELECT f1();
> > WARNING:  Error occurred while executing PL/pgSQL function f1
> > WARNING:  line 5 at select into variables
> > ERROR:  Attribute "result" not found
> >
> > CREATE TYPE mytype AS (val1 INTEGER, val2 INTEGER, val3 INTEGER);
> >
> > CREATE OR REPLACE FUNCTION f1() RETURNS mytype AS '
> > DECLARE
> >    result mytype%ROWTYPE;
> > BEGIN
> >    result.val1:=1;
> >    SELECT val2, val3 INTO result.val2, result.val3 FROM f2(result);
>
> It looks like plpgsql doesn't support composite type variables as
> arguments to functions that are called from within a function. The error
> is saying it cannot find an attribute named result -- that's because
> there is no *attribute* called result, there is a rowtype variable.
>
> I'm not sure right off what is involved in fixing this, but you can
> always pass the individual attributes to f2:
>
> CREATE TYPE mytype AS (val1 INTEGER, val2 INTEGER, val3 INTEGER);
>
> CREATE OR REPLACE FUNCTION f2(int,int,int) RETURNS mytype AS '
> DECLARE
>     arg1 ALIAS FOR $1;
>     arg2 ALIAS FOR $2;
>     arg3 ALIAS FOR $3;
>     newval2 int;
>     newval3 int;
>     result mytype%ROWTYPE;
> BEGIN
>     newval2 := coalesce(arg2,2) * arg1;
>     newval3 := coalesce(arg3,3) * arg1;
>     SELECT INTO result.val1, result.val2, result.val3
>       arg1, newval2, newval3;
>     RETURN result;
> END;
> ' LANGUAGE 'plpgsql';
>
> CREATE OR REPLACE FUNCTION f1(int) RETURNS mytype AS '
> DECLARE
>     result mytype%ROWTYPE;
> BEGIN
>     result.val1:=$1;
>     SELECT INTO result.val2, result.val3 val2, val3
>       FROM f2(result.val1, result.val2, result.val3);
>     RETURN result;
> END;
> ' LANGUAGE 'plpgsql';
>
> regression=# select * from f1(2);
>   val1 | val2 | val3
> ------+------+------
>      2 |    4 |    6
> (1 row)
>
> HTH,
>
> Joe