Skip to Main Content
  • Questions
  • problem with FOR LOOP with PL/SQL Function that returns a ref cursor

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question.

Asked: June 26, 2006 - 5:52 pm UTC

Last updated: June 06, 2013 - 4:05 pm UTC

Version: 10g

Viewed 10K+ times! This question is

You Asked

Here is how I defined my ref cursor:



create or replace PACKAGE SPRINGAPP_REFCURSOR_PKG AS

TYPE LOGIN_NAME IS RECORD(FNAME SPRINGAPP.LOGIN_USER.FIRST_NAME%TYPE, LNAME SPRINGAPP.LOGIN_USER.LAST_NAME%TYPE);

TYPE LOGIN_NAME_CURSOR IS REF CURSOR RETURN LOGIN_NAME;

END SPRINGAPP_REFCURSOR_PKG;



Here is my function code:



CREATE OR REPLACE

FUNCTION Get_Login_User_Func (USER_NAME SPRINGAPP.LOGIN_USER.FIRST_NAME%TYPE)

RETURN

SPRINGAPP.SPRINGAPP_REFCURSOR_PKG.LOGIN_NAME_CURSOR

IS

USER_INFO SPRINGAPP.SPRINGAPP_REFCURSOR_PKG.LOGIN_NAME_CURSOR;

BEGIN

OPEN USER_INFO FOR SELECT FIRST_NAME, LAST_NAME FROM LOGIN_USER WHERE USERNAME = USER_NAME;

RETURN USER_INFO;

EXCEPTION

WHEN OTHERS THEN

IF (USER_INFO%isOpen) THEN

CLOSE USER_INFO;

END IF;

RAISE;

END Get_Login_User_Func;



Now if I call my function in the following code:



DECLARE

USER_NAME VARCHAR2(255);

mycursor SPRINGAPP.SPRINGAPP_REFCURSOR_PKG.LOGIN_NAME_CURSOR;

BEGIN

USER_NAME := 'jay';



mycursor := GET_LOGIN_USER_FUNC(

USER_NAME

);



FOR rs IN mycursor

LOOP

DBMS_OUTPUT.PUT_LINE('FIRST NAME = ' || rs.FNAME);

DBMS_OUTPUT.PUT_LINE('LAST NAME = ' || rs.LNAME);

END LOOP;



END;



I got the following oracle error:

ORA-06550: line 11, column 13:
PLS-00221: 'MYCURSOR' is not a procedure or is undefined
ORA-06550: line 11, column3:
PL/SQL: Statement ignored
ORA-06512: at line 12

However, it works if I do:

DECLARE

USER_NAME VARCHAR2(255);
mycursor SPRINGAPP.SPRINGAPP_REFCURSOR_PKG.LOGIN_NAME_CURSOR;
rs SPRINGAPP.SPRINGAPP_REFCURSOR_PKG.LOGIN_NAME
BEGIN
USER_NAME := 'jay';

mycursor := GET_LOGIN_USER_FUNC(
USER_NAME
);

LOOP
FETCH mycursor into rs
EXIT WHEN mycursor%NOTFOUND

DBMS_OUTPUT.PUT_LINE('FIRST NAME = ' || rs.FNAME);
DBMS_OUTPUT.PUT_LINE('LAST NAME = ' || rs.LNAME);

END LOOP;
CLOSE mycursor;
END;

Question is WHY????

and Tom said...

Because you can only loop over unopened cursors implicitly.

The implicit cursor for loop:


for x IN (select * from t...)

for x in CURSOR_NAME

does the IMPLICIT open, fetch and close of the cursor.


you have stolen the "open", it is opened. If you OPENED a cursor, you must explicitly fetch and close it yourself.


ref cursors are ALWAYS explicit cursors.

