Raise application error 20001

В этом учебном материале вы узнаете, как использовать исключительные ситуации, определенные программистом в Oracle/PLSQL c синтаксисом и примерами.

В этом учебном материале вы узнаете, как использовать исключительные ситуации, определенные программистом в Oracle/PLSQL c синтаксисом и примерами.

Описание

Иногда для программистов необходимо, определять и перехватывать свои собственные исключительные ситуации — те, которые не определены в PL/SQL.

Синтаксис

Рассмотрим синтаксис исключительных ситуаций определенных программистом в процедуре и функции.

Синтаксис для процедур

CREATE [OR REPLACE] PROCEDURE procedure_name
[ (parameter [,parameter]) ]
IS
[declaration_section]exception_name EXCEPTION;

BEGIN
executable_section
RAISE exception_name;

EXCEPTION
WHEN exception_name THEN
[statements]

WHEN OTHERS THEN
[statements]

END [procedure_name];

Синтаксис для функций

CREATE [OR REPLACE] FUNCTION function_name
[ (parameter [,parameter]) ]
RETURN return_datatypeIS | AS
[declaration_section]

exception_name EXCEPTION;

BEGIN
executable_section

RAISE exception_name;

EXCEPTION
WHEN exception_name THEN
[statements]

WHEN OTHERS THEN
[statements]

END [function_name];

Пример

Пример процедуры, в которой используется исключительная ситуация определенная программистом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

CREATE OR REPLACE PROCEDURE add_new_order

   (order_id_in IN NUMBER, sales_in IN NUMBER)

IS

   no_sales EXCEPTION;

BEGIN

   IF sales_in = 0 THEN

      RAISE no_sales;

   ELSE

      INSERT INTO orders (order_id, total_sales )

      VALUES ( order_id_in, sales_in );

   END IF;

EXCEPTION

   WHEN no_sales THEN

      raise_application_error (-20001,‘У вас должны быть продажи по заказу, для закрытия заказа.’);

   WHEN OTHERS THEN

      raise_application_error (-20002,‘Произошла ошибка при добавлении заказа.’);

END;

В этом примере объявили исключительную ситуацию no_sales объявленную следующим кодом:

no_sales EXCEPTION;

Вызываем исключение в выполняемой части кода:

IF sales_in = 0 THEN
RAISE no_sales;

Теперь, если переменная sales_in содержит нуль, то наш выполнение кода перейдет к исключительной ситуации no_sales.

Наконец, мы указываем нашей процедуре, что делать, когда исключительная ситуация no_sales включается в оператор WHEN:

WHEN no_sales THEN
raise_application_error (-20001,’У вас должны быть продажи по заказу, для закрытия заказа.’);

Мы также используем оператор WHEN OTHERS для перехвата всех остальных исключений:

WHEN OTHERS THEN
raise_application_error (-20002,’Произошла ошибка при добавлении заказа.’);

How RAISE_APPLICATION_ERROR ( ) used in ORACLE? How we
define Custom Error messages in ORACLE?

RAISE_APPLICATION_ERROR
( )
allows
users to create custom error messages.
 

RAISE_APPLICATION_ERROR is a built-in procedure in oracle which is
used to display the user-defined error messages along with the error number
whose range is in between -20000 and -20999.

Whenever a
message is displayed using RAISE_APPLICATION_ERROR, all previous transactions
which are not committed within the PL/SQL Block are rolled back automatically
(i.e. change due to INSERT, UPDATE, or DELETE statements).

RAISE_APPLICATION_ERROR
raises an exception but does not handle it.
RAISE_APPLICATION_ERROR
is used for the following reasons,

a) To create a unique
id for a user-defined exception.
b) To make the user-defined exception look like an Oracle error.

C) Used to replace
generic Oracle exception messages with our own, more meaningful messages.

d) Used to
create exception conditions of our own, when Oracle would not throw them.

The
General Syntax to use this procedure is:

RAISE_APPLICATION_ERROR (Error_Number, Error_Message);


• The Error number must be between
-20000 and -20999
 
• The Error_message is the message you want to display when the error occurs.

Steps to
be followed to use RAISE_APPLICATION_ERROR procedure:
1. Declare a
user-defined exception in the declaration section.
2. Raise the user-defined exception based on a specific business rule in the
execution section.
3. Finally, catch the exception and link the exception to a user-defined error
number in RAISE_APPLICATION_ERROR.

Let’s use this and see how it works-

SQL> SELECT * FROM EMP_TEST;

        ID NAME           SALARY STATUS         DEPTNO  MANAGERID
---------- ---------- ---------- ---------- ---------- ----------
       102 Ankit            8000 Active             20        101
       104 Nikhil          69000 Active             10        101
       105 Rajan           18000 Active             20        112
       107 Karan          101000 Active             20        112
       110 Sajal           88000 Active             10        101
       103 Ravi            45000 InActive           30        104
       106 Surya           67000 Active             30        104
       108 Sam             99000 InActive           20        105
       109 Jack            77000 Active             10        106

9 rows selected.

Let’s define an Exception which
will check that salary inserted should not be less than the minimum limit set.
Bind the same rule using the RAISE_APPLICATION_ERROR

DECLARE

     Low_Sal_Exc EXCEPTION;

     Min_sal NUMBER:= 8000;

     New_Sal NUMBER:= 4700;

    BEGIN

     INSERT INTO EMP_TEMP(ID, NAME, DEPTNO,
SALARY)

                      VALUES
(108,’Tom’,30,New_Sal);

     IF New_Sal < Min_Sal THEN

        RAISE Low_Sal_Exc;

    END IF;

    DBMS_OUTPUT.PUT_LINE (‘Record Inserted
Successfully’);

    Commit;

   EXCEPTION

   WHEN Low_Sal_Exc THEN

      Rollback;

      RAISE_APPLICATION_ERROR (-20102, ‘Salary
is Less than ‘||Min_Sal);

   WHEN OTHERS THEN

      DBMS_OUTPUT.PUT_LINE (SQLERRM);

END;

SQL> DECLARE
  2       Low_Sal_Exc EXCEPTION;
  3       Min_sal NUMBER:= 8000;
  4       New_Sal NUMBER:= 4700;
  5      BEGIN
  6       INSERT INTO EMP_TEMP(ID, NAME, DEPTNO, SALARY)
  7                        VALUES (108,'Tom',30,New_Sal);
  8
  9       IF New_Sal < Min_Sal THEN
 10          RAISE Low_Sal_Exc;
 11      END IF;
 12      DBMS_OUTPUT.PUT_LINE ('Record Inserted Successfully');
 13
 14      Commit;
 15     EXCEPTION
 16     WHEN Low_Sal_Exc THEN
 17        Rollback;
 18        RAISE_APPLICATION_ERROR (-20102, 'Salary is Less than '||Min_Sal);
 19     WHEN OTHERS THEN
 20        DBMS_OUTPUT.PUT_LINE (SQLERRM);
 21  END;
 22  /
DECLARE
*
ERROR at line 1:
ORA-20102: Salary is Less than 8000
ORA-06512: at line 18

Let’s
take another Example – Where we will fetch data from below table with DEPTNO
and if no records found with that DEPTNO then Exception will be raised using
RAISE_APPLICATION_ERROR.

DECLARE

   L_DEPTID NUMBER := 40;

   L_ENAME VARCHAR2(20);

   L_SAL NUMBER;

CURSOR
C IS

   SELECT NAME,
