summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2013-07-20 16:44:37 +0000
committerTom Lane2013-07-20 16:45:02 +0000
commitc0977b465ad26857910cb0a37a2382e2429a7b9a (patch)
tree9d7c352a5516fcc25b46d42f9ad3ea50c3c8f1f8
parente8ceb47bd3b86fea9fcf0c30bc3e0ec33ad6616b (diff)
Fix error handling in PLy_spi_execute_fetch_result().
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.
-rw-r--r--src/pl/plpython/plpy_spi.c30
1 files changed, 15 insertions, 15 deletions
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 00156e6658e..44b29638beb 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -406,16 +406,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);
@@ -424,23 +414,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();