1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +03:00

Detect mismatched CONTINUE and EXIT statements at plpgsql compile time.

With a bit of tweaking of the compile namestack data structure, we can
verify at compile time whether a CONTINUE or EXIT is legal.  This is
surely better than leaving it to runtime, both because earlier is better
and because we can issue a proper error pointer.  Also, we can get rid
of the ad-hoc old way of detecting the problem, which only took care of
CONTINUE not EXIT.

Jim Nasby, adjusted a bit by me
This commit is contained in:
Tom Lane
2015-08-21 20:17:19 -04:00
parent 072710dff3
commit fcdfce6820
7 changed files with 226 additions and 85 deletions

View File

@ -2830,21 +2830,58 @@ NOTICE: 10
(1 row)
-- CONTINUE is only legal inside a loop
create function continue_test2() returns void as $$
drop function continue_test1();
drop table conttesttbl;
-- should fail: CONTINUE is only legal inside a loop
create function continue_error1() returns void as $$
begin
begin
continue;
end;
return;
end;
$$ language plpgsql;
-- should fail
select continue_test2();
ERROR: CONTINUE cannot be used outside a loop
CONTEXT: PL/pgSQL function continue_test2()
-- CONTINUE can't reference the label of a named block
create function continue_test3() returns void as $$
LINE 4: continue;
^
-- should fail: EXIT is only legal inside a loop
create function exit_error1() returns void as $$
begin
begin
exit;
end;
end;
$$ language plpgsql;
ERROR: EXIT cannot be used outside a loop
LINE 4: exit;
^
-- should fail: no such label
create function continue_error2() returns void as $$
begin
begin
loop
continue no_such_label;
end loop;
end;
end;
$$ language plpgsql;
ERROR: label "no_such_label" does not exist
LINE 5: continue no_such_label;
^
-- should fail: no such label
create function exit_error2() returns void as $$
begin
begin
loop
exit no_such_label;
end loop;
end;
end;
$$ language plpgsql;
ERROR: label "no_such_label" does not exist
LINE 5: exit no_such_label;
^
-- should fail: CONTINUE can't reference the label of a named block
create function continue_error3() returns void as $$
begin
<<begin_block1>>
begin
@ -2854,14 +2891,28 @@ begin
end;
end;
$$ language plpgsql;
-- should fail
select continue_test3();
ERROR: CONTINUE cannot be used outside a loop
CONTEXT: PL/pgSQL function continue_test3()
drop function continue_test1();
drop function continue_test2();
drop function continue_test3();
drop table conttesttbl;
ERROR: block label "begin_block1" cannot be used in CONTINUE
LINE 6: continue begin_block1;
^
-- On the other hand, EXIT *can* reference the label of a named block
create function exit_block1() returns void as $$
begin
<<begin_block1>>
begin
loop
exit begin_block1;
raise exception 'should not get here';
end loop;
end;
end;
$$ language plpgsql;
select exit_block1();
exit_block1
-------------
(1 row)
drop function exit_block1();
-- verbose end block and end loop
create function end_label1() returns void as $$
<<blbl>>
@ -2891,7 +2942,7 @@ begin
end loop flbl1;
end;
$$ language plpgsql;
ERROR: label does not exist at or near "flbl1"
ERROR: end label "flbl1" specified for unlabelled block
LINE 5: end loop flbl1;
^
-- should fail: end label does not match start label

View File

@ -2361,21 +2361,51 @@ end; $$ language plpgsql;
select continue_test1();
-- CONTINUE is only legal inside a loop
create function continue_test2() returns void as $$
drop function continue_test1();
drop table conttesttbl;
-- should fail: CONTINUE is only legal inside a loop
create function continue_error1() returns void as $$
begin
begin
continue;
end;
return;
end;
$$ language plpgsql;
-- should fail
select continue_test2();
-- should fail: EXIT is only legal inside a loop
create function exit_error1() returns void as $$
begin
begin
exit;
end;
end;
$$ language plpgsql;
-- CONTINUE can't reference the label of a named block
create function continue_test3() returns void as $$
-- should fail: no such label
create function continue_error2() returns void as $$
begin
begin
loop
continue no_such_label;
end loop;
end;
end;
$$ language plpgsql;
-- should fail: no such label
create function exit_error2() returns void as $$
begin
begin
loop
exit no_such_label;
end loop;
end;
end;
$$ language plpgsql;
-- should fail: CONTINUE can't reference the label of a named block
create function continue_error3() returns void as $$
begin
<<begin_block1>>
begin
@ -2386,13 +2416,21 @@ begin
end;
$$ language plpgsql;
-- should fail
select continue_test3();
-- On the other hand, EXIT *can* reference the label of a named block
create function exit_block1() returns void as $$
begin
<<begin_block1>>
begin
loop
exit begin_block1;
raise exception 'should not get here';
end loop;
end;
end;
$$ language plpgsql;
drop function continue_test1();
drop function continue_test2();
drop function continue_test3();
drop table conttesttbl;
select exit_block1();
drop function exit_block1();
-- verbose end block and end loop
create function end_label1() returns void as $$