diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 1f52af7fe0..4d615b41cc 100644
--- a/src/pl/plpython/expected/plpython_error.out
+++ b/src/pl/plpython/expected/plpython_error.out
@@ -422,3 +422,26 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
 	-- NOOP
 END
 $$ LANGUAGE plpgsql;
+/* test the context stack trace for nested execution levels
+ */
+CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
+plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
+return 1
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
+plpy.execute("SELECT notice_innerfunc()")
+return 1
+$$ LANGUAGE plpythonu;
+\set SHOW_CONTEXT always
+SELECT notice_outerfunc();
+NOTICE:  inside DO
+CONTEXT:  PL/Python anonymous code block
+SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
+PL/Python function "notice_innerfunc"
+SQL statement "SELECT notice_innerfunc()"
+PL/Python function "notice_outerfunc"
+ notice_outerfunc 
+------------------
+                1
+(1 row)
+
diff --git a/src/pl/plpython/expected/plpython_error_0.out b/src/pl/plpython/expected/plpython_error_0.out
index 5323906122..290902b182 100644
--- a/src/pl/plpython/expected/plpython_error_0.out
+++ b/src/pl/plpython/expected/plpython_error_0.out
@@ -422,3 +422,26 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
 	-- NOOP
 END
 $$ LANGUAGE plpgsql;
+/* test the context stack trace for nested execution levels
+ */
+CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
+plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
+return 1
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
+plpy.execute("SELECT notice_innerfunc()")
+return 1
+$$ LANGUAGE plpythonu;
+\set SHOW_CONTEXT always
+SELECT notice_outerfunc();
+NOTICE:  inside DO
+CONTEXT:  PL/Python anonymous code block
+SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
+PL/Python function "notice_innerfunc"
+SQL statement "SELECT notice_innerfunc()"
+PL/Python function "notice_outerfunc"
+ notice_outerfunc 
+------------------
+                1
+(1 row)
+
diff --git a/src/pl/plpython/expected/plpython_error_5.out b/src/pl/plpython/expected/plpython_error_5.out
index 5ff46ca50a..bc66ab5534 100644
--- a/src/pl/plpython/expected/plpython_error_5.out
+++ b/src/pl/plpython/expected/plpython_error_5.out
@@ -422,3 +422,26 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
 	-- NOOP
 END
 $$ LANGUAGE plpgsql;
+/* test the context stack trace for nested execution levels
+ */
+CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
+plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
+return 1
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
+plpy.execute("SELECT notice_innerfunc()")
+return 1
+$$ LANGUAGE plpythonu;
+\set SHOW_CONTEXT always
+SELECT notice_outerfunc();
+NOTICE:  inside DO
+CONTEXT:  PL/Python anonymous code block
+SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
+PL/Python function "notice_innerfunc"
+SQL statement "SELECT notice_innerfunc()"
+PL/Python function "notice_outerfunc"
+ notice_outerfunc 
+------------------
+                1
+(1 row)
+
diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c
index 5a197ce27a..6a66eba176 100644
--- a/src/pl/plpython/plpy_main.c
+++ b/src/pl/plpython/plpy_main.c
@@ -237,23 +237,26 @@ plpython_call_handler(PG_FUNCTION_ARGS)
 	/*
 	 * Push execution context onto stack.  It is important that this get
 	 * popped again, so avoid putting anything that could throw error between
-	 * here and the PG_TRY.  (plpython_error_callback expects the stack entry
-	 * to be there, so we have to make the context first.)
+	 * here and the PG_TRY.
 	 */
 	exec_ctx = PLy_push_execution_context(!nonatomic);
 