SALARY   FROM EMP_TEMP  

   WHERE DEPTNO =
L_DEPTID;

BEGIN

  
DBMS_OUTPUT.PUT_LINE(‘Opening Cursor’);

   OPEN C;

   FETCH C INTO L_ENAME,
L_SAL;

   IF C%ROWCOUNT =0 THEN

     
RAISE_APPLICATION_ERROR(-20001,’ No Employees in the Department
:’||L_DEPTID);

   END IF;

   CLOSE C;

  
DBMS_OUTPUT.PUT_LINE(‘Closing Cursor’);

END;

SQL> DECLARE
  2     L_DEPTID NUMBER := 40;
  3     L_ENAME VARCHAR2(20);
  4     L_SAL NUMBER;
  5  CURSOR C IS
  6     SELECT NAME, SALARY   FROM EMP_TEMP
  7     WHERE DEPTNO = L_DEPTID;
  8  BEGIN
  9     DBMS_OUTPUT.PUT_LINE('Opening Cursor');
 10     OPEN C;
 11     FETCH C INTO L_ENAME, L_SAL;
 12     IF C%ROWCOUNT =0 THEN
 13        RAISE_APPLICATION_ERROR(-20001,' No Employees in the Department :'||L_DEPTID);
 14     END IF;
 15     CLOSE C;
 16     DBMS_OUTPUT.PUT_LINE('Closing Cursor');
 17  END;
 18  /
Opening Cursor
DECLARE
*
ERROR at line 1:
ORA-20001:  No Employees in the Department :40
ORA-06512: at line 13

Get involved
and leave your Comments in the Box Below. The more people get involved, the
more we all benefit.

So, leave your thoughts before you leave
the page. 

Most programmers don’t like exceptions, but you should consider them as your closest friends. They are the ones that honestly say what is wrong with your program. We cannot foresee all possible problematic events, and even the best programmers write bugs. Exceptions There are three kinds of exceptions Internally defined: A system error, defined by Oracle, that occurs. Predefined: The

Most programmers don’t like exceptions, but you should consider them as your closest friends. They are the ones that honestly say what is wrong with your program. We cannot foresee all possible problematic events, and even the best programmers write bugs.

Exceptions

There are three kinds of exceptions

  • Internally defined: A system error, defined by Oracle, that occurs.
  • Predefined: The most common internally defined exceptions that are given predefined names.
  • User defined: A logical error which you define and raise yourself

System errors could occur from improper coding, like the “ORA-01001: Invalid cursor”, which you should try to fix as soon as possible in your code. And the “TOO_MANY_ROWS”-error might give you clues about bad data quality. To resolve these bugs, it is important to know where, when and why it happened.

But system errors could also occur from hardware failures, like the “ORA-12541: TNS: no listener”, when an ftp-server might be unreachable over the network. In that case, all you can do, and should do, is provide proper error handling and transaction management, and give as detailed information as possible about this situation to the people that need to know.

These system-errors always have an error number assigned, so you can easily identify the error. The 22 predefined exceptions also have a name assigned, which allows for easier, and more readable exception handling. For the other, non-predefined, system-errors, a name can be linked by using the pragma “EXCEPTION_INIT”.

DECLARE

  network_error EXCEPTION;

  PRAGMA EXCEPTION_INIT(network_error, 12541);

BEGIN

  ...

EXCEPTION

  WHEN too_many_rows THEN

    ...

  WHEN network_error THEN

    ...

END;

User defined errors we will raise ourselves. They can be given a number and a name.

To raise a user defined error with a chosen number and error message, we call the procedure “RAISE_APPLICATION_ERROR”. Oracle allows us the create error numbers in the range of -20000 to -20999. This allows us to create 1000 unique error codes for our logical errors throughout our application. Just like we did for system errors, we can name our user defined errors by using the pragma “EXCEPTION_INIT”.

BEGIN

  RAISE_APPLICATION_ERROR(20000,Logical error occured);

END;

If we do not care about the error code and error message, and we will foresee an exception block to directly handle the error, we could also raise errors by the keyword “RAISE”, followed by the exception name. If we do not handle the error, the error ORA-65000, “Unhandled user exception” is propagated.

DECLARE

  logical_error EXCEPTION;

BEGIN

  RAISE logical_error;

EXCEPTION

  WHEN logical_error THEN

    ...

END;

Besides user defined errors, we could also raise one of the predefined errors. Although it is recommended to use proper a description for your errors, instead of recycling error codes.
In an exception block, the keyword “RAISE” could also be used without an exception name, which can be useful to add logging or to execute clean-up code, before propagating the error.

BEGIN

  RAISE no_data_found;

EXCEPTION

  WHEN no_data_found THEN

    ...

    RAISE;

END;

Error Propagation

When an error occurs, further execution of the execution block is halted, and an appropriate exception handler is searched. If no handler is found in the current block, the error is propagated to the calling block. As a side note, errors that occur in the declaration section are also handled in the calling block.

BEGIN

  BEGIN

    RAISE no_data_found;

  END;

EXCEPTION

  WHEN no_data_found THEN

    ...

END;

Transactions stay pending when errors are raised, it is our own responsibility to rollback or commit, although most frameworks will rollback an unhandled exception themselves.

Handling errors

Errors will occur, and when they do, it is important that we know about them, and get as much details from them as possible. When troubleshooting we need the “what”, “where”, “when” and “why”.

For this reason, I add following block to every public function or procedure:

PROCEDURE test(p_param1 IN NUMBER

              ,p_param2 IN VARCHAR2)

IS

BEGIN

  ...

EXCEPTION

  WHEN OTHERS THEN

    log_error($$PLSQL_UNIT,$$PLSQL_LINE,p_param1,p_param2);

    RAISE;

END;

The “log_error”-procedure defined as autonomous transaction, writing the information we need for troubleshooting to a table. Simplified, it looks like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

PROCEDURE log_error(p_object_name IN log_messages.object_name%TYPE

                   ,p_line         IN log_messages.line%TYPE

                   ,p_attribute1   IN log_messages.attribute1%TYPE   DEFAULT NULL

                   ,p_attribute2   IN log_messages.attribute2%TYPE   DEFAULT NULL

                   ,p_attribute3   IN log_messages.attribute3%TYPE   DEFAULT NULL

                   ,p_attribute4   IN log_messages.attribute4%TYPE   DEFAULT NULL)

IS

  PRAGMA AUTONOMOUS_TRANSACTION;

BEGIN

  INSERT INTO log_messages(seq

                          ,object_name

                          ,line

                          ,error_stack

                          ,error_backtrace

                          ,call_stack

                          ,attribute1

                          ,attribute2

                          ,attribute3

                          ,attribute4

                          ,log_dt

                          ,log_user)

                   VALUES(seq.nextval

                          ,p_object_name

                          ,p_line

                          ,dbms_utility.format_error_stack

                          ,dbms_utility.format_error_backtrace

                          ,dbms_utility.format_call_stack

                          ,p_attribute1

                          ,p_attribute2

                          ,p_attribute3

                          ,p_attribute4

                          ,SYSDATE

                          ,USER);

  COMMIT;

END log_error;

Going over the different parameters:

Seq:

Adding a sequence will allow us to order the message in the order they occurred

Object_name/Line:

By using the PL/SQL-directives $$PLSQL_UNIT and $$PLSQL_LINE, we know where the log was created.

Error_stack/Error_backtrace/Call_stack:

