实现PostgreSQL函数自定义例外处理

别等时光非礼了梦想. 提交于 2019-11-29 07:23:29

代码搬运也需要发挥想象力,让不可能变为可能,这里讲一个例子。

1、 有人问PostgreSQL有没有自定义例外,Oracle是有的:

--定义 myex Exception; --抛出 RAISE myex; --捕获 WHEN myex THEN

简单易用

2、再来看PostgreSQL的PL/pgSQL

RAISE [ level ] condition_name [ USING option = expression [, ... ] ]; RAISE [ level ] SQLSTATE 'sqlstate' [ USING option = expression [, ... ] ];

这两种语法似乎有一定的灵活性,实际上它们只能使用预定义的例外,文档中有说明,如果不能识别会报错。

ERROR: unrecognized exception condition "xxxxxxx" CONTEXT: compilation of PL/pgSQL function "func_a" near line 3

ERROR: invalid SQLSTATE code at or near "'12345'" LINE 5: RAISE SQLSTATE '12345' USING MESSAGE = 'zzz';

3、代码实现

这段是强行加戏,防止篇幅过小的一个例外处理,完全可以跳过而不会有任何影响。

for (i = 0; exception_label_map[i].label != NULL; i++) {    if (strcmp(condname, exception_label_map[i].label) == 0)      return exception_label_map[i].sqlerrstate; }

可以看出,能使用的名字或编码在编译时已经确定,不能自己定义。

4、但是,我们仍有办法可以做到

尽量选择一个上下文无关的错误,也就是这段代码不可能会抛出的例外,避免程序出错被错误拦截。

比如:0A000 feature_not_supported

我们可以抛出一个例外,用错误信息标记它的特殊性:

RAISE SQLSTATE '0A000' USING MESSAGE = 'flying0001:failed to ...';

在捕获它时可以按条件处理:

WHEN SQLSTATE '0A000' THEN DECLARE   m text; BEGIN   GET STACKED DIAGNOSTICS m = MESSAGE_TEXT;   IF ( strpos(m, 'flying0001:')=1) THEN     RAISE WARNING 'got flying0001';   ELSIF     ...   END IF; END;

虽然啰嗦,但确实是实现了同样的功能。

5、完整演示

也是加戏,凑篇幅用。

CREATE OR REPLACE FUNCTION func_a() RETURNS void AS $$ BEGIN RAISE SQLSTATE '0A000' USING MESSAGE = 'flying0001:Do one thing at a time, and do well.'; EXCEPTION WHEN feature_not_supported THEN DECLARE   m text; BEGIN   GET STACKED DIAGNOSTICS m = MESSAGE_TEXT;   IF (strpos(m, 'flying0001:')=1) THEN     RAISE WARNING 'got flying0001';   END IF; END; END; $$ LANGUAGE plpgsql;

很多时候,写代码需要更加开阔的视野,在不可能上创造可能。这样实现并不方便,但是肯定比改PL/pgSQL引擎简单的多。

等哪天心血来潮,写一个直接的支持实现,搬代码并不难,只是比较麻烦。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!