You Asked
Good day Tom,
Many thanks for receiving my question regarding ref cursors.
I am working on an application that uses a generic weakly typed ref cursor to return rows to an active server page that uses vbscript to format a web page. I would like to be able to return that same weakly typed ref cursor to a plsql procedure that would display the rows on a web page.
For example, the following creates a table of output with an update and delete link. Active server pages just executes this and receives the data in a record set.
Procedure get_parm_groups
(p_group_name in varchar2 default null,
p_result_set out types.cursor_type)
is
Begin
Open p_result_set for
select pg.group_name,
pg.group_desc,
'<A HREF="parm_group_parms.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
decode(rec_count.parms_by_group(pg.rowid),0,'">Parameters</A>',
'">Parameters ('||
rec_count.parms_by_group(pg.rowid) ||
')</A>') "Detail Link",
'<A HREF="parm_group_updt.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
'">Update</A>' "Update Link",
decode(nvl(rec_count.parms_by_group(pg.rowid),0),0,
('<A HREF="parm_group_delete.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
'">Delete</A>'),
' ') "Delete Link",
'<a href="parm_group_insert.asp?ReFresh=No">New Group</a>' "New Link"
from parm_group pg
where nvl(p_group_name,pg.group_desc) = pg.group_desc
order by lower(pg.group_name);
In active server pages the following happens:
set rs = Server.CreateObject("ADODB.Recordset")
Set rs = cmdStoredProc.Execute
'Fomat the output - Note the Add new Group is in the header
if (not rs.EOF) then
Response.Write ("<h2>Parameter Groups - " & rs (5) & "</h2>" & vbCrLf)
emptyTable = "No"
Response.Write ("<table border = 1>" & vbCrLf)
Response.Write ("<tr>" & vbCrLf)
Response.Write ("<th>Group Name </th>" & vbCrLf)
Response.Write ("<th>Group Desc </th>" & vbCrLf)
Response.Write ("<th>Detail </th>" & vbCrLf)
Response.Write ("<th>Update </th>" & vbCrLf)
Response.Write ("<th>Delete </th>" & vbCrLf)
Response.Write ("</tr>" & vbCrLf)
While (Not rs.EOF)
Response.Write ("<tr>" & vbCrLf)
Response.Write ("<td>" & rs (0) & "</td>" & vbCrLf)
Response.Write ("<td>" & rs (1) & "</td>" & vbCrLf)
Response.Write ("<td>" & rs (2) & "</td>" & vbCrLf)
Response.Write ("<td>" & rs (3) & "</td>" & vbCrLf)
Response.Write ("<td>" & rs (4) & "</td>" & vbCrLf)
Response.Write ("</tr>" & vbCrLf)
rs.MoveNext
Wend
Response.Write ("</table>" & vbCrLf)
else
Response.Write ("<h2>No Parameter Groups Currently Defined</h2>" & vbCrLf)
Please correct me if I am wrong (fingers crossed, as I hope I am getting corrected), but from what I have learned by searching your site amoung other things, is that the out parameter would need to change to an in out parameter and a record type would need to be created to recieve the data in another plsql procedure.
What I am hoping you will tell me is that there is a way to interrogate the ref cursor at run time similiar to the following for dynamic sql (after opening a cursor and doing a parse of a select statement):
dbms_sql.describe_columns(theCursor,v_column_count,v_describe_table);
...or maybe there is a way to extract the select statement from the ref cursor, and re-parse and describe...Or maybe the only way is to copy that select statement out ( Hmmm... 2 things to change in 2 places when something changes) of that procedure and use the dbms_sql package to parse the statement...
I am open to any suggestion that would allow both active server pages to use the procedure, as well as plsql, with a minimum of change.
Again, many thanks for accepting my question and assistance you may offer.
Les Davidner
and Tom said...
You cannot do this with a ref cursor -- not in plsql. You would have to use DBMS_SQL to open the query -- not a ref cursor.
If you do not know the number and types of output elements in the cursor at compile time -- there is simply NO way for plsql to execute the "fetch ref_cursor into <unknown list of variables>".
you need to use the procedural API for dyanmic sql in this case.
The only suggestion I have is to put the procedure in a package (to isolate the code) and create overloaded procedures -- on that returns a ref cursor and one that returns a dbms_sql cursor.
Looking on the bright side - I really truly thing you want to recode that procedure anyway-- that trick you are using:
where nvl(p_group_name,pg.group_desc) = pg.group_desc
is a KILLER -- it is a pretty bad thing. It obviates indexes, forces a full scan. What you should code is:
if ( p_group_name is not NULL )
then
Open p_result_set for
select pg.group_name,
pg.group_desc,
'<A HREF="parm_group_parms.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
decode(rec_count.parms_by_group(pg.rowid),0,'">Parameters</A>',
'">Parameters ('||
rec_count.parms_by_group(pg.rowid) ||
')</A>') "Detail Link",
'<A HREF="parm_group_updt.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
'">Update</A>' "Update Link",
decode(nvl(rec_count.parms_by_group(pg.rowid),0),0,
('<A HREF="parm_group_delete.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
'">Delete</A>'),
' ') "Delete Link",
'<a href="parm_group_insert.asp?ReFresh=No">New Group</a>' "New
Link"
from parm_group pg
where p_group_name = pg.group_desc
order by lower(pg.group_name);
else
Open p_result_set for
select pg.group_name,
pg.group_desc,
'<A HREF="parm_group_parms.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
decode(rec_count.parms_by_group(pg.rowid),0,'">Parameters</A>',
'">Parameters ('||
rec_count.parms_by_group(pg.rowid) ||
')</A>') "Detail Link",
'<A HREF="parm_group_updt.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
'">Update</A>' "Update Link",
decode(nvl(rec_count.parms_by_group(pg.rowid),0),0,
('<A HREF="parm_group_delete.asp?theRowID='||
urlencode(rowidtochar(pg.rowid))||
'&Refresh=No'||
'">Delete</A>'),
' ') "Delete Link",
'<a href="parm_group_insert.asp?ReFresh=No">New Group</a>' "New
Link"
from parm_group pg
order by lower(pg.group_name);
end if;
You'll get the best performance that way.
Rating
(6 ratings)
Is this answer out of date? If it is, please let us know via a Comment