Oracle兼容-存储过程-GOTO


1. 语法

  1. GOTO label

label后面的语句块支持以下几种用法:

  1. {
  2. sp_proc_stmt_statement
  3. | exit [label]/exit [label] when
  4. | leave label
  5. | iterate label
  6. | goto label
  7. | open cursor
  8. | fetch cursor
  9. | close cursor
  10. | return
  11. | if elsif
  12. | case when
  13. | forall loop
  14. | declare body begin .. end
  15. | sp_labeled_control
  16. }
  17. sp_proc_stmt_statement:
  18. {
  19. DDL_statement ...
  20. DML_statement ...
  21. SHOW_statement ...
  22. }
  23. sp_labeled_control:
  24. {
  25. for_loop_stmt
  26. | while loop
  27. | loop end loop
  28. | repeat until
  29. }

2. 定义和用法

GreatSQL的存储过程中支持用 label 标记位置,并用 GOTO label 跳到指定标记位置。

注意:谨慎使 GOTO 语法,容易造成死循环。

3. Oracle兼容说明

GreatSQL的存储过程中支持用 label 标记位置,并用 GOTO label 跳到指定标记位置。该用法如下所述:

  1. 如果 GOTO 语句退出游标 FOR LOOP 循环语句块,则游标将会被关闭。

  2. 不能利用 GOTO 语句将控制转移到 IF / CASE / LOOP 等语句或子块中。

  3. 不能利用 GOTO 语句将控制从一个 IF 语句子句转移到另一个,或从一个 CASE WHEN 子句转移到另一个。

  4. 不能利用 GOTO 语句将控制转移出子程序。

  5. 不能利用 GOTO 语句将控制转移到异常处理程序中。

  6. 不能利用 GOTO 语句将控制从异常处理程序转移回当前块(但它可以将控制从异常处理程序转移到封闭块)。

  7. 可以利用 GOTO 可以跳转到除了以上提到的几种情况之外的任何地方,GreatSQL原生的 LEAVE label 只能在 LOOPBEGIN END 模块内使用。

  8. 只支持单个label标记,不支持多个label同时标记位置。如下例所示:

  1. <<label1>>
  2. <<label12>> -- 不支持同时标记位置,二者必须删掉一个
  3. a := b;
  1. 支持在 EVENT / TRIGGER / PACKAGE / 匿名块 内使用 GOTO 语法。如果在 EVENT / TRIGGER 中因逻辑错误可能造成死循环,会造成系统资源浪费,应该谨慎使用。

