diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index 84650aa9e1e221d49721003fb7736d35a39da059..54307b611018d3995e73405f40ccca85905f8538 100644
--- a/src/pl/plpython/plpy_elog.c
+++ b/src/pl/plpython/plpy_elog.c
@@ -21,7 +21,8 @@ PyObject   *PLy_exc_fatal = NULL;
 PyObject   *PLy_exc_spi_error = NULL;
 
 
-static void PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth);
+static void PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
+			  char **xmsg, char **tbmsg, int *tb_depth);
 static void PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail,
 					   char **hint, char **query, int *position);
 static char *get_source_line(const char *src, int lineno);
@@ -53,16 +54,20 @@ PLy_elog(int elevel, const char *fmt,...)
 	int			position = 0;
 
 	PyErr_Fetch(&exc, &val, &tb);
+
 	if (exc != NULL)
 	{
+		PyErr_NormalizeException(&exc, &val, &tb);
+
 		if (PyErr_GivenExceptionMatches(val, PLy_exc_spi_error))
 			PLy_get_spi_error_data(val, &sqlerrcode, &detail, &hint, &query, &position);
 		else if (PyErr_GivenExceptionMatches(val, PLy_exc_fatal))
 			elevel = FATAL;
 	}
-	PyErr_Restore(exc, val, tb);
 
-	PLy_traceback(&xmsg, &tbmsg, &tb_depth);
+	/* this releases our refcount on tb! */
+	PLy_traceback(exc, val, tb,
+				  &xmsg, &tbmsg, &tb_depth);
 
 	if (fmt)
 	{
@@ -113,6 +118,9 @@ PLy_elog(int elevel, const char *fmt,...)
 			pfree(xmsg);
 		if (tbmsg)
 			pfree(tbmsg);
+		Py_XDECREF(exc);
+		Py_XDECREF(val);
+
 		PG_RE_THROW();
 	}
 	PG_END_TRY();
@@ -123,21 +131,24 @@ PLy_elog(int elevel, const char *fmt,...)
 		pfree(xmsg);
 	if (tbmsg)
 		pfree(tbmsg);
+	Py_XDECREF(exc);
+	Py_XDECREF(val);
 }
 
 /*
- * Extract a Python traceback from the current exception.
+ * Extract a Python traceback from the given exception data.
  *
  * The exception error message is returned in xmsg, the traceback in
  * tbmsg (both as palloc'd strings) and the traceback depth in
  * tb_depth.
+ *
+ * We release refcounts on all the Python objects in the traceback stack,
+ * but not on e or v.
  */
 static void
-PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
+PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
+			  char **xmsg, char **tbmsg, int *tb_depth)
 {
-	PyObject   *e,
-			   *v,
-			   *tb;
 	PyObject   *e_type_o;
 	PyObject   *e_module_o;
 	char	   *e_type_s = NULL;
@@ -148,12 +159,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
 	StringInfoData tbstr;
 
 	/*
-	 * get the current exception
-	 */
-	PyErr_Fetch(&e, &v, &tb);
-
-	/*
-	 * oops, no exception, return
+	 * if no exception, return nulls
 	 */
 	if (e == NULL)
 	{
@@ -164,8 +170,6 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
 		return;
 	}
 
-	PyErr_NormalizeException(&e, &v, &tb);
-
 	/*
 	 * Format the exception and its value and put it in xmsg.
 	 */
@@ -332,8 +336,6 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
 	Py_XDECREF(e_type_o);
 	Py_XDECREF(e_module_o);
 	Py_XDECREF(vob);
-	Py_XDECREF(v);
-	Py_DECREF(e);
 }
 
 /*
@@ -342,7 +344,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
 static void
 PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position)
 {
-	PyObject   *spidata = NULL;
+	PyObject   *spidata;
 
 	spidata = PyObject_GetAttrString(exc, "spidata");
 	if (!spidata)
@@ -352,8 +354,6 @@ PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hin
 		goto cleanup;
 
 cleanup:
-	PyErr_Clear();
-	/* no elog here, we simply won't report the errhint, errposition etc */
 	Py_XDECREF(spidata);
 }