Library tutorials & articles

Oracle8 and Oracle8i

Reference Cursors

Oracle has released version 8.1.6 of its own provider, Oracle Provider for OLE DB. This provider has a class name of OraOLEDB.Oracle that is used when defining your ADO connection string. It supports the same set of Oracle data types as Microsoft's OLE DB Provider for Oracle with the additional support for the binary object types BLOB, CLOB, NCLOB, and BFILE, but as with Microsoft's provider, it also does not provide support for the Oracle8i object data types .

This provider gives us pretty much the same level of functionality as Microsoft's, except that it supports the use of Oracle reference cursors so that we can return back an ADO Recordset object from a stored procedure. A reference cursor is a pointer to a memory location that can be passed between different PL/SQL clients, thus allowing query result sets to be passed back and forth between clients.

A reference cursor is a variable type defined using the PL/SQL TYPE  statement within an Oracle package, much like a PL/SQL table:

TYPE ref_type_name IS REF CURSOR RETURN return_type;

Here, ref_type_name is the name given to the type and return_type represents a record in the database. You do not have to specify the return type as this could be used as a general catch-all reference cursor. Such non-restrictive types are known as weak, whereas specifying the return type is restrictive, or strong. The following example uses %ROWTYPE to define a strong return type that represents the record structure of the emp table:

DECLARE TYPE EmpCurType IS REF CURSOR RETURN emp%ROWTYPE;

So let's jump straight to an example. We'll create a new Oracle package that contains a single procedure, EmployeeSearch, which returns a list of matching employee names. From your SQL editor, execute the following code to create the package specification:

CREATE OR REPLACE PACKAGE Employee_RefCur_pkg
AS
   TYPE empcur IS REF CURSOR;
   PROCEDURE EmployeeSearch(i_EName     IN  VARCHAR2,
                           o_EmpCursor OUT empcur);
END Employee_RefCur_pkg;

We've created a new type called empcur that returns a weak reference cursor that we use as an output parameter to the EmployeeSearch procedure. Now we need the package body :

CREATE OR REPLACE PACKAGE BODY Employee_RefCur_pkg
AS 
   PROCEDURE EmployeeSearch(i_EName     IN  VARCHAR2,
                            o_EmpCursor OUT empcur)
   IS
   BEGIN
      OPEN o_EmpCursor FOR       
         SELECT emp.empno, emp.ename, emp.job,
             emp.sal, dept.dname, dept.loc
         FROM emp, dept
         WHERE ename LIKE '%' || i_EName || '%'
            AND emp.deptno = dept.deptno
         ORDER BY UPPER(emp.ename);
   END EmployeeSearch;
END Employee_RefCur_pkg;

This code is very similar to our previous stored procedure, except that we don't need to transfer each column in distinct PL/SQL tables, as the reference cursor, o_EmpCursor, is returned back to the client. The Oracle Provider for OLE DB converts any parameters that reference cursors into an ADO Recordset for us – but only if we add PLSQLRSet=1 to our connection string, which we'll cover next .


Let's have a look at the results page that calls this stored procedure:

The actual ASP is very similar to our previous example so we'll just concentrate on the sections that
are different :

<%
Dim strSearchName
Dim objConnection
Dim objCommand
Dim objRecordSet
Dim objNameParam
Dim varEmpNo
strSearchName = Request.Form("txtSearchName")
If strSearchName = "" Then strSearchName = "%"
Set objConnection = Server.CreateObject("ADODB.Connection")

So far it's just the same, except that we define a new variable, objNameParam, that we'll use as an ADO Parameter object to pass in the search name entered.

With objConnection
  .ConnectionString = "Provider=OraOLEDB.Oracle;" & _
                      "Data Source=Oracle8i_dev;" & _
                      "User ID=scott;" & _
                      "Password=tiger;" & _
                      "PLSQLRSet=1;"
  .Open
  Response.Write "ADO Provider=" & .Provider & "<P>"
End With

Here we tell ADO to use the Oracle Provider for OLE DB, OraOLEDB.Oracle, and we set the PLSQLRSet attribute to tell the provider that it should parse the PL/SQL stored procedures to determine if any parameters  return a record set. OraOLEDB can only return one recordset per stored procedure. If you call a stored procedure that returns more than one recordset then OraOLEDB will only return the first argument of a ref cursor type.

If you omit the PLSQLRSet attribute, or you set it to 0, then you'll receive the following Oracle error:

ORA-06550: line 1, column 7: PLS-00306: wrong number or types of arguments in call to 'EMPLOYEESEARCH' ORA-06550: line 1, column 7: PL/SQL: Statement ignored

The rest of the code goes as follows:

Set objCommand = Server.CreateObject("ADODB.Command")
With objCommand
   Set .ActiveConnection = objConnection
   .CommandText = "{call Employee_RefCur_pkg.EmployeeSearch(?)}"
   Set objNameParam = .CreateParameter("SearchName", adBSTR, _
                                        adParamInput, , strSearchName)
   .Parameters.Append objNameParam
   Set objRecordSet = .Execute()
End With

Although our stored procedure has two parameters, the search name and the reference cursor that is returned, you must not bind the reference cursor as a parameter using the ? attribute when using OraOLEDB, so we've included only one ? character to represent the Name input parameter .