-	/*
-	 * Setup error traceback support for ereport()
-	 */
-	plerrcontext.callback = plpython_error_callback;
-	plerrcontext.previous = error_context_stack;
-	error_context_stack = &plerrcontext;
-
 	PG_TRY();
 	{
 		Oid			funcoid = fcinfo->flinfo->fn_oid;
 		PLyProcedure *proc;
 
+		/*
+		 * Setup error traceback support for ereport().  Note that the PG_TRY
+		 * structure pops this for us again at exit, so we needn't do that
+		 * explicitly, nor do we risk the callback getting called after we've
+		 * destroyed the exec_ctx.
+		 */
+		plerrcontext.callback = plpython_error_callback;
+		plerrcontext.arg = exec_ctx;
+		plerrcontext.previous = error_context_stack;
+		error_context_stack = &plerrcontext;
+
 		if (CALLED_AS_TRIGGER(fcinfo))
 		{
 			Relation	tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
@@ -279,9 +282,7 @@ plpython_call_handler(PG_FUNCTION_ARGS)
 	}
 	PG_END_TRY();
 
-	/* Pop the error context stack */
-	error_context_stack = plerrcontext.previous;
-	/* ... and then the execution context */
+	/* Destroy the execution context */
 	PLy_pop_execution_context();
 
 	return retval;
@@ -333,21 +334,22 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
 	/*
 	 * Push execution context onto stack.  It is important that this get
 	 * popped again, so avoid putting anything that could throw error between
-	 * here and the PG_TRY.  (plpython_inline_error_callback doesn't currently
-	 * need the stack entry, but for consistency with plpython_call_handler we
-	 * do it in this order.)
+	 * here and the PG_TRY.
 	 */
 	exec_ctx = PLy_push_execution_context(codeblock->atomic);
 
-	/*
-	 * Setup error traceback support for ereport()
-	 */
-	plerrcontext.callback = plpython_inline_error_callback;
-	plerrcontext.previous = error_context_stack;
-	error_context_stack = &plerrcontext;
-
 	PG_TRY();
 	{
+		/*
+		 * Setup error traceback support for ereport().
+		 * plpython_inline_error_callback doesn't currently need exec_ctx, but
+		 * for consistency with plpython_call_handler we do it the same way.
+		 */
+		plerrcontext.callback = plpython_inline_error_callback;
+		plerrcontext.arg = exec_ctx;
+		plerrcontext.previous = error_context_stack;
+		error_context_stack = &plerrcontext;
+
 		PLy_procedure_compile(&proc, codeblock->source_text);
 		exec_ctx->curr_proc = &proc;
 		PLy_exec_function(&fake_fcinfo, &proc);
@@ -361,9 +363,7 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
 	}
 	PG_END_TRY();
 
-	/* Pop the error context stack */
-	error_context_stack = plerrcontext.previous;
-	/* ... and then the execution context */
+	/* Destroy the execution context */
 	PLy_pop_execution_context();
 
 	/* Now clean up the transient procedure we made */
@@ -391,7 +391,7 @@ PLy_procedure_is_trigger(Form_pg_proc procStruct)
 static void
 plpython_error_callback(void *arg)
 {
-	PLyExecutionContext *exec_ctx = PLy_current_execution_context();
+	PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
 
 	if (exec_ctx->curr_proc)
 	{
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index 990a33cc6d..4e06413cd4 100644
--- a/src/pl/plpython/plpy_procedure.c
+++ b/src/pl/plpython/plpy_procedure.c
@@ -47,9 +47,7 @@ init_procedure_caches(void)
 }
 
 /*
- * Get the name of the last procedure called by the backend (the
- * innermost, if a plpython procedure call calls the backend and the
- * backend calls another plpython procedure).
+ * PLy_procedure_name: get the name of the specified procedure.
  *
  * NB: this returns the SQL name, not the internal Python procedure name
  */
diff --git a/src/pl/plpython/sql/plpython_error.sql b/src/pl/plpython/sql/plpython_error.sql
index d0df7e607d..d712eb1078 100644
--- a/src/pl/plpython/sql/plpython_error.sql
+++ b/src/pl/plpython/sql/plpython_error.sql
@@ -328,3 +328,19 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
 	-- NOOP
 END
 $$ LANGUAGE plpgsql;
+
+/* test the context stack trace for nested execution levels
+ */
+CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
+plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
+return 1
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
+plpy.execute("SELECT notice_innerfunc()")
+return 1
+$$ LANGUAGE plpythonu;
+
+\set SHOW_CONTEXT always
+
+SELECT notice_outerfunc();