]> granicus.if.org Git - postgresql/commitdiff
Fix error handling in PLy_spi_execute_fetch_result().
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 20 Jul 2013 16:44:37 +0000 (12:44 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 20 Jul 2013 16:44:37 +0000 (12:44 -0400)
If an error is thrown out of the datatype I/O functions called by this
function, we need to do subtransaction cleanup, which the previous coding
entirely failed to do.  Fortunately, both existing callers of this function
already have proper cleanup logic, so re-throwing the exception is enough.

Also, postpone creation of the resultset tupdesc until after the I/O
conversions are complete, so that we won't leak memory in TopMemoryContext
when such an error happens.

src/pl/plpython/plpy_spi.c

index c9182eb71a3002b605988e4c775ac7d5113a5653..ed1f21cd6a51a83bd57157f16af003654b47b46c 100644 (file)
@@ -407,16 +407,6 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
                {
                        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)
                        {
                                Py_DECREF(result->rows);
@@ -425,23 +415,33 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
                                PLy_input_tuple_funcs(&args, tuptable->tupdesc);
                                for (i = 0; i < rows; i++)
                                {
-                                       PyObject   *row = PLyDict_FromTuple(&args, tuptable->vals[i],
+                                       PyObject   *row = PLyDict_FromTuple(&args,
+                                                                                                               tuptable->vals[i],
                                                                                                                tuptable->tupdesc);
 
                                        PyList_SetItem(result->rows, i, row);
                                }
                        }
+
+                       /*
+                        * 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.  (Do this as late as
+                        * possible, to minimize the number of ways the tupdesc could get
+                        * leaked due to errors.)
+                        */
+                       oldcontext2 = MemoryContextSwitchTo(TopMemoryContext);
+                       result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
+                       MemoryContextSwitchTo(oldcontext2);
                }
                PG_CATCH();
                {
                        MemoryContextSwitchTo(oldcontext);
-                       if (!PyErr_Occurred())
-                               PLy_exception_set(PLy_exc_error,
-                                          "unrecognized error in PLy_spi_execute_fetch_result");
                        PLy_typeinfo_dealloc(&args);
                        SPI_freetuptable(tuptable);
                        Py_DECREF(result);
-                       return NULL;
+                       PG_RE_THROW();
                }
                PG_END_TRY();