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:
@ -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
|
||||
|
@ -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 $$
|
||||
|
Reference in New Issue
Block a user