Oracle兼容-存储过程-Exception Handler


在存储过程/存储函数中,当发生异常时,支持以下几种不同处理方式:

  1. 异常处理 Exception Handler

  2. 异常声明 Exception Declaration

  3. 抛出异常 Exception Raise

1. 异常处理 Exception Handler

在存储过程/存储函数中,发生异常的原因可能来自于设计错误、编码错误、硬件故障及其他,无法预测所有可能的异常。

但可以针对这些状况,编写异常处理程序,让程序在异常发生时仍可继续运行。

任何语句块都可以有一个异常处理部分,可以有一个或多个异常处理程序。

1.1 语法

  1. 1. WHEN { exception [ OR exception2 ]... | OTHERS }
  2. THEN handler_statement [ handler_statement2 ]...
  3. END;
  4. 2. EXCEPTION
  5. WHEN exception THEN handler_statement -- Exception handler1
  6. WHEN exception2 OR exception3 THEN handler_statement2 -- Exception handler2
  7. WHEN OTHERS THEN handler_statement3 -- Exception handler3
  8. END;

1.2 定义和用法

  • exception:异常名,预定义的异常(见下方表格)或用户定义的异常的名称。

  • OTHERS:其他异常,在代码块异常处理部分没有明确指定的其他所有异常。

  • handler_statement:异常处理语句,当触发了异常,将会执行指定的处理语句。

  • 已预定义好的异常名(表格1):

Oracle中的异常名GreatSQL是否支持映射到GreatSQL中对应的异常名
NO_DATA_FOUNDYER_SP_FETCH_NO_DATA
INVALID_CURSORYER_SP_CURSOR_NOT_OPEN
DUP_VAL_ON_INDEXYER_DUP_ENTRY
DUP_VAL_ON_INDEXYER_DUP_ENTRY_WITH_KEY_NAME
TOO_MANY_ROWSYER_TOO_MANY_ROWS
INVALID_NUMBERYER_DATA_OUT_OF_RANGE
CURSOR_ALREADY_OPENYER_SP_CURSOR_ALREADY_OPEN
VALUE_ERRORYER_WRONG_VALUE
STORAGE_ERRORYER_GET_ERRNO
ZERO_DIVIDEYER_DIVISION_BY_ZERO
ACCESS_INTO_NULLN
CASE_NOT_FOUNDN
COLLECTION_IS_NULLN
LOGIN_DENIEDN
NO_DATA_NEEDEDN
NOT_LOGGED_ONN
PROGRAM_ERRORN
ROWTYPE_MISMATCHN
SELF_IS_NULLN
SUBSCRIPT_BEYOND_COUNTN
SUBSCRIPT_OUTSIDE_LIMITN
SYS_INVALID_ROWIDN
TIMEOUT_ON_RESOURCEN

更多预定义的异常错误信息,详见参考:Server Error Message Reference异常处理 EXCEPTION HANDLER - 图1 (opens new window)

关于Oracle异常错误,详见参考:Exception Declaration异常处理 EXCEPTION HANDLER - 图2 (opens new window)

提示:错误号本身不能兼容Oracle,因为它和GreatSQL为各自体系错误信息,不存在复用。

2. 异常声明 Exception Declaration

2.1 语法

  1. 1. exception_name EXCEPTION
  2. 2. PRAGMA EXCEPTION_INIT ( EXCEPTION, ERROR_CODE ) ;

2.2 定义

  1. 自定义异常名称。只能在 EXCEPTION_INIT PRAGMARAISERAISE_APPLICATION_ERROR 调用或异常处理程序中使用异常。
  1. exception_name EXCEPTION
  1. EXCEPTION_INIT pragma 将此名称分配给内部定义的异常。
  1. PRAGMA EXCEPTION_INIT ( EXCEPTION, ERROR_CODE ) ;

关于 EXCEPTION_INIT 的用法可参考下方示例4、示例6。

参考:

3. 抛出异常

3.1 RAISE

3.1.1 语法

  1. RAISE [ exception ]

3.1.2 定义

可以调用 RAISE 主动触发抛出异常,在异常处理程序之外,必须指定异常名称。

在异常处理程序中,如果省略异常名称,则该 RAISE 语句会重新引发当前异常。

  • 参数 exception 可以是以下两种
      1. 预定义异常名称 (见上方所示表格1)。
      1. 自定义声明的异常名。

