The attached patch implements spi_query() and spi_fetchrow() functions

for PL/Perl, to avoid loading the entire result set into memory as the
existing spi_exec_query() function does.

Here's how one might use the new functions:

    $x = spi_query("select ...");
    while (defined ($y = spi_fetchrow($x))) {
        ...
        return_next(...);
    }

The changes do not affect the spi_exec_query() interface in any way.

Abhijit Menon-Sen
This commit is contained in:
Bruce Momjian 2005-07-10 15:19:43 +00:00
parent d1cffe2f77
commit 6d92f2106f
5 changed files with 125 additions and 1 deletions

View File

@ -103,5 +103,21 @@ spi_return_next(rv)
CODE:
plperl_return_next(rv);
SV *
spi_spi_query(query)
char *query;
CODE:
RETVAL = plperl_spi_query(query);
OUTPUT:
RETVAL
SV *
spi_spi_fetchrow(cursor)
char *cursor;
CODE:
RETVAL = plperl_spi_fetchrow(cursor);
OUTPUT:
RETVAL
BOOT:
items = 0; /* avoid 'unused variable' warning */

View File

@ -350,3 +350,20 @@ SELECT * from perl_srf_rn() AS (f1 INTEGER, f2 TEXT, f3 TEXT);
3 | Hello | PL/Perl
(3 rows)
--
-- Test spi_query/spi_fetchrow
--
CREATE OR REPLACE FUNCTION perl_spi_func() RETURNS SETOF INTEGER AS $$
$x = spi_query("select 1 as a union select 2 as a");
while (defined ($y = spi_fetchrow($x))) {
return_next($y->{a});
}
return;
$$ LANGUAGE plperl;
SELECT * from perl_spi_func();
perl_spi_func
---------------
1
2
(2 rows)

View File

@ -33,7 +33,7 @@
* ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.81 2005/07/06 22:44:49 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.82 2005/07/10 15:19:43 momjian Exp $
*
**********************************************************************/
@ -118,6 +118,7 @@ Datum plperl_validator(PG_FUNCTION_ARGS);
void plperl_init(void);
HV *plperl_spi_exec(char *query, int limit);
SV *plperl_spi_query(char *);
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
@ -229,6 +230,7 @@ plperl_safe_init(void)
"$PLContainer->permit_only(':default');"
"$PLContainer->permit(qw[:base_math !:base_io sort time]);"
"$PLContainer->share(qw[&elog &spi_exec_query &return_next "
"&spi_query &spi_fetchrow "
"&DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED ]);"
;
@ -1525,3 +1527,77 @@ plperl_return_next(SV *sv)
heap_freetuple(tuple);
MemoryContextSwitchTo(cxt);
}
SV *
plperl_spi_query(char *query)
{
SV *cursor;
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
BeginInternalSubTransaction(NULL);
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
void *plan;
Portal portal = NULL;
plan = SPI_prepare(query, 0, NULL);
if (plan)
portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
if (portal)
cursor = newSVpv(portal->name, 0);
else
cursor = newSV(0);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
SPI_restore_connection();
croak("%s", edata->message);
return NULL;
}
PG_END_TRY();
return cursor;
}
SV *
plperl_spi_fetchrow(char *cursor)
{
SV *row = newSV(0);
Portal p = SPI_cursor_find(cursor);
if (!p)
return row;
SPI_cursor_fetch(p, true, 1);
if (SPI_processed == 0) {
SPI_cursor_close(p);
return row;
}
row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
SPI_tuptable->tupdesc);
SPI_freetuptable(SPI_tuptable);
return row;
}

View File

@ -18,3 +18,5 @@ int spi_ERROR(void);
/* this is actually in plperl.c */
HV *plperl_spi_exec(char *, int);
void plperl_return_next(SV *);
SV *plperl_spi_query(char *);
SV *plperl_spi_fetchrow(char *);

View File

@ -247,3 +247,16 @@ for ("World", "PostgreSQL", "PL/Perl") {
return;
$$ language plperl;
SELECT * from perl_srf_rn() AS (f1 INTEGER, f2 TEXT, f3 TEXT);
--
-- Test spi_query/spi_fetchrow
--
CREATE OR REPLACE FUNCTION perl_spi_func() RETURNS SETOF INTEGER AS $$
$x = spi_query("select 1 as a union select 2 as a");
while (defined ($y = spi_fetchrow($x))) {
return_next($y->{a});
}
return;
$$ LANGUAGE plperl;
SELECT * from perl_spi_func();