--Example 11–14 Exception that Propagates
Beyond Scope is Handled
CREATE
OR REPLACE
PROCEDURE p
AUTHID DEFINER
AS
BEGIN
DECLARE
past_due EXCEPTION;
PRAGMA EXCEPTION_INIT (past_due, -4910);
due_date DATE := TRUNC (SYSDATE)
- 1;
todays_date DATE := TRUNC
(SYSDATE);
BEGIN
IF due_date < todays_date
THEN
RAISE past_due;
END IF;
END;
EXCEPTION
WHEN OTHERS
THEN
ROLLBACK;
RAISE;
END;
/
--Example 11–15 Exception that Propagates
Beyond Scope is Not Handled
BEGIN
DECLARE
past_due EXCEPTION;
due_date DATE := TRUNC (SYSDATE)
- 1;
todays_date DATE := TRUNC
(SYSDATE);
BEGIN
IF due_date < todays_date
THEN
RAISE past_due;
END IF;
END;
END;
/
--Example 11–16 Exception Raised in
Declaration is Not Handled
DECLARE
credit_limit CONSTANT
NUMBER (3) := 5000;
-- Maximum value is 999
BEGIN
NULL;
EXCEPTION
WHEN VALUE_ERROR
THEN
DBMS_OUTPUT.PUT_LINE
('Exception raised in declaration.');
END;
/
--Example 11–17 Exception Raised in
Declaration is Handled by Enclosing Block
BEGIN
DECLARE
credit_limit CONSTANT NUMBER (3) := 5000;
BEGIN
NULL;
END;
EXCEPTION
WHEN VALUE_ERROR
THEN
DBMS_OUTPUT.PUT_LINE
('Exception raised in declaration.');
END;
/
--Example 11–18 Exception Raised in
Exception Handler is Not Handled
CREATE
PROCEDURE print_reciprocal (n NUMBER)
AUTHID DEFINER
IS
BEGIN
DBMS_OUTPUT.PUT_LINE
(1 / n); -- handled
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Error:');
DBMS_OUTPUT.PUT_LINE
(1 / n || ' is undefined'); -- not handled
END;
/
BEGIN
-- invoking block
print_reciprocal (0);
END;
--Example 11–18 Exception Raised in
Exception Handler is Not Handled
CREATE
PROCEDURE print_reciprocal (n NUMBER)
AUTHID DEFINER
IS
BEGIN
DBMS_OUTPUT.PUT_LINE
(1 / n); -- handled
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Error:');
DBMS_OUTPUT.PUT_LINE
(1 / n || ' is undefined'); -- not handled
END;
/
BEGIN
-- invoking block
print_reciprocal (0);
END;
--Example 11–20 Exception Raised in
Exception Handler is Handled by Enclosing Block
CREATE
PROCEDURE print_reciprocal (n NUMBER)
AUTHID DEFINER
IS
BEGIN
BEGIN
DBMS_OUTPUT.PUT_LINE
(1 / n);
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Error in inner block:');
DBMS_OUTPUT.PUT_LINE
(1 / n || ' is undefined.');
END;
EXCEPTION
WHEN ZERO_DIVIDE
THEN
-- handles exception raised
in exception handler
DBMS_OUTPUT.PUT
('Error in outer block: ');
DBMS_OUTPUT.PUT_LINE
('1/0 is undefined.');
END;
/
BEGIN
print_reciprocal (0);
END;
/
--Example 11–21 Exception Raised in
Exception Handler is Not Handled
CREATE
PROCEDURE descending_reciprocals (n INTEGER)
AUTHID DEFINER
IS
i INTEGER;
i_is_one EXCEPTION;
BEGIN
i := n;
LOOP
IF i = 1
THEN
RAISE i_is_one;
ELSE
DBMS_OUTPUT.PUT_LINE
('Reciprocal of ' || i || ' is '
|| 1 / i);
END IF;
i := i - 1;
END LOOP;
EXCEPTION
WHEN i_is_one
THEN
DBMS_OUTPUT.PUT_LINE
('1 is its own reciprocal.');
DBMS_OUTPUT.PUT_LINE
(
'Reciprocal of '
|| TO_CHAR (i - 1)
|| ' is '
|| TO_CHAR (1 / (i - 1)));
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Error:');
DBMS_OUTPUT.PUT_LINE
(1 / n || ' is undefined');
END;
/
BEGIN
descending_reciprocals (3);
END;
/
--Example 11–22 Exception Raised in
Exception Handler is Handled by Enclosing Block
CREATE
PROCEDURE descending_reciprocals (n INTEGER)
AUTHID DEFINER
IS
i INTEGER;
i_is_one EXCEPTION;
BEGIN
BEGIN
i := n;
LOOP
IF i = 1
THEN
RAISE i_is_one;
ELSE
DBMS_OUTPUT.PUT_LINE
('Reciprocal of ' || i || ' is '
|| 1 / i);
END IF;
i := i - 1;
END LOOP;
EXCEPTION
WHEN i_is_one
THEN
DBMS_OUTPUT.PUT_LINE
('1 is its own reciprocal.');
DBMS_OUTPUT.PUT_LINE
(
'Reciprocal of '
|| TO_CHAR (i - 1)
|| ' is '
|| TO_CHAR (1 / (i - 1)));
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Error:');
DBMS_OUTPUT.PUT_LINE
(1 / n || ' is undefined');
END;
EXCEPTION
WHEN ZERO_DIVIDE
THEN
-- handles exception raised
in exception handler
DBMS_OUTPUT.PUT_LINE
('Error:');
DBMS_OUTPUT.PUT_LINE
('1/0 is undefined');
END;
/
BEGIN
descending_reciprocals (3);
END;
/
--Example 11–23 Displaying SQLCODE and
SQLERRM Values
DROP TABLE errors;
CREATE
TABLE errors
(
code NUMBER,
MESSAGE VARCHAR2
(64)
);
CREATE
OR REPLACE
PROCEDURE p
AUTHID DEFINER
AS
name EMPLOYEES.LAST_NAME%TYPE;
v_code NUMBER;
v_errm VARCHAR2
(64);
BEGIN
SELECT last_name
INTO name
FROM EMPLOYEES
WHERE EMPLOYEE_ID = -1;
EXCEPTION
WHEN OTHERS
THEN
v_code := SQLCODE;
v_errm := SUBSTR (SQLERRM,
1, 64);
DBMS_OUTPUT.PUT_LINE
('Error code ' || v_code || ': ' || v_errm);
/* Invoke another procedure,
declared with PRAGMA AUTONOMOUS_TRANSACTION,
to insert information about errors. */
INSERT INTO errors
(code, MESSAGE)
VALUES (v_code, v_errm);
RAISE;
END;
/
--Example 11–24 Exception Handler Runs
and Execution Ends
DROP TABLE employees_temp;
CREATE
TABLE employees_temp
AS
SELECT employee_id, salary, commission_pct FROM employees;
DECLARE
sal_calc NUMBER
(8, 2);
BEGIN
INSERT INTO employees_temp (employee_id, salary, commission_pct)
VALUES (301, 2500, 0);
SELECT (salary / commission_pct)
INTO sal_calc
FROM employees_temp
WHERE employee_id = 301;
INSERT INTO employees_temp
VALUES (302, sal_calc / 100, .1);
DBMS_OUTPUT.PUT_LINE
('Row inserted.');
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Division by zero.');
END;
/
--Example 11–25 Exception Handler Runs
and Execution Continues
DECLARE
sal_calc NUMBER
(8, 2);
BEGIN
INSERT INTO employees_temp (employee_id, salary, commission_pct)
VALUES (301, 2500, 0);
BEGIN
SELECT (salary / commission_pct)
INTO sal_calc
FROM employees_temp
WHERE employee_id = 301;
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Substituting 2500 for undefined number.');
sal_calc := 2500;
END;
INSERT INTO employees_temp
VALUES (302, sal_calc / 100, .1);
DBMS_OUTPUT.PUT_LINE
('Enclosing block: Row inserted.');
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE
('Enclosing block: Division by zero.');
END;
/
--Example 11–26 Retrying Transaction
After Handling Exception
DROP TABLE results;
CREATE
TABLE results
(
res_name VARCHAR
(20),
res_answer VARCHAR2
(3)
);
CREATE
UNIQUE INDEX
res_name_ix
ON results (res_name);
INSERT
INTO results (res_name, res_answer)
VALUES ('SMYTHE', 'YES');
INSERT
INTO results (res_name, res_answer)
VALUES ('JONES', 'NO');
DECLARE
name VARCHAR2 (20) := 'SMYTHE';
answer VARCHAR2
(3) := 'NO';
suffix NUMBER
:= 1;
BEGIN
FOR i IN 1 .. 5
LOOP -- Try transaction at most 5 times.
DBMS_OUTPUT.PUT
('Try #' || i);
BEGIN
-- sub-block begins
SAVEPOINT start_transaction;
-- transaction begins
DELETE FROM results
WHERE res_answer = 'NO';
INSERT INTO results (res_name, res_answer)
VALUES (name, answer);
-- Nonunique name raises
DUP_VAL_ON_INDEX.
-- If transaction succeeded:
COMMIT;
DBMS_OUTPUT.PUT_LINE
(' succeeded.');
EXIT;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
DBMS_OUTPUT.PUT_LINE
(' failed; trying again.');
ROLLBACK TO start_transaction; -- Undo changes.
suffix := suffix + 1; -- Try to fix problem.
name := name || TO_CHAR
(suffix);
END;
-- sub-block ends
END LOOP;
END;
/