mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
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:
parent
d1cffe2f77
commit
6d92f2106f
@ -103,5 +103,21 @@ spi_return_next(rv)
|
|||||||
CODE:
|
CODE:
|
||||||
plperl_return_next(rv);
|
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:
|
BOOT:
|
||||||
items = 0; /* avoid 'unused variable' warning */
|
items = 0; /* avoid 'unused variable' warning */
|
||||||
|
@ -350,3 +350,20 @@ SELECT * from perl_srf_rn() AS (f1 INTEGER, f2 TEXT, f3 TEXT);
|
|||||||
3 | Hello | PL/Perl
|
3 | Hello | PL/Perl
|
||||||
(3 rows)
|
(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)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
* ENHANCEMENTS, OR MODIFICATIONS.
|
* ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
void plperl_init(void);
|
||||||
|
|
||||||
HV *plperl_spi_exec(char *query, int limit);
|
HV *plperl_spi_exec(char *query, int limit);
|
||||||
|
SV *plperl_spi_query(char *);
|
||||||
|
|
||||||
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
|
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
@ -229,6 +230,7 @@ plperl_safe_init(void)
|
|||||||
"$PLContainer->permit_only(':default');"
|
"$PLContainer->permit_only(':default');"
|
||||||
"$PLContainer->permit(qw[:base_math !:base_io sort time]);"
|
"$PLContainer->permit(qw[:base_math !:base_io sort time]);"
|
||||||
"$PLContainer->share(qw[&elog &spi_exec_query &return_next "
|
"$PLContainer->share(qw[&elog &spi_exec_query &return_next "
|
||||||
|
"&spi_query &spi_fetchrow "
|
||||||
"&DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED ]);"
|
"&DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED ]);"
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -1525,3 +1527,77 @@ plperl_return_next(SV *sv)
|
|||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
MemoryContextSwitchTo(cxt);
|
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;
|
||||||
|
}
|
||||||
|
@ -18,3 +18,5 @@ int spi_ERROR(void);
|
|||||||
/* this is actually in plperl.c */
|
/* this is actually in plperl.c */
|
||||||
HV *plperl_spi_exec(char *, int);
|
HV *plperl_spi_exec(char *, int);
|
||||||
void plperl_return_next(SV *);
|
void plperl_return_next(SV *);
|
||||||
|
SV *plperl_spi_query(char *);
|
||||||
|
SV *plperl_spi_fetchrow(char *);
|
||||||
|
@ -247,3 +247,16 @@ for ("World", "PostgreSQL", "PL/Perl") {
|
|||||||
return;
|
return;
|
||||||
$$ language plperl;
|
$$ language plperl;
|
||||||
SELECT * from perl_srf_rn() AS (f1 INTEGER, f2 TEXT, f3 TEXT);
|
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();
|
||||||
|
Loading…
Reference in New Issue
Block a user