Rating

  (9 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Great Answer!

Edward Suryadi, June 27, 2006 - 12:03 pm UTC

Thanks Tom!

procedure in for loop

Kuldeep, October 05, 2009 - 8:17 am UTC

PLS-00221: 'MYCURSOR' is not a procedure or is undefined

Does above error means we can use a PROCEDURE in FOR LOOP as we can use a Query. If Yes then how?

Thanks and regards,

Tom Kyte
October 08, 2009 - 6:43 am UTC

huh?

no clue at all what you mean, what you are trying to ask, what the context is here at all.

start over, be a bit more "clear and precise"

procedure in for loop

Kuldeep, October 05, 2009 - 8:18 am UTC

PLS-00221: 'MYCURSOR' is not a procedure or is undefined

Does above error give the hint that we can use a PROCEDURE in FOR LOOP as we can use a Query. If Yes then how?

Thanks and regards,

Use of procedure in FOR loop

Kuldeep, October 21, 2009 - 5:08 am UTC

Apology for last incomplete and unclear post.

my example:

SQL> ;
  1  declare
  2     type ref_cursor is ref cursor;
  3     --
  4     rc         ref_cursor;
  5  begin
  6     open rc for 'select * from tab';
  7     for i in rc
  8     loop
  9        dbms_output.put_line ('TNAME='||i.tname);
 10     end loop;
 11* end;
SQL> /
   for i in rc
            *
ERROR at line 7:
ORA-06550: line 7, column 13:
PLS-00221: 'RC' is not a procedure or is undefined  <---***
ORA-06550: line 7, column 4:
PL/SQL: Statement ignored

While opening ref cursor in a for loop it gives error. It is clear to me that ref cursor can't be opened in FOR loop. But the error 'PLS-00221: 'RC' is not a procedure or is undefined' says RC is not a procedure.

So my question is nothing about reference cursor but about the use of a procedure in FOR loop.

Is this possible we can use a procedure to feed data to a FOR loop like we can use procedure to populate database block in Oracle Forms.

If it is possible please tell how it can be used. I serached web but have not found any related material.

Thanks and regards,

Tom Kyte
October 23, 2009 - 11:25 am UTC

you cannot do implicit (for i in ...) with an explicit cursor (anything you call "open" on is by definition an explicit cursor)


You would have to:

open rc for ....
loop
   fetch rc into <host variables>;
   exit when rc%notfound;
   process record
end loop;
close rc;


ref cursors can only be explicitly processed, you can never use an "implicit" thing on them (for to be implicit means the COMPILER knows all about them since the compiler is the thing generating the code you would normally write - the problem is the compiler cannot know all about them since they are pointers and could point to any result set at runtime.

for loop without begin

Biswaranjan., October 17, 2012 - 6:30 am UTC

Hi Tom,
Hope you are fine.

long back while I was seeing some of your post found a magic line :) but forgot to save that.
It was about a for loop without "begin end".I copied and ran that and it gave the corresponding result.
#####
for i in 1..5 loop dbms_output.put_line('hello'); end loop;
something like this,dont remember exact text.
#####
not like ####
begin for i in 1..5 loop dbms_output.put_line('hello'); end loop; end;
#####
But now when I am trying to write similar code , am getting error as expected(but I am very sure that you havent used any begin and end statement).
I searched some of your posted pages but didnt find it.

Could you plz tell that line again or plz tell that I have mistaken something.

thanks & regards,
Biswaranjan.


Tom Kyte
October 17, 2012 - 3:14 pm UTC

in sqlplus, you can use the 'execute' sqlplus feature to do this

SQL> exec for i in 1..5 loop dbms_output.put_line( 'x' ); end loop;


exec(ute) tells sqlplus to put a begin/end; on the line of input and execute that sql statement.

dont know how to express in words.

Biswaranjan., October 17, 2012 - 11:02 pm UTC

thank you , long live.

fetch into

Tony Fernandez, June 06, 2013 - 3:22 pm UTC

Tom,

In you prior reply, you have:

you cannot do implicit (for i in ...) with an explicit cursor (anything you call "open" on is by definition an explicit cursor)


You would have to:

open rc for ....
loop
fetch rc into <host variables>;
exit when rc%notfound;
process record
end loop;
close rc;

Where/how do you define <host variable> when rc was defined as ref cursor?
Tom Kyte
June 06, 2013 - 3:31 pm UTC

in your declare block. You need to know *what that is* at compile time.



if you don't know what your cursor fetches at compile you, you'll have to use dbms_sql. It can procedurally describe, define the host variables and fetch them - a ref cursor cannot do that. A ref cursor - in the fetch line - needs to know what it is fetching into *at compile time*

Tony Fernandez, June 06, 2013 - 3:38 pm UTC

Can you please provide a succinct example?

Regards,
Tom Kyte
June 06, 2013 - 4:05 pm UTC

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:68212348056

a data unloader that takes any query and dumps it to a file.

Thank you

Tony Fernandez, June 12, 2013 - 9:05 pm UTC

Tom, that is helpful !

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library