dbTalk Databases Forums  

Returning arbitrary row sets from a function

comp.databases.postgresql.novice comp.databases.postgresql.novice


Discuss Returning arbitrary row sets from a function in the comp.databases.postgresql.novice forum.



Reply
 
Thread Tools Display Modes
  #1  
Old   
Gerard Mason
 
Posts: n/a

Default Returning arbitrary row sets from a function - 12-16-2003 , 08:20 AM






I would like to be able to deny client applications access to tables, and
insulate the database through an api of functions. Updater, inserter and
deleter functions look to be easy enough, but I am having a problem with
rowset-returning functions: how do I declare return types that are a SETOF
rows containing columns from an arbitrary query?

For example, suppose I want a function that returns a display-formatted
organisation, by joining with countries so that the country appears as a
name rather than an integer. What is currently happening is that the client
is sending the query:

SELECT o.name, c.name AS country, o.phone, o.mobile, o.fax, o.email,
o.website
FROM organisations o, countries c
WHERE c.id = o.country

What I'd *like* to happen is that the client calls, say, get_org_long() and
retrieves the same data. But what would the return type be? The only way I
can think to do it at the moment would be to create a view and return a
setof that view's rowtype, but that seems to be using a sledgehammer to
crack a nut. Also my first attempt at defining a test function that just
returns rows from the organisations table fails with the message:

ERROR: parser: parse error at or near "%"

It looks like this:

CREATE FUNCTION gems_test()
RETURNS SETOF organisations%ROWTYPE AS

That seems to be what the documentation is suggesting the return type should
be (the examples are very incomplete!), but it doesn't work (7.1.3, and I
can't upgrade without buying a new machine, which I don't want to do just
yet).


Cheers,
Gerard.

__________________________________________________ _______________
Hotmail messages direct to your mobile phone http://www.msn.co.uk/msnmobile


---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings


Reply With Quote
  #2  
Old   
Gerard Mason
 
Posts: n/a

Default Re: Returning arbitrary row sets from a function - 12-16-2003 , 09:16 AM






We appear to be having the same problems posting ;-)

Well, is it possible to run two different versions of postgresql
side-by-side on the same machine? I don't want to end up with a non-working
database just because I've made some stupid mistake installing a new
version, and then find that I can't revert back to the old one either.

Is it at least possible to have two different versions installed
side-by-side, even if you can only have one running at a time?


Cheers,
Gerard.


Quote:
From: Tom Lane <tgl (AT) sss (DOT) pgh.pa.us
To: "Gerard Mason" <gerardmason (AT) hotmail (DOT) com
CC: pgsql-novice (AT) postgresql (DOT) org
Subject: Re: [NOVICE] Returning arbitrary row sets from a function Date:
Tue, 16 Dec 2003 09:28:04 -0500
Received: from mc5-f1.hotmail.com ([65.54.252.8]) by mc5-s6.hotmail.com
with Microsoft SMTPSVC(5.0.2195.6713); Tue, 16 Dec 2003 06:33:44 -0800
Received: from noon.pghoster.com ([64.246.0.64]) by mc5-f1.hotmail.com with
Microsoft SMTPSVC(5.0.2195.6824); Tue, 16 Dec 2003 06:33:43 -0800
Received: from svr1.postgresql.org ([200.46.204.71] helo=postgresql.org)by
noon.pghoster.com with esmtp (Exim 4.24)id 1AWGCE-00055p-BQ; Tue, 16 Dec
2003 08:29:10 -0600
Received: from localhost (neptune.hub.org [200.46.204.2])by
svr1.postgresql.org (Postfix) with ESMTP id 5D1F5D1DBD0for
pgsql-novice-postgresql.org (AT) loc...postgresql.org>; Tue, 16 Dec 2003
14:28:33 +0000 (GMT)
Received: from svr1.postgresql.org ([200.46.204.71]) by localhost
(neptune.hub.org [200.46.204.2]) (amavisd-new, port 10024) with ESMTP id
43887-04 for <pgsql-novice-postgresql.org (AT) localhost (DOT) postgresql.org>; Tue,
16 Dec 2003 10:28:05 -0400 (AST)
Received: from sss.pgh.pa.us (unknown [192.204.191.242])by
svr1.postgresql.org (Postfix) with ESMTP id 8C331D1DC11for
pgsql-novice (AT) postgresql (DOT) org>; Tue, 16 Dec 2003 10:28:01 -0400 (AST)
Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1])by
sss.pgh.pa.us (8.12.10/8.12.10) with ESMTP id hBGES419021036;Tue, 16 Dec
2003 09:28:04 -0500 (EST)
X-Message-Info: pdGgd64CkwbpMDe6De87M4BVeULv8cLfHTWRrON5Om0=
X-Original-To: pgsql-novice-postgresql.org (AT) loc...postgresql.org
In-reply-to: <BAY7-F113qicRfZ7iHY0003b340 (AT) hotmail (DOT) com> References:
BAY7-F113qicRfZ7iHY0003b340 (AT) hotmail (DOT) com
Comments: In-reply-to "Gerard Mason" <gerardmason (AT) hotmail (DOT) com>message dated
"Tue, 16 Dec 2003 14:18:54 +0000"
Message-ID: <21035.1071584884 (AT) sss (DOT) pgh.pa.us
X-Virus-Scanned: by amavisd-new at postgresql.org
X-Mailing-List: pgsql-novice
Precedence: bulk
X-AntiAbuse: This header was added to track abuse, please include it with
any abuse report
X-AntiAbuse: Primary Hostname - noon.pghoster.com
X-AntiAbuse: Original Domain - hotmail.com
X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12]
X-AntiAbuse: Sender Address Domain - postgresql.org
Return-Path: pgsql-novice-owner+M9061 (AT) postgresql (DOT) org
X-OriginalArrivalTime: 16 Dec 2003 14:33:43.0294 (UTC)
FILETIME=[9B0DD9E0:01C3C3E1]

