Can anyone resolve my 'cannot access serially reusable package issue'? - sql

Working on below package, when i execute P_proc3 , I receive error as
"ORA-06534: Cannot access Serially Reusable package" Need help in resolving this
I read
"The SERIALLY_REUSABLE pragma indicates that the package state is needed only for the duration of one call to the server (for example, an OCI call to the database or a stored procedure call through a database link). After this call, the storage for the package variables can be reused, reducing the memory overhead for long-running sessions."
But just understood that this package instance will not be in buffer memory.
CODE given below
create or replace PACKAGE BODY COG_MIGR_TRNS
as
PRAGMA SERIALLY_REUSABLE;
function get_itr_nm return varchar2
as
itr_name varchar2(30);
cursor c1 is
select value
from params where obj_id =45877;
begin
open c1;
fetch c1 into itr_name;
close c1;
return itr_name;
EXCEPTION
WHEN OTHERS THEN RAISE;
end;
-----------------------------------
PROCEDURE P_proc1
IS
v_nm varchar(100);
cursor c1 is
select get_iteration_name()
from dual;
BEGIN
open c1;
fetch c1 into v_nm;
close c1;
<Some more code Here using v_nm>
EXCEPTION
WHEN OTHERS THEN RAISE;
end;
------------------------
PROCEDURE P_proc2
IS
v_nm varchar(100);
cursor c1 is
select get_iteration_name()
from dual;
BEGIN
open c1;
fetch c1 into v_nm;
close c1;
<Some more code Here using v_nm>
EXCEPTION
WHEN OTHERS THEN RAISE;
end;
-------------------
PROCEDURE P_proc3
IS
v_nm varchar(100);
cursor c1 is
select get_iteration_name()
from dual;
BEGIN
P_Proc1;
P_Proc2;
EXCEPTION
WHEN OTHERS THEN RAISE;
end;

Related

How to execute dynamic sql into cursor in Oracle?

I have problem with execute dynamic sql statement into sys_refcursor in my stored procedure.
I have looked in documentation and I think that I build my procedure properly, but I still do not know why error occurs.
Please look below, what I created:
CREATE TABLE REKOM_CROSS_PROM (
LINIA_PROD VARCHAR2(20),
ID_REKOM_OFERTA VARCHAR2(20),
PRICE NUMBER,
MAX_PRICE NUMBER
);
/
CREATE OR REPLACE TYPE prodType AS OBJECT (
p_line VARCHAR2(20)
,p_price NUMBER
);
/
CREATE OR REPLACE TYPE prodTypeList IS TABLE OF prodType;
/
CREATE OR REPLACE PROCEDURE my_proc (prodLines IN prodTypeList ,rekom OUT SYS_REFCURSOR)
IS
v_pLine VARCHAR2(20);
v_query VARCHAR2(4000);
BEGIN
v_query := 'SELECT ID_REKOM_OFERTA FROM REKOM_CROSS_PROM WHERE
LINIA_PROD=NULL';
FOR i IN 1 .. prodLines.COUNT
LOOP
v_pLine := prodLines(i).p_line;
v_query := v_query || ' UNION ALL SELECT ID_REKOM_OFERTA FROM
REKOM_CROSS_PROM WHERE LINIA_PROD=''' || v_pLine || '''';
END LOOP;
OPEN rekom FOR v_query;
END my_proc;
/
And when I want to call the procedure, error occur.
set serveroutput on
declare
type1 prodTypeList := prodTypeList(prodType('test1',1), prodType('test2', 20));
rc SYS_REFCURSOR;
row varchar2(200);
BEGIN
MY_PROC(type1, rc);
fetch rc into row;
while (rc%found) loop
dbms_output.put_line(row);
end loop;
close rc;
end;
I get the message:
ORA-20000: ORU-10027: buffer overflow, limit of 1000000 bytes
*Cause: The stored procedure 'raise_application_error'
was called which causes this error to be generated.
*Action: Correct the problem as described in the error message or contact
the application administrator or DBA for more information.
Can sombody help me to resolve the problem?
You have an infinite loop. That means you're calling dbms_output.put_line forever - or until it runs out of buffer space, and throws that exception.
BEGIN
MY_PROC(type1, rc);
-- fetch first row from result set
fetch rc into row;
-- check if last fetch found something - always true
while (rc%found) loop
dbms_output.put_line(row);
end loop;
close rc;
end;
Every time around the loop you're checking the result of that first fetch, which stays true (assuming there is any data). You need to fetch each time round the loop:
BEGIN
MY_PROC(type1, rc);
-- fetch first row from result set
fetch rc into row;
-- check if last fetch found something
while (rc%found) loop
dbms_output.put_line(row);
-- fetch next row from result set
fetch rc into row;
end loop;
close rc;
end;
Or perhaps more commonly, only fetch inside the loop, and stop when nothing is found, using %notfound rather than %found:
BEGIN
MY_PROC(type1, rc);
loop
-- fetch row from result set
fetch rc into row;
-- check if last fetch found something
exit when rc%notfound;
dbms_output.put_line(row);
end loop;
close rc;
end;
Not related to your current issue, but the predicate WHERE LINIA_PROD=NULL is never true; null isn't equal to (or not equal to) anything else. You need to use WHERE LINIA_PROD IS NULL instead.

