mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
   inane, useless, annoying, and often misleading comments. Here's
   a sample: "plperl_init_all() - Initialize all".
   (I have tried to add some useful comments here and there, and will
   continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
   to return the result set, based on the PL/PgSQL model.
   There are two major consequences: result sets will spill to disk when
   they can no longer fit in work_mem; and "select foo_srf()" no longer
   works. (I didn't lose sleep over the latter, since that form is not
   valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
   would cause empty functions to fail in bizarre ways. I suspect that
   there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
   function, to make it possible to expose the functionality to
   Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
    create or replace function foo() returns setof record as $$
    $i = 0;
    for ("World", "PostgreSQL", "PL/Perl") {
        spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
    }
    return;
    $$ language plperl;
    select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
		
	
			
		
			
				
	
	
		
			108 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
/* this must be first: */
 | 
						|
#include "postgres.h"
 | 
						|
/* Defined by Perl */
 | 
						|
#undef _
 | 
						|
 | 
						|
/* perl stuff */
 | 
						|
#include "EXTERN.h"
 | 
						|
#include "perl.h"
 | 
						|
#include "XSUB.h"
 | 
						|
#include "ppport.h"
 | 
						|
 | 
						|
#include "spi_internal.h"
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Implementation of plperl's elog() function
 | 
						|
 *
 | 
						|
 * If the error level is less than ERROR, we'll just emit the message and
 | 
						|
 * return.  When it is ERROR, elog() will longjmp, which we catch and
 | 
						|
 * turn into a Perl croak().  Note we are assuming that elog() can't have
 | 
						|
 * any internal failures that are so bad as to require a transaction abort.
 | 
						|
 *
 | 
						|
 * This is out-of-line to suppress "might be clobbered by longjmp" warnings.
 | 
						|
 */
 | 
						|
static void
 | 
						|
do_spi_elog(int level, char *message)
 | 
						|
{
 | 
						|
	MemoryContext oldcontext = CurrentMemoryContext;
 | 
						|
 | 
						|
	PG_TRY();
 | 
						|
	{
 | 
						|
		elog(level, "%s", message);
 | 
						|
	}
 | 
						|
	PG_CATCH();
 | 
						|
	{
 | 
						|
		ErrorData  *edata;
 | 
						|
 | 
						|
		/* Must reset elog.c's state */
 | 
						|
		MemoryContextSwitchTo(oldcontext);
 | 
						|
		edata = CopyErrorData();
 | 
						|
		FlushErrorState();
 | 
						|
 | 
						|
		/* Punt the error to Perl */
 | 
						|
		croak("%s", edata->message);
 | 
						|
	}
 | 
						|
	PG_END_TRY();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
MODULE = SPI PREFIX = spi_
 | 
						|
 | 
						|
PROTOTYPES: ENABLE
 | 
						|
VERSIONCHECK: DISABLE
 | 
						|
 | 
						|
void
 | 
						|
spi_elog(level, message)
 | 
						|
	int level
 | 
						|
	char* message
 | 
						|
	CODE:
 | 
						|
		if (level > ERROR)		/* no PANIC allowed thanks */
 | 
						|
			level = ERROR;
 | 
						|
		if (level < DEBUG5)
 | 
						|
			level = DEBUG5;
 | 
						|
		do_spi_elog(level, message);
 | 
						|
 | 
						|
int
 | 
						|
spi_DEBUG()
 | 
						|
 | 
						|
int
 | 
						|
spi_LOG()
 | 
						|
 | 
						|
int
 | 
						|
spi_INFO()
 | 
						|
 | 
						|
int
 | 
						|
spi_NOTICE()
 | 
						|
 | 
						|
int
 | 
						|
spi_WARNING()
 | 
						|
 | 
						|
int
 | 
						|
spi_ERROR()
 | 
						|
 | 
						|
SV*
 | 
						|
spi_spi_exec_query(query, ...)
 | 
						|
	char* query;
 | 
						|
	PREINIT:
 | 
						|
		HV *ret_hash;
 | 
						|
		int limit = 0;
 | 
						|
	CODE:
 | 
						|
		if (items > 2)
 | 
						|
			croak("Usage: spi_exec_query(query, limit) or spi_exec_query(query)");
 | 
						|
		if (items == 2)
 | 
						|
			limit = SvIV(ST(1));
 | 
						|
		ret_hash = plperl_spi_exec(query, limit);
 | 
						|
		RETVAL = newRV_noinc((SV*) ret_hash);
 | 
						|
	OUTPUT:
 | 
						|
		RETVAL
 | 
						|
 | 
						|
void
 | 
						|
spi_spi_return_next(rv)
 | 
						|
	SV *rv;
 | 
						|
	CODE:
 | 
						|
		plperl_return_next(rv);
 | 
						|
 | 
						|
BOOT:
 | 
						|
    items = 0;  /* avoid 'unused variable' warning */
 |