Need to extract a Oracle CLOB from table to CSV delimited with pipe, but encountered the 32700 character limit. The value has more than 300,000 characters. Also, how can we replace the new line with spaces. I tried regexp_replace but it has again 32700 limit..
Any suggestions.
Thank you
how can we replace the new line with spaces. I tried regexp_replace but it has again 32700 limit.
Just use the REPLACE function as, when the input is a CLOB then the output is a CLOB:
REPLACE returns char with every occurrence of search_string replaced with replacement_string. If replacement_string is omitted or null, then all occurrences of search_string are removed. If search_string is null, then char is returned.
Both search_string and replacement_string, as well as char, can be any of the datatypes CHAR, VARCHAR2, NCHAR, NVARCHAR2, CLOB, or NCLOB. The string returned is in the same character set as char. The function returns VARCHAR2 if the first argument is not a LOB and returns CLOB if the first argument is a LOB.
For the sample data:
CREATE TABLE table_name ( value CLOB );
DECLARE
p_value CLOB := EMPTY_CLOB();
BEGIN
FOR i IN 1 .. 20 LOOP
p_value := p_value || LPAD( '123456789' || CHR(10), 4000, '123456789|' );
END LOOP;
INSERT INTO table_name ( value ) VALUES ( p_value );
END;
/
Then the query:
SELECT LENGTH( REPLACE( value, CHR(10), ' ' ) ) AS len,
REPLACE( value, CHR(10), ' ' ) AS value
FROM table_name
Outputs:
LEN VALUE
40000 123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789 123456789|123456789|123456789|123456789|12345<snip...>56789|123456789 123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789
After that, just extract the CLOB in the normal manner for the application you are using to access the database.
db<>fiddle here
Related
I am using Toad For Oracle and I have a procedure in a package where I'm getting the CLOB value for result. I'll be using dummy variables only but I'll be putting the whole process here.
My goal is to a rest web service where my output will be a JSON CLOB.
START OF THE BODY PACKAGE
TYPE in_emp_type IS RECORD ( emp_id NUMBER,
emp_fname VARCHAR2(50), emp_lname VARCHAR2(50),
city VARCHAR2(40), country(50) )
in_emp_rec in_emp_type ;
TYPE out_emp_type IS RECORD (emp_addr_1 VARCHAR2(100), emp_addr_2 VARCHAR2(100);
TYPE out_emp_tab_type IS TABLE OF out_emp_type;
query_tab out_emp_tab_type := out_emp_tab_type ();
PROCEDURE get_employee_details(api_key VARCHAR2, emp_id NUMBER,
emp_fname VARCHAR2, emp_lname VARCHAR2, out_result_json OUT CLOB ) IS
CURSOR get_all_emp IS
select city, country from emp_table
where emp_id = emp_id
and fname = emp_fname
and lname = emp_lname ;
CURSOR get_emp_addr (emp_id NUMBER, city VARCHAR2) IS
select addr_1, addr_2 from emp_addr
where emp_id = emp_id and city = city;
v_city VARCHAR2;
v_country VARCHAR2;
v_json_input CLOB;
v_result_json CLOB;
BEGIN
open get_all_emp;
fetch get_all_emp into v_city , v_country ;
close get_all_emp;
v_json_input := '{"EmployeeDetails":
{"EmployeeID": || emp_id || ' ",
"EmployeeFirstName": || emp_fname || '",
"EmployeeLastName": || emp_lname || '",
"EmployeeCity": || v_city || '",
"EmployeeCountry": || v_country || '"}'
convert_input_json(v_json_input,in_emp_rec);
open get_emp_addr (emp_id, city);
fetch get_emp_addr bulk collect into query_tab ;
v_result_json := convert_result_json(query_tab);
out_result_json := v_result_json;
END;
And this is my sample of the convert_input_json procedures & convert_result_json function
PROCEDURE convert_input_json(input_json IN CLOB, output_json OUT in_emp_type) IS
CURSOR get_details IS
select emp_id, emp_fname, emp_lname, city, country
from json_table(input_json, '$' COLUMNS (
emp_id NUMBER PATH '$.EmployeeDetails.EmployeeID',
emp_fname VARCHAR2(50) PATH '$.EmployeeDetails.EmployeeFirstName',
emp_lname VARCHAR2(50) PATH '$.EmployeeDetails.EmployeeLastName', ... includeother fields here)
BEGIN
output_json := in_emp_type( emp_id => NULL, emp_fname => NULL....)
open get_details;
fetch get_details into output_json.emp_id , output_json.emp_fname ....);
close get_details;
END;
FUNCTION convert_result_json (in_result out_emp_tab_type) RETURN CLOB IS
v_clob CLOB
BEGIN
FOR i in 1...query_tab.count LOOP
v_clob := '{ '||chr(13)||'"customerResults": {'
v_clob := v_clob||chr(13)||chr(9)||chr(9)||'"addr1": "'||query_tab(i).emp_addr_1 ||'",';
v_clob := v_clob||chr(13)||chr(9)||chr(9)||'"addr2": "'||query_tab(i).emp_addr_2 ||'",';
END LOOP;
RETURN (v_clob)
END;
So when I try to run this, I'm getting the ORA-06502: PL/SQL: numeric or value error: character string buffer too small
And I'm not really sure why am I getting this error. Can someone please help me.
There should be an error stack trace showing the line number that raised the exception. Looking at your code, there are two obvious places where this can happen:
The JSON_TABLE COLUMNS mapping - ensure that emp_fname/emp_lname never overflows the allotted 50 characters.
In the convert_result_json function, you are using || to append new addresses to an existing CLOB value. || will convert the operands to varchar2(32767). If the size of the CLOB + the new string being appended > 32KB, it will fail due to the varchar2 datatype limit. If this is your issue, use dbms_lob to append to your LOBs, not ||.
I have a procedure (see test case below), which works fine that appends data to a CLOB. In addition to appending the data in the CLOB I'm encapsulating the VALUE of SYSDATE in tags so I can keep track of when the data was updated in the CLOB.
Though I'm only showing data with 10-20 characters in my example the CLOB can be extremely big and in many cases concatenated within a block before being placed into the CLOB.
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE table t(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
c CLOB DEFAULT ' ',
create_date DATE DEFAULT SYSDATE
);
/
insert into t (c) values (' ')
/
CREATE OR REPLACE PROCEDURE lob_append(
p_clob IN OUT CLOB,
p_text IN VARCHAR2
)
AS
l_text varchar2(32760);
l_date_string VARCHAR2(50);
BEGIN
select '[' || TO_CHAR (SYSDATE, 'MMDDYYYY-HH24:MI:SS') || ']'
into l_date_string from dual;
-- newline each time code is appended for clarity.
l_text :=chr(10) || l_date_string || chr(10)
|| p_text || chr(10)
|| l_date_string||chr(10);
dbms_lob.writeappend(p_clob, length(l_text), l_text );
END;
/
DECLARE
l_clob CLOB := empty_clob();
BEGIN
SELECT c INTO l_clob FROM t WHERE seq_num = 1 FOR UPDATE;
lob_append(l_clob, rpad('Z',20,'Z'));
l_clob := empty_clob();
SELECT c INTO l_clob FROM t WHERE seq_num = 1 FOR UPDATE;
lob_append(l_clob, rpad('Y',10,'Y'));
END;
/
I'm looking to do something like this but by calling a procedure similar to the one posted above.
UPDATE T
SET C = RPAD('A',20,'A') || CHR(10) || C
WHERE SEQ_NUM = 1
/
I welcome any and all helpful suggestions and or design changes since this hasn't been implemented yet. Thanks in advance to all who answer.
I have a three tables as below.
Create table t1_Fact ( Cur_date Date, Name varchar2(10), Event varchar2(50), Price Number(10,0), TAX Number(10,0), Flag Number );
Create table App_Fact ( Application_ID Number, Application_Name varchar2(100), Application_Price Number, Appliation_Tax Number, Flag Number );
Create table t2 ( Table_Name Varchar2(100), Table_Columns Varchar(100), Table_Measure varchar2(100), t3_columns varchar2(100), t3_measures varchar2(100), t3_Where_Clause varchar2(100) );
Create table t3 ( Cur_date Date, Name varchar2(10), Event varchar2(50), Application_ID Number, Application_Name varchar2(100), Application_Price Number, Appliation_Tax Number, Price Number(10,0), TAX Number(10,0), Flag Number );
table t2 contains all the table names,column names of each source and destination tables and where clause conditions.
[t2 Details][1]
Here I need to insert the data from t3 to particular fact table by using group by the column names of fact table, measures and where clause by passing the fact table name as parameter.
Like if we pass t1_Fact table in procedure, we must get all the details from t2 and get the details from t3 and insert into t1_Fact and also save them into CSV file
I have tried the following procedure however I'm not able to insert the data into csv file
Create or Replace Procedure CommonProcedure(sourceTableName IN VARCHAR2) Is
tablename t2.Table_Name%TYPE;
destcolumns t2.Table_Columns%TYPE;
destMeasures t2.Table_Measure%TYPE;
whereClause t2.t3_Where_Clause%TYPE;
sourceColumns t2.t3_columns%TYPE;
sourceMeasures t2.t3_measures%TYPE;
q1 VARCHAR2(3000 BYTE);
pathInfo VARCHAR2(3000 BYTE);
v_file UTL_FILE.FILE_TYPE;
Cursor TableName Is SELECT Table_Name FROM t2;
Begin
--Path will be getting from another table using the function in the format of '/data/Oracle-files/Table_CSV'
pathInfo := getDBConfigParamValue('FILE_LOCATION');
Open c1;
Loop
Fetch TableName Into tablename;
Exit When TableName%notfound;
SELECT Table_Columns, Table_Measure, t3_columns, t3_measures INTO destcolumns,destMeasures,sourceColumns,sourceMeasures FROM t2 where Table_Name = tablename;
q1 := 'INSERT INTO '||tablename||'('||destColumns||','||destMeasures||')'||
' ( SELECT '||sourceColumns||','||sourceMeasures||','||sourceTableName
||' FROM '||sourceTableName||' GROUP BY '||sourceColumns||')';
Execute Immediate q1;
--Need to load the data into tablename.CSV
v_file := UTL_FILE.FOPEN('' || pathInfo ||',' ||destinationTableName ||'.csv' || '','W');
UTL_FILE.PUT_LINE(v_file,'' ||destColumns ||',' ||destMeasures ||'');
UTL_FILE.FCLOSE(v_file);
End Loop;
Close TableName;
End;
When I compile the above procedure getting following error
LINE/COL ERROR
-------- -----------------------------------------------------------------
47/13 PL/SQL: Statement ignored
47/23 PLS-00306: wrong number or types of arguments in call to 'FOPEN'
Please assist me further.
Thanks in advance.
PLS-00306: wrong number or types of arguments in call to 'FOPEN'
Your fopen call is only passing two arguments; you are concatenating a comma into the first value, rather than using it as an argument separator, so you are passing the constructed string '<pathInfo>,<destinationTableName>.csv' as the location, 'W' as the filename, and no third argument for the open mode.
You can see the problem if I highlight it:
v_file := UTL_FILE.FOPEN('' || pathInfo ||',' ||destinationTableName ||'.csv' || '','W');
^^^^^^^^
Continuing your pattern of concatenating empty strings (?) you have it the wrong side of a closing quote:
v_file := UTL_FILE.FOPEN('' || pathInfo ||'', destinationTableName ||'.csv' || '','W');
or maybe even:
v_file := UTL_FILE.FOPEN('' || pathInfo ||'', '' || destinationTableName ||'.csv' || '','W');
but you don't need to do all that confusing concatenation, you can just do:
v_file := UTL_FILE.FOPEN(pathInfo, destinationTableName ||'.csv', 'W');
I am trying to take a comma delimited string and insert each value as a new row into a table. I have taken the below example from Lalit Kumar B and modified the data to resemble what my data will look like.
DECLARE
L_INPUT VARCHAR2(4000) := '522,33-23,125,658,25,12-500';
L_COUNT BINARY_INTEGER;
L_ARRAY DBMS_UTILITY.LNAME_ARRAY;
BEGIN
DBMS_UTILITY.COMMA_TO_TABLE(LIST => REGEXP_REPLACE(L_INPUT, '(^|,)', '\1x'), TABLEN => L_COUNT, TAB => L_ARRAY);
DBMS_OUTPUT.PUT_LINE(L_COUNT);
FOR I IN 1 .. L_COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('Element ' || TO_CHAR(I) || ' of array contains: ' || SUBSTR(L_ARRAY(I), 2));
INSERT INTO TEST22 VALUES
(SUBSTR(L_ARRAY(I), 2)
);
COMMIT;
END LOOP;
END;
I am receiving the following oracle error: ORA-20001: comma-separated list invalid near 33-23
What can i do to handle data of the form "33-23"? If I take the '-' out of my data the above will run as desired. This is not ideal as some of my data will have '-' in it and it cannot be removed.
One way is to use CONNECT BY to effectively loop through the string elements. If you run just the query you'll see how this works. The regular expression allows for NULL list elements should they occur.
insert into TEST(col_a)
select regexp_substr('522,33-23,125,658,25,12-500', '(.*?)(,|$)', 1, level, null, 1)
from dual
connect by level <= regexp_count('522,33-23,125,658,25,12-500', ',')+1
I had same problem with DBMS_UTILITY.COMMA_TO_TABLE. It has some bugs with numeric strings. I tried some methods and finally write this function instead of it.
CREATE OR REPLACE PACKAGE UTILITY_METHODS IS
TYPE STRING_TAB IS TABLE OF VARCHAR2(512) INDEX BY BINARY_INTEGER;
FUNCTION SPLIT_STR( P_STRING IN VARCHAR2
, P_SEPRATOR_CHAR IN VARCHAR2)
RETURN STRING_TAB;
END UTILITY_METHODS;
CREATE OR REPLACE PACKAGE BODY UTILITY_METHODS IS
FUNCTION SPLIT_STR( P_STRING IN VARCHAR2
, P_SEPRATOR_CHAR IN VARCHAR2)
RETURN STRING_TAB
IS
STR_TAB STRING_TAB;
L_SEP_CHAR VARCHAR2(1) := NVL(P_SEPRATOR_CHAR, ',');
L_PATERN VARCHAR2(10) := '[^' || L_SEP_CHAR || ']+';
BEGIN
IF P_STRING IS NULL THEN
RETURN STR_TAB;
END IF;
FOR RC IN (
WITH L_LINE(STR) AS
(
SELECT P_STRING
FROM DUAL
)
SELECT REGEXP_SUBSTR(STR, L_PATERN, 1, LEVEL) SP_STR
FROM L_LINE
CONNECT BY LEVEL <= REGEXP_COUNT(STR, L_SEP_CHAR) + 1
)
LOOP
STR_TAB(STR_TAB.COUNT) := RC.SP_STR;
END LOOP;
RETURN STR_TAB;
END;
END UTILITY_METHODS;
If you want use this function in a select statement you can change the return type of function to PIPE_LINED.
I have a task that involves updating many triggers which are exactly the same query but applied to several different tables. Is there a way to update all these TRIGGERS using a FOR or similar statement? Actually what I need to do is modify the WHEN clause for all this triggers.
you can use dbms_metadat for this.
for example:
declare
type arr_tab is table of varchar2(30);
v_arr arr_tab;
v_trig clob;
begin
dbms_metadata.set_transform_param( DBMS_METADATA.SESSION_TRANSFORM,
'SQLTERMINATOR', FALSE );
v_arr := arr_tab('TEST_TRIG', 'TEST2_TRIG'); -- change these triggers.
for idx in 1..v_arr.count
loop
v_trig := dbms_metadata.get_ddl('TRIGGER',v_arr(idx), user);
execute immediate regexp_replace(regexp_replace(v_trig, 'ALTER TRIGGER.*', ''), 'WHEN ([^\)]*\))', 'WHEN (1=1)', 1, 1, 'mi');
end loop;
end;
/
the 'WHEN ([^\)]*\))', 'WHEN (1=1)' part replaces the WHEN clause with (in my case) WHEN (1=1).
You can use dba_triggers to extract the text of the trigger into CREATE or replace statements. But due to some of the columns being LONG datatype you will have trouble extracting them as VARCHAR2. This can be resolved by using Tom Kytes package which is lost somewhere on the oracle site. I include my own version which you may have to modify to meet your needs.
Run the select, insert your when clause and then run the create or replace statements.
This won't work due to the trigger_body being a long datatype
select 'CREATE OR REPLACE TRIGGER '|| description
||trigger_body
from dba_triggers
where owner = 'Your schema'
but this should work if your triggers are not more than 4000 characters
select 'CREATE OR REPLACE TRIGGER '|| description
|| ADMIN.LONG_HELP.SUBSTR_OF('select trigger_body from dba_triggers where trigger_name = :0',
1,4000,'0',dt.trigger_name)
from dba_triggers dt
where owner = 'YourSchema';
CREATE OR REPLACE PACKAGE ADMIN.LONG_HELP
/******************************************************************************
NAME: LONG_HELP
PURPOSE: Read fields of type long. (commonly found in data dictionary)
REVISIONS:
Ver Date Author Description
--------- ---------- --------------- ------------------------------------
1.0 10/27/2011 1. Created this package. based on Tom Kyte's column here
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:839298816582
note that it only retrieves the first 4000 characters of any LONG column
USAGE in a WHERE
INSTR(
ADMIN.LONG_HELP.SUBSTR_OF('SELECT text from all_views where view_name =:o ',
1,4000,'o',m2.obj_name),m1.FK_ID) > 0
******************************************************************************/
--AUTHID CURRENT_USER
--removed to get around ORA-29470: Effective userid or roles are not the same as when cursor was parsed
--restrict usage to admin schema for Oracle 11g
AS
FUNCTION substr_of (p_query IN VARCHAR2,
p_from IN NUMBER,
p_for IN NUMBER,
p_name1 IN VARCHAR2 DEFAULT NULL ,
p_bind1 IN VARCHAR2 DEFAULT NULL ,
p_name2 IN VARCHAR2 DEFAULT NULL ,
p_bind2 IN VARCHAR2 DEFAULT NULL ,
p_name3 IN VARCHAR2 DEFAULT NULL ,
p_bind3 IN VARCHAR2 DEFAULT NULL ,
p_name4 IN VARCHAR2 DEFAULT NULL ,
p_bind4 IN VARCHAR2 DEFAULT NULL )
RETURN VARCHAR2;
END LONG_HELP;
/
CREATE OR REPLACE PACKAGE BODY ADMIN.LONG_HELP
AS
g_cursor NUMBER := DBMS_SQL.open_cursor;
g_query VARCHAR2 (32765);
PROCEDURE bind_variable (p_name IN VARCHAR2, p_value IN VARCHAR2)
IS
BEGIN
IF (p_name IS NOT NULL)
THEN
DBMS_SQL.bind_variable (g_cursor, p_name, p_value);
END IF;
END BIND_VARIABLE;
FUNCTION substr_of (p_query IN VARCHAR2,
p_from IN NUMBER,
p_for IN NUMBER,
p_name1 IN VARCHAR2 DEFAULT NULL ,
p_bind1 IN VARCHAR2 DEFAULT NULL ,
p_name2 IN VARCHAR2 DEFAULT NULL ,
p_bind2 IN VARCHAR2 DEFAULT NULL ,
p_name3 IN VARCHAR2 DEFAULT NULL ,
p_bind3 IN VARCHAR2 DEFAULT NULL ,
p_name4 IN VARCHAR2 DEFAULT NULL ,
p_bind4 IN VARCHAR2 DEFAULT NULL )
RETURN VARCHAR2
AS
/******************************************************************************
NAME: LONG_HELP.SUBSTR_OF
PURPOSE: CONVERT long data fields into VARCHAR2
WHOSE DATA IS CHANGED: none
WHAT USES THIS:
WHERE ARE THE RESOURCES NEEDED:
******************************************************************************/
l_buffer VARCHAR2 (4000);
l_buffer_len NUMBER;
BEGIN
IF (NVL (p_from, 0) <= 0)
THEN
raise_application_error (-20002,
'From must be >= 1 (positive numbers)');
END IF;
IF (NVL (p_for, 0) NOT BETWEEN 1 AND 4000)
THEN
raise_application_error (-20003, 'For must be between 1 and 4000');
END IF;
IF (p_query <> g_query OR g_query IS NULL)
THEN
IF (UPPER (TRIM (NVL (p_query, 'x'))) NOT LIKE 'SELECT%')
THEN
raise_application_error (-20001, 'This must be a select only');
END IF;
DBMS_SQL.parse (g_cursor, p_query, DBMS_SQL.native);
g_query := p_query;
END IF;
bind_variable (p_name1, p_bind1);
bind_variable (p_name2, p_bind2);
bind_variable (p_name3, p_bind3);
bind_variable (p_name4, p_bind4);
DBMS_SQL.define_column_long (g_cursor, 1);
IF (DBMS_SQL.execute_and_fetch (g_cursor) > 0)
THEN
DBMS_SQL.column_value_long (g_cursor,
1,
p_for,
p_from - 1,
l_buffer,
l_buffer_len);
END IF;
RETURN l_buffer;
END substr_of;
END LONG_HELP;
/