I have this procedure:
PROCEDURE proc_with_cursor( P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR)
IS
v_sql VARCHAR2 (32767);
v_script VARCHAR2 (32767);
v_bind_vars VARCHAR2 (32767);
BEGIN
v_sql := 'BEGIN OPEN :1 FOR :2 ';
v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;
v_sql := v_sql||' USING '||v_bind_vars||'; ';
--tried also following but also couldn't catch the error!
--v_sql := v_sql ||'EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(''error: ''||SQLCODE||'' - ''||SQLERRM); END;';
v_sql := v_sql||' END;';
v_script := 'select sysdate from dual where 1= :bind_first and 2 = :bindsecond';
EXECUTE IMMEDIATE v_sql using P_CURSOR_OUT, v_script;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM); -- this part is not catching the error!!!!!
END;
Sometimes, the script will throw an error like:
ORA-12847: retry parsing due to concurrent DDL operation
[Error] Execution (1: 1): ORA-12847: retry parsing due to concurrent DDL operation
My question is: how to catch that error?
You cannot bind object names (e.g. cursor names) and variable names into dynamic SQL, only values. I think this may do what you intend:
PROCEDURE proc_with_cursor( p_param1_in NUMBER, p_param2_in NUMBER, p_cursor_out OUT SYS_REFCURSOR)
IS
v_script VARCHAR2 (32767);
BEGIN
v_script := 'select sysdate from dual where 1= :bind_first and 2 = :bindsecond';
OPEN p_cursor_out FOR v_script USING p_param1_in, p_param2_in;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('error: '||sqlcode||' - '||sqlerrm);
END;
I don't understand your problem. If you have this procedure
CREATE OR REPLACE PROCEDURE proc_with_cursor( p_param1_in NUMBER, p_param2_in NUMBER, p_cursor_out OUT SYS_REFCURSOR)
IS
v_script VARCHAR2 (32767);
BEGIN
v_script := 'select sysdate fromM dual where 1= :bind_first and 2 = :bindsecond';
OPEN p_cursor_out FOR v_script USING p_param1_in, p_param2_in;
END;
Then you get this:
DECLARE
cur SYS_REFCURSOR;
BEGIN
proc_with_cursor(1, 2, cur);
end;
/
Error at line 1
ORA-00923: FROM keyword not found where expected
ORA-06512: at "xxx.PROC_WITH_CURSOR", line 6
ORA-06512: at line 4
What else would you like to get? Your (poor) code is working:
CREATE OR REPLACE PROCEDURE proc_with_cursor( P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR) IS
v_sql VARCHAR2 (32767);
v_script VARCHAR2 (32767);
v_bind_vars VARCHAR2 (32767);
BEGIN
v_sql := 'BEGIN OPEN :1 FOR :2 ';
v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;
v_sql := v_sql||' USING '||v_bind_vars||'; ';
v_sql := v_sql||' END;';
v_script := 'select sysdate fromm dual where 1= :bind_first and 2 = :bindsecond';
EXECUTE IMMEDIATE v_sql USING P_CURSOR_OUT, v_script;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM);
END;
DECLARE
cur SYS_REFCURSOR;
BEGIN
proc_with_cursor(1,2, cur);
END;
Prints error: -923 - ORA-00923: FROM keyword not found where expected on the DBMS_OUTPUT.
If you like to get the exception then do
CREATE OR REPLACE PROCEDURE proc_with_cursor( P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR) IS
v_sql VARCHAR2 (32767);
v_script VARCHAR2 (32767);
v_bind_vars VARCHAR2 (32767);
BEGIN
...
EXECUTE IMMEDIATE v_sql USING P_CURSOR_OUT, v_script;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM);
RAISE;
END;
Related
whenever i call this function it will return error like - invalid cursor
so, this is the body part of the package, the package specification also return a sys_refcursor. the error message shows that sys_refcursor invalid cursor.
FUNCTION SUMMARY
(i_name VARCHAR2, i_id VARCHAR2, i_label VARCHAR2)
RETURN SYS_REFCURSOR
IS
rc_result SYS_REFCURSOR;
v_sql CLOB;
Server VARCHAR2(100) := '#AI';
v_r_count NUMBER;
v_sp_count VARCHAR2(200);
V VARCHAR2(10);
BEGIN
EXECUTE IMMEDIATE 'select count(*) from run'||Server||' where id='''||i_id||''' and label='''||i_label||''' and re is not null' INTO v_r_count;
EXECUTE IMMEDIATE 'select table_name from all_tables where table_name like ''%se%'' and owner ='''||i_name||'''' INTO v_sp_count;
IF v_r_count > 0 THEN
BEGIN
v_sql := 'select RE from run'||v_Server||' where id='''||i_id||''' and label='''||i_label||'''';
END;
ELSIF v_sp_count IS NOT NULL THEN
BEGIN
v_sql := 'SELECT
process,
desc,
p_desc,
date
FROM
'||i_name||'.se
WHERE
errors = 1
AND lower(p_desc) LIKE lower(''%summary%'')';
END;
ELSE v_sql := NULL;
END IF;
OPEN result FOR v_sql;
RETURN result;
EXCEPTION
WHEN no_data_found THEN
RETURN NULL;
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
You can simply assign NULL to the refcursor like this: Example
PROCEDURE test( id_number IN VARCHAR2,
resultIN OUT SYS_REFCURSOR) AS
BEGIN
if false then
OPEN resultIN FOR
SELECT dummy
from dual;
ELSE
resultIN := null;
END IF;
END;
I am writing a stored procedure where I have to do following: I want to have a file (any format properties, json, xml) which will have information of which columns I want to extract from my table.
For example: my table has columns A,B,C,D,E, and suppose my file.properties has below information
A=1
B=0
C=1
D=1
F=0
So my generated query should be Select A,C,D from my table;
How can I do this in Oracle 11G?
I think you need this
SQL> set serveroutput on;
SQL> create or replace procedure pr_dynamic_sql( v_result out sys_refcursor ) is
v_outfile utl_file.file_type;
v_path varchar2(100) := 'UTL_FILE_DIR';
-- alias for the directory where your text files generated at OS.
v_row varchar2(100);
v_file varchar2(100);
v_letter varchar2(10);
v_number varchar2(10);
v_sql varchar2(100):= 'select ';
begin
v_file := 'myfile.properties';
v_outfile := utl_file.fopen(v_path, v_file, 'r');
loop
begin
utl_file.get_line(v_outfile,v_row);
v_letter := regexp_substr(v_row,'[^=]');
v_number := substr(regexp_substr(v_row,'[^=]+$'),1,1);
if v_number = '1' then
v_sql := v_sql||v_letter||',';
end if;
exception when no_data_found then exit;
end;
end loop;
utl_file.fclose(v_outfile);
v_sql := rtrim(v_sql,',')||' from mytable';
open v_result for v_sql;
end;
and call
SQL> begin
pr_dynamic_sql(v_result => :v_result);
end;
/
to get results as of cursor type.
I am using Oracle 12, and I want to make a dynamic procedure which selects rows from specific table but according to an unknown conditio. That condition will be specified as input parameter.
Suppose I have a column called employee id and I want to call the procedure
with the following condition
execute s('employeeid = 2')
My code is
create or replace procedure s (condition varchar)
as
TYPE EmpCurTyp IS REF CURSOR; -- define weak REF CURSOR type
emp_cv EmpCurTyp; -- declare cursor variable
my_ename VARCHAR2(15);
my_sal NUMBER := 2;
mycondition varchar2(100):=condition;
BEGIN
OPEN emp_cv FOR -- open cursor variable
'SELECT employeeid, employeename FROM employees WHERE = :s' USING mycondition;
END;
but I am getting an error
missing expression
What am I doing wrong, and will the result of this procedure be selected rows from employees table that satisfy applied condition ?
The USING is meant to handle values, not pieces of code; if you need to edit your query depending on an input parameter ( and I believe this is a very dangerous way of coding), you should treat the condition as a string to concatenate to the query.
For example, say you have this table:
create table someTable(column1 number)
This procedure does somthing similar to what you need:
create or replace procedure testDyn( condition IN varchar2) is
cur sys_refcursor;
begin
open cur for 'select column1 from sometable where ' || condition;
/* your code */
end;
Hot it works:
SQL> exec testDyn('column1 is null');
PL/SQL procedure successfully completed.
SQL> exec testDyn('column99 is null');
BEGIN testDyn('column99 is null'); END;
*
ERROR at line 1:
ORA-00904: "COLUMN99": invalid identifier
ORA-06512: at "ALEK.TESTDYN", line 4
ORA-06512: at line 1
This is not embedded in a procedure yet but I tested this and works:
DECLARE
TYPE OUT_TYPE IS TABLE OF VARCHAR2 (20)
INDEX BY BINARY_INTEGER;
l_cursor INTEGER;
l_fetched_rows INTEGER;
l_sql_string VARCHAR2 (250);
l_where_clause VARCHAR2 (100);
l_employeeid VARCHAR2 (20);
l_employeename VARCHAR2 (20);
l_result INTEGER;
o_employeeid OUT_TYPE;
o_employeename OUT_TYPE;
BEGIN
l_cursor := DBMS_SQL.OPEN_CURSOR;
l_sql_string := 'SELECT employeeid, employeename FROM employees WHERE ';
l_where_clause := 'employeeid = 2';
l_sql_string := l_sql_string || l_where_clause;
DBMS_SQL.PARSE (l_cursor, l_sql_string, DBMS_SQL.V7);
DBMS_SQL.DEFINE_COLUMN (l_cursor,
1,
l_employeeid,
20);
DBMS_SQL.DEFINE_COLUMN (l_cursor,
2,
l_employeename,
20);
l_fetched_rows := 0;
l_result := DBMS_SQL.EXECUTE_AND_FETCH (l_cursor);
LOOP
EXIT WHEN l_result = 0;
DBMS_SQL.COLUMN_VALUE (l_cursor, 1, l_employeeid);
DBMS_SQL.COLUMN_VALUE (l_cursor, 2, l_employeename);
l_fetched_rows := l_fetched_rows + 1;
o_employeeid (l_fetched_rows) := l_employeeid;
o_employeename (l_fetched_rows) := l_employeename;
l_result := DBMS_SQL.FETCH_ROWS (l_cursor);
END LOOP;
DBMS_SQL.CLOSE_CURSOR (l_cursor);
DBMS_OUTPUT.PUT_LINE (o_employeeid (1));
DBMS_OUTPUT.PUT_LINE (o_employeename (1));
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE ('GENERAL FAILURE: ' || SQLERRM);
END;
I'm trying to execute a stored procedure, but I'm not sure if my syntax is wrong or not.
set dbms_output.put_line on;
declare
v_premnum NUMBER(10);
v_util_type CHAR(10);
v_result VARCHAR2(200);
Begin
execute myprocedure( 'E', v_util_type, 73105 , v_premnum);
dbms_output.put_line = v_result
end;
/
There are two ways. Either your procedure has an output parameter:
declare
v_premnum NUMBER(10) := 1234;
v_util_type CHAR(10) := 'the type';
v_result VARCHAR2(200);
begin
myprocedure('E', v_util_type, 73105 , v_premnum, v_result);
dbms_output.put_line(v_result);
end;
Or it should be a function returning the desired value:
declare
v_premnum NUMBER(10) := 1234;
v_util_type CHAR(10) := 'the type';
v_result VARCHAR2(200);
begin
v_result := myfunction('E', v_util_type, 73105 , v_premnum);
dbms_output.put_line(v_result);
end;
Trying to execute a procedure dynamically with DBMS_SQL that takes 'table of varchar' and sys_refcursor as an argument using the code below:
DECLARE
TYPE CriteriaMap IS TABLE OF VARCHAR (100)
INDEX BY VARCHAR2 (100);
o_cursor SYS_REFCURSOR;
v_cid INTEGER;
v_dummy INTEGER;
v_date_to_run DATE := SYSDATE;
v_sql_execute_proc VARCHAR2 (1024);
v_filter_criteria CriteriaMap;
BEGIN
v_sql_execute_proc :=
'begin MY_PROCEDURE(:v_date_to_run, :filter_criteria, :o_cursor); end;';
v_cid := DBMS_SQL.open_cursor;
DBMS_SQL.parse (v_cid, v_sql_execute_proc, DBMS_SQL.native);
DBMS_SQL.bind_variable (v_cid, 'v_date_to_run', v_date_to_run);
DBMS_SQL.bind_variable (v_cid, 'filter_criteria', v_filter_criteria);
DBMS_SQL.bind_variable (v_cid, 'o_cursor', o_cursor);
v_dummy := DBMS_SQL.execute (v_cid);
DBMS_SQL.close_cursor (v_cid);
END;
as the result the following error is thrown
Error report:
ORA-06550: line 14, column 3:
PLS-00306: wrong number or types of arguments in call to 'BIND_VARIABLE'
Documentation http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm says that BIND_VARIABLE takes only a limited number of data types and 'table of varchar' and sys_refcursor are not in the list.
Is there any workaround to pass arguments to a dynamic function which data types are not in the list?
table of varchar is suppoorted through bind_array (though it has to be as per the spec in dbms_sql which is indexed by integer and not varchar2).
can you explain more on why you're using dynamic SQL in this case? as your example does not warrant dynamic SQL as the structure of the call is fixed here.
I know it's old... but if anyone encounters this - it is possible (in 11g, not sure about earlier) to convert the sys ref cursor to a cursor number, bind it, and then transform it to a refcursor after the execute - something like:
declare
vSQL varchar2(1000) := 'declare
v_rc sys_refcursor;
begin
open v_rc for select ''this is a test'' from dual;
:v_cursor_number := dbms_sql.to_cursor_number(v_rc);
end;';
v_rc sys_refcursor;
v_cursor_number NUMBER;
v_cur number;
v_result number;
vFetchValue varchar2(20);
begin
--open the cursor
v_cur := DBMS_SQL.OPEN_CURSOR;
--parse
DBMS_SQL.PARSE(v_cur, vSQL, dbms_sql.native);
--bind the cursor number
DBMS_SQL.BIND_VARIABLE(v_cur, 'v_cursor_number', v_cursor_number);
--execute
v_result := DBMS_SQL.EXECUTE(v_cur);
-- get back the value of the bind cursor number
DBMS_SQL.VARIABLE_VALUE(v_cur,'v_cursor_number', v_cursor_number);
--transform it to a standard sys_refcursor
v_rc := DBMS_SQL.TO_REFCURSOR (v_cursor_number);
--close the cursor
DBMS_SQL.CLOSE_CURSOR(v_cur);
fetch v_rc into vFetchValue;
close v_rc;
dbms_output.put_line(vFetchValue);
end;
/