CREATE TABLE employees AS SELECT * FROM hr.employees
Table created.
WHEN OTHERS THEN NULL
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
/* Lots of code executing and then... */
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
Procedure created.
What, Me Failed?
BEGIN my_procedure (100); END;
Statement processed.
Want to Ignore Error? Make it Explicit and Log It Anyway
CREATE OR REPLACE PROCEDURE my_procedure (name_in IN VARCHAR2)
AUTHID DEFINER
IS
e_table_already_exists EXCEPTION;
PRAGMA EXCEPTION_INIT (e_table_already_exists, -955);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE ' || name_in || ' (n number)';
EXCEPTION
/* A named handler */
WHEN e_table_already_exists
THEN
/* Even better: write a message to log. */
NULL;
/* CHecking SQLCODE inside WHEN OTHERS */
WHEN OTHERS
THEN
IF SQLCODE = -955
THEN
/* ORA-00955: name is already used by an existing object */
NULL;
ELSE
RAISE;
END IF;
END;
Procedure created.
Bad Table Name
BEGIN my_procedure ('NEW!!TABLE'); END;
ORA-00922: missing or invalid option ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 23 ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 7 ORA-06512: at line 1 ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-00922
Table Already Exists? Fine.
BEGIN my_procedure ('EMPLOYEES'); END;
Statement processed.
A Handler That Only Re-Raises: Why Bother?
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
/* Lots of code executing and then... */
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
RAISE;
END;
Procedure created.
BEGIN my_procedure (100); END;
ORA-06501: PL/SQL: program error ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 10 ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 6 ORA-06512: at line 1 ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-06501
"Log" Error with DBMS_OUTPUT? No Way!
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
/* Lots of code executing and then... */
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Program failed!');
END;
Procedure created.
BEGIN my_procedure (100); END;
Program failed!
Display Error and Re-Raise - Better But Still Pathetic
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
/* Lots of code executing and then... */
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;
Procedure created.
BEGIN my_procedure (100); END;
ORA-06501: PL/SQL: program error
Convert Exception to Status Code?
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER,
status_out OUT INTEGER)
AUTHID DEFINER
IS
BEGIN
IF value_in > 100
THEN
/* All is fine */
/* Execute some code */
/* Set status to "ok" */
status_out := 0;
ELSE
RAISE PROGRAM_ERROR;
END IF;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
status_out := SQLCODE;
END;
Procedure created.
But Oh the Resulting Code!
DECLARE
l_status INTEGER;
BEGIN
my_procedure (100, l_status);
IF l_status <> 0
THEN
/* That didn't go well. Need to stop or do *something*! */
RAISE program_error;
END IF;
my_procedure (110, l_status);
IF l_status <> 0
THEN
/* That didn't go well. Need to stop or do *something*! */
RAISE program_error;
END IF;
END;
ORA-06501: PL/SQL: program error ORA-06512: at line 9 ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-06501
Write Errors to Log Table
CREATE TABLE error_log
(
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
title VARCHAR2 (200),
info CLOB,
created_on DATE DEFAULT SYSDATE,
created_by VARCHAR2 (100),
callstack CLOB,
errorstack CLOB,
errorbacktrace CLOB
)
ORA-06501: PL/SQL: program error
But Never Write to Log Table This Way!
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
INSERT INTO error_log (title,
info,
created_by,
callstack,
errorstack,
errorbacktrace)
VALUES ('Program failed',
'value_in = ' || value_in,
USER,
DBMS_UTILITY.format_call_stack,
DBMS_UTILITY.format_error_stack,
DBMS_UTILITY.format_error_backtrace);
RAISE;
END;
Procedure created.
BEGIN my_procedure (100); END;
ORA-06501: PL/SQL: program error ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 22 ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 5 ORA-06512: at line 1 ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-06501
See? No Log Info!
SELECT title, info FROM error_log
no data found
So I Should Get "Fancy" with Savepoints?
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
SAVEPOINT my_transaction;
UPDATE employees
SET salary = value_in;
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
ROLLBACK TO my_transaction;
INSERT INTO error_log (title,
info,
created_by,
callstack,
errorstack,
errorbacktrace)
VALUES ('Program failed',
'value_in = ' || value_in,
USER,
DBMS_UTILITY.format_call_stack,
DBMS_UTILITY.format_error_stack,
DBMS_UTILITY.format_error_backtrace);
SAVEPOINT error_logged;
RAISE;
END;
Procedure created.
BEGIN
my_procedure (100);
EXCEPTION
WHEN OTHERS
THEN
ROLLBACK to error_logged;
DBMS_OUTPUT.PUT_LINE ('Process terminated with error');
END;
Process terminated with error
SELECT title, info FROM error_log
TITLE | INFO | Program failed | value_in = 100 |
---|
Best Approach: Reusable Error Logger
CREATE OR REPLACE PROCEDURE log_error (title_in IN error_log.title%TYPE,
info_in IN error_log.info%TYPE)
AUTHID DEFINER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO error_log (title,
info,
created_by,
callstack,
errorstack,
errorbacktrace)
VALUES (title_in,
info_in,
USER,
DBMS_UTILITY.format_call_stack,
DBMS_UTILITY.format_error_stack,
DBMS_UTILITY.format_error_backtrace);
COMMIT;
END;
Procedure created.
Ah, This is More Like It
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
l_local_variable DATE;
BEGIN
l_local_variable :=
CASE WHEN value_in > 100 THEN SYSDATE - 10 ELSE SYSDATE + 10 END;
UPDATE employees
SET salary = value_in;
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
log_error (
'my_procedure failed',
'value_in = '
|| value_in
|| ' | l_local_variable = '
|| TO_CHAR (l_local_variable, 'YYYY-MM-DD HH24:MI:SS'));
RAISE;
END;
Procedure created.
BEGIN my_procedure (100); END;
ORA-06501: PL/SQL: program error ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 23 ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 12 ORA-06512: at line 1 ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-06501
SELECT TO_CHAR (created_on, 'YYYY-MM-DD HH24:MI:SS') log_ts, title, info, errorbacktrace
FROM error_log
ORDER BY id DESC
LOG_TS | TITLE | INFO | ERRORBACKTRACE | 2017-01-26 07:19:42 | my_procedure failed | value_in = 100 | l_local_variable = 2017-02-05 07:19:42 | ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 12 | 2017-01-26 07:19:42 | Program failed | value_in = 100 | ORA-06512: at "SQL_UUOSBQCXHGMVLZPIOONWLQXQR.MY_PROCEDURE", line 10 |
---|
Use Compile-Time Warnings to Help Identify Weak Handlers
ALTER SESSION SET PLSQL_WARNINGS = 'ENABLE:ALL'
Statement processed.
Automatic Detection of Awful Handler
CREATE OR REPLACE PROCEDURE my_procedure (value_in IN INTEGER)
AUTHID DEFINER
IS
BEGIN
/* Lots of code executing and then... */
RAISE PROGRAM_ERROR;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
Warning: PROCEDURE MY_PROCEDURE Line: 8 PLW-06009: procedure "MY_PROCEDURE" OTHERS handler does not end in RAISE or RAISE_APPLICATION_ERRORMore Details: https://docs.oracle.com/error-help/db/ora-20001