一个通用的错误处理器

书上的一个例子:比较好

set serveroutput on size 200000
set linesize 250

-- These 3 procedures illustrate the use of FORMAT_CALL_STACK.
CREATE OR REPLACE PROCEDURE C AS
v_CallStack VARCHAR2(2000);
BEGIN
v_CallStack := DBMS_UTILITY.FORMAT_CALL_STACK;
DBMS_OUTPUT.PUT_LINE(v_CallStack);
END C;
/

CREATE OR REPLACE PROCEDURE B AS
BEGIN
C;
END B;
/

CREATE OR REPLACE PROCEDURE A AS
BEGIN
B;
END A;
/

exec A;

DROP TABLE errors;
CREATE TABLE errors (
module VARCHAR2(50),
seq_number NUMBER,
error_number NUMBER,
error_mesg VARCHAR2(100),
error_stack VARCHAR2(2000),
call_stack VARCHAR2(2000),
timestamp DATE,
PRIMARY KEY (module, seq_number));

DROP TABLE call_stacks;
CREATE TABLE call_stacks (
module VARCHAR2(50),
seq_number NUMBER,
call_order NUMBER,
object_handle VARCHAR2(10),
line_num NUMBER,
object_name VARCHAR2(80),
PRIMARY KEY (module, seq_number, call_order),
FOREIGN KEY (module, seq_number) REFERENCES errors ON DELETE CASCADE);

DROP TABLE error_stacks;
CREATE TABLE error_stacks (
module VARCHAR2(50),
seq_number NUMBER,
error_order NUMBER,
facility CHAR(3),
error_number NUMBER(5),
error_mesg VARCHAR2(100),
PRIMARY KEY (module, seq_number, error_order),
FOREIGN KEY (module, seq_number) REFERENCES errors ON DELETE CASCADE);

DROP SEQUENCE error_seq;
CREATE SEQUENCE error_seq
START WITH 1
INCREMENT BY 1;

/* Generic error-handling package, using
DBMS_UTILITY.FORMAT_ERROR_STACK and DBMS_UTILITY.FORMAT_CALL_STACK.
This package will store general error information in the errors
table, with detailed call stack and error stack information in the
call_stacks and error_stacks tables, respectively. */
CREATE OR REPLACE PACKAGE ErrorPkg AS

-- Entry point for handling errors. HandleAll should be called
-- from all exception handlers where you want the error to be
-- logged. p_Top should be TRUE only at the topmost level of
-- procedure nesting. It should be FALSE at other levels.
PROCEDURE HandleAll(p_Top BOOLEAN);

-- Prints the error and call stacks (using DBMS_OUTPUT) for the
-- given module and sequence number.
PROCEDURE PrintStacks(p_Module IN errors.module%TYPE,
p_SeqNum IN errors.seq_number%TYPE);

-- Unwinds the call and error stacks, and stores them in the errors
-- and call_stacks tables. Returns the sequence number under which
-- the error is stored.
-- If p_CommitFlag is TRUE, then the inserts are committed.
-- In order to use StoreStacks, an error must have been handled.
-- Thus HandleAll should have been called with p_Top = TRUE.
PROCEDURE StoreStacks(p_Module IN errors.module%TYPE,
p_SeqNum OUT errors.seq_number%TYPE,
p_CommitFlag BOOLEAN DEFAULT FALSE);
END ErrorPkg;
/
show errors

CREATE OR REPLACE PACKAGE BODY ErrorPkg AS

v_NewLine CONSTANT CHAR(1) := CHR(10);

v_Handled BOOLEAN := FALSE;
v_ErrorStack VARCHAR2(2000);
v_CallStack VARCHAR2(2000);

PROCEDURE HandleAll(p_Top BOOLEAN) IS
BEGIN
IF p_Top THEN
v_Handled := FALSE;
ELSIF NOT v_Handled THEN
v_Handled := TRUE;
v_ErrorStack := DBMS_UTILITY.FORMAT_ERROR_STACK;
v_CallStack := DBMS_UTILITY.FORMAT_CALL_STACK;
END IF;
END HandleAll;

PROCEDURE PrintStacks(p_Module IN errors.module%TYPE,
p_SeqNum IN errors.seq_number%TYPE) IS
v_TimeStamp errors.timestamp%TYPE;
v_ErrorMsg errors.error_mesg%TYPE;

CURSOR c_CallCur IS
SELECT object_handle, line_num, object_name
FROM call_stacks
WHERE module = p_Module
AND seq_number = p_SeqNum
ORDER BY call_order;

