I'm thinking about is it whether possible to write Oracle blobs to OS files. On first glance it is possible only using external procedures but may be something changed....
How to save a BLOB to a file on disk in PL/SQL From: Thomas Kyte
Use DBMS_LOB to read from the BLOB
You will need to create an external procedure to take binary data and
write it to the operating system, the external procedure can be
written in C. If it was CLOB data, you can use UTL_FILE to write it to
the OS but UTL_FILE does not support the binary in a BLOB.
Migrations of files from table to OS files de SO, using DB Job
Example base on table fou_archvos, it has files on column "archivo", id+nombre will be concatenated.
SQL> desc fou_archvos
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
NOMBRE NOT NULL VARCHAR2(300)
ACTIVO NOT NULL CHAR(1)
ARCHIVO BLOB
Create a folder on OS, it should have permission OS Oracle user owner.
su - oracle
mkdir /tmp/fou_archvo
Create a directory object on DB, eg TUKLI_FOU_ARCHVOS, grant permission to a scheme where be the procedure, eg PROD.
connect system/***#DB
CREATE OR REPLACE DIRECTORY TUKLI_FOU_ARCHVOS AS '/tmp/fou_archvos';
GRANT READ, WRITE ON DIRECTORY TUKLI_FOU_ARCHVOS TO PROD;
Crear el TU24X7_ARCHVES_TO_OSFILE.prc en PROD scheme, object
CREATE or replace PROCEDURE TU24X7_ARCHVES_TO_OSFILE(p_from_id number default null )
as
l_file UTL_FILE.FILE_TYPE;
l_buffer RAW(32767);
l_amount BINARY_INTEGER := 32767;
l_pos INTEGER;
--l_blob BLOB;
l_blob_len INTEGER;
l_id varchar2(10);
BEGIN
FOR rFile IN (SELECT archivo, to_char(id)||'_'||nombre filename
FROM fou_archvos
where 1=1
and id >= nvl(p_from_id,id)
)
LOOP
l_pos := 1;
l_blob_len := DBMS_LOB.getlength(rFile.archivo);
l_file := UTL_FILE.fopen('TUKLI_FOU_ARCHVOS',rFile.filename,'wb', 32767);
WHILE l_pos <= l_blob_len LOOP
DBMS_LOB.read(rFile.archivo, l_amount, l_pos, l_buffer);
UTL_FILE.put_raw(l_file, l_buffer, TRUE);
l_pos := l_pos + l_amount;
END LOOP;
-- Close the file.
UTL_FILE.fclose(l_file);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
-- Close the file if something goes wrong.
IF UTL_FILE.is_open(l_file) THEN
UTL_FILE.fclose(l_file);
END IF;
RAISE;
END;
/
Execure using JOB DB
connect PROD/XX#DB
declare
l_jobid number := null;
begin
dbms_job.submit
(
job => l_jobid,
what => 'TU24X7_ARCHVES_TO_OSFILE;',
next_date => sysdate,
interval => null
);
commit;
end;
/
Related
Good Day
i have a database which allows the user to upload documents from the system and store the document on the sever which is access by a url as seen below.
Procedure
create or replace PROCEDURE blob_to_file (p_blob IN OUT NOCOPY BLOB,
p_dir IN VARCHAR2,
p_filename IN VARCHAR2)
AS
l_file UTL_FILE.FILE_TYPE;
l_buffer RAW(32767);
l_amount BINARY_INTEGER := 32767;
l_pos INTEGER := 1;
l_blob_len INTEGER;
BEGIN
l_blob_len := DBMS_LOB.getlength(p_blob);
-- Open the destination file.
l_file := UTL_FILE.fopen(p_dir, p_filename,'WB', 32767);
-- Read chunks of the BLOB and write them to the file until complete.
WHILE l_pos <= l_blob_len LOOP
DBMS_LOB.read(p_blob, l_amount, l_pos, l_buffer);
UTL_FILE.put_raw(l_file, l_buffer, TRUE);
l_pos := l_pos + l_amount;
END LOOP;
-- Close the file.
UTL_FILE.fclose(l_file);
EXCEPTION
WHEN OTHERS THEN
-- Close the file if something goes wrong.
IF UTL_FILE.is_open(l_file) THEN
UTL_FILE.fclose(l_file);
END IF;
RAISE;
/* WHEN UTL_FILE.invalid_operation THEN dbms_output.PUT_LINE('cannot open file invalid name');
WHEN UTL_FILE.read_error THEN dbms_output.PUT_LINE('cannot be read');
WHEN no_data_found THEN dbms_output.PUT_LINE('end of file');
UTL_FILE.fclose(l_file);
RAISE;*/
END blob_to_file;
Insert statement to table
DECLARE
l_blob BLOB;
VID NUMBER;
BEGIN
select BLOB_CONTENT INTO l_blob FROM apex_application_temp_files
where NAME= :P48_BLOB_CONTENT ;
blob_to_file(p_blob => l_blob,
p_dir => 'STOCK_DIRECTORY',
p_filename => :P48_ATTACHMENT_NAME||'.pdf')
;
INSERT INTO ATTACHMENTS(ATTACHMENTS_ID, ATTACHMENT_NAME,CASE_ID,DATE_CREATED, MIME_TYPE,designation)
VALUES("ATTACHMENTS_SEQ".nextval,:P48_ATTACHMENT_NAME,:P48_CASE_ID,SYSDATE,'application/pdf','http://192.168.XXX.XXX:80/oracle_projects/dppcms/files/'||:P48_ATTACHMENT_NAME||'.pdf');
END;
What i will like however is to not move the document via the above procedure but to actual store in the attachment table the path of the original file.
so for example if a file is uploaded from the user my documents folder the path stored in the attachment table should show :c\users\mydocuments ect. instead of using the procedure to send it to http://192.168.XXX.XXX:80 etc
I'm really green. I want to extract images (JPGs) from Oracle PDB. Table Looks something like this:
select * from BOB.USER_ID t
LINK_ID ID_SCAN
1 340101001 <BLOB>...
2 340101002 <BLOB>...
3 340101003 <BLOB>...
4 340101004 <BLOB>...
5 ...
If possible, I want to extract them, with LINK_ID names (340101001.jpg).
I can extract them one-by-one, but there are ~5000 images... I would love to do it with some command or something...
I've looked for solution, but things that I could understand a little, they didn't work.
Thank you and sorry for inconvenience.
I tried to do "cart" method,? but it didn't work out. I couldn't open files that were extracted. I also tried third-party software, OraLobEditor.
Other then that, I could not understand codes and commands, I found in internet.
I'm trying to use SQL and PL/SQL Developer.
Here's a package that has a bunch of file utilities that all work with Oracle DIRECTORY objects and the files within them. With this and some PL/SQL, you could easily extract BLOB's to files at the OS level. The procedure you're going to want to work with is blob_into_file. But you need to start by creating an Oracle directory object, which points to the location on the OS that you want to save the files. Note that the directory needs to be writable by the same OS user that the database is running as.
Example, where MY_IMAGES is the Oracle directory object, and '/tmp/my_images' is the directory on the filesystem, wriable by the user running the database - "oracle", for example.
Create or replace directory MY_IMAGES as '/tmp/my_images';
Grant read, write on directory MY_IMAGES to BOB;
Next, a simple loop that will write the objects to the OS after you've compiled the fileutils package provided below. This can be run via SQL*Plus or SQL-Developer.
--
-- This is the code that does the export of the images
--
Set serveroutput on;
Begin
For i in (Select link_id, id_scan from bob.user_id) loop
dbms_output.put_line('Exporting image '||i.link_id||'.jpg');
fileutils.blob_into_file('MY_IMAGES',i.link_id||'.jpg',i.id_scan);
End loop;
End;
/
Package spec
Create or replace package fileutils as
--
-- This procedure deletes a file, and depends on an Oracle DIRECTORY object being passed
--
Procedure delete_os_file (i_directory varchar2, i_filename varchar2);
--
-- This procedure moves and optionally renames a file,
-- and depends on an Oracle DIRECTORY object being passed
--
Procedure move_os_file ( i_source_directory in varchar2, i_source_file in varchar2, i_target_directory in varchar2, i_target_file in varchar2);
--
-- This procedure takes a blob variable and writes it to a file,
-- and depends on an Oracle DIRECTORY object being passed
--
Procedure blob_into_file (i_directory in varchar2, i_file_name in varchar2, i_blob in blob);
--
-- This procedure takes a file and uploads it into a blob variable
-- and depends on an Oracle DIRECTORY object being passed
--
Procedure file_into_blob(i_directory in varchar2, i_file_name in varchar2, o_blob out blob);
--
-- This procedure converts a clob to a blob
--
Procedure convert_clob_to_blob (i_clob in clob, o_blob out blob);
--
-- This procedure converts a blob to a clob
--
Procedure convert_blob_to_clob (i_blob in blob, o_clob out clob);
--
-- This one checks for file existence without Java
--
Function file_exists (i_directory in varchar2, i_filename in varchar2) return boolean;
--
-- Returns the basename of a filename
-- Works with Windows and UNIX pathnames
--
Function basename (i_filename in varchar2) return varchar2;
--
-- This takes a Base64 string and converts it to a binary BLOB
--
Procedure base64_string_to_blob (i_clob in clob, o_blob out blob);
Function base64_string_to_blob (i_clob in clob) return blob;
--
-- This takes a binary BLOB and converts it to a Base64 string
--
Procedure blob_to_base64_string (i_blob in blob, o_clob out clob);
Function blob_to_base64_string (i_blob in blob) return clob;
End fileutils;
/
Show error;
Package body
Set define off;
Create or replace package body fileutils as
Procedure delete_os_file (i_directory varchar2, i_filename varchar2)
is
Begin
utl_file.fremove(i_directory,i_filename);
End;
Procedure move_os_file
(
i_source_directory in varchar2,
i_source_file in varchar2,
i_target_directory in varchar2,
i_target_file in varchar2
)
is
srcdir varchar2(255) := upper(i_source_directory);
tgtdir varchar2(255) := upper(i_target_directory);
begin
--
-- NOTE: If you're getting the all-too-familiar
-- ORA-29292: file rename operation failed
-- and you're SURE that your directory names are correct,
-- and you're SURE that your privileges are correct, both at the
-- OS level, and within the database, there's one last thing that
-- can get you. I learned the hard way that this command will NOT
-- work successfully renaming a file from one filesystem to another,
-- at least when those filesystems are NFS mounted. That is all.
--
utl_file.frename(srcdir,i_source_file,tgtdir,i_target_file,TRUE);
end move_os_file;
Procedure blob_into_file (i_directory in varchar2, i_file_name in varchar2, i_blob in blob)
is
l_file utl_file.file_type;
l_buffer raw(32767);
l_amount binary_integer := 32767;
l_pos integer := 1;
i_blob_len integer;
Begin
i_blob_len := dbms_lob.getlength(i_blob);
l_pos:= 1;
-- Open the destination file.
l_file := utl_file.fopen(i_directory,i_file_name,'wb', 32767);
-- Read chunks of the BLOB and write them to the file
-- until complete.
while l_pos < i_blob_len loop
dbms_lob.read(i_blob, l_amount, l_pos, l_buffer);
utl_file.put_raw(l_file, l_buffer, TRUE);
l_pos := l_pos + l_amount;
end loop;
-- Close the file.
utl_file.fclose(l_file);
End blob_into_file;
Procedure file_into_blob(i_directory in varchar2, i_file_name in varchar2, o_blob out blob)
is
src_loc bfile := bfilename(i_directory, i_file_name);
Begin
-- Initialize the dest blob
o_blob := empty_blob();
-- Open source binary file from OS
dbms_lob.open(src_loc, dbms_lob.lob_readonly);
-- Create temporary LOB object
dbms_lob.createtemporary(
lob_loc => o_blob
, cache => true
, dur => dbms_lob.session
);
-- Open temporary lob
dbms_lob.open(o_blob, dbms_lob.lob_readwrite);
-- Load binary file into temporary LOB
dbms_lob.loadfromfile(
dest_lob => o_blob
, src_lob => src_loc
, amount => dbms_lob.getLength(src_loc));
-- Close lob objects
dbms_lob.close(o_blob);
dbms_lob.close(src_loc);
End file_into_blob;
Function basename (i_filename in varchar2) return varchar2
is
v_basename varchar2(1024);
Begin
--
-- If the regex's below don't match, then it's already at its base name
-- Return what was passed.
--
v_basename := i_filename;
if regexp_like(i_filename,'^.*\\') then
dbms_output.put_line('This is a Windows file');
v_basename := regexp_substr(i_filename,'[^\]*$');
dbms_output.put_line('Basename is : '||v_basename);
end if;
if regexp_like(i_filename,'^/') then
dbms_output.put_line('This is a UNIX file');
v_basename := regexp_substr(i_filename,'[^/]*$');
dbms_output.put_line('Basename is : '||v_basename);
end if;
return v_basename;
End basename;
Function file_exists (i_directory in varchar2, i_filename in varchar2) return boolean
is
v_exists boolean;
v_file_length number;
v_block_size number;
Begin
utl_file.fgetattr(upper(i_directory), i_filename, v_exists, v_file_length, v_block_size);
if (v_exists) then
dbms_output.put_line('File '||i_filename||' exists, '||v_file_length||' bytes');
else
dbms_output.put_line('File '||i_filename||' does not exist');
end if;
return v_exists;
end file_exists;
Procedure convert_clob_to_blob (i_clob in clob, o_blob out blob)
is
v_in pls_Integer := 1;
v_out pls_Integer := 1;
v_lang pls_Integer := 0;
v_warning pls_Integer := 0;
Begin
dbms_lob.createtemporary(o_blob,TRUE);
dbms_lob.converttoblob(o_blob,i_clob,DBMS_lob.getlength(i_clob),v_in,v_out,dbms_lob.default_csid,v_lang,v_warning);
End convert_clob_to_blob;
Procedure convert_blob_to_clob (i_blob in blob, o_clob out clob)
is
v_in pls_Integer := 1;
v_out pls_Integer := 1;
v_lang pls_Integer := 0;
v_warning pls_Integer := 0;
Begin
dbms_lob.createtemporary(o_clob,TRUE);
dbms_lob.converttoclob(o_clob,i_blob,DBMS_lob.getlength(i_blob),v_in,v_out,dbms_lob.default_csid,v_lang,v_warning);
End convert_blob_to_clob;
Procedure blob_to_base64_string (i_blob in blob, o_clob out clob)
is
v_out_cl clob;
file_len pls_integer;
modulo pls_integer;
pieces pls_integer;
amt binary_integer := 23808;
buf raw (32767);
buf_tx varchar2(32767);
pos pls_integer := 1;
filepos pls_integer := 1;
counter pls_integer := 1;
Begin
dbms_lob.createtemporary (v_out_cl, true, dbms_lob.call);
file_len := dbms_lob.getlength (i_blob);
modulo := mod (file_len, amt);
pieces := trunc (file_len / amt);
while (counter <= pieces) loop
dbms_lob.read (i_blob, amt, filepos, buf);
buf_tx:=utl_raw.cast_to_varchar2 (utl_encode.base64_encode (buf));
dbms_lob.writeappend (v_out_cl,length(buf_tx),buf_tx);
filepos := counter * amt + 1;
counter := counter + 1;
end loop;
if (modulo <> 0) THEN
dbms_lob.read (i_blob, modulo, filepos, buf);
buf_tx:=utl_raw.cast_to_varchar2 (utl_encode.base64_encode (buf));
dbms_lob.writeappend (v_out_cl,length(buf_tx),buf_tx);
end if;
o_clob := v_out_cl;
End blob_to_base64_string;
Function blob_to_base64_string (i_blob in blob) return clob
is
v_out_cl clob;
file_len pls_integer;
modulo pls_integer;
pieces pls_integer;
amt binary_integer := 23808;
buf raw (32767);
buf_tx varchar2(32767);
pos pls_integer := 1;
filepos pls_integer := 1;
counter pls_integer := 1;
Begin
dbms_lob.createtemporary (v_out_cl, true, dbms_lob.call);
file_len := dbms_lob.getlength (i_blob);
modulo := mod (file_len, amt);
pieces := trunc (file_len / amt);
while (counter <= pieces) loop
dbms_lob.read (i_blob, amt, filepos, buf);
buf_tx:=utl_raw.cast_to_varchar2 (utl_encode.base64_encode (buf));
dbms_lob.writeappend (v_out_cl,length(buf_tx),buf_tx);
filepos := counter * amt + 1;
counter := counter + 1;
end loop;
if (modulo <> 0) THEN
dbms_lob.read (i_blob, modulo, filepos, buf);
buf_tx:=utl_raw.cast_to_varchar2 (utl_encode.base64_encode (buf));
dbms_lob.writeappend (v_out_cl,length(buf_tx),buf_tx);
end if;
return v_out_cl;
End blob_to_base64_string;
Procedure base64_string_to_blob (i_clob in clob, o_blob out blob)
is
v_out_bl blob;
clob_size number;
pos number;
charBuff varchar2(32767);
dBuffer RAW(32767);
v_readSize_nr number;
v_line_nr number;
begin
dbms_lob.createTemporary (v_out_bl, true, dbms_lob.call);
v_line_nr:=greatest(65, instr(i_clob,chr(10)), instr(i_clob,chr(13)));
v_readSize_nr:= floor(32767/v_line_nr)*v_line_nr;
clob_size := dbms_lob.getLength(i_clob);
pos := 1;
while (pos < clob_size) loop
dbms_lob.read (i_clob, v_readSize_nr, pos, charBuff);
dBuffer := UTL_ENCODE.base64_decode (utl_raw.cast_to_raw(charBuff));
dbms_lob.writeAppend (v_out_bl,utl_raw.length(dBuffer),dBuffer);
pos := pos + v_readSize_nr;
end loop;
o_blob := v_out_bl;
end base64_string_to_blob;
Function base64_string_to_blob (i_clob in clob) return blob
is
v_out_bl blob;
clob_size number;
pos number;
charBuff varchar2(32767);
dBuffer RAW(32767);
v_readSize_nr number;
v_line_nr number;
begin
dbms_lob.createTemporary (v_out_bl, true, dbms_lob.call);
v_line_nr:=greatest(65, instr(i_clob,chr(10)), instr(i_clob,chr(13)));
v_readSize_nr:= floor(32767/v_line_nr)*v_line_nr;
clob_size := dbms_lob.getLength(i_clob);
pos := 1;
while (pos < clob_size) loop
dbms_lob.read (i_clob, v_readSize_nr, pos, charBuff);
dBuffer := UTL_ENCODE.base64_decode (utl_raw.cast_to_raw(charBuff));
dbms_lob.writeAppend (v_out_bl,utl_raw.length(dBuffer),dBuffer);
pos := pos + v_readSize_nr;
end loop;
return v_out_bl;
end base64_string_to_blob;
end fileutils;
/
Show error;
I'm currently using this code to generate an XLS file from a query in Oracle PL/SQL saving a file with HTML tags using this code.
CREATE OR REPLACE PROCEDURE GENERATE_XLS(querie VARCHAR2) IS
v_file VARCHAR2 (20) := 'TEST-EXCEL.xls';
v_directory VARCHAR2 (60) := 'C:\';
p_write LIB_FILES.file_type;
v_sql varchar2(32767) := 'SELECT LASTNAME, NAME, ID
FROM DUAL';
header VARCHAR(1000) := '<html> <head><center><B><U> TEST XLS </U></B></center>
<table></tr><tr><th>LASTNAME</th><th>NAME</th><th>ID</th></tr>';
BEGIN
p_write := LIB_FILES.fopen (v_directory, v_file, 'W');
LIB_FILES.put_line (p_write, header);
FOR REGISTRY IN querie LOOP
LIB_FILES.put_line (p_write,'<tr><td>'||REGISTRY.LASTNAME||'</td><td>'||REGISTRY.NAME||'</td><td>'||REGISTRY.ID||'</td></tr>');
END LOOP;
LIB_FILES.put_line (p_write,'</table>');
LIB_FILES.fflush (p_write);
LIB_FILES.fclose (p_write);
END;
This is working right now, but I need to add to this procedure a parameter, which is an SQL query, and then generate the file based on the query
I'm currently use this code to get the columns name
CREATE OR REPLACE PROCEDURE GET_COLUMNS IS
v_cursor_id integer;
v_col_cnt integer;
v_columns dbms_sql.desc_tab;
v_sql varchar2(3000) :='SELECT LASTNAME, NAME, ID FROM DUAL';
header VARCHAR(1000):='<html> <head><center><B><U> TEST XLS </U></B></center>
<table></tr><tr>';
begin
v_cursor_id := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor_id, v_sql, dbms_sql.native);
dbms_sql.describe_columns(v_cursor_id, v_col_cnt, v_columns);
for i in 1 .. v_columns.count loop
header := header || '<th>'|| v_columns(i).col_name ||'</th>';
end loop;
header := header || '</tr>';
dbms_sql.close_cursor(v_cursor_id);
exception when others then
dbms_sql.close_cursor(v_cursor_id);
raise;
end;
But here I'm facing the same issue, I need to make this procedures works with dynamic queries coming from a parameter instead of declaring the query in the procedure.
How can I achieve this?
I don't have oracle installed , as of my knowledge I gave these details ... check and verify this
CREATE OR REPLACE PROCEDURE GET_COLUMNS (p_sql IN VARCHAR2 , p_header IN VARCHAR2)
IS
v_cursor_id integer;
v_col_cnt integer;
v_columns dbms_sql.desc_tab;
v_sql varchar2(3000) := p_sql;
header VARCHAR(1000):= p_header;
begin
v_cursor_id := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor_id, v_sql, dbms_sql.native);
dbms_sql.describe_columns(v_cursor_id, v_col_cnt, v_columns);
for i in 1 .. v_columns.count loop
header := header || '<th>'|| v_columns(i).col_name ||'</th>';
end loop;
header := header || '</tr>';
dbms_sql.close_cursor(v_cursor_id);
exception when others then
dbms_sql.close_cursor(v_cursor_id);
raise;
end;
To execute
Execute GET_COLUMNS ('SELECT LASTNAME, NAME, ID FROM DUAL','<html> <head><center><B><U> TEST XLS </U></B></center>
<table></tr><tr>');
If you define your query as a ref cursor instead of a string, e.g.
open your_refcursor for select * from dual;
then you can convert it to a dbms_sql cursor ID using
v_cursor_id := dbms_sql.to_cursor_number(your_refcursor);
Here is one I wrote earlier:
http://www.williamrobertson.net/documents/refcursor-to-csv.shtml
I suggest read the following article, about a package to create Excel files from Oracle:
Create an Excel-file with PL/SQL
..
FILE1 := UTL_FILE.FOPEN('DIR','cg.csv','w',32000);
..
we are generating a csv file which has concatenated value of many columns of a view.
Is there any way to use the utl_file to generate a csv from data more than 32000 in oracle plsql
declare
FILEHANDLE UTL_FILE.FILE_TYPE;
WRITEMESSAGE varchar2(200);
longLine varchar2(32767);
newline char(2) := CHR(13) || CHR(10);
begin
longLine := LPAD('aaaa', 32766,'x');
FILEHANDLE := UTL_FILE.FOPEN('XMLDIR','lonLineFile.txt','wb',32767);
for i in 1 .. 5 loop
UTL_FILE.PUT_RAW (filehandle,UTL_RAW.CAST_TO_RAW (longLine),true);
UTL_FILE.PUT_RAW (filehandle,UTL_RAW.CAST_TO_RAW (longLine),true);
UTL_FILE.PUT_RAW (filehandle,UTL_RAW.CAST_TO_RAW (longLine),true);
UTL_FILE.PUT_RAW (filehandle,UTL_RAW.CAST_TO_RAW (newline),true);
end loop;
UTL_FILE.FCLOSE(filehandle);
end;
/
Open file in 'wb' write byte mode. Next write raw to file and end of line char.
According to Oracle's documentation for the function UTL_FILE.FOPEN:
FOPEN max_linesize parameter must be a number in the range 1 and 32767
so you can increase it to 32767, but not further then that.
You might want to consider creating multiple files.
Yes there is a way - use clob data type instead of varchar2. clob maximum size in PL/SQL is 128TB.
In your PL/SQL code first collect data to a temporary clob. Second iterate the clob in chunks and feed those to utl_file.
Below is a random internet code snippet that writes an arbitrary clob to a user defined file:
procedure save (
p_text in clob,
p_path in varchar2,
p_filename in varchar2
) as
v_lob_temp blob;
begin
--
-- exit if any parameter is null
--
if p_text is null
or p_path is null
or p_filename is null then
return;
end if;
--
-- convert a clob to a blob
--
declare
v_dest_offset pls_integer := 1;
v_src_offset pls_integer := 1;
v_lang_context pls_integer := dbms_lob.default_lang_ctx;
v_warning pls_integer := dbms_lob.no_warning;
begin
dbms_lob.createtemporary(lob_loc => v_lob_temp,
cache => true,
dur => dbms_lob.call);
dbms_lob.converttoblob(dest_lob => v_lob_temp,
src_clob => p_text,
amount => dbms_lob.lobmaxsize,
dest_offset => v_dest_offset,
src_offset => v_src_offset,
blob_csid => dbms_lob.default_csid,
lang_context => v_lang_context,
warning => v_warning);
-- TODO raise (what?) when warning
end;
--
-- write a blob to a file
--
declare
v_lob_len pls_integer;
v_fh utl_file.file_type;
v_pos pls_integer := 1;
v_buffer raw(32767);
v_amount pls_integer := 32767;
begin
v_fh := utl_file.fopen(p_path, p_filename, 'wb', 32767);
v_lob_len := dbms_lob.getlength(v_lob_temp);
while v_pos < v_lob_len loop
dbms_lob.read(v_lob_temp, v_amount, v_pos, v_buffer);
utl_file.put_raw(file => v_fh,
buffer =>v_buffer,
autoflush => false);
v_pos := v_pos + v_amount;
end loop;
utl_file.fclose(v_fh);
dbms_lob.freetemporary(v_lob_temp);
end;
end;
Problem:
I'm new to Oracle, and I think I'm missing some basic knowledge that is causing my temp tablespace to fill up.
I'm opening a connection to my database and running a pl/sql procedure multiple times to insert rows. Each time I run the procedure, the number of free blocks decreases in my TEMP tablespace. When the number of free blocks gets too low, the procedure will fail with the error "ORA-01652 - unable to extend temp segment by 4096 in tablespace". If I close the database connection, the free blocks in the TEMP tablespace resets to the total number of blocks, and I can continue rerunning the procedure. How do I free up the TEMP tablespace blocks without having to close and open the database? I thought I needed to add a commit statement, but that didn't help.
Thanks
Code:
Query to check free_MB (this decreases each time I run the procedure).
SELECT tablespace_name,
total_blocks,
used_blocks,
free_blocks,
total_blocks*16/1024 as total_MB,
used_blocks*16/1024 as used_MB,
free_blocks*16/1024 as free_MB
FROM v$sort_segment;
SQL I run multiple times until free_mb reduces to 0 and I get errors:
DECLARE
p_samples LOG_ENTRY_ARRAY;
longSample clob;
BEGIN
For v_COUNTER IN 1..32767 LOOP
longSample := longSample || 'a';
END loop;
-- initialize the input
p_samples := LOG_ENTRY_ARRAY(longSample, 'short sample');
for i in 1..100 LOOP
INSERT_SUMMARY_SAMPLES('TABLE1', 1000, 1, 2, p_samples);
END loop;
commit;
END;
The procedure being called which does a bunch of inserts into two tables:
create or replace
PROCEDURE INSERT_SUMMARY_SAMPLES
(
p_TABLE_NAME IN VARCHAR2
, p_TS IN NUMBER
, p_SIGNATURE_ID IN NUMBER
, p_COUNT IN NUMBER
, p_SAMPLES IN LOG_ENTRY_ARRAY
) AS
tbl_summary varchar2(30);
tbl_samples varchar2(30);
summary_id number(10,0);
sample varchar2(32767);
BEGIN
tbl_summary := 'TBL_' || p_TABLE_NAME || '_SUMMARIES';
tbl_samples := 'TBL_' || p_TABLE_NAME || '_SAMPLES';
-- insert summary and get the id
EXECUTE IMMEDIATE 'INSERT INTO ' || tbl_summary
|| ' (agg_start_ts, signature_id, count, num_samples) VALUES (:a,:b,:c,:d) returning id into :1'
using p_ts, p_signature_id, p_count, p_SAMPLES.count returning into summary_id;
dbms_output.put_line('new summary_id is : ' || summary_id);
-- insert samples
FOR i in 1..p_SAMPLES.count LOOP
-- convert clob to varchar2
CLOB_TO_VARCHAR(p_SAMPLES(i),sample);
EXECUTE IMMEDIATE 'INSERT INTO ' || tbl_samples || ' (summary_id, log_entry) VALUES (:a,:b)' using summary_id, sample;
-- dbms_output.put_line('insert sample : ' || TO_CHAR(p_SAMPLES(i)));
END LOOP;
END INSERT_SUMMARY_SAMPLES;
CLOB_TO_VARCHAR is another procedure:
create or replace
PROCEDURE CLOB_TO_VARCHAR (
p_clob IN CLOB,
p_varchar OUT VARCHAR2
)
AS
v_output varchar2(32767);
l_amount BINARY_INTEGER := 32767;
l_pos INTEGER := 1;
l_clob_len INTEGER := 0;
BEGIN
l_clob_len := DBMS_LOB.getlength (p_clob);
WHILE l_pos < l_clob_len
LOOP
dbms_lob.READ(p_clob, l_amount, l_pos, v_output);
l_pos := l_pos + l_amount;
END LOOP;
p_varchar := v_output;
END CLOB_TO_VARCHAR;
Your TEMP table space is getting filled fast. You might need to increase the tablespace manually. Possible duplicate of ORA-01652 Unable to extend temp segment by in tablespace and
ORA-01652: unable to extend temp segment by 128 in tablespace SYSTEM: How to extend?
I would guess that you've got a temporary lob somewhere but it's not being explicitly freed. Where is LOG_ENTRY_ARRAY defined?