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;
/
Related
I am using UTL_FILE to extract output from the .csv file and trying to append the gender to the already existing file data. But in everyway I tried I am unable to get the expected output. Need quick help on this.
Actual File (Details.csv):
Name,Country,State,City
Lina,Brazil,Bahia,Salvador
John,USA,Texas,Austin
Ashton,Australia,Tasmania,Hobart
My output:
Name,Country,State,City
,Gender
Lina,Brazil,Bahia,Salvador
,Female
John,USA,Texas,Austin
,Male
Ashton,Australia,Tasmania,Hobart
,Male
Expected Output (Details_upd.csv):
Name,Country,State,City,Gender
Lina,Brazil,Bahia,Salvador,Female
John,USA,Texas,Austin,Male
Ashton,Australia,Tasmania,Hobart,Male
------Code--------
DECLARE
f_line VARCHAR2 (32767);
file_1 UTL_FILE.file_type;
file_2 UTL_FILE.file_type;
f_dir VARCHAR2 (25) := 'DATA';
L_check_UPDATED BOOLEAN;
l_line VARCHAR2(32767);
BEGIN
file_1 := UTL_FILE.fopen (f_dir,'Details.csv','R');
file_2 := UTL_FILE.fopen (f_dir,'Details_upd.csv', 'W');
UTL_FILE.get_line (file_1, f_line);
l_line := trim(f_line);
UTL_FILE.PUT_LINE(file_2,l_line||','||'Gender');
LOOP
L_check_UPDATED := TRUE;
/*--omitting the LOGIC part of code--*/
IF (L_check_UPDATED) THEN
l_line := trim(f_line);
UTL_FILE.PUT(file_2,l_line||',Male');
ELSE
l_line := trim(f_line);
UTL_FILE.PUT_LINE(file_2,l_line||',Female');
END IF;
END LOOP;
UTL_FILE.fclose (file_1);
UTL_FILE.fclose (file_2);
END;
You will need to strip off the new-line character at the end of the string that you have read using GET_LINE. Try:
l_line := rtrim (f_line, ' ' || CHR (10) || CHR (13))
Most likely your oracle is unix (line terminator character is chr(10)) and your file is binary transferred windows (line terminator chr(13)+chr(10))
And after utl_file read chr(13) is left over. You can use dump function to analyze the contents of the buffer.
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;
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.
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
I am new to PL/SQL... In Varray how can i get multiple value from IN parameter..... else Is there another ways to get the values...
I want to interate the values through VArray... if any other options then its fine..
coding:
CREATE OR REPLACE
PROCEDURE dynamic_query_build(
vr_plan_sku_id IN VARCHAR2 )
IS
type plan_sku_id_array IS VARRAY(999) OF VARCHAR2(5000);
plan_sku_id plan_sku_id_array;
total INTEGER;
vrx_plan_sku_id VARCHAR2(3000);
BEGIN
vrx_plan_sku_id:= REPLACE(vr_plan_sku_id,',',chr(39)||','||chr(39));
plan_sku_id := plan_sku_id_array(chr(39)||vrx_plan_sku_id||chr(39));
total := plan_sku_id.count;
FOR i IN 1 .. total
LOOP
dbms_output.put_line(plan_sku_id(i));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END dynamic_query_build;
Execution:
set serveroutput on;
declare
vr_plan_sku_id varchar2(200) := '5863314,5863315';
BEGIN
dynamic_query_build(vr_plan_sku_id);
END;
/
My Output:
anonymous block completed
'5863314','5863315'
Expected output:
5863314
5863315
now it is considering as single value....
I created anonymous block with procedure dynamic_query_build. Added there code, that will split VARCHAR2 variable into varray.
I think, the key to your question is this line - plan_sku_id.EXTEND();
You can extend varray dynamically, but only till it reaches defined maximum (in your case - 999).
DECLARE
vr_plan_sku_id varchar2(200) := '5863314,5863315';
PROCEDURE dynamic_query_build(
vr_plan_sku_id IN VARCHAR2 )
IS
type plan_sku_id_array IS VARRAY(999) OF VARCHAR2(5000);
plan_sku_id plan_sku_id_array;
total INTEGER;
position PLS_INTEGER := 0;
last_position PLS_INTEGER := 1;
tmp VARCHAR2(5000);
counter PLS_INTEGER := 1;
BEGIN
plan_sku_id := plan_sku_id_array();
LOOP
position := INSTR(vr_plan_sku_id, ',', last_position);
IF position > 0 THEN
tmp := SUBSTR(vr_plan_sku_id, last_position, position - last_position);
last_position := position + 1;
ELSE
tmp := SUBSTR(vr_plan_sku_id, last_position);
END IF;
plan_sku_id.EXTEND();
plan_sku_id(counter) := tmp;
counter := counter + 1;
EXIT WHEN position = 0 OR counter > 10;
END LOOP;
total := plan_sku_id.count;
FOR i IN 1 .. total
LOOP
dbms_output.put_line(plan_sku_id(i));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END dynamic_query_build;
BEGIN
dynamic_query_build(vr_plan_sku_id);
END;
/
Put a replace in the dbms_output statement this will eliminate the quotes from the string
....
dbms_output.put_line replace (replace (plan_sku_id(i), '''' ))',',chr(10);
.....