diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c index 12c34402192..285bf9f96c5 100644 --- a/src/pl/plpython/plpy_elog.c +++ b/src/pl/plpython/plpy_elog.c @@ -143,14 +143,7 @@ PLy_elog_impl(int elevel, const char *fmt,...) { Py_XDECREF(exc); Py_XDECREF(val); - /* Must release all the objects in the traceback stack */ - while (tb != NULL && tb != Py_None) - { - PyObject *tb_prev = tb; - - tb = PyObject_GetAttrString(tb, "tb_next"); - Py_DECREF(tb_prev); - } + Py_XDECREF(tb); /* For neatness' sake, also release our string buffers */ if (fmt) pfree(emsg.data); @@ -347,6 +340,17 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb, tb = PyObject_GetAttrString(tb, "tb_next"); if (tb == NULL) elog(ERROR, "could not traverse Python traceback"); + + /* + * Release the refcount that PyObject_GetAttrString acquired on the + * next frame object. We don't need it, because our caller has a + * refcount on the first frame object and the frame objects each have + * a refcount on the next one. If we tried to hold this refcount + * longer, it would greatly complicate cleanup in the event of a + * failure in the above PG_TRY block. + */ + Py_DECREF(tb); + (*tb_depth)++; } @@ -380,6 +384,10 @@ PLy_get_sqlerrcode(PyObject *exc, int *sqlerrcode) /* * Extract the error data from a SPIError + * + * Note: the returned string values are pointers into the given PyObject. + * They must not be free()'d, and are not guaranteed to be valid once + * we stop holding a reference on the PyObject. */ static void PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, @@ -416,6 +424,11 @@ PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, * * Note: position and query attributes are never set for Error so, unlike * PLy_get_spi_error_data, this function doesn't return them. + * + * Note: the returned string values are palloc'd in the current context. + * While our caller could pfree them later, there's no real need to do so, + * and it would be complicated to handle both this convention and that of + * PLy_get_spi_error_data. */ static void PLy_get_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint,