diff --git a/expected/plpgsql_check_active.out b/expected/plpgsql_check_active.out index 9cbe8a9..f70b773 100644 --- a/expected/plpgsql_check_active.out +++ b/expected/plpgsql_check_active.out @@ -8981,3 +8981,44 @@ select * from plpgsql_check_function('fx1'); (9 rows) drop function fx1; +-- tracer test +set plpgsql_check.enable_tracer to on; +select plpgsql_check_tracer(true); +NOTICE: tracer is active +NOTICE: tracer verbosity is verbose + plpgsql_check_tracer +---------------------- + t +(1 row) + +create role plpgsql_check_test_role; +DO $$ +begin + begin + -- should to fail + create role plpgsql_check_test_role; + exception + when duplicate_object then + -- Role already exists + -- the exception handler is empty (#156) + end; +end; +$$; +NOTICE: #0 ->> start of block inline_code_block (oid=0) +NOTICE: #0.1 2 --> start of statement block +NOTICE: #0.2 3 --> start of statement block +NOTICE: #0.3 5 --> start of SQL statement (query='create role plpgsql_check_test ..') +NOTICE: #0.1 <-- end of SQL statement (elapsed time=0.010 ms) aborted +NOTICE: #0.2 <-- end of statement block (elapsed time=0.010 ms) +NOTICE: #0.3 <-- end of statement block (elapsed time=0.010 ms) +NOTICE: #0 <<- end of block (elapsed time=0.010 ms) +drop role plpgsql_check_test_role; +set plpgsql_check.enable_tracer to off; +select plpgsql_check_tracer(false); +NOTICE: tracer is not active +NOTICE: tracer verbosity is verbose + plpgsql_check_tracer +---------------------- + f +(1 row) + diff --git a/expected/plpgsql_check_active_1.out b/expected/plpgsql_check_active_1.out index 902eeca..9fab853 100644 --- a/expected/plpgsql_check_active_1.out +++ b/expected/plpgsql_check_active_1.out @@ -8984,3 +8984,44 @@ select * from plpgsql_check_function('fx1'); (9 rows) drop function fx1; +-- tracer test +set plpgsql_check.enable_tracer to on; +select plpgsql_check_tracer(true); +NOTICE: tracer is active +NOTICE: tracer verbosity is verbose + plpgsql_check_tracer +---------------------- + t +(1 row) + +create role plpgsql_check_test_role; +DO $$ +begin + begin + -- should to fail + create role plpgsql_check_test_role; + exception + when duplicate_object then + -- Role already exists + -- the exception handler is empty (#156) + end; +end; +$$; +NOTICE: #0 ->> start of block inline_code_block (oid=0) +NOTICE: #0.1 2 --> start of statement block +NOTICE: #0.2 3 --> start of statement block +NOTICE: #0.3 5 --> start of SQL statement (query='create role plpgsql_check_test ..') +NOTICE: #0.1 <-- end of SQL statement (elapsed time=0.010 ms) aborted +NOTICE: #0.2 <-- end of statement block (elapsed time=0.010 ms) +NOTICE: #0.3 <-- end of statement block (elapsed time=0.010 ms) +NOTICE: #0 <<- end of block (elapsed time=0.010 ms) +drop role plpgsql_check_test_role; +set plpgsql_check.enable_tracer to off; +select plpgsql_check_tracer(false); +NOTICE: tracer is not active +NOTICE: tracer verbosity is verbose + plpgsql_check_tracer +---------------------- + f +(1 row) + diff --git a/sql/plpgsql_check_active.sql b/sql/plpgsql_check_active.sql index cc77a90..fd6e525 100644 --- a/sql/plpgsql_check_active.sql +++ b/sql/plpgsql_check_active.sql @@ -5254,3 +5254,27 @@ $$ language plpgsql immutable; select * from plpgsql_check_function('fx1'); drop function fx1; + +-- tracer test +set plpgsql_check.enable_tracer to on; +select plpgsql_check_tracer(true); + +create role plpgsql_check_test_role; + +DO $$ +begin + begin + -- should to fail + create role plpgsql_check_test_role; + exception + when duplicate_object then + -- Role already exists + -- the exception handler is empty (#156) + end; +end; +$$; + +drop role plpgsql_check_test_role; + +set plpgsql_check.enable_tracer to off; +select plpgsql_check_tracer(false); diff --git a/src/pldbgapi2.c b/src/pldbgapi2.c index 64ef385..f0686ea 100644 --- a/src/pldbgapi2.c +++ b/src/pldbgapi2.c @@ -1190,6 +1190,29 @@ pldbgapi2_stmt_end(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) current_fmgr_plpgsql_cache = fcache_plpgsql; + /* + * The exception handler can be empty (see issue #156). In this case + * the statement on stack can be different, then current statemnt, and + * we should to fix stack. + */ + if (stmt->cmd_type == PLPGSQL_STMT_BLOCK) + { + while (fcache_plpgsql->current_stmtid_stack_size > 0 && + fcache_plpgsql->stmtid_stack[fcache_plpgsql->current_stmtid_stack_size] != stmt->stmtid) + { + int stmtid = fcache_plpgsql->stmtid_stack[fcache_plpgsql->current_stmtid_stack_size]; + + for (i = 0; i < nplpgsql_plugins2; i++) + { + if (plpgsql_plugins2[i]->stmt_end2_aborted) + (plpgsql_plugins2[i]->stmt_end2_aborted)(estate->func->fn_oid, stmtid, + &fcache_plpgsql->plugin2_info[i]); + } + + fcache_plpgsql->current_stmtid_stack_size -= 1; + } + } + if (fcache_plpgsql->stmtid_stack[fcache_plpgsql->current_stmtid_stack_size] != stmt->stmtid) elog(ERROR, "pldbgapi2 statement call stack is broken");