"Gerard Mason" <gerardmason (AT) hotmail (DOT) com> writes:
That seems to be what the documentation is suggesting the return type
should
be (the examples are very incomplete!), but it doesn't work (7.1.3,
^^^^^

That seems to be your problem ;-)

and I can't upgrade without buying a new machine, which I don't want
to do just yet).

Surely you can upgrade. If the problem is lack of RPMs for whatever OS
you are running, you could just compile Postgres from source.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo (AT) postgresql (DOT) org)
__________________________________________________ _______________
It's fast, it's easy and it's free. Get MSN Messenger today!
http://www.msn.co.uk/messenger


---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
joining column's datatypes do not match



Reply With Quote
  #3  
Old   
Joe Conway
 
Posts: n/a

Default Re: Returning arbitrary row sets from a function - 12-16-2003 , 12:12 PM



Gerard Mason wrote:
Quote:
how do I declare return types that are a SETOF rows containing
columns from an arbitrary query?
Declare the function to return "setof record" and then specify the
rowtype at runtime. See:
http://techdocs.postgresql.org/guide...rningFunctions
for a good tutorial.

Quote:
For example, suppose I want a function that returns a
display-formatted organisation, by joining with countries so that the
country appears as a name rather than an integer. What is currently
happening is that the client is sending the query:

SELECT o.name, c.name AS country, o.phone, o.mobile, o.fax, o.email,
o.website FROM organisations o, countries c WHERE c.id = o.country

What I'd *like* to happen is that the client calls, say,
get_org_long() and retrieves the same data. But what would the return
type be? The only way I can think to do it at the moment would be to
create a view and return a setof that view's rowtype, but that seems
to be using a sledgehammer to crack a nut.
Why? At some point you have to let the planner/optimizer know what the
data types are. There's no way around it. If you don't want to use a
view, see CREATE TYPE (which is more appropriate anyway):
http://www.postgresql.org/docs/curre...reatetype.html

In any case, why not just use a view -- it doesn't sound like you need a
function, at least not from your example.


Quote:
Also my first attempt at defining a test function that just returns
rows from the organisations table fails with the message:

ERROR: parser: parse error at or near "%"

It looks like this:

CREATE FUNCTION gems_test() RETURNS SETOF organisations%ROWTYPE AS
I can't see where you'd get that impression.