In the dbms_utilty package, we find three functions that give us valuable information about the error that was raised. The error stack gives us an overview of all the errors that were raised, giving more information than “SQLCODE” and “SQLERRM”. The error stack gives us the exact line number where the error occurred. The call stack will give us information about which code called the procedure or function raising the error. Later on, I will explain this in more detail.

Attribute1-4:

To reproduce the error, it can be helpful to know which parameters where used when the error occurred.

Log_dt/Log_user:

Further helpful information are the “who” and “when”. Depending on the technology used, you might want to use your own logic to retrieve the application user instead of the Oracle user.

Dbms_utilty example

Let’s take a look at what these functions produce by executing following block of code:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

DECLARE

  PROCEDURE proc1

  IS

  BEGIN

    RAISE NO_DATA_FOUND;

  END;

  PROCEDURE proc2

  IS

  BEGIN

    proc1;

  END;

  PROCEDURE proc3

  IS

  BEGIN

    proc2;

  EXCEPTION

    WHEN OTHERS THEN

      log_error($$PLSQL_UNIT,$$PLSQL_LINE);

      RAISE_APPLICATION_ERROR(20001,‘Unhandled exception occured.’,TRUE);

    END;

  PROCEDURE proc4

  IS

  BEGIN

    proc3;

  END;

BEGIN

  proc4;

EXCEPTION

  WHEN OTHERS THEN

    log_error($$PLSQL_UNIT,$$PLSQL_LINE);

  RAISE;

END;

As you can see, I’ve created four procedures, calling each other. Proc1 raises an error, which is caught in proc3, logged, and followed by the raise of a different error. There is a second log written in the anonymous block, so we end up with two records.

The two call stacks are

“ORA-01403: no data found”

And

“ORA-20001: Unhandled exception occured.
ORA-06512: at line 21
ORA-01403: no data found”

As you can see in the code of proc3, I have added a third parameter to the “RAISE_APPLICATION_ERROR”-procedure, telling it to keep the error stack. Our first message tells us a “no data found”-error occurred, our second message tells us we had two errors, first the ORA-01403, followed by the user-defined ORA-20001. The ORA-06512 is merely telling us the line number.

The two backtraces are:

“ORA-06512: at line 5
ORA-06512: at line 11
ORA-06512: at line 17″

And

“ORA-06512: at line 21
ORA-06512: at line 27
ORA-06512: at line 30″

The first back trace tells us that the error occurred at line 5, after proc1 was called at line 11, after proc2 was called on line 17. It points us to the error. If we look at the second backtrace, it points us to line 21, were we find the call to “RAISE_APPLICATION_ERROR”. Notice how it loses the information of the original error on line 5, so it is vital to store the back trace whenever we catch an exception.

Finally, looking at the first call stack, we find following information:

“—– PL/SQL Call Stack —–
object      line  object
handle    number  name
1CA24A88         1  anonymous block
1C9CDCC0        10  procedure SCOTT.LOG_ERROR
1CA121EC        20  anonymous block
1CA121EC        27  anonymous block
1CA121EC        30  anonymous block”

It points us to the original call. The actual log is written in the procedure “log_error”, which was called in proc3 at line 20. Proc3 was called by proc4 at line 27, and proc4 was called at line 30. Where the back trace tells us everything that happened between the error and the logging, the call stack tells us everything that happened before the error.

Conclusion

Troubleshooting errors can be difficult, especially if you don’t know what was going on. But by preparing yourself for these situations, and making sure you have all the information you need, you will be able to pinpoint the problem much faster.

I tried to highlight the most important aspect of error handling in my opinion. If you feel something is missing, please share your knowledge by leaving a comment.

Most of the time that an exception is raised in your application, Oracle Database will do the raising. That is, some kind of problem has occurred during the execution of your code. You have no control over that; once the exception has been raised, all you can do is handle the exception — or let it «escape» unhandled to the host environment.

You can, however, raise exceptions yourself in your own code. Why would you want to do this? Because not every error in an application is the result of a failure of internal processing in the Oracle database. It is also possible that a certain data condition constitutes an error in your application, in which case you need to stop the processing of your algorithms and, quite likely, notify the user that something is wrong.

PL/SQL offers two ways for you to raise an exception:

  1. The RAISE statement
  2. The RAISE_APPLICATION_ERROR built-in procedure

Of course, you could also force the raising of an exception by Oracle, with code like this:

BEGIN
   my_variable := 1/0;
END;

But I am going to show you how to terminate block execution with lots more control and information than that will do for you.

RAISE

Use RAISE to raise a previously-defined exception. It could be a system exception, provided by PL/SQL itself, such as NO_DATA_FOUND. Or it could be an exception that you declare yourself.

Suppose I have a procedure that accepts a new salary to be assigned to an employee. The rule you want to enforce is that the new salary cannot be negative. This is a sort of «value error», so you could simply raise that pre-defined exception.

[Note: all code in this post may found in my LiveSQL script.]

CREATE OR REPLACE PROCEDURE use_salary (salary_in IN NUMBER)
   AUTHID DEFINER
IS
BEGIN
   IF salary_in < 0 
   THEN
      RAISE VALUE_ERROR;
   END IF;

   ... rest of procedure
END;

When you run this procedure as follows:

BEGIN
   use_salary (salary_in => -1);
END;

You will see this error:

 ORA-06502: PL/SQL: numeric or value error  

So you stopped the program from continuing, and that’s great. It can, however, be confusing to people maintaining your code and users seeing your error message to fall back on the generic PL/SQL exception. So you could declare your own exception in exactly the same way that PL/SQL defines exceptions like VALUE_ERROR.

Which probably has you thinking: how does PL/SQL define these exceptions? They are, for the most part, found in a special package named STANDARD. You probably haven’t heard of it, and that’s OK. It is one of the two default packages of PL/SQL: STANDARD and DBMS_STANDARD.

By default, I mean that you can reference elements in these packages without including their package name. For example, I could reference VALUE_ERROR in the use_salary procedure as follows:

PROCEDURE use_salary (salary_in IN NUMBER) 

   AUTHID DEFINER

IS

BEGIN

   IF salary_in < 0 

   THEN

      RAISE STANDARD.VALUE_ERROR;

   END IF;

But I don’t have to. If the compiler cannot otherwise resolve the reference to VALUE_ERROR (without the package name), it will then see if that identifier can be resolved in STANDARD or DBMS_STANDARD.

And if we look inside the STANDARD package, we find code like this:

  VALUE_ERROR exception;
  pragma EXCEPTION_INIT(VALUE_ERROR, '-6502');

Let’s apply that same technique in use_salary:

CREATE OR REPLACE PROCEDURE use_salary (salary_in IN NUMBER)
   AUTHID DEFINER
IS
   negative_salary EXCEPTION;
   PRAGMA EXCEPTION_INIT (negative_salary, '-6502');
BEGIN
   IF salary_in < 0 
   THEN
      RAISE negative_salary;
   END IF;

   ... rest of procedure
END;

And when I execute the procedure and pass it -1, I see the same error information.

ORA-06502: PL/SQL: numeric or value error 

So what’s the advantage of switching to own exception? In this case (so far), very minor: Your code raises an exception which by name tells you and anyone maintaining the code later what the problem is.The information presented to the user, however, is no more informative than before. If you want to change that message to something more understandable to users, you will want to «switch» to RAISE_APPLICATION_ERROR, which I cover below.

