Blob file download from databse to local folder which is having size greater >32767 using UTL oracle package - sql

I want to download/export Blob data from database to local machine with the help of UTL package, but UTL package has a limit of 32767 bytes. is there are any alternative ways to download files .
Many thanks in advance
declare
bblobb blob;
v_buff raw(32767);
v_buff_size binary_integer;
v_amount binary_integer;
v_offset number(38):=1;
v_chunksize INTEGER;
v_out_file utl_file.file_type;
begin
select blob_col into bblobb from test_blob
where id=12;
v_chunksize := DBMS_LOB.GETCHUNKSIZE(bblobb);
IF (v_chunksize < 32767) THEN
v_buff_size := v_chunksize;
ELSE
v_buff_size := V_CHUNKSIZE;
END IF;
v_amount := v_buff_size;
v_out_file:=utl_file.fopen('IMAGE','2.PDF','wb');
dbms_lob.read(lob_loc=>bblobb, amount =>v_amount, offset =>v_offset, buffer =>v_buff);
utl_file.put_raw(file =>v_out_file, buffer =>v_buff, autoflush =>true);
utl_file.fflush(file=>v_out_file);
utl_file.fclose(v_out_file);
end;
I need to download the file which is above the size 32767

Related

long raw to pdf

good afternoon,
I am in need of help to read a field in the Oracle database.
I have a long raw field that contains a pdf and I need to save it to a file.
Does anyone have any suggestions on how I can do it?
If you have access to Oracle Support, there is an example in Doc ID 1433573.1
Sample Procedure
CREATE OR REPLACE PROCEDURE WritePDFToFILE (myfilename IN VARCHAR2)
IS
v_blob BLOB;
blob_length INTEGER;
out_file UTL_FILE.FILE_TYPE;
-- chunk size and buffer size must match
chunk_size BINARY_INTEGER := 32767;
v_buffer RAW (32767);
blob_position INTEGER := 1;
BEGIN
-- Retrieve the BLOB for reading
SELECT filedata
INTO v_blob
FROM blob_pdf_tbl
WHERE filename = myfilename;
-- Retrieve the SIZE of the BLOB
blob_length := DBMS_LOB.GETLENGTH (v_blob);
-- Open a handle to the location where you are going to write the BLOB to a file
-- NOTE: The 'wb' parameter means "write in byte mode" and is only availabe
-- in the UTL_FILE package with Oracle 10g or later
out_file :=
UTL_FILE.FOPEN ('PDF_DIR_LOC',
myfilename,
'wb',
chunk_size);
-- Write the BLOB to file in chunks
WHILE blob_position <= blob_length
LOOP
IF blob_position + chunk_size - 1 > blob_length
THEN
chunk_size := blob_length - blob_position + 1;
END IF;
DBMS_LOB.READ (v_blob,
chunk_size,
blob_position,
v_buffer);
UTL_FILE.PUT_RAW (out_file, v_buffer, TRUE);
blob_position := blob_position + chunk_size;
END LOOP;
-- Close the file handle
UTL_FILE.FCLOSE (out_file);
END;
/

Generate XML files from Oracle query

I have a query which return 50 millions rows. I want to generate XML files for each row (file max. size is 100k). Of course I know the tags but I don't know how to write this in the most efficient way. Any help ?
Thanks
I wouldn't recommend trying to write 50M files to disk, but here's some code you can play with to demonstrate why its not a good idea
1: a function that writes files to disk using a directory
create or replace function WRITETOFILE (dir in VARCHAR2,fn in VARCHAR2, dd IN clob) return clob AS
ff UTL_FILE.FILE_TYPE;
l_amt number := 30000;
l_offset number := 1;
l_length number := nvl(dbms_lob.getlength(dd),0);
buf varchar2(30000);
begin
ff := UTL_FILE.FOPEN(dir,fn,'W',32760);
while ( l_offset < l_length ) loop
buf := dbms_lob.substr(dd,l_amt,l_offset);
utl_file.put(ff, buf);
utl_file.fflush(ff);
utl_file.new_line(ff);
l_offset := l_offset+length(buf);
end loop;
UTL_FILE.FCLOSE(ff);
return dd;
END WRITETOFILE;
/
2: statement creating a table with all rows from a query that makes use of function above - suggesting that you keep the number of rows small to see how it plays
create table tmptbl as
select writetofile('DMP_DIR','xyz-'||level||'.xml', xmlelement("x", level).getClobVal()) tmpcol, systimestamp added_at
from dual CONNECT BY LEVEL <= 10;
3: drop table to repeat create table statement with more rows
drop table tmptbl purge;
I did 10k files in 10 seconds - which would give 1000 seconds for 1M files and 50000 seconds for 50M files (i.e. just under 14 hours).

