PROMPT Creating Table 'mam_named_exceptions'
Unsupported Command
CREATE TABLE mam_named_exceptions(
mne_sqlcode NUMBER(7,0) NOT NULL
,mne_errorname VARCHAR2(30) NOT NULL
,mne_errorlevel NUMBER(2,0) NOT NULL
,mne_description VARCHAR2(2000) NOT NULL
,mne_errortext VARCHAR2(2000) NOT NULL
)
Table created.
COMMENT ON COLUMN mam_named_exceptions.mne_sqlcode IS 'SQL_CODE of the error'
Statement processed.
COMMENT ON COLUMN mam_named_exceptions.mne_errorname IS 'Registered name of the named exception'
Statement processed.
COMMENT ON COLUMN mam_named_exceptions.mne_errortext IS 'error text. Parametrise text with ~ e.g. "Invalid values: ~ to ~ overlaps with existing intervals". Add the parameter values to your error text when you raise an error "|value1|value2|value3"'
Statement processed.
COMMENT ON COLUMN mam_named_exceptions.mne_errorlevel IS 'Severity of the errors from Debug to Fatal 0-5'
Statement processed.
COMMENT ON COLUMN mam_named_exceptions.mne_description IS 'Description of the error, e.g. "Intervals must not overlap"'
Statement processed.
COMMENT ON TABLE mam_named_exceptions IS 'Managing Named Exceptions.'
Statement processed.
PROMPT Creating Primary Key on 'mam_named_exceptions'
Unsupported Command
ALTER TABLE mam_named_exceptions ADD
CONSTRAINT mne_pk
PRIMARY KEY (mne_sqlcode)
Table altered.
PROMPT Creating Unique Key on 'mam_named_exceptions'
Unsupported Command
ALTER TABLE mam_named_exceptions ADD
CONSTRAINT mne_uk
UNIQUE (mne_errorname)
Table altered.
INSERT INTO mam_named_exceptions (mne_sqlcode,mne_errorname,mne_errorlevel,mne_errortext,mne_description)
VALUES (-20500,'stop',5,'Termination of the program execution. See log messages','Log sufficient information before raising this error. Calling programs can safely assume that the error has aready been logged.')
1 row(s) inserted.
INSERT INTO mam_named_exceptions (mne_sqlcode,mne_errorname,mne_errorlevel,mne_errortext,mne_description)
VALUES (-20501,'outOfRange',5,'The value of ~ is out of range. Expected ~ to ~, is ~.','The value of a parameter is not within the expected range.')
1 row(s) inserted.
INSERT INTO mam_named_exceptions (mne_sqlcode,mne_errorname,mne_errorlevel,mne_errortext,mne_description)
VALUES (-20502,'notGapless',5,'The intervals must have no gaps.','The intervals must have no gaps.')
1 row(s) inserted.
COMMIT
Statement processed.
CREATE OR REPLACE PACKAGE mam_exceptions
IS
c_packageName CONSTANT VARCHAR2(30) := 'mam_exceptions';
/*+*Begin of generated code. Do not remove this comment!*+*/
e_stop EXCEPTION;
c_stop CONSTANT INTEGER := -20500;
PRAGMA EXCEPTION_INIT (e_stop, -20500);
e_outOfRange EXCEPTION;
c_outOfRange CONSTANT INTEGER := -20501;
PRAGMA EXCEPTION_INIT (e_outOfRange, -20501);
e_notGapless EXCEPTION;
c_notGapless CONSTANT INTEGER := -20502;
PRAGMA EXCEPTION_INIT (e_notGapless, -20502);
FUNCTION getStop
RETURN INTEGER;
FUNCTION getOutOfRange
RETURN INTEGER;
FUNCTION getNotGapless
RETURN INTEGER;
/*+*End of generated code. Do not remove this comment!*+*/
/**
* @desc raise_application_error with decoding of the error text
* for unregistered SQLCODEs
* @param p_sqlcode SQLCODE / mne_sqlcode
* @param p_text error message
* @param p_keepErrorStack Keep error stack
*/
PROCEDURE rae
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
,p_text IN mam_named_exceptions.mne_errortext%TYPE
,p_keepErrorStack IN BOOLEAN := FALSE
);
/**
* @desc Check whether the SQLCODE is a registered exception
* @param p_sqlcode SQLCODE
* @return TRUE, if SQLCODE in mam_named_exceptions, else FALSE
*/
FUNCTION isNamedException
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
)
RETURN BOOLEAN;
/**
* @desc get row from mam_named_exceptions for SQLCODE
* @param p_sqlcode SQLCODE
* @return Row from mam_named_exceptions, NULL if SQLCODE is not registered
*/
FUNCTION getNamedException
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
)
RETURN mam_named_exceptions%ROWTYPE;
/**
* @desc get message text for SQLCODE
* Replace parameters in message text
* @param p_sqlcode SQLCODE
* @param p_arg Parameters for parametrised texts
* @return message text
*/
FUNCTION getMessagetext
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
,p_arg IN mam_named_exceptions.mne_errortext%TYPE := NULL
)
RETURN mam_named_exceptions.mne_errortext%TYPE;
/**
* @Desc generate a new version of this package from mam_named_exceptions.
* EXEC mam_exceptions.generateNamedExceptions(<directory_name>);
* Replace the code between "/*+*Begin/End of generated code..." with
* declarations for the named exceptions. Other code will not be changed.
* @param p_pfad Oracle Directorie for output files
*/
PROCEDURE generateNamedExceptions
(
p_path IN all_directories.directory_name%TYPE
);
END mam_exceptions;
Package created.
CREATE OR REPLACE PACKAGE BODY mam_exceptions
IS
c_typeHeader user_source.type%TYPE := 'PACKAGE';
c_typeBody user_source.type%TYPE := 'PACKAGE BODY';
CURSOR cur_source (
p_type IN VARCHAR2
,p_from IN user_source.line%TYPE
,p_to IN user_source.line%TYPE
)
IS
SELECT us.text
FROM user_source us
WHERE us.type = p_type
AND UPPER(us.name) = UPPER(c_packageName)
AND ( us.line > p_from
OR p_from IS NULL
)
AND ( us.line < p_to
OR p_to IS NULL
)
ORDER BY line;
CURSOR cur_exceptions
IS
SELECT mne.*
FROM mam_named_exceptions mne
WHERE mne.mne_sqlcode BETWEEN -20999 AND -20000
ORDER BY mne.mne_sqlcode DESC;
/*+*Begin of generated code. Do not remove this comment!*+*/
FUNCTION getStop
RETURN INTEGER
IS
BEGIN
RETURN c_stop;
END;
FUNCTION getOutOfRange
RETURN INTEGER
IS
BEGIN
RETURN c_outOfRange;
END;
FUNCTION getNotGapless
RETURN INTEGER
IS
BEGIN
RETURN c_notGapless;
END;
/*+*End of generated code. Do not remove this comment!*+*/
FUNCTION decodeText
(
p_text IN VARCHAR2
)
RETURN VARCHAR2
IS
v_values VARCHAR2(2000);
v_posTilde PLS_INTEGER := 0;
v_posPipe PLS_INTEGER := 0;
v_posPipe2 PLS_INTEGER := 0;
v_length PLS_INTEGER := 0;
v_text VARCHAR2(2000) := p_text;
BEGIN
IF INSTR(v_text,'|') > 0 THEN
v_values := SUBSTR(v_text,INSTR(v_text,'|'));
v_text := SUBSTR(v_text, 1, INSTR(v_text, '|') - 1);
LOOP
-- get first place marker
v_posTilde := INSTR(v_text, '~', v_posTilde + 1);
--get first value marker
v_posPipe := INSTR(v_values, '|', v_posPipe + 1);
--get second value marker
v_posPipe2 := INSTR(v_values, '|', v_posPipe + 1);
IF v_posTilde = 0
OR v_posPipe = 0
THEN
EXIT;
ELSIF v_posPipe2 > 0 THEN
v_length := v_posPipe2 - v_posPipe - 1;
ELSE
v_length := LENGTH(v_values) - v_posPipe;
END IF;
-- replace place marker with value
v_text := SUBSTR(v_text, 1, v_posTilde - 1)||
SUBSTR(v_values, v_posPipe + 1, v_length)||
SUBSTR(v_text, v_posTilde + 1);
END LOOP;
END IF;
RETURN v_text;
END decodeText;
/**
* @desc raise_application_error with decoding of the error text
* for unregistered SQLCODEs
* @param p_sqlcode SQLCODE / mne_sqlcode
* @param p_text error message
* @param p_keepErrorStack Keep error stack
*/
PROCEDURE rae
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
,p_text IN mam_named_exceptions.mne_errortext%TYPE
,p_keepErrorStack IN BOOLEAN := FALSE
)
IS
v_backtrace VARCHAR(500);
BEGIN
IF isNamedException(p_sqlcode) THEN
RAISE_APPLICATION_ERROR (
p_sqlcode
,p_text
,p_keepErrorStack
);
ELSE
RAISE_APPLICATION_ERROR (
p_sqlcode
,decodeText(p_text)
,p_keepErrorStack
);
END IF;
END rae;
/**
* @desc Check whether the SQLCODE is a registered exception
* @param p_sqlcode SQLCODE
* @return TRUE, if SQLCODE in mam_named_exceptions, else FALSE
*/
FUNCTION isNamedException
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
)
RETURN BOOLEAN
IS
v_count PLS_INTEGER;
BEGIN
SELECT COUNT(*)
INTO v_count
FROM mam_named_exceptions
WHERE mne_sqlcode = p_sqlcode
AND ROWNUM < 2;
RETURN v_count > 0;
END isNamedException;
/**
* @desc get row from mam_named_exceptions for SQLCODE
* @param p_sqlcode SQLCODE
* @return Row from mam_named_exceptions, NULL if SQLCODE is not registered
*/
FUNCTION getNamedException
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
)
RETURN mam_named_exceptions%ROWTYPE
IS
r_mne mam_named_exceptions%ROWTYPE;
BEGIN
SELECT *
INTO r_mne
FROM mam_named_exceptions
WHERE mne_sqlcode = p_sqlcode;
RETURN r_mne;
END getNamedException;
/**
* @desc get message text for SQLCODE
* Replace parameters in message text
* @param p_sqlcode SQLCODE
* @param p_arg Parameters for parametrised texts
* @return message text
*/
FUNCTION getMessagetext
(
p_sqlcode IN mam_named_exceptions.mne_sqlcode%TYPE
,p_arg IN mam_named_exceptions.mne_errortext%TYPE := NULL
)
RETURN mam_named_exceptions.mne_errortext%TYPE
IS
v_text mam_named_exceptions.mne_errortext%TYPE;
BEGIN
IF isNamedException(p_sqlcode) THEN
v_text := getNamedException(p_sqlcode).mne_errortext||SUBSTR(p_arg,INSTR(p_arg,'|'));
ELSE
v_text := p_arg;
END IF;
RETURN decodeText(v_text);
END getMessagetext;
/**
* @Desc Search begin and end of generated code
* @param p_typ Search Header c_typeHeader or Body c_typeBody
* @param p_begin first line
* @param p_end last line
*/
PROCEDURE getGeneratedLines
(
p_type IN VARCHAR2
,p_begin OUT user_source.line%TYPE
,p_end OUT user_source.line%TYPE
)
IS
BEGIN
SELECT MIN(us.line)
INTO p_begin
FROM user_source us
WHERE us.type = p_type
AND UPPER(us.name) = UPPER(c_packageName)
AND us.text LIKE '/*+*Begin of generated code. Do not remove this comment!*+*%';
SELECT MIN(us.line)
INTO p_end
FROM user_source us
WHERE us.type = p_type
AND UPPER(us.name) = UPPER(c_packageName)
AND us.text LIKE '/*+*End of generated code. Do not remove this comment!*+*%';
END getGeneratedLines;
/**
* @Desc generate a new version of this package from mam_named_exceptions.
* EXEC mam_exceptions.generateNamedExceptions(<directory_name>);
* Replace the code between "/*+*Begin/End of generated code..." with
* declarations for the named exceptions. Other code will not be changed.
* @param p_pfad Oracle Directorie for output files
*/
PROCEDURE generateNamedExceptions
(
p_path IN all_directories.directory_name%TYPE
)
IS
v_from user_source.line%TYPE;
v_to user_source.line%TYPE;
v_text user_source.text%TYPE;
v_fileHandle utl_file.FILE_TYPE;
v_firstLine BOOLEAN := TRUE;
BEGIN
getGeneratedLines(
c_typeHeader
,v_from
,v_to
);
v_fileHandle := utl_file.fopen (p_path, c_packageName||'.pck', 'W', 32760);
-- Read and write code until begin of generated part
FOR r_source IN cur_source (c_typeHeader,NULL,v_from + 1) LOOP
IF v_firstLine THEN
utl_file.put_line(v_fileHandle,'CREATE OR REPLACE '||RTRIM(r_source.text,CHR(10)));
v_firstLine := FALSE;
ELSE
utl_file.put_line(v_fileHandle,RTRIM(r_source.text,CHR(10)));
END IF;
END LOOP;
-- Define Exceptions and register as Named Exceptions
FOR r_exceptions IN cur_exceptions LOOP
utl_file.put_line(v_fileHandle,' e_' || SUBSTR(r_exceptions.mne_errorname,1,28) || ' EXCEPTION;');
utl_file.put_line(v_fileHandle,' c_' || SUBSTR(r_exceptions.mne_errorname,1,28) || ' CONSTANT INTEGER := ' || r_exceptions.mne_sqlcode || ';');
utl_file.put_line(v_fileHandle,' PRAGMA EXCEPTION_INIT (e_' ||SUBSTR(r_exceptions.mne_errorname,1,28) || ', ' || r_exceptions.mne_sqlcode || ');');
utl_file.put_line(v_fileHandle,'');
END LOOP;
-- Functions to read SQL-CODES, e.g. from Forms.
FOR r_exceptions IN cur_exceptions LOOP
utl_file.put_line(v_fileHandle,'FUNCTION get' || UPPER(SUBSTR(r_exceptions.mne_errorname,1,1))||SUBSTR(r_exceptions.mne_errorname,2,26));
utl_file.put_line(v_fileHandle,' RETURN INTEGER;');
utl_file.put_line(v_fileHandle,'');
END LOOP;
-- Read and write code from end of generated part
FOR r_source IN cur_source (c_typeHeader,v_to - 1,NULL) LOOP
utl_file.put_line(v_fileHandle,RTRIM(r_source.text,CHR(10)));
END LOOP;
utl_file.put_line(v_fileHandle,'/');
utl_file.put_line(v_fileHandle,'');
utl_file.put_line(v_fileHandle,'SHOW ERRORS');
utl_file.fclose(v_fileHandle);
getGeneratedLines(
c_typeBody
,v_from
,v_to
);
v_fileHandle := utl_file.fopen(p_path, c_packageName||'.pcb', 'W', 32760);
-- Read and write code until begin of generated part
v_firstLine := TRUE;
FOR r_source IN cur_source (c_typeBody,NULL,v_from + 1) LOOP
IF v_firstLine THEN
utl_file.put_line(v_fileHandle,'CREATE OR REPLACE '||RTRIM(r_source.text,CHR(10)));
v_firstLine := FALSE;
ELSE
utl_file.put_line(v_fileHandle,RTRIM(r_source.text,CHR(10)));
END IF;
END LOOP;
-- Functions to read SQL-CODES, e.g. from Forms.
FOR r_exceptions IN cur_exceptions LOOP
utl_file.put_line(v_fileHandle,'FUNCTION get' || UPPER(SUBSTR(r_exceptions.mne_errorname,1,1))||SUBSTR(r_exceptions.mne_errorname,2,26));
utl_file.put_line(v_fileHandle,' RETURN INTEGER');
utl_file.put_line(v_fileHandle,'IS');
utl_file.put_line(v_fileHandle,'BEGIN');
utl_file.put_line(v_fileHandle,' RETURN c_' || SUBSTR(r_exceptions.mne_errorname,1,28) || ';');
utl_file.put_line(v_fileHandle,'END;');
utl_file.put_line(v_fileHandle,'');
END LOOP;
-- Read and write code from end of generated part
FOR r_source IN cur_source (c_typeBody,v_to - 1,NULL) LOOP
utl_file.put_line(v_fileHandle,RTRIM(r_source.text,CHR(10)));
END LOOP;
utl_file.put_line(v_fileHandle,'/');
utl_file.put_line(v_fileHandle,'');
utl_file.put_line(v_fileHandle,'SHOW ERRORS');
utl_file.fclose(v_fileHandle);
END generateNamedExceptions;
END mam_exceptions;
Package Body created.
SET SERVEROUTPUT ON
Unsupported Command
BEGIN
dbms_output.put_line(mam_exceptions.getMessagetext(-20502,NULL));
dbms_output.put_line(mam_exceptions.getMessagetext(-20501));
dbms_output.put_line(mam_exceptions.getMessagetext(-20501,'|param1|1|2|3'));
dbms_output.put_line(mam_exceptions.getMessagetext(0,'Text with replace ~ here|text'));
END;
The intervals must have no gaps.
The value of ~ is out of range. Expected ~ to ~, is ~.
The value of param1 is out of range. Expected 1 to 2, is 3.
Text with replace text here
BEGIN
RAISE mam_exceptions.e_stop;
EXCEPTION
WHEN mam_exceptions.e_stop THEN
dbms_output.put_line(mam_exceptions.getMessagetext(mam_exceptions.c_stop));
END;
Termination of the program execution. See log messages
BEGIN
mam_exceptions.rae(mam_exceptions.c_outOfRange,'|param1|1|2|3');
EXCEPTION
WHEN mam_exceptions.e_outOfRange THEN
dbms_output.put_line(mam_exceptions.getMessagetext(SQLCODE,SQLERRM));
END;
The value of param1 is out of range. Expected 1 to 2, is 3.