Before we move on, though, here are some thoughts on why you might want to define your own exceptions: Suppose I have several error conditions, and for each error condition, I need to take different actions. I could write code like this in my executable section:

CREATE OR REPLACE PROCEDURE use_salary (salary_in IN NUMBER)
IS
BEGIN
   CASE
      WHEN salary_in < 0 
      THEN 
         notify_support (
            'Negative salary submitted ' || salary_in); 
         RAISE VALUE_ERROR;
      WHEN salary_in > 10000 
      THEN 
         notify_support (
            'Too large salary submitted ' || salary_in); 
         RAISE VALUE_ERROR;
      WHEN salary_in < 100 
      THEN 
         notify_hr (
            'No one should be treated so shabbily! ' || 
            salary_in);  
         RAISE VALUE_ERROR;
      ELSE
         /* No problems, proceed with normal execution*/
         NULL;
   END CASE;

/* Rest of procedure */

END;

But then I have filled up the first part of the executable section with error-handling code. That makes it harder to see through the «noise» and focus on the actual algorithm I wrote to implement use_salary. A better approach is as follows.

CREATE OR REPLACE PROCEDURE use_salary (salary_in IN NUMBER)
IS
   negative_salary EXCEPTION;
   too_large_salary EXCEPTION;
   too_small_salary EXCEPTION;
BEGIN
   CASE
      WHEN salary_in < 0 THEN RAISE negative_salary;
      WHEN salary_in > 10000 THEN RAISE too_large_salary;
      WHEN salary_in < 100 THEN RAISE too_small_salary;
      ELSE NULL;
   END CASE;

   /* Rest of procedure */

EXCEPTION
   WHEN negative_salary
   THEN
      notify_support (
         'Negative salary submitted ' || salary_in); 
      RAISE VALUE_ERROR;

   WHEN too_large_salary
   THEN
      notify_support (
         'Too large salary submitted ' || salary_in); 
      RAISE VALUE_ERROR;

   WHEN too_small_salary
   THEN
      notify_hr (
         'No one should be treated so shabbily! ' || salary_in);  
      RAISE VALUE_ERROR;
END;

Now all my exception-handling code is in the exception section where it belongs.

Notice that I do not use the pragma to assign an error code to my exceptions. That means that the value returned by SQLCODE will be 1. All the time. Which is not too helpful in terms of distinguishing between the errors. In this case, it does not matter, because we are logging the specifics with support or HR and then causing the procedure to fail with a generic message via VALUE_ERROR (often a good idea from the standpoint of security).

RAISE_APPLICATION_ERROR

This built-in, actually defined in the DBMS_STANDARD package, should be used when you need to communicate an application-specific error message to your users.

With RAISE_APPLICATION_ERROR, you provide both the error code and error message as follows:

BEGIN
   RAISE_APPLICATION_ERROR (-20000, 'Say whatever you want');
END;

And when you run the above block it will fail with an unhandled exception, displaying this information:

 ORA-20000: Say whatever you want  

So if I do want to communicate a context-sensitive and user-informative message when there is a failure in my use_salary procedure, I would  do something like this:

CREATE OR REPLACE PROCEDURE use_salary (salary_in IN NUMBER)
IS
   negative_salary EXCEPTION;
   too_large_salary EXCEPTION;
   too_small_salary EXCEPTION;
BEGIN
   CASE
      WHEN salary_in < 0 THEN RAISE negative_salary;
      WHEN salary_in > 10000 THEN RAISE too_large_salary;
      WHEN salary_in < 100 THEN RAISE too_small_salary;
      ELSE NULL;
   END CASE;

   /* Rest of procedure */
EXCEPTION
   WHEN negative_salary
   THEN
      notify_support (
         'Negative salary submitted ' || salary_in); 
      RAISE_APPLICATION_ERROR (-20001,
         'Negative salaries are not allowed. Please re-enter.');

   WHEN too_large_salary
   THEN
      notify_support (
         'Too large salary submitted ' || salary_in); 
      RAISE_APPLICATION_ERROR (-20002,
         'We are not nearly that generous. Please re-enter.');

   WHEN too_small_salary
   THEN
      notify_hr (
         'No one should be treated so shabbily! ' || salary_in);
      RAISE_APPLICATION_ERROR (-20003,
         'C''mon, a person''s gotta eat! Please re-enter.');
END;

And then when I execute the procedure and pass in -1, I will see:

 ORA-20001: Negative salaries are not allowed. Please re-enter. 

Some things to remember about RAISE_APPLICATION_ERROR:

  • You must provide an error code between -20999 and -20000.
  • If you do not pass TRUE for the third parameter, then the full error stack will not be kept, and only the most recent error message will be shown.
  • You can pass a string of up to 32767 characters to the built-in, but that string will be truncated to either 512 or 1899 bytes when calling SQLERRM or DBMS_UTILITY.FORMAT_ERROR_STACK respectively.

To Conclude

Usually, we leave it to the PL/SQL runtime engine to raise exceptions when an error occurs. Sometimes, however, you will need to raise your own exceptions. To do this, you can use RAISE or RAISE_APPLICATION_ERROR. The latter is especially helpful when you need to communicate an application-specific error message to your users.

Take advantage of PL/SQL’s separate exception handling section to centralize as much of your error-related logic as possible. Keep your executable section clean and focused on executing the «positive» statements — what should be happening when there are not any errors.

totn Oracle / PLSQL


This Oracle tutorial explains how to use Named Programmer-Defined Exceptions in Oracle/PLSQL with syntax and examples.

What is a named programmer-defined exception in Oracle?

Sometimes, it is necessary for programmers to name and trap their own exceptions — ones that aren’t defined already by PL/SQL. These are called Named Programmer-Defined Exceptions.

Syntax

We will take a look at the syntax for Named Programmer-Defined Exceptions in both procedures and functions.

Syntax for Procedures

The syntax for the Named Programmer-Defined Exception in a procedure is:

CREATE [OR REPLACE] PROCEDURE procedure_name
   [ (parameter [,parameter]) ]
IS
   [declaration_section]

   exception_name EXCEPTION;

BEGIN
   executable_section
   RAISE exception_name;

EXCEPTION
   WHEN exception_name THEN
      [statements]

   WHEN OTHERS THEN
      [statements]

END [procedure_name];

Syntax for Functions

The syntax for the Named Programmer-Defined Exception in a function is:

CREATE [OR REPLACE] FUNCTION function_name
   [ (parameter [,parameter]) ]
   RETURN return_datatype

IS | AS
   [declaration_section]

   exception_name EXCEPTION;

BEGIN
   executable_section

   RAISE exception_name;

EXCEPTION
   WHEN exception_name THEN
      [statements]

   WHEN OTHERS THEN
      [statements]

END [function_name];

Example

Here is an example of a procedure that uses a Named Programmer-Defined Exception:

CREATE OR REPLACE PROCEDURE add_new_order
   (order_id_in IN NUMBER, sales_in IN NUMBER)
IS
   no_sales EXCEPTION;

BEGIN
   IF sales_in = 0 THEN
      RAISE no_sales;

   ELSE
      INSERT INTO orders (order_id, total_sales )
      VALUES ( order_id_in, sales_in );
   END IF;

EXCEPTION
   WHEN no_sales THEN
      raise_application_error (-20001,'You must have sales in order to submit the order.');

   WHEN OTHERS THEN
      raise_application_error (-20002,'An error has occurred inserting an order.');

END;

In this example, we have declared a Named Programmer-Defined Exception called no_sales in our declaration statement with the following code:

no_sales EXCEPTION;

We’ve then raised the exception in the executable section of the code:

IF sales_in = 0 THEN
   RAISE no_sales;

Now if the sales_in variable contains a zero, our code will jump directly to the Named Programmer-Defined Exception called no_sales.

Finally, we tell our procedure what to do when the no_sales exception is encountered by including code in the WHEN clause:

WHEN no_sales THEN
   raise_application_error (-20001,'You must have sales in order to submit the order.');

We are also using the WHEN OTHERS clause to trap all remaining exceptions:

WHEN OTHERS THEN
   raise_application_error (-20002,'An error has occurred inserting an order.');

If you are a programmer, you might be familiar with the concept of exception handling is an integral part of any programming language. As errors are inevitable and even the smartest of us can make mistakes while writing code, we must be acquainted with how to handle them. In this article, we will be learning particularly about the exception handling in PL/SQL.

SQL-Exception Handling in PL/SQL-EdurekaBelow are the topics covered in this article :

  • What is an Exception?
  • Syntax of Exception Handling
  • Types of Exceptions
    • System defined
      • Named system exceptions
      • Unnamed system exceptions
    • User-defined
      • Steps to declare User-defined functions
      • Examples of User-defined functions

What is an Exception?

Any abnormal condition or event that interrupts the normal flow of our program instructions at run time or in simple words an exception is an error.

DECLARE
<declarations section>
BEGIN
<executable command(s)>
EXCEPTION
<exception handling goes here >
WHEN exception1 THEN
exception1-handling-statements
WHEN exception2&nbsp; THEN
exception2-handling-statements
WHEN exception3 THEN
exception3-handling-statements
........

WHEN others THEN
exception3-handling-statements
END;

Here, we can list down as many exceptions as we want to handle. The default exception will be handled using ‘WHEN others THEN’

Example of Exception Handling in PL/SQL

The below program displays the name and address of a student whose ID is given. Since there is no student with ID value 8 in our database, the program raises the run-time exception NO_DATA_FOUND, which is captured in the EXCEPTION block.

DECLARE 
   s_id studentS.id%type := 8; 
   s_name studentS.Name%type; 
   s_loc studentS.loc%type; 
BEGIN 
   SELECT  name, loation INTO  s_name, s_loc 
   FROM students 
   WHERE id = s_id;  
   DBMS_OUTPUT.PUT_LINE ('Name: '||  s_name); 
   DBMS_OUTPUT.PUT_LINE ('Location: ' || s_loc);
EXCEPTION 
   WHEN no_data_found THEN 
      dbms_output.put_line('No such student!'); 
   WHEN others THEN 
      dbms_output.put_line('Oops, Error!'); 
END; 

Output

No such student!
PL/SQL procedure successfully completed.  

Here, we can list down as many exceptions as we want to handle. The default exception will be handled using ‘WHEN others THEN

Types of Exceptions in PL/SQL

  • System defined
  • User defied

Next in this article on exception handling in PL/SQL, let us discuss about both of these types in detail.

System defined

Defined and maintained implicitly by the Oracle server, these exceptions are mainly defined in the Oracle Standard Package. Whenever an exception occurs inside the program, Oracle server matches and identifies the appropriate exception from the available set of exceptions available in the oracle standard package. Basically, these exceptions are predefined in PL/SQL which gets raised WHEN particular database rule is violated.

The System-defined exceptions are further divided into two categories:

  • Named system exceptions
  • Unnamed system exceptions

Named system Exceptions

The named PL/SQL exceptions are named in the standard package of PL/SQL, hence the developer does not need to define the PL/SQL exceptions in their code. PL/SQL provides many pre-defined named exceptions, which are executed when any database rule is violated by a program. The following table lists a few of the important pre-defined exceptions −

Exception Oracle Error SQLCODE Description
ACCESS_INTO_NULL 06530 -6530 It is raised when a null object is automatically assigned a value.
CASE_NOT_FOUND 06592 -6592 It is raised when none of the choices in the WHEN clause of a CASE statement is selected, and there is no ELSE clause.
COLLECTION_IS_NULL 06531 -6531 It is raised when a program attempts to apply collection methods other than EXISTS to an uninitialized nested table or varray, or the program attempts to assign values to the elements of an uninitialized nested table or varray.
DUP_VAL_ON_INDEX 00001 -1 It is raised when duplicate values are attempted to be stored in a column with a unique index.
INVALID_CURSOR 01001 -1001 It is raised when attempts are made to make a cursor operation that is not allowed, such as closing an unopened cursor.
INVALID_NUMBER 01722 -1722 It is raised when the conversion of a character string into a number fails because the string does not represent a valid number.
LOGIN_DENIED 01017 -1017 It is raised when a program attempts to log on to the database with an invalid username or password.
NO_DATA_FOUND 01403 +100 It is raised when a SELECT INTO statement returns no rows.
NOT_LOGGED_ON 01012 -1012 It is raised when a database call is issued without being connected to the database.
PROGRAM_ERROR 06501 -6501 It is raised when PL/SQL has an internal problem.
ROWTYPE_MISMATCH 06504 -6504 It is raised when a cursor fetches value in a variable having incompatible data type.
SELF_IS_NULL 30625 -30625 It is raised when a member method is invoked, but the instance of the object type was not initialized.
STORAGE_ERROR 06500 -6500 It is raised when PL/SQL ran out of memory or memory was corrupted.
TOO_MANY_ROWS 01422 -1422 It is raised when a SELECT INTO statement returns more than one row.
VALUE_ERROR 06502 -6502 It is raised when an arithmetic, conversion, truncation, or size constraint error occurs.
ZERO_DIVIDE 01476 1476 It is raised when an attempt is made to divide a number by zero.

Example

CREATE OR REPLACE PROCEDURE add_new_student
      (student _id_in IN NUMBER, student _name_in IN VARCHAR2)
IS
BEGIN
       INSERT INTO student (student _id, student _name )
       VALUES ( student _id_in, student _name_in );
EXCEPTION
       WHEN DUP_VAL_ON_INDEX THEN
 raise_application_error (-20001,'Duplicate student _id');
       WHEN OTHERS THEN
raise_application_error (-20002,'An error occurred.');
END;

Moving on in this article on exception handling in PL/SQL, let us understand what are unnamed system exceptions.

Unnamed System Exceptions

The system exceptions for which Oracle does not have a name are known as unnamed system exceptions. These exceptions do not occur frequently and are written with a code and an associated message.

There are basically two ways to handle unnamed system exceptions:

1. Using the WHEN OTHERS exception handler

2. Associating the exception code to a name and using it as a named exception.

Some steps followed for unnamed system exceptions are:

  • Raise them implicitly.
  • In case they are not handled in ‘WHEN Others’ then, they have to be handled explicitly.
  • To handle the exception explicitly, they can be declared using Pragma EXCEPTION_INIT and handled by referencing the user-defined exception name in the exception section.

An example of handling unnamed exceptions using Pragma EXCEPTION_INIT is provided later in the article. Moving on in this article on exception handling in PL/SQL, let us understand the User-defined excetpions.

User-defined

Like all other programming languages, Oracle also allows you to declare ad implement your own exceptions. Unlike System defined exceptions, these exceptions are raised explicitly in the PL/SQL block.

Steps to declare User-defined exceptions in the Oracle database

We can define User-defined exceptions in Oracle database in the following 3 ways:

  • Using Variable of EXCEPTION type