PLS-00103: Encountered the symbol "IS" when expecting one of the following

I am trying to create a function right now (instead of a package) that selects the column data that is currently inside of my OP_GUIDE_VIEW.
Just need a function that selects what's there. Not modifying anything, don't think I need parameters or anything either. What I have so far is the following; however, I cannot figure out this error to save my life: - Has an error # IS C1 V_CURSOR;
What I have right now:
create or replace
PACKAGE PKG_OPGUIDE_COLLECTIONDATA AS
type v_cursor is ref cursor
return OPGUIDE_VIEW%rowtype;
c2 v_cursor;
r_c2 c2%rowtype;
function fn_opview return v_cursor
is c1 v_cursor;
begin
open c1 for select * from OPGUIDE_VIEW;
return c1;
end;
begin
c2 := fn_opview;
loop
fetch c2 into r_c2;
exit when c2%notfound;
dbms_output.put_line(initcap(r_c2.JOB_NAME));
end loop;
close c2;
end;
END PKG_OPGUIDE_COLLECTIONDATA;
Error:
PLS-00103: Encountered the symbol "IS" when expecting one of the following:
constant exception <an identifier>
<a double-quoted delimited-identifier> table long double ref
char time timestamp interval date binary national character
nchar
Can give more information if needed.
You're trying to create a package header and body at the same time.
You have to create an header, then a body, with separate queries; here you find something more.
An example of how you could edit your code:
setup:
create table OPGUIDE_VIEW(JOB_NAME varchar2(100));
insert into OPGUIDE_VIEW values ('job1');
insert into OPGUIDE_VIEW values ('job2');
package creation:
CREATE OR REPLACE PACKAGE PKG_OPGUIDE_COLLECTIONDATA AS
FUNCTION fn_opview
RETURN SYS_REFCURSOR;
PROCEDURE printData;
END;
/
CREATE OR REPLACE PACKAGE BODY PKG_OPGUIDE_COLLECTIONDATA AS
FUNCTION fn_opview
RETURN SYS_REFCURSOR IS
c1 SYS_REFCURSOR;
BEGIN
OPEN c1 FOR SELECT * FROM OPGUIDE_VIEW;
RETURN c1;
END;
PROCEDURE printData IS
c2 SYS_REFCURSOR;
r_c2 OPGUIDE_VIEW%ROWTYPE;
BEGIN
c2 := fn_opview();
LOOP
FETCH c2 INTO r_c2;
EXIT WHEN c2%NOTFOUND;
DBMS_OUTPUT.put_line(INITCAP(r_c2.JOB_NAME));
END LOOP;
CLOSE c2;
END;
END PKG_OPGUIDE_COLLECTIONDATA;
Call your procedure:
SQL> set serveroutput on
SQL>
SQL> begin
2 PKG_OPGUIDE_COLLECTIONDATA.printData;
3 end;
4 /
Job1
Job2
PL/SQL procedure successfully completed.
SQL>

Print first 100 values using cursor in PL/SQL

