Skip to Main Content
  • Questions
  • page 732 strong vs weak ref cursors.

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question.

Asked: October 16, 2001 - 10:01 pm UTC

Last updated: August 20, 2007 - 12:31 pm UTC

Version: 8.1.6

Viewed 10K+ times! This question is

You Asked

tom:

i am reading your book page 732.

i don't understand what is strongly typed REF CURSOR and weakly
typed REF CURSOR.

can you explain more about that?

Thanks


and Tom said...

Well, as I said on that page when describing a strongly typed ref cursor "That is, a ref cursor whose structure is known by the compiler at compile time".


scott@ORA717DEV.US.ORACLE.COM> create or replace package my_pkg
2 as
3 type strong is ref cursor return emp%rowtype;
4
5 type weak is ref cursor;
6 end;
7 /

Package created.

STRONG's structure -- the columns, their datatypes, their lengths, everything -- are well known at compile time. It can only be used to return rows that look exactly like the EMP table (doesn't have to be from the EMP table -- just must be the same STRUCTURE)

WEAK's structure -- not known. It could be used with:

open a_weak_one for select * from dual;

or

open a_weak_one for select * from dept;

Its structure is NOT known at compile time and may actually change from use to use.

Rating

  (7 ratings)

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

Comments

Performance

Senthil., October 17, 2001 - 11:10 am UTC

Would weakly defined cursor affects performance anyway...compared to strongly defined.

Tom Kyte
October 17, 2001 - 12:41 pm UTC

good question, lets see:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table run_stats ( runid varchar2(15), name varchar2(80), value int );
Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace view stats
  2  as select 'STAT...' || a.name name, b.value
  3        from v$statname a, v$mystat b
  4       where a.statistic# = b.statistic#
  5      union all
  6      select 'LATCH.' || name,  gets
  7        from v$latch;
View created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> declare
  2          type strong is ref cursor return emp%rowtype;
  3          type weak   is ref cursor;
  4  
  5      l_x     number := 0;
  6      l_start number;
  7          l_strong strong;
  8          l_weak   weak;
  9          l_rec    emp%rowtype;
 10  begin
 11      insert into run_stats select 'before', stats.* from stats;
 12  
 13      l_start := dbms_utility.get_time;
 14      for i in 1 .. 1000
 15      loop
 16                  open l_strong for select * from emp;
 17                  loop
 18                          fetch l_strong into l_rec;
 19                          exit when l_strong%notfound;
 20                  end loop;
 21                  close l_strong;
 22      end loop;
 23      dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 24  
 25      insert into run_stats select 'after 1', stats.* from stats;
 26  
 27      l_start := dbms_utility.get_time;
 28      for i in 1 .. 1000
 29      loop
 30                  open l_weak for select * from emp;
 31                  loop
 32                          fetch l_weak into l_rec;
 33                          exit when l_weak%notfound;
 34                  end loop;
 35                  close l_weak;
 36      end loop;
 37          commit;
 38      dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 39  
 40      insert into run_stats select 'after 2', stats.* from stats;
 41  end;
 42  /
162 hsecs
174 hsecs

PL/SQL procedure successfully completed.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select a.name, b.value-a.value run1, c.value-b.value run2,
  2         ( (c.value-b.value)-(b.value-a.value)) diff
  3    from run_stats a, run_stats b, run_stats c
  4   where a.name = b.name
  5     and b.name = c.name
  6     and a.runid = 'before'
  7     and b.runid = 'after 1'
  8     and c.runid = 'after 2'
  9     and (c.value-a.value) > 0
 10     and (c.value-b.value) <> (b.value-a.value)
 11     and a.name like '%redo%'
 12   order by abs( (c.value-b.value)-(b.value-a.value))
 13  /

NAME                                           RUN1       RUN2       DIFF
---------------------------------------- ---------- ---------- ----------
LATCH.redo writing                                3          2         -1
STAT...redo entries                              16         14         -2
LATCH.redo allocation                            13         25         12
STAT...redo size                              21488      21520         32


So, nothing significant really.  Maybe a 7% decrease in runtime over 1,000 iterations.  No difference in resource usage... 

page 732 strong vs weak ref cursors

Paul, August 30, 2002 - 3:50 am UTC

Tom,

Thanks a lot for the benchmarking - saved me the trouble!
If there's no/negligible performance benefits in strong vs weak, why bother with strong at all?

I'm lazy, if I can get away with writing less code, I will!

Tom Kyte
August 30, 2002 - 9:20 am UTC

Strongly typed ones can be "described" -- it is well known what the procedure would be returning -- some tools will work better with it (eg: layout/GUI toosl -- they can tell how many columns/types there are).

ops$tkyte@ORA920.US.ORACLE.COM> create or replace package my_pkg
  2  as
  3     type rc1 is ref cursor return emp%rowtype;
  4     type rc2 is ref cursor;
  5
  6     procedure p1( x in out rc1 );
  7     procedure p2( x in out rc2 );
  8     procedure p3( x in out sys_refcursor );  /* New in 9i */
  9  end;
 10  /