CURSOR c_ErrorCur IS
SELECT facility, error_number, error_mesg
FROM error_stacks
WHERE module = p_Module
AND seq_number = p_SeqNum
ORDER BY error_order;
BEGIN
SELECT timestamp, error_mesg
INTO v_TimeStamp, v_ErrorMsg
FROM errors
WHERE module = p_Module
AND seq_number = p_SeqNum;

-- Output general error information.
DBMS_OUTPUT.PUT(TO_CHAR(v_TimeStamp, 'DD-MON-YY HH24:MI:SS'));
DBMS_OUTPUT.PUT(' Module: ' || p_Module);
DBMS_OUTPUT.PUT(' Error #' || p_SeqNum || ': ');
DBMS_OUTPUT.PUT_LINE(v_ErrorMsg);

-- Output the call stack.
DBMS_OUTPUT.PUT_LINE('Complete Call Stack:');
DBMS_OUTPUT.PUT_LINE(' Object Handle Line Number Object Name');
DBMS_OUTPUT.PUT_LINE(' ------------- ----------- -----------');
FOR v_CallRec in c_CallCur LOOP
DBMS_OUTPUT.PUT(RPAD(' ' || v_CallRec.object_handle, 15));
DBMS_OUTPUT.PUT(RPAD(' ' || TO_CHAR(v_CallRec.line_num), 13));
DBMS_OUTPUT.PUT_LINE(' ' || v_CallRec.object_name);
END LOOP;

-- Output the error stack.
DBMS_OUTPUT.PUT_LINE('Complete Error Stack:');
FOR v_ErrorRec in c_ErrorCur LOOP
DBMS_OUTPUT.PUT(' ' || v_ErrorRec.facility || '-');
DBMS_OUTPUT.PUT(TO_CHAR(v_ErrorRec.error_number) || ': ');
DBMS_OUTPUT.PUT_LINE(v_ErrorRec.error_mesg);
END LOOP;

END PrintStacks;

PROCEDURE StoreStacks(p_Module IN errors.module%TYPE,
p_SeqNum OUT errors.seq_number%TYPE,
p_CommitFlag BOOLEAN DEFAULT FALSE) IS
v_SeqNum NUMBER;

v_Index NUMBER;
v_Length NUMBER;
v_End NUMBER;

v_Call VARCHAR2(100);
v_CallOrder NUMBER := 1;
v_Handle call_stacks.object_handle%TYPE;
v_LineNum call_stacks.line_num%TYPE;
v_ObjectName call_stacks.object_name%TYPE;

v_Error VARCHAR2(120);
v_ErrorOrder NUMBER := 1;
v_Facility error_stacks.facility%TYPE;
v_ErrNum error_stacks.error_number%TYPE;
v_ErrMsg error_stacks.error_mesg%TYPE;

v_FirstErrNum errors.error_number%TYPE;
v_FirstErrMsg errors.error_mesg%TYPE;
BEGIN
-- First get the error sequence number.
SELECT error_seq.nextval
INTO v_SeqNum
FROM dual;

p_SeqNum := v_SeqNum;

-- Insert the first part of the header information into the
-- errors table.
INSERT INTO errors
(module, seq_number, error_stack, call_stack, timestamp)
VALUES
(p_Module, v_SeqNum, v_ErrorStack, v_CallStack, SYSDATE);

-- Unwind the error stack to get each error out. We do this by
-- scanning the error stack string. Start with the index at the
-- beginning of the string.
v_Index := 1;

-- Loop through the string, finding each newline. A newline ends
-- each error on the stack.
WHILE v_Index < LENGTH(v_ErrorStack) LOOP
-- v_End is the position of the newline.
v_End := INSTR(v_ErrorStack, v_NewLine, v_Index);

-- Thus, the error is between the current index and the
-- newline.
v_Error := SUBSTR(v_ErrorStack, v_Index, v_End - v_Index);

-- Skip over the current error, for the next iteration.
v_Index := v_Index + LENGTH(v_Error) + 1;

-- An error looks like 'facility-number: mesg'. We need to get
-- each piece out for insertion.

-- First, the facility is the first 3 characters of the error.
v_Facility := SUBSTR(v_Error, 1, 3);

-- Remove the facility and the dash (always 4 characters).
v_Error := SUBSTR(v_Error, 5);