I am trying to print the first 100 values for a field using cursor.I get an ORA-06550 error here though.Could someone tell me what is that I am missing .
Declare
BG_TOTAL number;
cursor c1 is
select BG_ID
from <tablename>;
Type BG_TAB_TYPE is table of c1%ROWTYPE;
BG_LIST BG_TAB_TYPE;
Begin
open c1;
FETCH c1 BULK COLLECT INTO BG_LIST;
close c1;
for i in 1..c1.count
loop
DBMS_OUTPUT.PUT_LINE(c1(i).BG_ID);
End loop;
end;
Yet another option is to use bulk collect with a limit.
This nicely separates the content, the limitation and the processing. The separation might not be an issue in your case but I have found this useful every now an then (helps me to write more modular code that's easy to test).
declare
-- data content
cursor tables_c is select * from all_tables;
type table_list_t is table of tables_c%rowtype;
v_table_list table_list_t;
begin
open tables_c;
-- limiting the data set
fetch tables_c bulk collect into v_table_list limit 8;
-- processing
for i in 1 .. v_table_list.count loop
dbms_output.put_line(v_table_list(i).table_name);
end loop;
close tables_c;
end;
/
You should loop through the nested table to which you bulk-collected records, not through the cursor. This is the corrected code:
Declare
BG_TOTAL number;
cursor c1 is
select BG_ID
from my_Tab524;
Type BG_TAB_TYPE is table of c1%ROWTYPE;
BG_LIST BG_TAB_TYPE;
Begin
open c1;
FETCH c1 BULK COLLECT INTO BG_LIST;
close c1;
for i in 1..BG_LIST.count
loop
DBMS_OUTPUT.PUT_LINE(BG_LIST(i).BG_ID);
EXIT WHEN i = 10;
End loop;
end;

How can I fetch the data from the SYS_REFCURSOR from one stored proc and use it in another?

I have a stored proc with the basic layout below that returns a sys_refcursor as a result set. (Technically it reurns four but for the sake of clarity I just say one). The result set is a selection from a temp table.
procedure aProcedure
( C1 in out sys_refcursor
) is
begin
--populate Temp_Table here with a stored proc call;
OPEN C1 FOR
SELECT Cols
FROM TEMP_TABLE;
I need to insert this result set from C1 into a permanent table using a different stored procedure. Is this Do-able or do I need to re-build the result set all over again?
I've been able to find information on working with cursors and result sets outside of oracle but not for working with them within itself.
I know it might make sense to just do the insert from the first stored proc but that's not really how I need it to happen. It's an optional requirement to save the result set permanently.
Thanks for any helpful info.
Assuming that the caller knows the structure of the cursor that aProcedure is opening, you can do something like this.
declare
l_rc sys_refcursor;
l_rec temp_table%rowtype;
begin
aProcedure( l_rc );
loop
fetch l_rc
into l_rec;
exit when l_rc%notfound;
dbms_output.put_line( l_rec.col1 );
end loop;
close l_rc;
end;
/
If you can't fetch into a record type, you can also fetch into a number of other scalar local variables (the number and type have to match the number and type of columns that aProcedure specifies in its SELECT list). In my case, I defined aProcedure to return two numeric columns
declare
l_rc sys_refcursor;
l_col1 number;
l_col2 number;
begin
aProcedure( l_rc );
loop
fetch l_rc
into l_col1, l_col2;
exit when l_rc%notfound;
dbms_output.put_line( l_col1 );
end loop;
close l_rc;
end;

How can I tell which record causes the error while doing a cursor fetch?

Is there any way to tell which record is causing the error while doing a cursor fetch? For example, let's say I have a table with one column (varchar2), "value", with the following values:
1,
2,
3,
4,
g,
5,
6
I do the following:
DECLARE
answer number;
CURSOR c1 IS
SELECT to_number(value) FROM table;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO answer;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(answer);
END LOOP;
CLOSE c1;
EXCEPTION WHEN invalid_number THEN
dbms_output.put_line('an invalid number exception was encountered');
END;
Would it ouput without issue until 'g' was encountered? This is a trivial example of a real issue I'm trying to debug. In the real example, it outputs the exception message and nothing else. Does this mean it's the first record that causes the issue, or it just doesn't work this way?
It should output values until the row with the exception is encountered, at least according to my test of your procedure. That is, unless you're doing an ORDER BY in your query, in which case you'll likely see the exception before any rows are fetched.
You can see for yourself what is being fetched by trying it without the TO_NUMBER function in your select. Something like this could help:
DECLARE
answer number;
temp VARCHAR2(10);
CURSOR c1 IS
SELECT ID FROM table;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO temp;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT(temp||': Converted is: ');
dbms_output.put_line(to_number(temp));
END LOOP;
CLOSE c1;
EXCEPTION WHEN invalid_number THEN
dbms_output.put_line('an invalid number exception was encountered');
WHEN OTHERS THEN
dbms_output.put_line('Some other error');
END;
/