summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2021-09-13 16:42:03 +0000
committerTom Lane2021-09-13 16:42:03 +0000
commitbdd6ce48d0356fbfaa0fe4a1fee20068f99abb70 (patch)
tree4d1bf1fc36cd49f150bf8eb92ab95f16da1280fc
parentb6a10ff4abe9538f16d9f52bda6bc04f90b77d0d (diff)
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
-rw-r--r--src/pl/plpgsql/src/expected/plpgsql_control.out11
-rw-r--r--src/pl/plpgsql/src/pl_comp.c6
-rw-r--r--src/pl/plpgsql/src/sql/plpgsql_control.sql12
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 73b23a35e56..e09a7aa98aa 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 871195a70cd..7e49d59a2d0 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1029,9 +1029,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