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 returning tuples
--
{
if (!proc->is_setof || proc->setof == NULL)
{
- /* Simple type returning function or first time for SETOF function */
+ /*
+ * Simple type returning function or first time for SETOF function:
+ * actually execute the function.
+ */
plargs = PLy_function_build_args(fcinfo, proc);
plrv = PLy_procedure_call(proc, "args", plargs);
if (!proc->is_setof)
}
/*
- * 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 it returns a set, call the iterator to get the next return item.
+ * We stay in the SPI context while doing this, because PyIter_Next()
+ * calls back into Python code which might contain SPI calls.
*/
- if (SPI_finish() != SPI_OK_FINISH)
- elog(ERROR, "SPI_finish failed");
-
if (proc->is_setof)
{
bool has_error = false;
(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");
+
/*
* If the function is declared to return void, the Python return value
* must be None. For void-returning functions, we also treat a None
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 returning tuples
SELECT test_setof_as_iterator(2, 'list');
SELECT test_setof_as_iterator(2, null);
+SELECT test_setof_spi_in_iterator();
+
-- Test tuple returning functions
SELECT * FROM test_table_record_as('dict', null, null, false);
SELECT * FROM test_table_record_as('dict', 'one', null, false);