World
(4 rows)
+-- setof function with an SPI result set (used to crash because of
+-- memory management issues across multiple calls)
+CREATE OR REPLACE FUNCTION get_user_records()
+RETURNS SETOF users
+AS $$
+ return plpy.execute("SELECT * FROM users ORDER BY username")
+$$ LANGUAGE plpythonu;
+SELECT get_user_records();
+ get_user_records
+----------------------
+ (jane,doe,j_doe,1)
+ (john,doe,johnd,2)
+ (rick,smith,slash,4)
+ (willem,doe,w_doe,3)
+(4 rows)
+
#include "executor/spi_priv.h"
#include "mb/pg_wchar.h"
#include "parser/parse_type.h"
+#include "utils/memutils.h"
#include "utils/syscache.h"
#include "plpython.h"
oldcontext = CurrentMemoryContext;
PG_TRY();
{
+ MemoryContext oldcontext2;
+
+ /*
+ * Save tuple descriptor for later use by result set metadata
+ * functions. Save it in TopMemoryContext so that it survives
+ * outside of an SPI context. We trust that PLy_result_dealloc()
+ * will clean it up when the time is right.
+ */
+ oldcontext2 = MemoryContextSwitchTo(TopMemoryContext);
result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
+ MemoryContextSwitchTo(oldcontext2);
if (rows)
{
SELECT test_setof_as_iterator(2, null);
SELECT test_setof_spi_in_iterator();
+
+
+-- setof function with an SPI result set (used to crash because of
+-- memory management issues across multiple calls)
+
+CREATE OR REPLACE FUNCTION get_user_records()
+RETURNS SETOF users
+AS $$
+ return plpy.execute("SELECT * FROM users ORDER BY username")
+$$ LANGUAGE plpythonu;
+
+SELECT get_user_records();