aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-09-13 12:42:03 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-09-13 12:42:03 -0400
commit745abdd951ab31f3276adbbbf67bbc3b7dac0923 (patch)
treeff9739e43a2a4a01a13738addfb12371d390d788
parentb7b8e2c4a5cb9d520c907f12fe9ebd3837dffc49 (diff)
downloadpostgresql-745abdd951ab31f3276adbbbf67bbc3b7dac0923.tar.gz
postgresql-745abdd951ab31f3276adbbbf67bbc3b7dac0923.zip
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 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 828ff5a288f..cb0ce3900b7 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1033,9 +1033,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