Skip to content

Commit c0977b4

Browse files
committed
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.
1 parent e8ceb47 commit c0977b4

File tree

1 file changed

+15
-15
lines changed

1 file changed

+15
-15
lines changed

src/pl/plpython/plpy_spi.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -406,16 +406,6 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
406406
{
407407
MemoryContext oldcontext2;
408408

409-
/*
410-
* Save tuple descriptor for later use by result set metadata
411-
* functions. Save it in TopMemoryContext so that it survives
412-
* outside of an SPI context. We trust that PLy_result_dealloc()
413-
* will clean it up when the time is right.
414-
*/
415-
oldcontext2 = MemoryContextSwitchTo(TopMemoryContext);
416-
result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
417-
MemoryContextSwitchTo(oldcontext2);
418-
419409
if (rows)
420410
{
421411
Py_DECREF(result->rows);
@@ -424,23 +414,33 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
424414
PLy_input_tuple_funcs(&args, tuptable->tupdesc);
425415
for (i = 0; i < rows; i++)
426416
{
427-
PyObject *row = PLyDict_FromTuple(&args, tuptable->vals[i],
417+
PyObject *row = PLyDict_FromTuple(&args,
418+
tuptable->vals[i],
428419
tuptable->tupdesc);
429420

430421
PyList_SetItem(result->rows, i, row);
431422
}
432423
}
424+
425+
/*
426+
* Save tuple descriptor for later use by result set metadata
427+
* functions. Save it in TopMemoryContext so that it survives
428+
* outside of an SPI context. We trust that PLy_result_dealloc()
429+
* will clean it up when the time is right. (Do this as late as
430+
* possible, to minimize the number of ways the tupdesc could get
431+
* leaked due to errors.)
432+
*/
433+
oldcontext2 = MemoryContextSwitchTo(TopMemoryContext);
434+
result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
435+
MemoryContextSwitchTo(oldcontext2);
433436
}
434437
PG_CATCH();
435438
{
436439
MemoryContextSwitchTo(oldcontext);
437-
if (!PyErr_Occurred())
438-
PLy_exception_set(PLy_exc_error,
439-
"unrecognized error in PLy_spi_execute_fetch_result");
440440
PLy_typeinfo_dealloc(&args);
441441
SPI_freetuptable(tuptable);
442442
Py_DECREF(result);
443-
return NULL;
443+
PG_RE_THROW();
444444
}
445445
PG_END_TRY();
446446

0 commit comments

Comments
 (0)