Thread: Cursors and PHP
I found very little information on the web about how to return a cursor from plpgsql to PHP using PEAR::DB. Here's what I managed to tack together. It works but I want to make sure I'm not overlooking the obvious or doing something boneheaded here, like setting myself up for a database crash under load. Here's an example: ======================== PLPGSQL: CREATE OR REPLACE FUNCTION get_user_data(REFCURSOR, INTEGER) RETURNS REFCURSOR AS ' DECLARE v_cursor ALIAS FOR $1; v_user_id ALIAS FOR $2; BEGIN OPEN v_cursor FOR SELECT * FROM users WHERE user_id = v_user_id; RETURN v_cursor; END; ' LANGUAGE 'plpgsql'; ========================== PHP: $cursor = 'my_user'; $query = "SELECT get_user_data('$cursor', $user_id);FETCH ALL IN $cursor;"; $res =& $dbh->query($query); if (DB::isError($res)) { ... process the error } $row = $res->fetchRow(DB_FETCHMODE_ASSOC); $dbh->query("CLOSE $cursor;"); $res->free(); return $row; ============================ Question #1: Is this the way to do it? Question #2: I'm using a persistent database connection. To avoid leaving an open cursor laying around I make another call to close the cursor after the result set is fetched. Do I need to do this or will the cursor be closed implicitly by Apache/PHP after the page is delivered?
Steve Manes <smanes@magpie.com> writes: > $query = "SELECT get_user_data('$cursor', $user_id);FETCH ALL IN > $cursor;"; > $res =& $dbh->query($query); Hm. This will return two different, not-compatible result sets (the SELECT's output and then the FETCH's). I don't know how PHP is defined to react to that. It seems that it's just discarding the first result set and giving you the second, but is that specified behavior or is it a bug that may get fixed someday? Might be best to do this in two queries. > Question #2: I'm using a persistent database connection. To avoid > leaving an open cursor laying around I make another call to close the > cursor after the result set is fetched. Do I need to do this or will > the cursor be closed implicitly by Apache/PHP after the page is delivered? The backend will implicitly close the cursor at transaction end. If the connection-pooling code is set up to issue a COMMIT after the page is processed, you need not close the cursor separately. regards, tom lane
Tom Lane wrote: > Steve Manes <smanes@magpie.com> writes: > >> $query = "SELECT get_user_data('$cursor', $user_id);FETCH ALL IN >>$cursor;"; > > >> $res =& $dbh->query($query); > > > Hm. This will return two different, not-compatible result sets (the > SELECT's output and then the FETCH's). Without the FETCH in that compound PHP query however, nothing gets returned from the SELECT. I'm not sure why but maybe it's because PEAR::DB doesn't have any direct support for cursors so it's just grabbing a result set.
I'm not sure why you're doing it the exact way you are, but you basically just call the same commands within a pg_query as you would on the psql command line to make it work: begin declare mycurs cursor as select * from table fetch 10 rollback / commit