Here, we can declare a User-defined exception by declaring a variable of EXCEPTION datatype in our code and raise it explicitly in our program using RAISE statement.

  • Using PRAGMA EXCEPTION_INIT function

We can define a non-predefined error number with the variable of EXCEPTION datatype

  • Using RAISE_APPLICATION_ERROR method

Using this method, we can declare a User-defined exception with our own customized error number and message.

Till now you might have got a rough idea on the ways in which we can raise User-defined exceptions in PL/SQL. We will learn about each of the above-mentioned methods with examples further in this article on exception handling in PL/SQL.

Next in this article, let us proceed with the demonstrations of User-defined exception handling.

Demonstration of User-defined Exceptions

Moving on in this article on Exception Handling in PL/SQL, let us understand how to use the variable of EXCEPTION type.

Using Variable of EXCEPTION type

The process of declaring user-defined exception is divided into three parts and these 3 parts are:

  • Declare a variable exception datatype
  • Raise the Exception
  • Handle the Exception

Let’s write a code to demonstrate the above steps in detail.

DECLARE
       var_dividend NUMBER :=10;
       var_divisor  NUMBER :=0
       var_result NUMBER;
       ex-DivZero EXCEPTION

In the above declaration block, we have four variables, among which the first three are normal number datatype variables and the fourth one which is ex_DivZero is the special exception datatype variable. The fourth one is our user-defined exception.

DECLARE
       var_dividend NUMBER :=10;
       var_divisor  NUMBER :=0
       var_result NUMBER;
       ex-DivZero EXCEPTION

The above execution part of this anonymous block, will come into action only when the divisor is 0. If the divisor is zero as it is in our case, the error will be raised and the control of the program will skip all the next steps and  will look for matching exception handler. In the case where it finds any other, it will perform the action accordingly, otherwise it will either terminate the program or prompt us with an unhandled system defined error.

EXCEPTION WHEN ex_DivZero THEN
DBMS_OUTPUT.PUT_LINE(‘ ERROR, The divisor can’t be zero’);

This the exception handler. As soon as the user enter divisor as 0, the above message string will be prompted.

Final Code:

DECLARE
       var_dividend NUMBER :=10;
       var_divisor  NUMBER :=0
       var_result NUMBER;
       ex-DivZero EXCEPTION
BEGIN
IF var_divisor =0 THEN
RAISE ex-DivZero;
END IF;
Var_result := var_dividend/var_divisor;
DBMS_OUTPUT.PUT_LINE (‘Result = ‘ || var_result);
BEGIN
IF var_divisor =0 THEN
RAISE ex-DivZero;
END IF;
Var_result := var_dividend/var_divisor;
DBMS_OUTPUT.PUT_LINE (‘Result = ‘ || var_result);
END;

Moving on in this article on exception handling in PL/SQL, let us understand how to use the PRAGMA_EXCEPTION_INIT method.

Using PRAGMA EXCEPTION_INIT function

In the PRAGMA EXCEPTION_INIT function,  an exception name is associated with an Oracle error number. This name can be used in designing the exception handler for the error. For huge projects with many user defined errors, PRAGMA EXCEPTION_INIT  is the most useful and suitable method.

Syntax:

PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);

Example

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;

The PRAGMA EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number as mentioned earlier. It  lets you refer to any internal exception by name and write a specific handler for it. When you see an error stack, or sequence of error messages, the one on top is the one that can be trapped and handled.

Moving on in this article on Exception Handling in PL/SQL, let us understand how to use the RAISE_APPLICATION_ERROR method.

Using RAISE_APPLICATION_ERROR method

It’s a procedure that comes inbuilt with the oracle software. Using this procedure we can associate an error number with a custom error message. Combining both the error number and the custom error message, an error string can be composed which looks similar to those default error strings which are displayed by oracle when an error is encountered. RAISE_APPLICATION_ERROR procedure is found inside DBMS_STANDARD package

Syntax

raise_application_error (error_number, message [, {TRUE | FALSE}]);

Example

/* A trigger trg_emp_detail_chk is created.*/
CREATE OR REPLACE TRIGGER trg_emp_detail_chk

/* The trigger timing is declared as BEFORE UPDATE on the EMPLOYEES table.*/
Before UPDATE ON employees

DECLARE
permission_denied EXCEPTION;
BEGIN

/*Start of the IF condition checking whether the day of the system time is either Saturday or Sunday or not.*/
IF trim(TO_CHAR(sysdate,'Day')) IN ('Saturday', 'Sunday') THEN
raise_application_error(-20000, 'You are not authorized to do any modification in the weekends!!');

/* The procedure raise_application_error is called with the first parameter value as -20000 and the second parameter
with a default text stating that the user is not authorized to do any modification in the weekends. */
END IF;
END;

With this we come to an end of this article on “Exception handling in PL/SQL”. I hope this topic is understood well and helped you. Try to write your own codes and incorporate the methods explained in this article.

If you want to get trained from professionals on this technology, you can opt for structured training from edureka! Check out this MySQL DBA Certification Training by Edureka, a trusted online learning company with a network of more than 250,000 satisfied learners spread across the globe. This course trains you on the core concepts & advanced tools and techniques to manage data and administer the MySQL Database. It includes hands-on learning on concepts like MySQL Workbench, MySQL Server, Data Modeling, MySQL Connector, Database Design, MySQL Command line, MySQL Functions etc. End of the training you will be able to create and administer your own MySQL Database and manage data.

Got a question for us? Please mention it in the comments section of this “Exception Handling in PL/SQL” article and we will get back to you as soon as possible.

Exception can be defined as the state of an entity, which is different from its conventional and normal behavior. In context to programming language, exception refers to the abnormal situation in the normal flow of the program. Oracle server raises exception whenever it encounters a logical violation of the flow during program execution.

I have listed the common situations which end up raising exceptions and subsequently termination of the program.

  1. Design Faults and illogical flow
  2. Exception propagation from referenced program unit
  3. Coding mistakes
  4. Hardware failures

Exception Propagation in a Program Unit

The figure below shows the program flow, which is followed when an exception situation occurs in the PL/SQL block and the exception has been handled. Once the exception has been raised and trapped, and the control moves to EXCEPTION section, the program propagates in the forward direction.

If the exception has not been handled, the program terminates abruptly or propagates to the calling environment.

Fig 1a: Program flow when the Exception has been trapped and handled

Fig 1b: Program flow when the Exception has not been handled

Exception Handling

Exceptions can be trapped in the EXCEPTION section of a PL/SQL block. Oracle supports two ways to raise exception in a program, implicitly or explicitly.

Exceptions which are automatically raised by the oracle server fall under the category of implicit way raising an exception. PL/SQL runtime engine identifies the abnormal flow and raises the exception. For example, NO_DATA_FOUND or TOO_MANY_ROWS are the system defined exceptions which are raised by the server during program execution.

Exceptions which are trapped in executable section and handled in the EXCEPTION block by the programmer are explicit ways raising exceptions. In this category, a user can either explicitly raise an already existing system defined exception or create a new exception and invoke in the program.

Syntax [1]
EXCEPTION
  WHEN exception1 [OR exception2 . . .] THEN
    statement1;
    statement2;
    . . .
  [WHEN exception3 [OR exception4 . . .] THEN
    statement1;
    statement2;
    . . .]
  [WHEN OTHERS THEN
    statement1;
    statement2;
    . . .]

