aboutsummaryrefslogtreecommitdiff
path: root/src
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
commitb1de90699e73a081ac450420b7d4f3fd1d49981b (patch)
treec9123acdb6674dc75d6b7490048497079494af96 /src
parent99a1c5d068d84f5097ab40842ecd766d69491d6c (diff)
downloadpostgresql-b1de90699e73a081ac450420b7d4f3fd1d49981b.tar.gz
postgresql-b1de90699e73a081ac450420b7d4f3fd1d49981b.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
Diffstat (limited to 'src')
-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 a1d45d51cd2..c99065a3bea 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