How to Write Blob from Oracle Column to the File System

my_images table consists of a blob column called images. I need to write these images to my image_dir which is 'C:\TEMP'.
When the following PL/SQL code is executed, only the first image is written to the directory as an image. The second blob is written as 0 byte (empty) and there is no other (Should be a total number of 8).
So the loop does not seem to work correctly. I am using Oracle 11g Express Edition (XE) and SQL Developer. Here is the error and the code:
Error starting at line : 53 in command -
BEGIN write_blob_to_file_v5; END;
Error report -
ORA-01403: no data found
ORA-06512: at "SYS.DBMS_LOB", line 1056
ORA-06512: at "SYS.WRITE_BLOB_TO_FILE_V5", line 40
ORA-06512: at line 1
01403. 00000 - "no data found"
*Cause: No data was found from the objects.
*Action: There was no data from the objects which may be due to end of fetch.
PL/SQL code
CREATE OR REPLACE PROCEDURE write_blob_to_file_v5
AS
v_lob_image_name VARCHAR (100);
v_lob_image_id NUMBER;
v_blob BLOB;
v_buffer RAW (32767);
v_buffer_size BINARY_INTEGER;
v_amount BINARY_INTEGER;
v_offset NUMBER (38) := 1;
v_chunksize INTEGER;
v_out_file UTL_FILE.file_type;
BEGIN
FOR i IN (SELECT DBMS_LOB.getlength (v_blob) v_len,
image_id v_lob_image_id,
"IMAGE_NAME" v_lob_image_name,
image v_blob
FROM sys.MY_IMAGES)
LOOP
v_chunksize := DBMS_LOB.getchunksize (i.v_blob);
IF (v_chunksize < 32767)
THEN
v_buffer_size := v_chunksize;
ELSE
v_buffer_size := 32767;
END IF;
v_amount := v_buffer_size;
DBMS_LOB.open (i.v_blob, DBMS_LOB.lob_readonly);
v_out_file :=
UTL_FILE.fopen (
location => 'IMAGE_DIR',
filename => ( ''
|| i.v_lob_image_id
|| '_'
|| i.v_lob_image_name
|| '.JPG'),
open_mode => 'wb',
max_linesize => 32767);
WHILE v_amount >= v_buffer_size
LOOP
DBMS_LOB.read (i.v_blob,
v_amount,
v_offset,
v_buffer);
v_offset := v_offset + v_amount;
UTL_FILE.put_raw (file => v_out_file,
buffer => v_buffer,
autoflush => TRUE);
UTL_FILE.fflush (file => v_out_file);
--utl_file.new_line(file => v_out_file);
END LOOP;
UTL_FILE.fflush (v_out_file);
UTL_FILE.fclose (v_out_file);
DBMS_LOB.close (i.v_blob);
END LOOP;
END;
The main problem is related NOT to re-initialize the parameter v_offset to 1 ( as in the declaration section ) :
v_offset := 1;
for every image id just before
v_chunksize := dbms_lob.getchunksize(i.v_blob);
assignment.
Moreover, the problem may arise about not yet closed or already opened blobs. To prevent these,
replace
dbms_lob.open(i.v_blob,dbms_lob.lob_readonly);
with
if ( dbms_lob.isopen(i.v_blob)=0 ) then
dbms_lob.open(i.v_blob,dbms_lob.lob_readonly);
end if;
and
replace
dbms_lob.close(i.v_blob);
with
if ( dbms_lob.isopen(i.v_blob)=1 ) then
dbms_lob.close(i.v_blob);
end if;