In the syntax, a single WHEN-THEN statement is called as Exception Handler. Likewise, there can be multiple exception handlers in the EXCEPTION section of a PL/SQL block. An exception handler consists of exception name and set of statements, which would be executed once the exception has been raised. An exception handler can have more than one exception aligned using OR operator. So, the same action would be applicable for multiple exceptions.

Out of multiple exception handlers, only one can be executed at a time before the termination of the block.

One exception handler handles a single exception. Repetitive handling of an exception is not allowed in a single block.

Exception Trapping Functions: SQLCODE and SQLERRM

Oracle uses two built in functions for catching exceptions and getting its information, SQLCODE and SQLERRM.

SQLCODE returns the error number for the latest occurred exception in the PL/SQL block, while SQLERRM returns the error message associated with the latter error number.

Code [1]:

The screen dump below shows the usage of SQLCODE and SQLERRM in a program.

Pre Defined Exceptions

Oracle maintains set of defined exceptions, which are implicitly raised by the server, if an abnormal situation occurs in the program. The table below lists some of the commonly occurring exceptions.

Error

Named Exception

ORA-00001

DUP_VAL_ON_INDEX

ORA-01001

INVALID_CURSOR

ORA-01012

NOT_LOGGED_ON

ORA-01017

LOGIN_DENIED

ORA-01403

NO_DATA_FOUND

ORA-01422

TOO_MANY_ROWS

ORA-01476

ZERO_DIVIDE

ORA-01722

INVALID_NUMBER

ORA-06504

ROWTYPE_MISMATCH

ORA-06511

CURSOR_ALREADY_OPEN

ORA-06530

ACCESS_INTO_NULL

ORA-06531

COLLECTION_IS_NULL

ORA-06532

SUBSCRIPT_OUTSIDE_LIMIT

ORA-06533

SUBSCRIPT_BEYOND_COUNT

Raising Exceptions Implicitly

These exceptions are automatically processed and raised by Oracle server.

As soon as Oracle server encounters any illogical flow in the program flow, it stops further execution of program, identifies and throws the appropriate exception; program terminates abruptly.

Refer the example illustration below.

Code [2]:

In the below PL/SQL block, a test message is displayed before and after the SELECT statement. The SELECT statement selects multiple rows through an SQL cursor. Since the query returns multiple rows, it raises an exception. As soon as the exception is raised, control jumps to the EXCEPTION section, skipping the further statements in executable section of the block. The message after the query was not displayed.

DECLARE
   L_DEPTID NUMBER := 10;
   L_ENAME VARCHAR2(100);
   L_SAL NUMBER;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Before SQL query');
 
   SELECT EMPLOYEE_NAME,SALARY
   INTO L_ENAME, L_SAL
   FROM EMPLOYEES
   WHERE DEPARTMENT_ID = L_DEPTID;
 
   DBMS_OUTPUT.PUT_LINE('After SQL query');
END;
/
 
BEFORE SQL query
DECLARE
*
ERROR at line 1:
ORA-01422: exact fetch RETURNS more than requested NUMBER OF ROWS
ORA-06512: at line 7

The above block also complies with the fact that the once the exception scenario is identified, server skips the execution of the further statements in the block and terminates immediately. For this reason, the second test message doesn’t appear in the output.

Raising Exception Explicitly: System Defined and User Defined Exceptions

A developer can explicitly raise the system defined exceptions. In the Code [], the TOO_MANY_ROWS exception can be captured by defining an exception handler in the EXCEPTION section.

Code [3]

In the below PL/SQL code, TOO_MANY_ROWS exception has been explicitly trapped by the developer bypass the situation (abnormal termination) with an informative message in the application.

DECLARE
   L_DEPTID NUMBER := 10;
   L_ENAME VARCHAR2(100);
   L_SAL NUMBER;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Before SQL query');
   SELECT EMPLOYEE_NAME,SALARY
   INTO L_ENAME, L_SAL
   FROM EMPLOYEES
   WHERE DEPARTMENT_ID = L_DEPTID;
   DBMS_OUTPUT.PUT_LINE('After SQL query');
EXCEPTION
   WHEN TOO_MANY_ROWS THEN
     DBMS_OUTPUT.PUT_LINE ('Use Oracle Bulk Collect feature or Cursor to select multiple rows from a table');
END;
/
 
BEFORE SQL query
USE Oracle Bulk Collect feature OR Cursor TO SELECT multiple ROWS FROM a TABLE
 
PL/SQL PROCEDURE successfully completed.

An exception handler may contain alternate operations to be performed at the situations of exception in the program.

System defined exceptions can be the part of business logic too. If a business logic implementation or conditional logic requires a system defined exception to be raised, it can be achieved using RAISE statement. Check the example below.

Code [4]:

Oracle raises NO_DATA_FOUND exception, when the SQL query in the executable section returns no records. To avoid the exception, it can be rewritten using a PL/SQL cursor, without omitting the exception action. System defined exception can be explicitly raised by the programmer like below.

DECLARE
   L_DEPTID NUMBER := 15;
   L_ENAME VARCHAR2(100);
   L_SAL NUMBER;
CURSOR C IS
   SELECT EMPLOYEE_NAME,SALARY
   FROM EMPLOYEES
   WHERE DEPARTMENT_ID = L_DEPTID;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Before SQL query');
   OPEN C;
   FETCH C INTO L_ENAME, L_SAL;
   IF C%ROWCOUNT = 0 THEN
      RAISE NO_DATA_FOUND;
   END IF;
   CLOSE C;
   DBMS_OUTPUT.PUT_LINE('After SQL query');
EXCEPTION
   WHEN NO_DATA_FOUND THEN
     DBMS_OUTPUT.PUT_LINE ('No Employees in the department');
END;
/
 
BEFORE SQL query
No Employees IN the department
 
PL/SQL PROCEDURE successfully completed.

User Defined Exceptions

User defined exceptions allow the developers to create their own customized exceptions and raise them within the program wherever required. They are declared in the DECLARE section of the block with type as EXCEPTION and raised using RAISE statement.

This feature gives them flexibility to create exception with their convenient name, which can be more handful for use and easy to remember in large formulated applications.

Code [5]:

The PL/SQL block used in the earlier examples has been reused to declare a user defined exception LOCAL_EXCEPTION. It is raised at the same logic (when no employees exist in a department) using RAISE statement.

DECLARE
   L_DEPTID NUMBER := 15;
   L_ENAME VARCHAR2(100);
   L_SAL NUMBER;
   LOCAL_EXCEPTION EXCEPTION;
CURSOR C IS
   SELECT EMPLOYEE_NAME,SALARY
   FROM EMPLOYEES
   WHERE DEPARTMENT_ID = L_DEPTID;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Before SQL query');
   OPEN C;
   FETCH C INTO L_ENAME, L_SAL;
   IF C%ROWCOUNT =0 THEN
      RAISE LOCAL_EXCEPTION;
   END IF;
   CLOSE C;
   DBMS_OUTPUT.PUT_LINE('After SQL query');
EXCEPTION
   WHEN LOCAL_EXCEPTION THEN
     DBMS_OUTPUT.PUT_LINE ('No Employees in the department');
END;
/
 
BEFORE SQL query
No Employees IN the department
 
PL/SQL PROCEDURE successfully completed.

Associating a User Defined Exception with an Error Number (or Exception Code)