Package created.

ops$tkyte@ORA920.US.ORACLE.COM>
ops$tkyte@ORA920.US.ORACLE.COM> desc my_pkg
PROCEDURE P1
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 X                              REF CURSOR              IN/OUT
                                RECORD                  IN/OUT
     EMPNO                      NUMBER(4)               IN/OUT
     ENAME                      VARCHAR2(10)            IN/OUT
     JOB                        VARCHAR2(9)             IN/OUT
     MGR                        NUMBER(4)               IN/OUT
     HIREDATE                   DATE                    IN/OUT
     SAL                        NUMBER(7,2)             IN/OUT
     COMM                       NUMBER(7,2)             IN/OUT
     DEPTNO                     NUMBER(2)               IN/OUT
PROCEDURE P2
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 X                              REF CURSOR              IN/OUT
PROCEDURE P3
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 X                              REF CURSOR              IN/OUT

ops$tkyte@ORA920.US.ORACLE.COM>


<b>see, only P1 can TELL us beforehand what'll be returning -- easier for a tool like forms or powerbuilder to layout a screen to hold the results</b>
 

A reader, May 22, 2003 - 11:23 am UTC


Catch-22

Steve, February 11, 2005 - 3:13 pm UTC

I've searched and read multiple threads and you've *almost* answered this question, but not quite... You say, strongly typed ref_cursors are "easier for a tool like forms or powerbuilder to layout a screen to hold the results." What if the application needs to use dynamic SQL to return results via a ref_cursor?

I'm using Oracle Reports 9 which supports a pl/sql-based data source returning data via a strongly-typed ref_cursor variable. Yet dynamic SQL requires a weakly-typed ref_cursor. I'm attempting to do something that I assume would be a common requirement... I want to build a query procedurally that contains the least number of joins, predicates and bind variables for performance purposes. The query will be built based on the values of parameters that Reports will pass to a stored database (8i) procedure.

Can DBMS_SQL return data to a calling program in a ref_cursor? Is there a way to "convert" a weakly-typed variable to a strongly-typed one by running "through" a second procedure/temporary table/array?


Tom Kyte
February 12, 2005 - 12:09 pm UTC

what if the application needs to use dynamic sql -- then the application needs to run describe on the returned cursor to figure out how many columns, what their datatypes are and what their names are.

if the cursor were strongly typed, you know by describing a compiled procedure what it returns (you need not run it) and not only that but you know precisely (at form compile time) how many columns, their names, their datatypes.

If you make up the query at runtime and it can have 1 column or 500 columns or any number of columns in fact -- you cannot statically lay out a form at form "development time" to hold its results.

dbms_sql cannot return a ref cursor at all (only native dynamic sql can dynamically do that)


there should be a single set of joins for a given query (you either query 5 tables and join them or not) but with something that mandates the use of a strongly typed ref cursor, you will have to use

if ( ... )
then
open c for select ... from ... where ...
elsif ( ... )
oipen c for a_different_select.....



In 9i, you could utilize pipelined functions (select from a function instead of a table, function builds sql, executes sql and returns rows) as well.

Reader

Tapan Shroff, May 16, 2005 - 2:22 am UTC

Thank you it was very much help full to me.

Describe a weak ref cursor in PL/SQL

grant.orr, August 14, 2007 - 1:25 pm UTC

I have a similar challenge.
I have a large number of procedures that return weak ref cursors as results for reports. A number of these result sets can have different columns based on different configurations. Currently the client applications describe the result set and apply some basic formatting and display the results.
I now have to find a way to support a requirement to schedule the run of any of these reports, format them as CSV and write them to a file. As I already have scheduling logic in the database that utilizes dbms_job / dbms_scheduler and logic that writes contents of a generic table (sequence number, generic_record varchar2(2000) ) to a file through PL/SQL, I wanted to find a way to describe the ref cursor in order to dynamically write a record into my generic table with a ',' separator between the columns as a string.
So far, I haven't been able to find any way to do this other than to overload all of the procedures so that they will also return the SQL statement to my new procedure in order to parse and describe the query.
That seems like a lot of work and I figure that if most of the available client tools can describe a ref cursor, PL/SQL must be able to.
Would you know how?
If it's not possible, any suggestions?


Thanks again in advance Tom.
Tom Kyte
August 20, 2007 - 12:31 pm UTC

Sorry, this is a new 11g feature - a new pair of functions will exist in that release that let you take a ref cursor and turn it into a dbms_sql cursor and vice versa.

If you take a ref cursor and dbms_sql it - we can describe it, bind it, and procedurally process it.

Until then, PLSQL will not be able to do this - you can write a java stored procedure instead perhaps... It can call the existing code, get the ref cursor and procedurally process it.

Strongly typed vs. weakly typed

John Flack, August 20, 2007 - 4:02 pm UTC

One reason that I prefer to use strongly typed ref cursors when possible is that errors in fetch commands are discovered at compile time.

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