4. 示例

    1. 示例1:往前跳转
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE goto_sp1(v_str IN OUT VARCHAR)
  4. AS
  5. BEGIN
  6. v_str := 'label1';
  7. GOTO label1;
  8. <<label1>>
  9. -- 又立即跳转到label2,即RETURN完成
  10. GOTO label2;
  11. v_str := 'label2';
  12. <<label2>>
  13. RETURN;
  14. END; //
  15. greatsql> CALL goto_sp1(@v_str) //
  16. Query OK, 0 rows affected (0.00 sec)
  17. greatsql> SELECT @v_str //
  18. +--------+
  19. | @v_str |
  20. +--------+
  21. | label1 |
  22. +--------+
  23. 1 row in set (0.00 sec)
    1. 示例2:往回跳转
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE goto_sp2(v_str IN OUT VARCHAR)
  4. AS
  5. BEGIN
  6. v_str := 'label1';
  7. <<label1>>
  8. IF (v_str = 'label2') THEN
  9. RETURN;
  10. END IF;
  11. v_str := 'label2';
  12. GOTO label1;
  13. END; //
  14. greatsql> CALL goto_sp2(@v_str) //
  15. greatsql> SELECT @v_str //
  16. +--------+
  17. | @v_str |
  18. +--------+
  19. | label2 |
  20. +--------+
  21. 1 row in set (0.00 sec)
    1. 示例3:支持条件判断处理
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE goto_sp3(n INT, ret OUT VARCHAR)
  4. AS
  5. a INT;
  6. BEGIN
  7. <<label1>>
  8. BEGIN
  9. SELECT a INTO a FROM information_schema.TABLES LIMIT n;
  10. EXCEPTION
  11. WHEN TOO_MANY_ROWS THEN
  12. BEGIN
  13. ret := ret||'--- too_many_rows cought 1 ---';
  14. GOTO label2;
  15. END;
  16. WHEN NO_DATA_FOUND THEN
  17. BEGIN
  18. ret := ret||'--- no_data_found cought 1 ---';
  19. n := 2;
  20. SELECT a INTO a FROM information_schema.TABLES LIMIT n;
  21. EXCEPTION
  22. WHEN TOO_MANY_ROWS THEN
  23. BEGIN
  24. ret := ret||'--- too_many_rows cought 2 ---';
  25. GOTO label1;
  26. END;
  27. WHEN NO_DATA_FOUND THEN ret := '--- no_data_found cought 2 ---';
  28. END;
  29. END;
  30. SET ret := ret||' error ';
  31. <<label2>>
  32. RETURN;
  33. END; //
  34. greatsql> CALL goto_sp3(0, @ret) //
  35. Query OK, 0 rows affected (0.00 sec)
  36. greatsql> SELECT @ret //
  37. +--------------------------------------------------------------------------------------------+
  38. | @ret |
  39. +--------------------------------------------------------------------------------------------+
  40. | --- no_data_found cought 1 ------ too_many_rows cought 2 ------ too_many_rows cought 1 --- |
  41. +--------------------------------------------------------------------------------------------+
  42. 1 row in set (0.00 sec)
  43. greatsql> CALL goto_sp3(0, @ret) //
  44. Query OK, 0 rows affected (0.00 sec)
  45. greatsql> SELECT @ret //
  46. +--------------------------------------------------------------------------------------------+
  47. | @ret |
  48. +--------------------------------------------------------------------------------------------+
  49. | --- no_data_found cought 1 ------ too_many_rows cought 2 ------ too_many_rows cought 1 --- |
  50. +--------------------------------------------------------------------------------------------+
  51. 1 row in set (0.00 sec)
  52. greatsql> CALL goto_sp3(3, @ret) //
  53. Query OK, 0 rows affected (0.00 sec)
  54. greatsql> SELECT @ret //
  55. +--------------------------------+
  56. | @ret |
  57. +--------------------------------+
  58. | --- too_many_rows cought 1 --- |
  59. +--------------------------------+
  60. 1 row in set (0.00 sec)
  61. greatsql> CALL goto_sp3(1, @ret) //
  62. Query OK, 1 row affected (0.00 sec)
  63. greatsql> SELECT @ret //
  64. +---------+
  65. | @ret |
  66. +---------+
  67. | error |
  68. +---------+
  69. 1 row in set (0.00 sec)
    1. 示例4:不能跳转到CASE WHEN语句块
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE goto_sp4()
  4. AS
  5. a INT;
  6. BEGIN
  7. GOTO label1;
  8. case 1
  9. WHEN 1 THEN
  10. <<label1>>
  11. a := 2;
  12. WHEN 2 THEN
  13. a := 1;
  14. END CASE;
  15. RETURN;
  16. END; //
  17. ERROR 1308 (42000): GOTO with no matching label: label1
    1. 示例5:不能跳转到另一个 CASE WHEN 语句块
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE goto_sp5()
  4. AS
  5. a INT;
  6. BEGIN
  7. CASE 1
  8. WHEN 1 THEN
  9. <<label1>>
  10. a := 2;
  11. WHEN 2 THEN
  12. a := 1;
  13. GOTO label1;
  14. end case;
  15. RETURN;
  16. END; //
  17. ERROR 1308 (42000): GOTO with no matching label: label1

问题反馈

联系我们

扫码关注微信公众号

greatsql-wx