

DMSQL程序运行过程中,总会不可避免地发生一些错误,这种错误大部分不是程序本身的问题,而是由于一些未预计的操作,导致产生超出DMSQL程序预计处理范围的数据等错误,我们将这些错误称为异常。
本章从异常的定义、抛出及异常处理来讲解DMSQL的异常处理。
本章内容已在如下环境上测试:
①操作系统:中标麒麟7;
②数据库版本:达梦8;
相关关键字:EXCEPTION、SQLCODE、SQLERRM
DMSQL语句块
异常属于DMSQL语句块的一部分,DMSQL语句块是DMSQL程序的基本单元。每个语句块由关键字DECLARE、BEGIN、EXCEPTION和END划分为声明部分、执行部分和异常处理三部分。其中执行部分是必须的,说明和异常处理部分可选。
语句块的语法如下:
[DECLARE <变量说明>{,<变量说明>};]
BEGIN
<执行部分>
[<异常处理部分>]
END
声明部分
声明部分由关键字DECLARE开始,用于定义变量和常量的数据类型和初始值。如果不需要声明变量或常量,可以忽略这一部分。游标的声明也放在这一部分。
执行部分
执行部分是语句块中的指令部分,由关键字BEGIN开始,以关键字EXCEPTION结束,如果EXCEPTION不存在,那么将以关键字END结束。所有的可执行语句或语句块都放在这一部分。
数据操作语句(DML)和事务控制语句COMMIT和ROLLBACK可用于执行部分;执行部分使用的变量和常量必须首先在声明部分声明;执行部分必须至少包括一条可执行语句,可以是NULL;DDL语句需要与EXECUTE IMMEDIATE一起使用。
执行部分可使用DMSQL程序丰富的控制结构,包括分支结构、循环控制结构、顺序结构等,实现更复杂的DMSQL程序功能。
异常处理部分
异常处理部分可选,这一部分处理程序中可能发生的异常或错误。
这里重点介绍DMSQL的异常处理部分。
异常处理
异常部分对DMSQL执行过程中抛出的异常进行处理,可以处理一个或多个异常。语法如下:
EXCEPTION
WHEN <异常名> {OR <异常名>} THEN
<执行部分>;
EXCEPTION关键字是异常处理部分的开始。如果在语句块的执行中出现异常,执行就被传递给语句块的异常处理部分。如果在本语句块的异常处理部分没有相应的异常处理对它进行处理,系统就会中止此语句块的执行,并将此异常传递到该语句块的上一层语句块或其调用者,一直传递到最外层。如果始终没有找到相应的异常处理,则中止本次调用语句,并向用户报告错误。
一个EXCEPTION子句,必须至少包含一个WHEN开头的异常子句。语句参考如下:
EXCEPTION
WHEN ex_name_1 THEN
statements_1;
WHEN ex_name_2 OR ex_name_3 THEN
statements_2;
WHEN OTHERS THEN
statements_3;
END;
预定义异常
为方便用户编程,DM数据库提供了一些预定义的异常,这些异常与常见的DM错误相对应,如下表所示。

除上述外,还有一个特殊的异常名OTHERS,它处理没有明确列出的异常。OTHERS对应的异常处理语句必须放在其他异常处理语句之后。
自定义异常
除了DM预定义的异常外,用户可以在DMSQL程序中自定义异常。程序员可以把一些特定的状态定义为异常,在一定的条件下抛出,然后利用DMSQL程序的异常机制进行处理。
DMSQL程序支持两种自定义异常的方法。
EXCEPTION FOR
使用EXCEPTION FOR将异常变量与错误号绑定,语法如下:
<异常变量名> EXCEPTION
[FOR <错误号> [, <错误描述>]];
异常变量在DMSQL程序的声明部分定义。其中,FOR子句用来为异常变量绑定错误号(SQLCODE)及错误描述(SQLERRM)。<错误号>必须是-20000到-30000间的负数值,<错误描述>则为字符串类型。如果未显式指定错误号,则系统在运行中在-15000至-19999区间中顺序为其绑定错误值。
使用方法参考例3.
EXCEPTION_INIT
使用EXCEPTION_INIT将一个特定的错误号与程序中所声明的异常标示符关联起来,语法如下(先声明一个异常变量,再使用EXCEPTION_INIT将一个特定的错误号与此异常变量关联):
<异常变量名> EXCEPTION;
PRAGMA EXCEPTION_INIT(<异常变量名>, <错误号>);
这种方式可以通过异常变量名引用任意的DM服务器内部异常(DM服务器内部异常可参考《DM8程序员手册》),并且可以通过异常名为异常编写适当的异常处理。
使用方法参考例1。
异常抛出
DMSQL程序运行时如果发生错误,系统会自动抛出异常;程序员也可以使用RAISE主动抛出一个异常。例如,当程序运行并不违反数据库规则,但是不满足应用的业务逻辑时,可以主动抛出一个异常并进行处理。
使用RAISE抛出异常,异常抛出分为有异常名和无异常名两种情况。
有异常名
语法如下:
RAISE <异常名>
可以使用RAISE语句抛出一个系统预定义异常或用户自定义异常。
无异常名
如果没有在声明部分定义异常变量,也可以在执行部分使用DM提供的系统过程直接抛出自定义异常。语法如下:
RAISE_APPLICATION_ERROR (
ERR_CODE IN INT,
ERR_MSG IN VARCHAR(2000)
);
ERR_CODE:错误码,取值范围为-20000~-30000;
ERR_MSG:用户自定义的错误信息,长度不能超过2000字节。
此方法只能抛出错误码定义在-20000~-30000的异常。
内置函数SQLCODE和SQLERRM
DMSQL程序提供了内置函数SQLCODE和SQLERRM返回异常对应的错误码和描述信息。SQLCODE返回错误码,为负数;SQLERRM返回异常的描述信息。
如果程序员想查询某个错误码对应的错误描述信息,可以调用SQLERRM函数,语法如下:
VARCHAR SQLERRM(
ERROR_NUMBER INT
);
ERROR_NUMBER:错误码参数。
SQLERRM返回值遵循如下规则。
若异常为DM服务器内部错误,则SQLERRM返回该错误的描述信息,否则SQLERRM的返回值遵循以下规则:
如果错误码在-15000至-19999间,返回'User-Defined Exception';
如果错误码在-20000至-30000之间,返回'DM-<错误码绝对值>';
如果错误码大于0或小于-65535,返回'-<错误码绝对值>: non-DM exception';
否则,返回'DM-<错误码绝对值>: Message <错误码绝对值> not found;'。
比如查询-3510错误码的描述信息,可以使用select sqlerrm(-3510)语句查询,结果显示如下:

异常处理示例
例1:使用EXCEPTION_INIT定义异常,并使用RAISE抛出异常,使用SQLCODE和SQLERRM查看异常码和异常描述信息:

执行结果如下:

例2:直接使用RAISE_APPLICATION_ERROR抛出用户自定义异常,并使用SQLCODE和SQLERRM查看异常码和描述信息。

执行结果如下:

如果将定义的错误码修改为-10001(不在-20000至-30000之间),则返回DM服务器内部异常。


调用此存储过程P_EXCEPTION_TEST,当员工邮箱不为空时,打印出员工信息和邮箱信息,当员工邮箱为空时,打印出员工名称和邮箱为空的提醒,当查询无此员工时,打印查无此人。

好,以上是本次分享内容,可以看出,DMSQL程序的异常定义、抛出、处理及异常函数基本兼容ORACLE的PL/SQL程序的异常处理。
往期 · 推荐





