summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pl/plpython/expected/plpython_error.out23
-rw-r--r--src/pl/plpython/expected/plpython_error_0.out23
-rw-r--r--src/pl/plpython/expected/plpython_error_5.out23
-rw-r--r--src/pl/plpython/plpy_main.c52
-rw-r--r--src/pl/plpython/plpy_procedure.c4
-rw-r--r--src/pl/plpython/sql/plpython_error.sql16
6 files changed, 112 insertions, 29 deletions
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 1f52af7fe09..4d615b41cc5 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 53239061222..290902b1828 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 5ff46ca50aa..bc66ab55340 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 5a197ce27ac..6a66eba1762 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 990a33cc6d2..4e06413cd4e 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 d0df7e607d3..d712eb1078f 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();