This question raised a very interesting point; there seems to be a contradiction in the Oracle documentation on whether it\'s possible for %NOTFOUND
to be null
I think the part that's tripping you up is this:
If FETCH never executes successfully, the EXIT WHEN condition is never TRUE and the loop is never exited.
Somewhere in the past there must have been a code example which looked like this:
LOOP
FETCH c1 INTO name;
EXIT WHEN c1%NOTFOUND;
-- Do stuff
END LOOP;
Given this chunk of code, then the statement rings true. If the fetch never executes (fails), then %NOTFOUND will be null. The EXIT WHEN
condition will not evaluate to TRUE (null evaluates to false). Then, indeed, the loop will continue forever.
This is a situation that is easily tested:
SET SERVEROUT ON;
DECLARE
-- this cursor returns a single row
CURSOR c1 IS
SELECT 1 FROM dual WHERE rownum = 1;
-- this cursor returns no rows
CURSOR c2 IS
SELECT 1 FROM dual WHERE 1=0;
v1 number;
BEGIN
OPEN c1;
FETCH c1 INTO v1; -- this returns a record
FETCH c1 INTO v1; -- this does not return a record
IF c1%NOTFOUND THEN
dbms_output.put_line('c1%NOTFOUND: TRUE');
ELSIF c1%NOTFOUND IS NULL THEN
dbms_output.put_line('c1%NOTFOUND: NULL');
ELSE
dbms_output.put_line('c1%NOTFOUND: FALSE');
END IF;
CLOSE c1;
OPEN c2;
FETCH c2 INTO v1; -- this does not return a record
IF c2%NOTFOUND THEN
dbms_output.put_line('c2%NOTFOUND: TRUE');
ELSIF c2%NOTFOUND IS NULL THEN
dbms_output.put_line('c2%NOTFOUND: NULL');
ELSE
dbms_output.put_line('c2%NOTFOUND: FALSE');
END IF;
CLOSE c2;
END;
/
The output of the script on Oracle APEX 4.1 is (I think APEX is running Oracle 11gR2, but you can easily run the script on any version):
c1%NOTFOUND: TRUE
c2%NOTFOUND: TRUE
Based on this test, %NOTFOUND
will not be NULL after a fetch has been executed. This matches what the 10g and 11g documentation says in the initial description of the %NOTFOUND
attribute. The note about the loop never exiting must be from an old version of the example. Since it's just a note, I'd says it's safe to trust the initial description and disregard the note.
I can find a situation where a fetch can fail:
declare
i integer;
cursor c is
select 1 / 0 from dual;
begin
open c;
begin
fetch c
into i;
exception
when others then
dbms_output.put_line('ex');
end;
if c%notfound is null then
dbms_output.put_line('null');
elsif c%notfound then
dbms_output.put_line('true');
else
dbms_output.put_line('false');
end if;
close c;
end;
But this only makes your question stronger since it will evaluate to null, neither in 10g nor in 11g ...