]> granicus.if.org Git - postgresql/commitdiff
PL/Python: Fix crash in functions returning SETOF and using SPI
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 2 May 2012 17:59:51 +0000 (20:59 +0300)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 2 May 2012 17:59:51 +0000 (20:59 +0300)
Allocate PLyResultObject.tupdesc in TopMemoryContext, because its
lifetime is the lifetime of the Python object and it shouldn't be
freed by some other memory context, such as one controlled by SPI.  We
trust that the Python object will clean up its own memory.

Before, this would crash the included regression test case by trying
to use memory that was already freed.

reported by Asif Naeem, analysis by Tom Lane

src/pl/plpython/expected/plpython_setof.out
src/pl/plpython/plpy_spi.c
src/pl/plpython/sql/plpython_setof.sql

index ac9765fc8824470629542c3a1297dd3a33bd8f3b..b3bbdd81238c82fd374d1f653a6ea50284dfe851 100644 (file)
@@ -124,3 +124,19 @@ SELECT test_setof_spi_in_iterator();
  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)
+
index cde3c08f967bd5d3aaf2af86fb7711905b9733e9..4bc3d96d5891408738c139a812d8faf59e2da8c1 100644 (file)
@@ -11,6 +11,7 @@
 #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"
@@ -403,7 +404,17 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
                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)
                        {
index 80a8d5b4c1ed78cb2a43f1dd7ce75cd6f3302a39..243f711dcc60dd8f9f005b25d406157c11ee620e 100644 (file)
@@ -62,3 +62,15 @@ SELECT test_setof_as_iterator(2, 'list');
 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();