调用 RAISE 主动抛出异常的行为等同于 SIGNAL Statement,可用的溢出与禁止使用的错误号详见文档:SIGNAL Statement异常处理 EXCEPTION HANDLER - 图5 (opens new window)

关于 RAISE exception 的用法可参考下方示例3、示例4。

3.2 RAISE_APPLICATION_ERROR

3.2.1 语法

  1. RAISE_APPLICATION_ERROR (ERROR_CODE, MESSAGE)

3.2.2 定义

利用 RAISE_APPLICATION_ERROR 可以主动抛出自定义错误。

参数定义
ERROR_CODESMALLINT UNSIGNED
MESSAGEVARCHAR(128)

关于 RAISE_APPLICATION_ERROR 的用法可参考下方示例5。

4. 示例

创建测试表并初始化数据

  1. greatsql> CREATE TABLE t1 (a INT NOT NULL, b VARCHAR(20) NOT NULL);
  2. greatsql> INSERT INTO t1 VALUES(1, 'row1'), (2, 'row2'), (3,'row3') ;
    1. 示例1,使用预定义异常 TOO_MANY_ROWSNO_DATA_FOUND
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE exception_sp1(n INT, ret OUT VARCHAR(50)) AS
  4. a INT;
  5. BEGIN
  6. SELECT a INTO a FROM t1 LIMIT n;
  7. EXCEPTION
  8. WHEN TOO_MANY_ROWS THEN
  9. SET ret = '--- TOO_MANY_ROWS cought ---';
  10. WHEN NO_DATA_FOUND THEN
  11. SET ret = '--- NO_DATA_FOUND cought ---';
  12. END; //
  13. greatsql> SET @ret = ''; CALL exception_sp1(0, @ret); SELECT @ret //
  14. Query OK, 0 rows affected (0.00 sec)
  15. Query OK, 0 rows affected (0.00 sec)
  16. +------------------------------+
  17. | @ret |
  18. +------------------------------+
  19. | --- NO_DATA_FOUND cought --- |
  20. +------------------------------+
  21. 1 row in set (0.00 sec)
  22. greatsql>
  23. greatsql> SET @ret = ''; CALL exception_sp1(1, @ret); SELECT @ret //
  24. Query OK, 0 rows affected (0.00 sec)
  25. Query OK, 1 row affected (0.00 sec)
  26. +------+
  27. | @ret |
  28. +------+
  29. | NULL |
  30. +------+
  31. 1 row in set (0.00 sec)
  32. greatsql>
  33. greatsql> SET @ret = ''; CALL exception_sp1(2, @ret); SELECT @ret //
  34. Query OK, 0 rows affected (0.00 sec)
  35. Query OK, 0 rows affected (0.00 sec)
  36. +------------------------------+
  37. | @ret |
  38. +------------------------------+
  39. | --- TOO_MANY_ROWS cought --- |
  40. +------------------------------+
  41. 1 row in set (0.00 sec)
    1. 示例2,处理 OTHERS 异常
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE exception_sp2(ret OUT VARCHAR(50)) AS
  4. BEGIN
  5. SELECT 1/0 ;
  6. EXCEPTION
  7. WHEN ZERO_DIVIDE THEN
  8. SET ret = '--- ZERO_DIVIDE cought ---';
  9. WHEN OTHERS THEN
  10. SET ret = '--- others cought ---';
  11. END; //
  12. greatsql> SET @ret = ''; CALL exception_sp2(@ret); SELECT @ret //
  13. Query OK, 0 rows affected (0.00 sec)
  14. Empty set (0.00 sec)
  15. Query OK, 0 rows affected (0.00 sec)
  16. +----------------------------+
  17. | @ret |
  18. +----------------------------+
  19. | --- ZERO_DIVIDE cought --- |
  20. +----------------------------+
  21. 1 row in set (0.00 sec)
    1. 示例3,调用 RAISE 抛出异常
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE exception_sp3() AS
  4. BEGIN
  5. BEGIN
  6. SELECT 'Hi GreatSQL';
  7. -- 通过RAISE直接抛出异常
  8. RAISE TOO_MANY_ROWS;
  9. EXCEPTION
  10. WHEN OTHERS THEN
  11. SELECT 'GET RAISE EXCEPTION FROM OTHERS AND RAISE' AS ret;
  12. -- 并且抛出 TOO_MANY_ROWS 异常
  13. RAISE;
  14. END;
  15. -- 捕获主动定义的TOO_MANY_ROWS异常
  16. EXCEPTION
  17. WHEN TOO_MANY_ROWS THEN
  18. SELECT 'GET TOO_MANY_ROWS FROM MANUALLY RAISE' AS ret;
  19. END; //
  20. greatsql> CALL exception_sp3() //
  21. +-------------+
  22. | Hi GreatSQL |
  23. +-------------+
  24. | Hi GreatSQL |
  25. +-------------+
  26. 1 row in set (0.00 sec)
  27. +-------------------------------------------+
  28. | ret |
  29. +-------------------------------------------+
  30. | GET RAISE EXCEPTION FROM OTHERS AND RAISE |
  31. +-------------------------------------------+
  32. 1 row in set (0.00 sec)
  33. +---------------------------------------+
  34. | ret |
  35. +---------------------------------------+
  36. | GET TOO_MANY_ROWS FROM MANUALLY RAISE |
  37. +---------------------------------------+
  38. 1 row in set (0.00 sec)
  39. Query OK, 0 rows affected (0.00 sec)
    1. 示例4,自定义异常
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE exception_sp4() AS
  4. a EXCEPTION;
  5. BEGIN
  6. DECLARE
  7. c EXCEPTION;
  8. BEGIN
  9. RAISE c;
  10. EXCEPTION
  11. WHEN c THEN
  12. SELECT 'GET c RAISE 1' AS ret;
  13. RAISE;
  14. END;
  15. EXCEPTION
  16. WHEN a THEN
  17. SELECT 'GET a RAISE 2 IS FAILED' AS ret;
  18. WHEN OTHERS THEN
  19. SELECT 'GET a RAISE OTHERS IS FAILED' AS ret;
  20. END; //
  21. greatsql> CALL exception_sp4() //
  22. +---------------+
  23. | ret |
  24. +---------------+
  25. | GET c RAISE 1 |
  26. +---------------+
  27. 1 row in set (0.00 sec)
  28. +------------------------------+
  29. | ret |
  30. +------------------------------+
  31. | GET a RAISE OTHERS IS FAILED |
  32. +------------------------------+
  33. 1 row in set (0.00 sec)
  34. Query OK, 0 rows affected (0.00 sec)
    1. 示例5,自定义异常与消息
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE exception_sp5() AS
  4. BEGIN
  5. RAISE_APPLICATION_ERROR(33306, 'GreatSQL exception in sp');
  6. END; //
  7. greatsql> CALL exception_sp5() //
  8. ERROR 33306 (HY000): GreatSQL exception in sp
    1. 示例6,异常绑定错误号
  1. greatsql> SET sql_mode = ORACLE;
  2. greatsql> DELIMITER //
  3. greatsql> CREATE OR REPLACE PROCEDURE exception_sp6(n INT) AS
  4. a EXCEPTION;
  5. b INT;
  6. PRAGMA EXCEPTION_INIT(a, 1329);
  7. BEGIN
  8. SELECT a INTO b FROM t1 LIMIT n;
  9. EXCEPTION
  10. WHEN a THEN
  11. SELECT '--NO_DATA_FOUND--' AS ret;
  12. WHEN OTHERS THEN
  13. SELECT 'GET OTHERS' AS ret;
  14. RAISE;
  15. END; //
  16. greatsql> CALL exception_sp6(0) //
  17. +-------------------+
  18. | ret |
  19. +-------------------+
  20. | --NO_DATA_FOUND-- |
  21. +-------------------+
  22. 1 row in set (0.00 sec)
  23. Query OK, 0 rows affected (0.00 sec)
  24. greatsql> CALL exception_sp6(1) //
  25. Query OK, 1 row affected (0.00 sec)
  26. greatsql>
  27. greatsql> CALL exception_sp6(2) //
  28. +------------+
  29. | ret |
  30. +------------+
  31. | GET OTHERS |
  32. +------------+
  33. 1 row in set (0.00 sec)
  34. ERROR 1172 (42000): Result consisted of more than one row

问题反馈

联系我们

扫码关注微信公众号

greatsql-wx