Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NO_DATA_FOUND exception not thrown when used in SELECT INTO

I noticed strange behaviour of NO_DATA_FOUND exception when thrown from function used in PLSQL.

Long story short - it does propagate from function when using assignment, and does not propagate (or is handled silently somewhere in between) when used in SELECT INTO.

So, given function test_me throwing NO_DATA_FOUND exception, when invoked as:

v_x := test_me(p_pk);

It throws an exception, while when invoked as:

SELECT test_me(p_pk) INTO v_x FROM dual;

it does not throw exception. This does not occur with other exceptions. Below You can find my test examples.

Could somebody please explain to me this behaviour?

set serveroutput on;
CREATE OR REPLACE FUNCTION test_me(p_pk NUMBER) RETURN NVARCHAR2
IS
    v_ret NVARCHAR2(50 CHAR);
BEGIN
    BEGIN
        SELECT 'PYK' INTO v_ret FROM dual WHERE 1 = 1/p_pk;
    EXCEPTION WHEN NO_DATA_FOUND THEN
        dbms_output.put_line(chr(9)||chr(9)||chr(9)||' (test_me NO_DATA_FOUND handled and rerised)');
        RAISE;
    END;
    RETURN v_ret;
END;
/
DECLARE
    v_x NVARCHAR2(500 CHAR);
    v_pk NUMBER;
    PROCEDURE test_example(p_pk NUMBER)
    IS
    BEGIN
        BEGIN
            dbms_output.put_line(chr(9)||chr(9)||'Test case 1: Select into.');
            SELECT test_me(p_pk) INTO v_x FROM dual;
            dbms_output.put_line(chr(9)||chr(9)||'Success: '||NVL(v_x,'NULL RETURNED'));
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                dbms_output.put_line(chr(9)||chr(9)||'Failure: NO_DATA_FOUND detected');
            WHEN OTHERS THEN
                dbms_output.put_line(chr(9)||chr(9)||'Failure: '||SQLCODE||' detected');
        END;
        dbms_output.put_line(' ');
        BEGIN
            dbms_output.put_line(chr(9)||chr(9)||'Test case 2: Assignment.');
            v_x := test_me(p_pk);
            dbms_output.put_line(chr(9)||chr(9)||'Success: '||NVL(v_x,'NULL RETURNED'));
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                dbms_output.put_line(chr(9)||chr(9)||'Failure: NO_DATA_FOUND detected');
            WHEN OTHERS THEN
                dbms_output.put_line(chr(9)||chr(9)||'Failure: '||SQLCODE||' detected');
        END;
    END;
BEGIN
    dbms_output.put_line('START');
    dbms_output.put_line(' ');
    dbms_output.put_line(chr(9)||'Example 1: Function throws some exception, both cases throws exception, everything is working as expected.');
    test_example(0);
    dbms_output.put_line(' ');
    dbms_output.put_line(chr(9)||'Example 2: Query returns row, there is no exceptions, everything is working as expected.');
    test_example(1);
    dbms_output.put_line(' ');
    dbms_output.put_line(chr(9)||'Example 3: Query inside function throws NO_DATA_FOUND, strange things happen - one case is throwing exception, the other is not.');
    test_example(2);
    dbms_output.put_line(' ');
    dbms_output.put_line('END');
END;
/
DROP FUNCTION test_me;
like image 919
T.Z. Avatar asked May 31 '16 11:05

T.Z.


People also ask

How do you handle no data found exception in SQL?

1. no_data_found :- Whenever PL/SQL Block having select into clause and also if requested data is not available then oracle server returns an error ora – 1403 : no data found. For handling this error oracle provided no_data_found exception name.

How avoid No data found exception in PL SQL?

Answer: To prevent the PLSQL code from dropping to the exception code when a record is not found, you'll have to perform a count first to determine the number of records that will be returned. For example: -- Check to make sure that at least one record is returned SELECT COUNT(1) INTO v_count FROM sales.

What are the 3 types of exceptions in SQL?

There are three types of exceptions: Predefined exceptions are error conditions that are defined by PL/SQL. Non-predefined exceptions include any standard TimesTen errors. User-defined exceptions are exceptions specific to your application.

How do I handle ORA 01403 without data found?

To fix this, re-create tables from the initial controlling database. The good news is that the ORA-01403 error is highly preventable. By creating the proper exceptions, the program should now operate free of the error and remain that way until edited again.


1 Answers

A minimal example is:

CREATE FUNCTION raise_exception RETURN INT
IS
BEGIN
  RAISE NO_DATA_FOUND;
END;
/

If you do:

SELECT raise_exception
FROM   DUAL;

You will get a single row containing a NULL value - Ask Tom states:

it has ALWAYS been that way

and then followed up with:

no_data_found is not an error - it is an "exceptional condition". You, the programmer, decide if something is an error by catching the exceptional condition and handling it (making it be "not an error") or ignoring it (making it be an error).

in sql, no data found quite simply means "no data found", stop.

Under the covers, SQL is raising back to the client application "hey buddy -- no_data_found". The client in this case says "ah hah, no data found means 'end of data'" and stops.

So the exception is raised in the function and the SQL client sees this and interprets this as there is no data which is a NULL value and "handles" the exception.

So

DECLARE
  variable_name VARCHAR2(50);
BEGIN
  SELECT raise_exception
  INTO   variable_name
  FROM   DUAL
END;
/

Will succeed as the DUAL table has a single row and the exception from the function will be handled (silently) and the variable will end up containing a NULL value.

However,

BEGIN
  DBMS_OUTPUT.PUT_LINE( raise_exception );
END;
/

The exception is this time being passed from the function to a PL/SQL scope - which does not handle the error and passes the exception to the exception handler block (which does not exist) so then gets passed up to the application scope and terminates execution of the program.

And Ask Tom states:

Under the covers, PLSQL is raising back to the client application "hey -- no_data_found. The client in this case says "uh-oh, wasn't expecting that from PLSQL -- sql sure, but not PLSQL. Lets print out the text that goes with this exceptional condition and continue on"

You see -- it is all in the way the CLIENT interprets the ORA-xxxxx message. That message, when raised by SQL, is interpreted by the client as "you are done". That message, when raised by PLSQL and not handled by the PLSQL programmer, is on the other hand interpreted as "a bad thing just happened"

Both PLSQL and SQL actually do the same thing here. It is the CLIENT that is deciding to do something different.

Now, if we change the function to raise a different exception:

CREATE OR REPLACE FUNCTION raise_exception RETURN INT
IS
BEGIN
  RAISE ZERO_DIVIDE;
END;
/

Then both:

SELECT raise_exception
FROM   DUAL;

and:

BEGIN
  DBMS_OUTPUT.PUT_LINE( raise_exception );
END;
/

do not know how to handle the exception and terminate with ORA-01476 divisor is equal to zero.

like image 79
MT0 Avatar answered Oct 19 '22 09:10

MT0