§ Oracle兼容-存储过程-GOTO
§ 1. 语法
GOTO label
1
label后面的语句块支持以下几种用法:
{
sp_proc_stmt_statement
| exit [label]/exit [label] when
| leave label
| iterate label
| goto label
| open cursor
| fetch cursor
| close cursor
| return
| if elsif
| case when
| forall loop
| declare body begin .. end
| sp_labeled_control
}
sp_proc_stmt_statement:
{
DDL_statement ...
DML_statement ...
SHOW_statement ...
}
sp_labeled_control:
{
for_loop_stmt
| while loop
| loop end loop
| repeat until
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
§ 2. 定义和用法
GreatSQL的存储过程中支持用 label
标记位置,并用 GOTO label
跳到指定标记位置。
注意:谨慎使 GOTO
语法,容易造成死循环。
§ 3. Oracle兼容说明
GreatSQL的存储过程中支持用 label
标记位置,并用 GOTO label
跳到指定标记位置。该用法如下所述:
如果
GOTO
语句退出游标FOR LOOP
循环语句块,则游标将会被关闭。不能利用
GOTO
语句将控制转移到IF / CASE / LOOP
等语句或子块中。不能利用
GOTO
语句将控制从一个IF
语句子句转移到另一个,或从一个CASE WHEN
子句转移到另一个。不能利用
GOTO
语句将控制转移出子程序。不能利用
GOTO
语句将控制转移到异常处理程序中。不能利用
GOTO
语句将控制从异常处理程序转移回当前块(但它可以将控制从异常处理程序转移到封闭块)。可以利用
GOTO
可以跳转到除了以上提到的几种情况之外的任何地方,GreatSQL原生的LEAVE label
只能在LOOP
和BEGIN END
模块内使用。只支持单个label标记,不支持多个label同时标记位置。如下例所示:
<<label1>>
<<label12>> -- 不支持同时标记位置,二者必须删掉一个
a := b;
1
2
3
2
3
- 支持在
EVENT / TRIGGER / PACKAGE / 匿名块
内使用GOTO
语法。如果在EVENT / TRIGGER
中因逻辑错误可能造成死循环,会造成系统资源浪费,应该谨慎使用。
§ 4. 示例
- 示例1:往前跳转
greatsql> SET sql_mode = ORACLE;
greatsql> DELIMITER //
greatsql> CREATE OR REPLACE PROCEDURE goto_sp1(v_str IN OUT VARCHAR)
AS
BEGIN
v_str := 'label1';
GOTO label1;
<<label1>>
-- 又立即跳转到label2,即RETURN完成
GOTO label2;
v_str := 'label2';
<<label2>>
RETURN;
END; //
greatsql> CALL goto_sp1(@v_str) //
Query OK, 0 rows affected (0.00 sec)
greatsql> SELECT @v_str //
+--------+
| @v_str |
+--------+
| label1 |
+--------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- 示例2:往回跳转
greatsql> SET sql_mode = ORACLE;
greatsql> DELIMITER //
greatsql> CREATE OR REPLACE PROCEDURE goto_sp2(v_str IN OUT VARCHAR)
AS
BEGIN
v_str := 'label1';
<<label1>>
IF (v_str = 'label2') THEN
RETURN;
END IF;
v_str := 'label2';
GOTO label1;
END; //
greatsql> CALL goto_sp2(@v_str) //
greatsql> SELECT @v_str //
+--------+
| @v_str |
+--------+
| label2 |
+--------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- 示例3:支持条件判断处理
greatsql> SET sql_mode = ORACLE;
greatsql> DELIMITER //
greatsql> CREATE OR REPLACE PROCEDURE goto_sp3(n INT, ret OUT VARCHAR)
AS
a INT;
BEGIN
<<label1>>
BEGIN
SELECT a INTO a FROM information_schema.TABLES LIMIT n;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
BEGIN
ret := ret||'--- too_many_rows cought 1 ---';
GOTO label2;
END;
WHEN NO_DATA_FOUND THEN
BEGIN
ret := ret||'--- no_data_found cought 1 ---';
n := 2;
SELECT a INTO a FROM information_schema.TABLES LIMIT n;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
BEGIN
ret := ret||'--- too_many_rows cought 2 ---';
GOTO label1;
END;
WHEN NO_DATA_FOUND THEN ret := '--- no_data_found cought 2 ---';
END;
END;
SET ret := ret||' error ';
<<label2>>
RETURN;
END; //
greatsql> CALL goto_sp3(0, @ret) //
Query OK, 0 rows affected (0.00 sec)
greatsql> SELECT @ret //
+--------------------------------------------------------------------------------------------+
| @ret |
+--------------------------------------------------------------------------------------------+
| --- no_data_found cought 1 ------ too_many_rows cought 2 ------ too_many_rows cought 1 --- |
+--------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
greatsql> CALL goto_sp3(0, @ret) //
Query OK, 0 rows affected (0.00 sec)
greatsql> SELECT @ret //
+--------------------------------------------------------------------------------------------+
| @ret |
+--------------------------------------------------------------------------------------------+
| --- no_data_found cought 1 ------ too_many_rows cought 2 ------ too_many_rows cought 1 --- |
+--------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
greatsql> CALL goto_sp3(3, @ret) //
Query OK, 0 rows affected (0.00 sec)
greatsql> SELECT @ret //
+--------------------------------+
| @ret |
+--------------------------------+
| --- too_many_rows cought 1 --- |
+--------------------------------+
1 row in set (0.00 sec)
greatsql> CALL goto_sp3(1, @ret) //
Query OK, 1 row affected (0.00 sec)
greatsql> SELECT @ret //
+---------+
| @ret |
+---------+
| error |
+---------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
- 示例4:不能跳转到
CASE WHEN
语句块
- 示例4:不能跳转到
greatsql> SET sql_mode = ORACLE;
greatsql> DELIMITER //
greatsql> CREATE OR REPLACE PROCEDURE goto_sp4()
AS
a INT;
BEGIN
GOTO label1;
case 1
WHEN 1 THEN
<<label1>>
a := 2;
WHEN 2 THEN
a := 1;
END CASE;
RETURN;
END; //
ERROR 1308 (42000): GOTO with no matching label: label1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 示例5:不能跳转到另一个
CASE WHEN
语句块
- 示例5:不能跳转到另一个
greatsql> SET sql_mode = ORACLE;
greatsql> DELIMITER //
greatsql> CREATE OR REPLACE PROCEDURE goto_sp5()
AS
a INT;
BEGIN
CASE 1
WHEN 1 THEN
<<label1>>
a := 2;
WHEN 2 THEN
a := 1;
GOTO label1;
end case;
RETURN;
END; //
ERROR 1308 (42000): GOTO with no matching label: label1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
扫码关注微信公众号