-- Now we can get the error number.
v_ErrNum :=
TO_NUMBER(SUBSTR(v_Error, 1, INSTR(v_Error, ':') - 1));

-- Remove the error number, colon and space (always 7
-- characters).
v_Error := SUBSTR(v_Error, 8);

-- What's left is the error message.
v_ErrMsg := v_Error;

-- Insert the errors, and grab the first error number and
-- message while we're at it.
INSERT INTO error_stacks
(module, seq_number, error_order, facility, error_number,
error_mesg)
VALUES
(p_Module, p_SeqNum, v_ErrorOrder, v_Facility, v_ErrNum, v_ErrMsg);

IF v_ErrorOrder = 1 THEN
v_FirstErrNum := v_ErrNum;
v_FirstErrMsg := v_Facility || '-' || TO_NUMBER(v_ErrNum) ||
': ' || v_ErrMsg;
END IF;

v_ErrorOrder := v_ErrorOrder + 1;
END LOOP;

-- Update the errors table with the message and code.
UPDATE errors
SET error_number = v_FirstErrNum,
error_mesg = v_FirstErrMsg
WHERE module = p_Module
AND seq_number = v_SeqNum;

-- Now we need to unwind the call stack, to get each call out.
-- We do this by scanning the call stack string. Start with the
-- index after the first call on the stack. This will be after
-- the first occurrence of 'name' and the newline.
v_Index := INSTR(v_CallStack, 'name') + 5;

-- Loop through the string, finding each newline. A newline ends
-- each call on the stack.
WHILE v_Index < LENGTH(v_CallStack) LOOP
-- v_End is the position of the newline.
v_End := INSTR(v_CallStack, v_NewLine, v_Index);

-- Thus, the call is between the current index and the newline.
v_Call := SUBSTR(v_CallStack, v_Index, v_End - v_Index);

-- Skip over the current call, for the next iteration.
v_Index := v_Index + LENGTH(v_Call) + 1;

-- Within a call, we have the object handle, then the line
-- number, then the object name, separated by spaces. We need
-- to separate them out for insertion.

-- Trim white space from the call first.
v_Call := LTRIM(v_Call);

-- First get the object handle.
v_Handle := SUBSTR(v_Call, 1, INSTR(v_Call, ' '));

-- Now, remove the object handle, then the white space from
-- the call.
v_Call := SUBSTR(v_Call, LENGTH(v_Handle) + 1);
v_Call := LTRIM(v_Call);

-- Now we can get the line number.
v_LineNum := TO_NUMBER(SUBSTR(v_Call, 1, INSTR(v_Call, ' ')));

-- Remove the line number, and white space.
v_Call := SUBSTR(v_Call, LENGTH(v_LineNum) + 1);
v_Call := LTRIM(v_Call);

-- What is left is the object name.
v_ObjectName := v_Call;

-- Insert all calls except the call for ErrorPkg.
IF v_CallOrder > 1 THEN
INSERT INTO call_stacks
(module, seq_number, call_order, object_handle, line_num,
object_name)
VALUES
(p_Module, v_SeqNum, v_CallOrder, v_Handle, v_LineNum,
v_ObjectName);
END IF;

v_Callorder := v_CallOrder + 1;

END LOOP;

IF p_CommitFlag THEN
COMMIT;
END IF;
END StoreStacks;

END ErrorPkg;
/
show errors


CREATE OR REPLACE TRIGGER temp_insert
BEFORE INSERT ON temp_table
BEGIN
RAISE ZERO_DIVIDE;
END ttt_insert;
/

CREATE OR REPLACE PROCEDURE C AS
BEGIN
INSERT INTO temp_table (num_col) VALUES (7);
EXCEPTION
WHEN OTHERS THEN
ErrorPkg.HandleAll(FALSE);
RAISE;
END C;
/

CREATE OR REPLACE PROCEDURE B AS
BEGIN
C;
EXCEPTION
WHEN OTHERS THEN
ErrorPkg.HandleAll(FALSE);
RAISE;
END B;
/

CREATE OR REPLACE PROCEDURE A AS
v_ErrorSeq NUMBER;
BEGIN
B;
EXCEPTION
WHEN OTHERS THEN
ErrorPkg.HandleAll(TRUE);
ErrorPkg.StoreStacks('Error Test', v_ErrorSeq, TRUE);
ErrorPkg.PrintStacks('Error Test', v_ErrorSeq);
END A;
/


SET SERVEROUTPUT ON SIZE 1000000 FORMAT TRUNCATED
exec A;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值