I saw many examples in the past when SQL statement was actually stored in CLOB field and programmer had to execute the statement dynamically.
All Oracle PL/SQL developers are familiar with “execute immediate” statement, but unfortunately it cannot use CLOB field as an input.
But it is not the only way to execute the code dynamically. Oracle also provides DBMS_SQL package that can execute the code dynamically and it can get the statement as an array data type. We will use it
Here how you can do it.
Let assume that your SQL will be stored in the following variable
l_stmt CLOB;
Now we need to split the CLOB to chunks that will became a member of array I mentioned previously
v_upperbound NUMBER;
This is array definition
v_sql DBMS_SQL.VARCHAR2S;
Calculate array length
v_upperbound := CEIL(DBMS_LOB.GETLENGTH(l_stmt)/256);
Fill array members:
FOR i IN 1..v_upperbound
LOOP
v_sql(i) := DBMS_LOB.SUBSTR(l_stmt
,256 -- amount
,((i-1)*256)+1 -- offset
);
END LOOP;
Create new cursor:
v_cur INTEGER;
v_cur := DBMS_SQL.OPEN_CURSOR;
Prepare your statement for execution , but parsing array members
DBMS_SQL.PARSE(v_cur, v_sql, 1, v_upperbound, FALSE, DBMS_SQL.NATIVE);
You can also use bind variables at this point
dbms_sql.bind_variable( v_cur, ':USER_NAME', ‘SYSADMIN’);
All what is left is to execute the statement
v_ret NUMBER;
v_ret := DBMS_SQL.EXECUTE(v_cur);
Bellow if full example that uses approach described above
declare
l_stmt CLOB;
v_upperbound NUMBER;
v_cur INTEGER;
v_sql DBMS_SQL.VARCHAR2S;
v_ret NUMBER;
begin
-- get sql statement into CLOB
select statement
into l_stmt
from XX_NEW_STATEMENTS_V --some view that holds CLOB
--with SQL
where statement_type = 'SETUP'
and seq_num = 10;
v_upperbound := CEIL(DBMS_LOB.GETLENGTH(l_stmt) / 256);
FOR i IN 1 .. v_upperbound LOOP
v_sql(i) := DBMS_LOB.SUBSTR(l_stmt, -- clob statement
256, -- amount
((i - 1) * 256) + 1
);
END LOOP;
v_cur := DBMS_SQL.OPEN_CURSOR;
-- parse sql statement
DBMS_SQL.PARSE(v_cur, v_sql, 1, v_upperbound, FALSE, DBMS_SQL.NATIVE);
-- use bind variable if you need
dbms_sql.bind_variable(v_cur, ':USER_ID', 235341);
-- execute
v_ret := DBMS_SQL.EXECUTE(v_cur);
end;
How large was your SQL and what was the error message?
ReplyDelete