The ADO Parameter object, objNameParam, is created using the Command object's CreateParameter function. CreateParameter is called in the following way:

Set parameter = command.CreateParameter(Name, Type, Direction, Size, Value)

objNameParam is declared as an adBSTR type because this maps to Oracle's VARCHAR2 data type. Once we've created the Parameter we need to add it to the Command object's Parameters collection using the Append method .

Finally we call the Execute function to return a Recordset object that represents the result set from the o_EmpCursor reference cursor parameter. That's all there is to it. We can then navigate through the Recordset object as usual.

It's worth remembering that if you try to call the stored procedure using the Parameters
collection directly:

   .CommandText = "{call Employee_RefCur_pkg.EmployeeSearch(?)}"
   .Parameters(0).Type = adBSTR
   .Parameters(0).Direction = adParamInput
   .Parameters(0).Value = strSearchName

you'll get the following runtime error:

The provider cannot derive parameter info and SetParameterInfo has not been called

Therefore you must use the CreateParameter function.

That wraps up our look at retrieving ADO Recordset objects from Oracle stored procedures. As you've seen, we have two choices: PL/SQL tables with the Microsoft ODBC for Oracle Driver or reference cursors with Oracle's Oracle Provider for OLE DB. On the face of it, the use of PL/SQL tables does appear rather convoluted in comparison to the ease of reference cursors. Both are relatively inefficient in terms of server performance and the Oracle Provider for OLE DB has been regarded as rather buggy. Again, it's your choice; it's difficult to define what each can and can't do. As ever, you should investigate how both methods perform in your own environment, looking at response times along with CPU  and memory usage.

Comments

  1. 23 Sep 2009 at 11:36

    hi i am awaneesh from new delhi. actually i have a problem in sql group by function. i have one table with 120 columns or variable. i want group by all. so for this work i have to select all the columns in select stmt and again write all columns in group by stmt. So plese tell me the way, how can i select all the cols & how can group by all cols in short method. like: select * from emp group by (120 columns) but i don't to write all the cols in select stmt and again all the cols in group by stmt. please tell me the way. & send the solution back to my e-mail id- awan_tiwari2005@yahoo.co.in i will be really grateful to you.

    With best wishes, Awaneesh Tiwari

  2. 21 May 2009 at 09:05

    fuck all programmers!

  3. 16 Mar 2004 at 10:45

    How can I create a master detail web form using ASP, ADO, vbscript, and HTML?jarvis@anteon.com">email me

  4. 02 Dec 2003 at 04:10
    Hi all,

    I've been trying to use the OLE DB connection from ASP to Oracle. Used the code from the examples. Working fine but it did not release the session connection and when the sessions reach the maximum defined, it will fail to work. Pls Help. Thank you.

    KK
  5. 19 Jun 2003 at 05:15
    Hi,
     I using .NET to access Oracle DB  (with OLEDB Provider for Oracle) but I have a trouble that I couldn't use Unicode datatype (such as: NCHAR, NVARCHAR2).
     
     Anyone knows how to do this or any Provider that allows us access Oracle DB with Unicode datatype?

     Thanks for you kindness.
     TCAN.
  6. 24 Feb 2003 at 12:17

    im trying to get this to work:


    when the form loads, a csv file is opened and whose contents are displayed in the Current list view control. if the user selects an item from the Current listview control and presses the "delete" key (i've been using the Keypress event), a message box will pop up asking them to confirm their decision. If they say yes, the entire row is cleared and that row's information is passed to another listview control (the Archives listview control, which is saved onto its own file)


    the main things i need to know are the ASCII code for the delete key (127 doesn't work...), and how to delete an entire row in a listview control (and the other records below it should be moved up as a result.) If you could tell me how to then pass it onto the second listview control as well, that would be greatly appreciated.


    thanks in advance

  7. 24 Feb 2003 at 10:39
    Hi,
         i am currently do a project on oracle and microsoft. The question is compare and contrast the latest database offerings from Oracle and Microsoft under the following headings: History and evolution of the products, Target Market, Functionality, Customers, Future Directions, and any other areas. Any inforamton would be appreciated
  8. 22 Dec 2002 at 06:06


    Hi ,

    I'm using resultset in oracle and vbscript as it was mentioned here as follow:

    create a package that return a ref cursor,execute the package in vbscript and get the resultset into the
    recordset .
    Sometime it works and othertime I get that error in the line when I call the execute to the procedure:

    OraOLEDB error '80004005'

    Unspecified error .

    I used the example you gave in page :http://www.developerfusion.com/show/671/12/

    Please help me
  9. 01 Jan 1999 at 00:00

    This thread is for discussions of Oracle8 and Oracle8i.

Leave a comment

Sign in or Join us (it's free).

Wrox Press
AddThis

Related podcasts

  • Java Posse #213 - Newscast for Oct 23rd 2008

    Newscast for Oct 23rd 2008 Fully formatted shownotes can always be found at http://javaposse.com The Android project has been released as open source, beating the rumored launch date for the source code by several months http://source.android.com/ And, Gizmodo and ZDNet both offer in-depth ...

We'd love to hear what you think! Submit ideas or give us feedback