A user defined exception can be associated with an error number using PRAGMA EXCEPTION_INIT. The pragma is a compiler directive which hints the compiler to accept the directions provided in the program. The PRAGMA EXCEPTION_INIT directs the compiler to align the user defined exception with a self assigned error number. The error number must be one of the valid ORA error codes, which are defined by the server.

Syntax [2]
PRAGMA EXCEPTION_INIT([EX NAME],[ERROR NUMBER], [TRUE | FALSE])
Code [6]

In the PL/SQL block below, the LOCAL_EXCEPTION exception is linked with the error number -100 through the PRAGMA EXCEPTION_INIT. Note the usage of SQLCODE, which returns the same associated error number.

DECLARE
   L_DEPTID NUMBER := 15;
   L_ENAME VARCHAR2(100);
   L_SAL NUMBER;
   LOCAL_EXCEPTION EXCEPTION;
   PRAGMA EXCEPTION_INIT(LOCAL_EXCEPTION, -100);
CURSOR C IS
   SELECT EMPLOYEE_NAME,SALARY
   FROM EMPLOYEES
   WHERE DEPARTMENT_ID = L_DEPTID;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Before SQL query');
   OPEN C;
   FETCH C INTO L_ENAME, L_SAL;
   IF C%ROWCOUNT =0 THEN
      RAISE LOCAL_EXCEPTION;
   END IF;
   CLOSE C;
   DBMS_OUTPUT.PUT_LINE('After SQL query');
EXCEPTION
   WHEN LOCAL_EXCEPTION THEN
     DBMS_OUTPUT.PUT_LINE (‘Exception Error NUMBER:’||SQLCODE);
     DBMS_OUTPUT.PUT_LINE ('No Employees in the department');
END;
/
 
BEFORE SQL query
Exception Error NUMBER:-100
No Employees IN the department
 
PL/SQL PROCEDURE successfully completed.

Customizing the Error Numbers: RAISE_APPLICATION_ERROR

Oracle facilitates the developer by privileging them to create an error number of their own choice and associating them with a customized message. RAISE_APPLICATION_ERROR is an Oracle API, which allows choosing the error numbers in range of -20000 to -20999 and fix them with an error message

It can be used in executable section or exception section in a PL/SQL block.

Syntax [3]
RAISE_APPLICATION_ERROR (error_number, error_message[, {TRUE | FALSE}])
Code [7]
DECLARE
   L_DEPTID NUMBER := 15;
   L_ENAME VARCHAR2(100);
   L_SAL NUMBER;
CURSOR C IS
   SELECT EMPLOYEE_NAME,SALARY
   FROM EMPLOYEES
   WHERE DEPARTMENT_ID = L_DEPTID;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Before SQL query');
   OPEN C;
   FETCH C INTO L_ENAME, L_SAL;
   IF C%ROWCOUNT =0 THEN
      RAISE_APPLICATION_ERROR(-20001,' No Employees in the department');
   END IF;
   CLOSE C;
   DBMS_OUTPUT.PUT_LINE('After SQL query');
END;
/
 
BEFORE SQL query
DECLARE
*
ERROR at line 1:
ORA-20001:  No Employees IN the department
ORA-06512: at line 14

Как отлавливать ошибки в Oracle (PLSQL) EXCEPTION,SQLERRM,SQLCODE

Осваиваем Oracle и PL/SQL

Маленькое руководство по отлавливанию ошибок в Oracle PLSQL.
Описание как использовать в Oracle (PLSQL) функции SQLERRM и SQLCODE для отлова ошибок EXCEPTION, с описанием синтаксиса и примером.

Функция SQLERRM возвращает сообщение об ошибке связанное с последним возникшим исключением (ошибкой).
Функция SQLERRM — не имеет параметров.

Функция SQLCODE возвращает код ошибки связанный с последним возникшим исключением (ошибкой)
Функция SQLERRM — не имеет параметров.

Обычно обработка исключений EXCEPTION выглядит следующим образом:

EXCEPTION
   WHEN наименование_ошибки_1 THEN
      [statements]

   WHEN наименование_ошибки_2 THEN
      [statements]

   WHEN наименование_ошибки_N THEN
      [statements]

   WHEN OTHERS THEN
      [statements]

END [наименование_процедуры];

Вы можете использовать функции SQLERRM и SQLCODE для вызова сообщения об ошибке например таким образом:

EXCEPTION
   WHEN OTHERS THEN
      raise_application_error(-20001,'Произошла ошибка - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
-- В данном случае появится всплывающее сообщение.

Или вы можете сохранить сообщение об ошибке в таблицу таким образом:

EXCEPTION
   WHEN OTHERS THEN
      err_code := SQLCODE;
      err_msg := SUBSTR(SQLERRM, 1, 200);

      INSERT INTO error_log_table (error_time, error_number, error_message)
      VALUES (sysdate, err_code, err_msg);
END;
--В данном случае ошибка будет помещена в таблицу error_log_table

Варианты основных возможных ошибок:

DUP_VAL_ON_INDEX
ORA-00001
При попытке произвести вставку INSERT или изменение UPDATE данных которое создает дублирующую запись нарушающую уникальный индекс (unique index).

TIMEOUT_ON_RESOURCE
ORA-00051
Происходит когда ресурс над которым производится операция заблокирован и произошел сброс по таймауту.

TRANSACTION_BACKED_OUT
ORA-00061
Произошёл частичный откат транзакции.

INVALID_CURSOR
ORA-01001
Попытка использовать курсор которого не существует. Может происходить если вы пытаетесь использовать FETCH курсор или закрыть CLOSE курсор до того как вы этот курсор открыли OPEN.

NOT_LOGGED_ON
ORA-01012
Попытка произвести действия не залогинившись.

LOGIN_DENIED
ORA-01017
Неудачная попытка залогиниться, в доступе отказано, не верный пользователь или пароль.

NO_DATA_FOUND
ORA-01403
Что то из перечисленного: Попытка произвести вставку SELECT INTO несуществующего набора значений (select — ничего не возвращает). Попытка доступа к неинициализированной строке/записи в таблице. Попытка чтения записи после окончания файла при помощи пакета UTL_FILE.

TOO_MANY_ROWS
ORA-01422
Попытка вставить значение в переменную при помощи SELECT INTO и select вернул более чем одно значение.

ZERO_DIVIDE
ORA-01476
Попытка деления на ноль.

INVALID_NUMBER
ORA-01722
Попытка выполнить SQL запрос который производит конвертацию строки (STRING) в число (NUMBER) при этом такое преобразование невозможно.

STORAGE_ERROR
ORA-06500
Либо нехватка памяти, либо ошибка в памяти.

PROGRAM_ERROR
ORA-06501
Внутренняя программная ошибка рекомендуется с такой ошибкой обращаться в службу поддержки Oracle.

VALUE_ERROR
ORA-06502
Попытка выполнить операцию конвертации данных которая закончилась с ошибкой (например: округление, преобразование типов, и т.п.).

CURSOR_ALREADY_OPEN
ORA-06511
Вы пытаетесь открыть курсор который уже открыт.

Вот пожалуй и всё.


Oracle
PLSQL
SQL
EXCEPTION
SQLERRM
SQLCODE
ошибки
программирование

Понравилась статья? Поделить с друзьями:
  • Rainmeter погода как изменить город
  • Rage mp error game injection has timed out if this happened most probably
  • Rage mp connection lost reconnecting как исправить
  • Rage 2 работа прекращена отчет об ошибке как исправить
  • Rage 2 проблемы со звуком как исправить