exception内核改造简单研究。
PG
1 实例
PG只支持预定义异常的处理,即异常code都是定义好的,触发后走EXCEPTION部分代码逻辑。
DROP TABLE db;
CREATE TABLE db (a INT PRIMARY KEY, b TEXT);
CREATE OR REPLACE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS
$$
DECLARE
text_var1 text;
text_var2 text;
text_var3 text;
BEGIN
LOOP
BEGIN
INSERT INTO db(a,b) VALUES (key, data);
RETURN;
EXCEPTION WHEN unique_violation THEN
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT, text_var2 = PG_EXCEPTION_DETAIL, text_var3 = PG_EXCEPTION_HINT;
RAISE NOTICE E'MESSAGE_TEXT: %\n', text_var1;
RAISE NOTICE E'PG_EXCEPTION_DETAIL: %\n', text_var2;
RAISE NOTICE E'PG_EXCEPTION_HINT: %\n', text_var3;
RETURN;
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
SELECT merge_db(1, 'david');
SELECT merge_db(1, 'dennis');
postgres=# SELECT merge_db(1, 'dennis');
NOTICE: MESSAGE_TEXT: duplicate key value violates unique constraint "db_pkey"
NOTICE: PG_EXCEPTION_DETAIL: Key (a)=(1) already exists.
NOTICE: PG_EXCEPTION_HINT:
merge_db
----------
(1 row)
2 PG异常处理语法
https://www.postgresql.org/docs/14/plpgsql-control-structures.html
[ <<label>> ]
[ DECLARE
declarations ]
BEGIN
statements
EXCEPTION
WHEN condition [ OR condition ... ] THEN
handler_statements
[ WHEN condition [ OR condition ... ] THEN
handler_statements
... ]
END;
-
其中condition在这里查阅:
https://www.postgresql.org/docs/14/errcodes-appendix.html -
支持两种形式的写法:
WHEN division_by_zero THEN ...
WHEN SQLSTATE '22012' THEN ...
Oracle
oracle支持三种异常形式:
https://docs.oracle.com/cd/E11882_01/timesten.112/e21639/exceptions.htm#TTPLS195
- 第一种Predefined TimesTen error是和PG概念相同的。可以直接迁移。
- 后两种需要PG代码改造实现。
1 预定义异常处理实例
SQL触发一些已经定义好的异常
Command> DECLARE v_invalid PLS_INTEGER;
> BEGIN
> v_invalid := 100/0;
> EXCEPTION
> WHEN ZERO_DIVIDE THEN
> DBMS_OUTPUT.PUT_LINE ('Attempt to divide by 0');
> END;
> /
Attempt to divide by 0
PL/SQL procedure successfully completed.
2 用户定义异常处理实例
代码中主动raise,跳转到异常逻辑继续执行
Command> DECLARE
> v_deptno NUMBER := 500;
> v_name VARCHAR2 (20) := 'Testing';
> e_invalid_dept EXCEPTION;
> BEGIN
> UPDATE departments
> SET department_name = v_name
> WHERE department_id = v_deptno;
> IF SQL%NOTFOUND THEN
> RAISE e_invalid_dept;
> END IF;
> ROLLBACK;
> EXCEPTION
> WHEN e_invalid_dept THEN
> DBMS_OUTPUT.PUT_LINE ('No such department');
> DBMS_OUTPUT.PUT_LINE (SQLERRM);
> DBMS_OUTPUT.PUT_LINE (SQLCODE);
> END;
> /
No such department
User-Defined Exception
1
PL/SQL procedure successfully completed.
The command succeeded.
3 非预定义异常处理
出现一个异常后,将异常CODE和自定义异常名字关联起来,触发后直接进入定义好的处理逻辑。
步骤
-- 定义
<异常情况> EXCEPTION;
-- 与标准的ORACLE错误联系起来
PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>);
-- 处理
实例
DECLARE
deadlock_detected EXCEPTION;
PRAGMA EXCEPTION_INIT(deadlock_detected, -60);
BEGIN
NULL; -- Some operation that causes an ORA-00060 error
EXCEPTION
WHEN deadlock_detected THEN
NULL; -- handle the error
END;
/
实例2
INSERT INTO departments VALUES(50, 'FINANCE', 'CHICAGO');
DECLARE
v_deptno departments.department_id%TYPE := &deptno;
deptno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(deptno_remaining, -2292);
/* -2292 是违反一致性约束的错误代码 */
BEGIN
DELETE FROM departments WHERE department_id = v_deptno;
EXCEPTION
WHEN deptno_remaining THEN
DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/errors.htm#i1863