plsql reading text file in an array

When I run this portion of my code, which is inside a package, I get an error (specifically at the l_cnt := 1_cnt + 1 line for some reason and the code crashes. What could I be doing wrong? I am trying to read in a file of certs. Here's what I have so far:
v_certList arr_claims_t := arr_claims_t();
v_certLst VARCHAR2(2000);
f UTL_FILE.FILE_TYPE;
s VARCHAR2(200);
-- used for looping
l_cnt simple_integer := 0;
/*cop procedure*/
PROCEDURE COP_DATALOAD_V2 AS
arr_claims arr_claims_t;
arr_sql arr_sql_t;
BEGIN
f := UTL_FILE.FOPEN('V_COP',
'certs_file.txt',
'R',
2500);
-- populata our v_certlist of arr_claims_t
loop
utl_file.get_line(f, s);
v_certList.extend();
l_cnt := l_cnt+1;
v_certList(l_cnt) := s;
end loop;
exception
when no_data_found then
utl_file.fclose(f);
I want the array to be succesfuly populated given a text file (and I understand this is not the best practice but this is what I will have to do for now)
I figured out the error! The s that it was reading in was too big for the array. This was because empty spaces in the files was included.
v_certList.extend(1);
l_cnt := l_cnt + 1;
v_certList(l_cnt) := substr(s,
0,
10)
This fixed it for me.

Oracle - measure time of reading blob files using sql

ive got a problem for which i couldnt find answwer so far.
Is there a way to read blob file from oracle table using sql or pl/sql and measure time of reading it? I mean like reading whole of it, i dont need it displayed anywhere. All i found was to read 4000 bytes of file but thats not enough.
For importing there is simply
SET TIMING ON and OFF option in sqlplus but using select on tablle gives only small portion of file and doesnt matter how big it is, it always takes the same time pretty much.
Any help anybody?
Not quite sure what you're trying to achieve, but you can get some timings in a PL/SQL block using dbms_utility.get_time as LalitKumarB suggested. The initial select is (almost) instant though, it's reading through or processing the data that's really measurable. This is reading a blob with three different 'chunk' sizes to show the difference it makes:
set serveroutput on
declare
l_start number;
l_blob blob;
l_byte raw(1);
l_16byte raw(16);
l_kbyte raw(1024);
begin
l_start := dbms_utility.get_time;
select b into l_blob from t42 where rownum = 1; -- your own query here obviously
dbms_output.put_line('select: '
|| (dbms_utility.get_time - l_start) || ' hsecs');
l_start := dbms_utility.get_time;
for i in 1..dbms_lob.getlength(l_blob) loop
l_byte := dbms_lob.substr(l_blob, 1, i);
end loop;
dbms_output.put_line('single byte: '
|| (dbms_utility.get_time - l_start) || ' hsecs');
l_start := dbms_utility.get_time;
for i in 1..(dbms_lob.getlength(l_blob)/16) loop
l_16byte := dbms_lob.substr(l_blob, 16, i);
end loop;
dbms_output.put_line('16 bytes: '
|| (dbms_utility.get_time - l_start) || ' hsecs');
l_start := dbms_utility.get_time;
for i in 1..(dbms_lob.getlength(l_blob)/1024) loop
l_kbyte := dbms_lob.substr(l_blob, 1024, i);
end loop;
dbms_output.put_line('1024 bytes: '
|| (dbms_utility.get_time - l_start) || ' hsecs');
end;
/
For a sample blob that gives something like:
anonymous block completed
select: 0 hsecs
single byte: 950 hsecs
16 bytes: 61 hsecs
1024 bytes: 1 hsecs
So clearly reading the blob in larger chunks is more efficient. So your "measure time of reading it" is a bit flexible...
I guess you already have the solution to access the BLOB data. For getting the time, use DBMS_UTILITY.GET_TIME before and after the step in your PL/SQL code. You could declare two variables, start_time and end_time to capture the respective times, and just subtract them to get the time elapsed/taken for the step.
See this as an example, http://www.oracle-base.com/articles/11g/plsql-new-features-and-enhancements-11gr1.php