On 24/10/10 00:32, Jan Urbański wrote: > On 21/10/10 20:48, Alvaro Herrera wrote: >> ... and presumably somebody can fix the real bug that Jean-Baptiste hit, >> too. > > AFAICS the error comes from PLy_function_handler disconnecting from SPI > after calling into the Python code and then going ahead and reading the > result from the iterator.
Here's a patch with a fix for that bug. Cheers, Jan
*** src/pl/plpython/expected/plpython_setof.out --- src/pl/plpython/expected/plpython_setof.out 2010-11-14 17:38:39.000000000 +0100 *************** *** 31,36 **** --- 31,44 ---- return self.icontent return producer(count, content) $$ LANGUAGE plpythonu; + CREATE FUNCTION test_setof_spi_in_iterator() RETURNS SETOF text AS + $$ + for s in ('Hello', 'Brave', 'New', 'World'): + plpy.execute('select 1') + yield s + plpy.execute('select 2') + $$ + LANGUAGE plpythonu; -- Test set returning functions SELECT test_setof_as_list(0, 'list'); test_setof_as_list *************** *** 107,109 **** --- 115,126 ---- (2 rows) + SELECT test_setof_spi_in_iterator(); + test_setof_spi_in_iterator + ---------------------------- + Hello + Brave + New + World + (4 rows) + *** src/pl/plpython/plpython.c --- src/pl/plpython/plpython.c 2010-11-14 17:38:39.000000000 +0100 *************** *** 1000,1012 **** } /* ! * Disconnect from SPI manager and then create the return values datum ! * (if the input function does a palloc for it this must not be ! * allocated in the SPI memory context because SPI_finish would free ! * it). */ - if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish failed"); if (proc->is_setof) { --- 1000,1010 ---- } /* ! * Cannot disconnect from SPI yet, because in case of a SRF returning a ! * Python iterator we will use PyIter_Next() which calls back into ! * Python code, which can contain calls to SPI functions. In that case ! * we will disconnect from SPI after the iterator is exhausted. */ if (proc->is_setof) { *************** *** 1064,1074 **** --- 1062,1085 ---- (errcode(ERRCODE_DATA_EXCEPTION), errmsg("error fetching next item from iterator"))); + /* Disconnect from the SPI manager before returning. */ + if (SPI_finish() != SPI_OK_FINISH) + elog(ERROR, "SPI_finish failed"); + fcinfo->isnull = true; return (Datum) NULL; } } + /* + * Disconnect from SPI manager and then create the return values datum + * (if the input function does a palloc for it this must not be + * allocated in the SPI memory context because SPI_finish would free + * it). + */ + if (SPI_finish() != SPI_OK_FINISH) + elog(ERROR, "SPI_finish failed"); + plerrcontext.callback = plpython_return_error_callback; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; *** src/pl/plpython/sql/plpython_setof.sql --- src/pl/plpython/sql/plpython_setof.sql 2010-11-14 17:38:39.000000000 +0100 *************** *** 35,40 **** --- 35,50 ---- return producer(count, content) $$ LANGUAGE plpythonu; + CREATE FUNCTION test_setof_spi_in_iterator() RETURNS SETOF text AS + $$ + for s in ('Hello', 'Brave', 'New', 'World'): + plpy.execute('select 1') + yield s + plpy.execute('select 2') + $$ + LANGUAGE plpythonu; + + -- Test set returning functions SELECT test_setof_as_list(0, 'list'); *************** *** 51,53 **** --- 61,65 ---- SELECT test_setof_as_iterator(1, 'list'); SELECT test_setof_as_iterator(2, 'list'); SELECT test_setof_as_iterator(2, null); + + SELECT test_setof_spi_in_iterator();
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers