postgres.git / summary / log / commit / refs

commit    4ffd3fe4d6ccc9ff36271e5a21ea3b065621b982
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Mon Sep 13 16:42:03 2021 +0000

    Fix EXIT out of outermost block in plpgsql.
    
    Ordinarily, using EXIT this way would draw "control reached end of
    function without RETURN".  However, if the function is one where we
    don't require an explicit RETURN (such as a DO block), that should
    not happen.  It did anyway, because add_dummy_return() neglected to
    account for the case.
    
    Per report from Herwig Goemans.  Back-patch to all supported branches.
    
    Discussion: https://postgr.es/m/868ae948-e3ca-c7ec-95a6-83cfc08ef750@gmail.com


src/pl/plpgsql/src/expected/plpgsql_control.out | 11 +++++++++++ src/pl/plpgsql/src/pl_comp.c | 6 ++++-- src/pl/plpgsql/src/sql/plpgsql_control.sql | 12 ++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/pl/plpgsql/src/expected/plpgsql_control.out b/src/pl/plpgsql/src/expected/plpgsql_control.out index fbfc939eae9..328bd485861 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_control.out +++ b/src/pl/plpgsql/src/expected/plpgsql_control.out @@ -413,6 +413,17 @@ begin raise notice 'should get here'; end$$; NOTICE: should get here +-- check exit out of outermost block +do $$ +<<outerblock>> +begin + <<innerblock>> + begin + exit outerblock; + raise notice 'should not get here'; + end; + raise notice 'should not get here, either'; +end$$; -- unlabeled exit does match a while loop do $$ begin diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index a68a2077c36..f5b1d5c4fac 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1038,9 +1038,11 @@ add_dummy_return(PLpgSQL_function *function) /* * If the outer block has an EXCEPTION clause, we need to make a new outer * block, since the added RETURN shouldn't act like it is inside the - * EXCEPTION clause. + * EXCEPTION clause. Likewise, if it has a label, wrap it in a new outer + * block so that EXIT doesn't skip the RETURN. */ - if (function->action->exceptions != NULL) + if (function->action->exceptions != NULL || + function->action->label != NULL) { PLpgSQL_stmt_block *new; diff --git a/src/pl/plpgsql/src/sql/plpgsql_control.sql b/src/pl/plpgsql/src/sql/plpgsql_control.sql index 61d6ca64513..ed7231134f4 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_control.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_control.sql @@ -311,6 +311,18 @@ begin raise notice 'should get here'; end$$; +-- check exit out of outermost block +do $$ +<<outerblock>> +begin + <<innerblock>> + begin + exit outerblock; + raise notice 'should not get here'; + end; + raise notice 'should not get here, either'; +end$$; + -- unlabeled exit does match a while loop do $$ begin [parent: 10faeb7ed504]