Thread: Select + Functions + Composite Types: Behavior

Select + Functions + Composite Types: Behavior

From
"David Johnston"
Date:
Hey,

I notice the following behavior but have not seen it documented anywhere.  I
am curious if:

A.  I missed the documentation
B.  Is poorly documented
C.  It's a bug

If I put a function that returns a composite type into the FROM clause of a
SELECT query (and it - the function - is the only source for the query) the
"*" select list expands so that there is a single record for each component
of the composite type.

For ctype [id bigin, data varchar ]

SELECT * FROM compositereturningfunction()
Yields -> 2 columns (one for id and one for data)

SELECT *, literal FROM compositereturningfunction()
Yields -> 2 Columns (one for the composite and one for the literal)

I've read quite a bit about plpgsql and composite types and do not recall
anything about this specific default behavior and methods to force
(workaround) to the other behavior.  Specifically, there is NO WAY that I've
seen to write the query so that it only outputs a single column for the
composite.

Also, it appears that if the function returns a single scalar and a single
composite then the composite IS NOT expanded and you'd only get two columns
instead of a column for each scalar and one for each part of the composite.

The function I am defining is using an OUT parameter with a user-defined
composite type and no explicit RETURNS type defined in the pl/pgsql function
definition.

I have also noticed the following does not appear to work (pl/pgsql):
SELECT compositefunction() INTO compositevariable;

I tried adding a ", literal" after the function and before the INTO and
still get a similar result.  I can provide a more detailed example if
requested.

*** What I am seeing is an [invalid input syntax for integer: "(92,)"]
error. ***

My type is defined as ( id bigint, data ctype[] );

If I execute it as;  SELECT *, 1 FROM function() INTO ctype it works just
fine

SO...

pl/pgsql:
SELECT function() INTO ctype; Fails
SELECT function(), 1 INTO ctype; Fails
SELECT * FROM function() INTO ctype; Fails
SELECT *, 1 FROM function() INTO ctype; Success - ctype is fully mapped and
the '1' is ignored

Interactive:
SELECT function(); 1 column (ctype)
SELECT function(), 1; 2 columns (ctype, '1')
SELECT * FROM function(); 2 columns (ctype.1, ctype.2)
SELECT *, 1 FROM function(); 2 column (ctype, '1')

Is this all expected?  If so did I just miss seeing (or understanding) this
behavior documented.  The main reason I care about being able to NOT expand
the composite type is that I wish to pass the type through a function call
chain without touching it so that original caller can use it in whatever
form currently exists and the "creating function" and tweak its use of the
composite type without requiring every possible caller of the "creating
function" to change if the type has additional components added to it.

David J.




Re: Select + Functions + Composite Types: Behavior

From
Tom Lane
Date:
"David Johnston" <polobo@yahoo.com> writes:
> If I put a function that returns a composite type into the FROM clause of a
> SELECT query (and it - the function - is the only source for the query) the
> "*" select list expands so that there is a single record for each component
> of the composite type.

> SELECT * FROM compositereturningfunction()
> Yields -> 2 columns (one for id and one for data)

> I've read quite a bit about plpgsql and composite types and do not recall
> anything about this specific default behavior and methods to force
> (workaround) to the other behavior.

It's just like tables. Try

    select x from compositereturningfunction() x

            regards, tom lane

Re: Select + Functions + Composite Types: Behavior

From
"David Johnston"
Date:
SELECT * FROM compositereturningfunction() 'alias' INTO compositevariable;

Does the trick [note the '*' instead of 'x' in the select list]
If I put the name of the alias in the select list, like your example shows,
I still get the error (though honestly, I expected it to fail to execute...)

At least this doesn't LOOK like a hack/workaround...

I also do not get how "It's just like tables."  Admittedly I've just gotten
into composite types but I am well aware of the ability to alias a table in
the FROM clause but for my understanding the alias nominally makes things
easier OR is required for anonymous sub-selects (and it throws an exception
if a name is not given).  In this instance adding the alias changes behavior
which, while useful, is obscure.

Also, the behavior for those cases where the function appears in the FROM
clause makes sense to me overall; but in the
SELECT function() [INTO variable];
situation I interactively get a single column result of the proper type but
when I add the "INTO variable" (same type) It fails.  Adding a column alias
does not seem to help either (though the query/function still compiles).
Somehow (from the error) it appears that PostgreSQL is trying to assign the
entire (composite) result of the function call to the "first" component of
variable (the bigint/integer) and failing: ' invalid input syntax for
integer: "(92,)" '

All behavior noticed in 9.0.3

David J


-----Original Message-----
From: pgsql-general-owner@postgresql.org
[mailto:pgsql-general-owner@postgresql.org] On Behalf Of Tom Lane
Sent: Saturday, February 12, 2011 5:33 PM
To: David Johnston
Cc: pgsql-general@postgresql.org
Subject: Re: [GENERAL] Select + Functions + Composite Types: Behavior

"David Johnston" <polobo@yahoo.com> writes:
> If I put a function that returns a composite type into the FROM clause
> of a SELECT query (and it - the function - is the only source for the
> query) the "*" select list expands so that there is a single record
> for each component of the composite type.

> SELECT * FROM compositereturningfunction() Yields -> 2 columns (one
> for id and one for data)

> I've read quite a bit about plpgsql and composite types and do not
> recall anything about this specific default behavior and methods to
> force
> (workaround) to the other behavior.

It's just like tables. Try

    select x from compositereturningfunction() x

            regards, tom lane

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org) To make
changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


Re: Select + Functions + Composite Types: Behavior

From
"David Johnston"
Date:
Tom,

BTW, with the quick response you provided (THANKS!) I probably should have
pinged the list sooner in my search...

David J.

-----Original Message-----
From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
Sent: Saturday, February 12, 2011 5:33 PM
To: David Johnston
Cc: pgsql-general@postgresql.org
Subject: Re: [GENERAL] Select + Functions + Composite Types: Behavior

"David Johnston" <polobo@yahoo.com> writes:
> If I put a function that returns a composite type into the FROM clause
> of a SELECT query (and it - the function - is the only source for the
> query) the "*" select list expands so that there is a single record
> for each component of the composite type.

> SELECT * FROM compositereturningfunction() Yields -> 2 columns (one
> for id and one for data)

> I've read quite a bit about plpgsql and composite types and do not
> recall anything about this specific default behavior and methods to
> force
> (workaround) to the other behavior.

It's just like tables. Try

    select x from compositereturningfunction() x

            regards, tom lane


Re: Select + Functions + Composite Types: Behavior

From
"David Johnston"
Date:
Another similar situation that I'll bring here first:

I want to do:

SELECT createdid, eventresult
FROM createvehiclesaleimport() er
INTO targetid, evtresult;

But this gives a function compilation error: ' "evtresult" is not a scalar
variable '

createdid/targeted are boolean
eventresult/evtresult are CompositeType

createvehiclesaleimport() returns (Boolean, CompositeType)

I can do:

SELECT createdid, (eventresult).prop1, (eventresult).prop2
FROM createvehiclesaleimport() er
INTO targetid, evtresult.prop1, evtresult.prop2

(with or without the 'er' alias)

What's the magic syntax to allow me to chain "eventresult/evtresult" without
having to explicitly address it's scalar components.  This is different than
the other situation in that the called function now returns both a scalar as
well as a composite type whereas the other behavior occurred when the sole
output for the called function was a compositetype.

9.0.3/plpgsql

Thanks.

David J