Please see the below procedure. I did not close cursor and it is working fine. Am I missing something here.
Is it mandatory to close cursor or Oracle closes it automatically?
CREATE OR REPLACE PROCEDURE pr_cursor_test IS
CURSOR emp_cur IS SELECT empno, ename FROM emp;
emprec emp_cur%rowtype;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur INTO emprec;
EXIT WHEN
emp_cur%notfound;
--Do Something
dbms_output.put_line(emprec.ename);
END LOOP;
END;
This article on Oracle website is pretty clear about it.
When you declare a cursor in a package (that is, not inside a
subprogram of the package) and the cursor is opened, it will stay open
until you explicitly close it or your session is terminated.
When the cursor is declared in a declaration section (and not in a
package), Oracle Database will also automatically close it when the
block in which it is declared terminates. It is still, however, a good
idea to explicitly close the cursor yourself. If the cursor is moved
to a package, you will have the now necessary CLOSE already in place.
And if it is local, then including a CLOSE statement will also show
other developers and your manager that you are paying attention.
In your code example CURSOR is declared as part of procedure (not as part of package), which means, cursor is closed automatically when procedure executioin is complete. However it is best coding practice to CLOSE cursor statement if you have OPEN cursor statement in code. It makes code easy to understand and support in future.
Related
I am having a bizarre problem that seems very specific to CURSOR FOR Loops inside of a stored procedure. For clarity, I am using Oracle within DBeaver and am attempting to loop over all of the columns in a table and print out the results of a select statement.
I don't have access to the exact code but this is functionally approximate:
CREATE OR REPLACE PROCEDURE column_null(table_name_in IN VARCHAR2)
AS
str_query VARCHAR2(1000);
temp_number NUMBER(10);
CURSOR col_cursor IS
SELECT * FROM user_tab_cols
WHERE table_name = table_name_in;
BEGIN
FOR c_id IN col_cursor
LOOP
str_query := 'select COUNT(*) FROM ' || table_name_in ||
' WHERE ' || c_id.column_name || ' IS NOT NULL';
EXECUTE IMMEDIATE str_query INTO temp_number;
DBMS_OUTPUT.PUT_LINE(temp_number);
END LOOP;
END;
Now, the bizarre part is that if I do this exact same code block outside of a stored function (minus an extra DECLARE keyword), it works as expected. Even if I try to just echo out 'Hello' within a loop it works as expected, but as soon as it becomes a stored procedure it stops working. I've been testing this for hours today, and am completely baffled; for reference, I have only recently become acquainted with PL/SQL so its mysteries escape me.
Furthermore, it seems specific to CURSOR FOR loops; if I replace the Cursor For loop with a generic numeric loop (i.e. FOR c_id IN 1 .. 10), a procedure will produce output just fine. And it isn't just DBMS_OUTPUT.PUT_LINE that's affected; pretty much everything that goes on inside the Cursor For loop is ignored in a stored procedure, including variable updates, even though they work fine otherwise in normal PL/SQL blocks.
To summarize: Works fine as a PL/SQL block, works fine in a numeric for loop, but for some reason the exact combination of stored procedure and cursor for loop causes no output to be produced; in fact from my testing it seems like nothing meaningful happens within the cursor for loop of a stored function.
Is this a DBeaver bug? A PL/SQL oddity? I'm posting here because I'm ignorant as to whether this is expected behavior due to how Procedures and/or Cursor For loops work, or if this is a bug of some kind.
What you have done is declaring a procedure. Now that you have declared it, you have to call it using a program like bellow. Most likely it will generate outputs.
Option 01
set serveroutput on;
Declare
v_table_name_in IN VARCHAR2(499);
Begin
v_table_name_in := 'your table name';
column_null(table_name_in => v_table_name_in);
end;
Option 02
Get a return parameter. ideally a table type as out parameter. and inside the above code, loop through it and print the value.
Option 03.
Log the outputs into a log table.
I found the error was solved by simply adding AUTHID current_user to the procedure; apparently the procedure didn't have permission to access the table it was trying to select. Strangely though, no error was produced when trying to run the procedure; it just didn't produce any output.
I am working on a system where Oracle 11g is the back end database.
I have very limited permissions on the database and as such all I can do is call procedures that reside in packages.
Gerally, these procedure return their result set via an OUT parameter of type sys_refcursor.
I can call them fine in C# and get data from the cursor via the C# OracleDataset type.
Here is my question.
I want to be able to run these procedures and see the results via SQL Developer.
I can execute the procedure fine, but seeing the contents of the sys_refcursor OUT parameter is boggling me.
I've done some gooling and people ar saying about creating type and other solutions I simply do not have the permissions to persue.
So, how can I possibly see the result set contained in a sys_refcursor?
So say I have a procedure with this signature....
procedure an_oracle_Proc(p_ref IN varchar2,
p_result_set OUT sys_refcursor);
I call it like this....
DECLARE
l_ref VARCHAR2(10);
l_result_set sys_refcursor;
BEGIN
oracle_pkg.an_oracle_Proc(p_ref => l_ref,
p_result_set => l_result_set);
--How to select from l_result_set with limited permissions
END
How can I look at the contents of l_result_Set?
This is repeating the answer I linked to before really but specifically for your code:
VARIABLE result_set refcursor;
DECLARE
l_ref VARCHAR2(10);
BEGIN
l_ref := 'whatever';
oracle_pkg.an_oracle_Proc(p_ref => l_ref,
p_result_set => :result_set);
END;
/
PRINT result_set
... and run all of that as a script from an SQL Worksheet. The contents of the ref cursor will be shown in the script output window.
Thought I'd have another look and found this - amazing what stepping away from the computer can do. ;)
I just have to select the appropriate variable on the left pane.
http://www.thatjeffsmith.com/archive/2011/12/sql-developer-tip-viewing-refcursor-output/
Still - it would be nice to write my own SQL to do this rather than using the execute window.
Sys_refcursor form an anonymous block is bit tricky. Use the sql-developer, explore the package or procedure , right click and execute the procedure/package.
Sql-developer will open an input/output UI where you can key in values. And you can see the output on the same UI as well. Let me know if you need more details. I was actually debugging the same a couple of weeks back successfully.
In our application, we call various stored procedures that return reference cursors in the following fashion:
SELECT foo_package.sp_Bar('arg1', 'arg2', 'arg3', 'arg4') FROM dual;
What the wrap_xml function does is to convert the cursor result to an XML type, which will then be used in the application. After the conversion, it immediately closes the cursor (this step has solved memory issues for us before).
FUNCTION wrap_xml (c_result SYS_REFCURSOR)
RETURN XMLTYPE
IS
xml_val XMLTYPE;
BEGIN
xml_val := xmltype.CreateXML (c_result);
IF c_result%ISOPEN
THEN
CLOSE c_result;
END IF;
RETURN xml_val;
END;
In most cases, this appears to work fine: the XML is created and the cursors are closed. However, since introducing a stored procedure that opens a cursor for a dynamic query, we are observing a rapid increase in open cursors, eventually leading to:
ORA-01000: maximum open cursors exceeded
The dynamic query is built in order to "simulate" the results returned from other cursors, for testing purposes. For example, the stored procedure would build a dynamic query like this:
SELECT '1' as "COLUMN1", '990' as "COLUMN2", 'N' as "COLUMN3", NULL as "COLUMN5" FROM dual;
It would then open a cursor for this query string, and return the cursor:
OPEN rc_return FOR v_sql_query;
RETURN rc_return;
The resulting reference cursor is again passed to the wrap_xml function above, which I would expect to close the cursor – just like it does any other cursor. However, this doesn't seem to be the case, as the number of open cursors just keeps on growing. What could be the reason for this?
Additional investigation:
Stepping through the wrap_xml function, I can see the program flow skipping over the body of the c_result%ISOPEN check, implying that the cursor has indeed been closed. Yet it appears that the open cursor count still increases!
We appear to have plugged the leak by removing the ISOPEN check from the wrap_xml function and just executing the close cursor command in all cases. Apparently the ISOPEN flag is not set on cursors opened for dynamic SQL queries.
I am, however, unable to find a reference for this. Can anyone back this up?
I'm having some troubles executing oracle stored procedure from package.
I've intalled PL/SQL developer on local machine, and when I try to test procedure I get generated code like this:
begin
-- Call the procedure
owner.mypackage.getallrequests(res => :res,
id=> :id);
end;
But I can't modify this query to return me data. Would really appreciate help.
Assuming you've got to this point by right-clicking on the procedure in the object explorer and choosing 'test', you'll have a Test Window with the anonymous PL/SQL block you showed. You haven't said, but I assume id is an in variable, and res is the out cursor variable. In the variable section in the bottom half of the window, type in the ID value you're searching for, then execute it (clicking the gear, or hitting F8).
Nothing obvious will change if those are the only variables; non-cursor out or in out variables would be highlighted in yellow if their values had changed, but the cursor is not, and in variables by definition won't have changed.
At the far right of the res cursor variable in the bottom of the test window, there's a small button with ... in it, which the help pages refer to as the 'cell button'. Click that, and a new window will open showing the cursor result set.
I've got an Oracle 10g database which is accessed from an ASP.NET application. Although I've used SQL Server heavily in many different aspects and Oracle for querying and reporting, this is my first time using Oracle as the OLTP database for an application.
The database-level procedures in the packages are typically of the form:
-- TYPE refcur IS REF CURSOR;
PROCEDURE get_some_stuff(o_cursor OUT refcur, p_param1 IN INTEGER, p_param2 IN INTEGER) IS
BEGIN
OPEN o_cursor FOR
SELECT whatever
FROM whatever
END
I assume these are done this way for the benefit of the ADO.NET layer able to use the cursor from the output param and it is my understanding that this is the acceptable best practice for calling Oracle procs from .NET.
In SQL Server, for example, we don't have explicit ref cursors, if a proc returns a result set (or several result sets), that's accessible as an output result set in both ADO.NET and SSMS, and you can simply test the SPs by doing EXEC spname param1, param2.
The problem I'm having is that I don't know how to call these directly in SQL in Toad, for example, to be able to test changes at the PL/SQL level first before going to the app. I'm very used to being able to exercise and even re-mix stored procs and functions in SQL Server to be able to refactor the database interface layer without affecting the external interface to application-level code.
look at the link that OMG Ponies posted, but what you can do is
var x refcursor;
declare
PROCEDURE GET_SOME_STUFF(O_CURSOR OUT SYS_REFCURSOR, P_PARAM1 IN NUMBER, P_PARAM2 IN NUMBER) IS
BEGIN
OPEN O_CURSOR FOR
SELECT LEVEL, p_param1 ,P_PARAM2 FROM DUAL CONNECT BY LEVEL < 3;
END ;
BEGIN
GET_SOME_STUFF(:x , 5, 10);
END;
/
PRINT X;
you pretty much just wrap it in a anonymous block ad it will run. I use SQL Developer (highly recommmend, free with plenty of support) or SQL plus so I cannot help with TOAD, but I would expect it to be the same. In SQL Developer (and in SQL Navigator if memory serves correct) you can simply right click the package/method you wish and it will create the script for you.
in toad and navigator I believe you may be able to get the ref cursor in a pretty grid while in developer you get it in text.
SQL Developer you can unit test as well
Try this:
DECLARE
aCursor SYS_REFCURSOR;
someVariable SOME_TYPE;
FUNCTION SOME_FUNC_RETURNING_A_CURSOR RETURN SYS_REFCURSOR IS
csrLocal SYS_REFCURSOR;
BEGIN
OPEN csrLocal FOR SELECT whatever FROM wherever;
RETURN csrLocal;
END SOME_FUNC_RETURNING_A_CURSOR;
BEGIN
aCursor := SOME_FUNC_RETURNING_A_CURSOR;
WHILE TRUE LOOP
FETCH aCursor INTO someVariable;
EXIT WHEN aCursor%NOTFOUND;
...do whatever with variables...
END LOOP;
COMMIT;
END;
Share and enjoy.
I found an easier way to this ...try it (This will also generate script for you)
In the Procedure Editor, load your procedure. Click on the lightning
bolt to execute and you will see the Set Parameters window, which is
also available via the button on the Proc Editor toolbar that has an
image similar to (...) on it, next to the lightning bolt. Click on the
output options button and you'll see your options. If this is a weak ref
cursor then you must use the in-memory grid option. Results go to the
cursor results tab at the bottom of the PE after you execute.
http://toad.10940.n7.nabble.com/display-ref-cursor-in-toad-td1427.html