背景
GOTO语句是一个无条件的跳转语句,可以将程序的执行流程跳转到某个标签指定位置。 标签必须在其执行范围内是唯一的。在LightDB Database 23.2版本中plorasql对GOTO语句进行了支持。
场景
plorasql中匿名块、FUNCTION、PROCEDURE中支持GOTO语句.
但是GOTO的使用存在如下限制
- 指定跳转位置的标签必须定义于一个可以执行的语句或PL/oraSQL块之前。
- 可以从嵌套块跳转到外部块,但不能从外层块跳转到嵌套块。
- 不能从IF语句外部跳到IF语句内部。
- 不能从循环体外跳到循环体内。
- 不能从子程序外部跳到子程序内部。
- 不能从CASE语句外跳转到CASE语句内。
- 不能从异常处理部分跳转到可执行部分,也不能从可执行部分跳到异常处理部分。
案例演示
以下案例使用ltsql命令可以执行运行。
创建oracle环境
create database test_oracle lightdb_syntax_compatible_type oracle;
连接 test_oracle数据库
\c test_oracle
设置output输出
select dbms_output.serveroutput(true);
嵌套BLOCK
goto不支持从外部block GOTO到内部block,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
BEGIN
DBMS_OUTPUT.PUT_LINE('in block 1');
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('in block 2');
END;
DBMS_OUTPUT.PUT_LINE('out block 3');
END;
/
输出结果如下:
out block 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
goto支持从内部block GOTO到外部block,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
<<testlabel>>
BEGIN
DBMS_OUTPUT.PUT_LINE('in block 1');
goto testlabel2;
DBMS_OUTPUT.PUT_LINE('in block 2');
END;
DBMS_OUTPUT.PUT_LINE('out block 3');
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('out block 4');
END;
/
输出结果如下:
out block 1
in block 1
out block 4
DO
LOOP
goto不支持从外部GOTO到LOOP内部,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('OUT LOOP 1');
goto testlabel;
LOOP
DBMS_OUTPUT.PUT_LINE('IN LOOP 1');
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('IN LOOP 2');
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 2');
END;
/
输出结果如下:
OUT LOOP 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
goto支持从LOOP内部GOTO到外部,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('OUT LOOP 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 2');
<<testlabel>>
LOOP
DBMS_OUTPUT.PUT_LINE('IN LOOP 1');
goto testlabel2;
DBMS_OUTPUT.PUT_LINE('IN LOOP 2');
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 3');
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('OUT LOOP 4');
END;
/
输出结果如下:
OUT LOOP 1
IN LOOP 1
OUT LOOP 4
DO
WHILE
goto不支持从外部GOTO到WHILE内部,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('OUT LOOP 1');
goto testlabel;
WHILE true LOOP
DBMS_OUTPUT.PUT_LINE('IN LOOP 1');
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('IN LOOP 2');
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 2');
END;
/
输出结果如下:
OUT LOOP 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
goto支持从WHILE内部GOTO到外部,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('OUT LOOP 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 2');
<<testlabel>>
WHILE true LOOP
DBMS_OUTPUT.PUT_LINE('IN LOOP 1');
goto testlabel2;
DBMS_OUTPUT.PUT_LINE('IN LOOP 2');
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 3');
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('OUT LOOP 4');
END;
/
输出结果如下:
OUT LOOP 1
IN LOOP 1
OUT LOOP 4
DO
FOR
goto不支持从外部block GOTO到FOR内部,如下案例:
DECLARE
i INTEGER;
BEGIN
DBMS_OUTPUT.PUT_LINE('OUT LOOP 1');
goto testlabel;
FOR i IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE('IN LOOP 1');
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('IN LOOP 2');
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 2');
END;
/
输出结果如下:
OUT LOOP 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
goto支持从内部FOR GOTO到外部block,如下案例:
DECLARE
i INTEGER;
BEGIN
DBMS_OUTPUT.PUT_LINE('OUT LOOP 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 2');
<<testlabel>>
FOR i IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE('IN LOOP 1');
goto testlabel2;
DBMS_OUTPUT.PUT_LINE('IN LOOP 2');
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUT LOOP 3');
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('OUT LOOP 4');
END;
/
输出结果如下:
OUT LOOP 1
IN LOOP 1
OUT LOOP 4
DO
COMMIT
goto支持GOTO到COMMIT,如下案例:
CREATE TABLE test1(a int);
BEGIN
INSERT INTO test1 (a) VALUES (1);
INSERT INTO test1 (a) VALUES (2);
goto testlabel;
INSERT INTO test1 (a) VALUES (3);
<<testlabel>>
COMMIT;
END;
/
select * from test1;
DROP TABLE test1;
输出结果如下:
DO
lightdb@postgres=# select * from test1;
a
---
1
2
(2 rows)
ROLLBACK
goto支持GOTO到rollback,如下案例:
CREATE TABLE test1(a int);
BEGIN
INSERT INTO test1 (a) VALUES (1);
INSERT INTO test1 (a) VALUES (2);
goto testlabel;
INSERT INTO test1 (a) VALUES (3);
<<testlabel>>
ROLLBACK;
END;
/
select * from test1;
DROP TABLE test1;
输出结果如下:
a
---
(0 rows)
DROP TABLE test1;
IF
goto不支持从外部block GOTO到IF内部block,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
IF true THEN
DBMS_OUTPUT.PUT_LINE('in block 1');
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('in block 2');
END IF;
DBMS_OUTPUT.PUT_LINE('out block 3');
END;
/
输出结果如下:
out block 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
goto支持从IF内部block GOTO到外部block,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
<<testlabel>>
IF true THEN
DBMS_OUTPUT.PUT_LINE('in block 1');
goto testlabel2;
DBMS_OUTPUT.PUT_LINE('in block 2');
END IF;
DBMS_OUTPUT.PUT_LINE('out block 3');
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('out block 4');
END;
/
输出结果如下:
out block 1
in block 1
out block 4
DO
CASE
goto不支持从外部block GOTO到CASE内部block,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
CASE 2
WHEN 1 THEN
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('in block 1');
ELSE
DBMS_OUTPUT.PUT_LINE('in block 2');
END CASE;
DBMS_OUTPUT.PUT_LINE('out block 3');
END;
/
输出结果如下:
out block 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
goto支持从CASE内部block GOTO到外部block,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
<<testlabel>>
CASE 2
WHEN 1 THEN
DBMS_OUTPUT.PUT_LINE('in block 1');
ELSE
DBMS_OUTPUT.PUT_LINE('in block 2');
goto testlabel2;
DBMS_OUTPUT.PUT_LINE('in block 3');
END CASE;
DBMS_OUTPUT.PUT_LINE('out block 3');
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('out block 4');
END;
/
输出结果如下:
out block 1
in block 2
out block 4
DO
EXIT
goto支持GOTO到EXIT,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
LOOP
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 2');
<<testlabel>>
EXIT;
END LOOP;
DBMS_OUTPUT.PUT_LINE('out block 3');
END;
/
输出结果如下:
out block 1
out block 3
DO
RETURN
goto支持GOTO到RETURN,如下案例:
BEGIN
DBMS_OUTPUT.PUT_LINE('out block 1');
LOOP
goto testlabel;
DBMS_OUTPUT.PUT_LINE('in block 1');
<<testlabel>>
RETURN;
END LOOP;
DBMS_OUTPUT.PUT_LINE('out block 2');
END;
/
输出结果如下:
out block 1
DO
GOTO
goto支持GOTO到GOTO,如下案例:
BEGIN
goto testlabel;
DBMS_OUTPUT.PUT_LINE('out block 1');
<<testlabel>>
goto testlabel3;
<<testlabel2>>
DBMS_OUTPUT.PUT_LINE('out block 2');
<<testlabel3>>
DBMS_OUTPUT.PUT_LINE('out block 3');
<<testlabel4>>
DBMS_OUTPUT.PUT_LINE('out block 4');
END;
/
输出结果如下:
out block 3
out block 4
DO
EXCEPTION
goto不支持从正常块与异常块相互GOTO,如下案例:
不支持从异常块GOTO到正常块。
DECLARE
i INTEGER ;
BEGIN
DBMS_OUTPUT.PUT_LINE('block 1');
i := 1/0;
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('block 2');
EXCEPTION
WHEN others THEN
DBMS_OUTPUT.PUT_LINE('exception block 1');
goto testlabel;
DBMS_OUTPUT.PUT_LINE('exception block 2');
END;
/
输出结果如下:
block 1
exception block 1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
也不支持从正常块GOTO到异常块
DECLARE
i INTEGER ;
BEGIN
DBMS_OUTPUT.PUT_LINE('1');
goto testlabel;
EXCEPTION
WHEN others THEN
<<testlabel>>
DBMS_OUTPUT.PUT_LINE('2');
return ;
END;
/
输出结果如下:
1
ERROR: illegal GOTO statement; this GOTO cannot branch to label "testlabel"
CONTEXT: PL/oraSQL function inline_code_block
NULL
支持GOTO到NULL,如下示例:
BEGIN
DBMS_OUTPUT.PUT_LINE('STEP 1');
GOTO testlabel;
DBMS_OUTPUT.PUT_LINE('STEP 2');
<<testlabel>>
NULL;
DBMS_OUTPUT.PUT_LINE('STEP 3');
END;
/
输出结果如下:
STEP 1
STEP 3
DO
结论
上面示例中演示了匿名块中的GOTO,plorasql函数(FUNCTION)与plorasql存储过程(PROCEDURE)也同样适用,值得注意的是,plorasql 23.2版本FUNCTION中还不支持事务,所以不能在FUNCTION中GOTO到COMMMIT/ROLLBACK。