Quote:
That seems to be what the documentation is suggesting the return type
should be (the examples are very incomplete!), but it doesn't work
(7.1.3, and I can't upgrade without buying a new machine, which I
^^^^^

That seems to be your problem. You need to be on 7.3 at least.

Joe




---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo (AT) postgresql (DOT) org



Reply With Quote
  #4  
Old   
Joe Conway
 
Posts: n/a

Default Re: Returning arbitrary row sets from a function - 12-16-2003 , 12:23 PM



Gerard Mason wrote:
Quote:
Well, is it possible to run two different versions of postgresql
side-by-side on the same machine? I don't want to end up with a
non-working database just because I've made some stupid mistake
installing a new version, and then find that I can't revert back to the
old one either.
Is the original installed from source, or from some sort of package? If
the latter, reverting should be easy. Just make sure you save a copy of
the old data directory off to the side somewhere (taken *after* dumping
and shutting down the old postmaster).

Quote:
Is it at least possible to have two different versions installed
side-by-side, even if you can only have one running at a time?
You can, but it's tricky to get it right.

Joe



---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster



Reply With Quote
  #5  
Old   
Gerard Mason
 
Posts: n/a

Default Re: Returning arbitrary row sets from a function - 12-16-2003 , 03:17 PM



Thanks for those responses. Well in a fit of what I like to think was
professional courage (but which was probably more like simple lunacy) I
downloaded 7.4, read the install docs, typed "./configure" and "make" (very
exciting!), err..., downloaded GNU bison, typed "./configure" and "make"
(still exciting!), err..., downloaded GNU readline, typed "./configure" and
"make" (yawn!), typed "make install" (very exciting again!), and got
something that looked like a postgresql 7.4 installation in /usr/local.
Hurrah! This was fine, because the machine is running Mandrake 8.1, and the
pre-packaged postgresql is spread out in /usr/bin, /usr/lib, /var/lib, and
so on, so I didn't have to delete it.

A bit later and I was hacking away at /etc/rc.d/init.d/postgres, which at
least does run 7.4 when invoked from the command line, though I haven't
actually rebooted yet. The only minor annoyance was that psql, createdb,
pg_ctl and so on were binaries in /usr/bin, so I renamed them to *.bak and
linked to the ones in /usr/local/pgsql/bin -- I hope I've got them all, I
wouldn't want to be running a 7.1.2 (yes, not 7.1.3 as I thought) binary
against a 7.4 database...


Thanks for your encouragement,
Gerard.

__________________________________________________ _______________
It's fast, it's easy and it's free. Get MSN Messenger today!
http://www.msn.co.uk/messenger


---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faqs/FAQ.html


Reply With Quote
  #6  
Old   
Gerard Mason
 
Posts: n/a

Default Re: Returning arbitrary row sets from a function - 12-16-2003 , 07:30 PM



Back to my original objective, with my shiny new 7.4 installation I've
created a view, then a function that returns that view's rowtype. All goes
well in interactive psql (or at least it does once I tried "select * from
api.get_organisations_display( 1 )" rather than the "select
api.get_organisations_display( 1 )" that I was expecting to use).

However, the client will be calling via jdbc. Now of course, first thing I
did was try just replacing the original client sql with the version that I
found to work in psql above; and, very nicely, that also worked in the
client. However that takes the form of a java.sql.PreparedStatement, whereas
I presume I should be using a java.sql.CallableStatement instead. But when I
try this:

con = dataSource.getConnection();
CallableStatement stmt = con.prepareCall( "{call
api.get_organisations_display( ? )}" );
stmt.setInt( 1, 1 );
stmt.execute();
ResultSet rs = stmt.getResultSet()

then I get this error at the execute() line:

java.sql.SQLException: ERROR: cannot display a value of type record


Now I'm not the only one to have come across this problem, see
http://archives.postgresql.org/pgsql...3/msg00143.php for example,
but it's interesting to note that there IS in fact a benefit to doing things
this way, which is that you can restrict access rights to your tables while
also insulating the client from changes to the implementation -- the
traditional benefits of an API in fact. In this context, using a
CallableStatement would be the database-independent way of doing it, whereas
doing a "select * from api.get_organisations_display( 1 )"-style prepared
statement might make the client dependent on a postgresql back end.

This is a bit of a ramble rather than a question requiring an answer. What I
think I'll do is use views for selects, which will give me almost all the
same benefits, maybe use the "select * from api.function( x, y )" approach
for complicated stuff, and use functions for updates, inserts and deletes.


Cheers,
Gerard.

__________________________________________________ _______________
On the move? Get Hotmail on your mobile phone http://www.msn.co.uk/msnmobile


---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo (AT) postgresql (DOT) org so that your
message can get through to the mailing list cleanly


Reply With Quote
Reply




Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.3
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.