Oracle loop through CLOB to get string - oracle

I want to convert all data in CLOB to string. DBMC_LOB.SUBSTR provides a way to fetch 4000 characters at once. I am from MS SQL background and not aware of Oracle queries. Can someone help me with the syntax.
I want to make a function and do something like
// Get the length of CLOB
// totalIterationsRequired = length/4000;
// LOOP around the CLOB and fetch 4000 char at once
For i in 1..totalIterationsRequired
LOOP
// Insert the substring into a varchar2
// DBMC_LOB.SUBSTR(xml_value,4000*i,(4000*(i-1)+1)
END LOOP
// The function will return the varchar2

create table save_table(rec varchar2(4000));
create or replace PROCEDURE save_clob (p_clob IN CLOB)
AS
l_length INTEGER;
l_start INTEGER := 1;
l_recsize CONSTANT INTEGER := 4000;
BEGIN
l_length := DBMS_LOB.getlength (p_clob);
WHILE l_start <= l_length
LOOP
INSERT INTO save_table (rec)
VALUES (DBMS_LOB.SUBSTR (p_clob, l_recsize, l_start));
l_start := l_start + l_recsize;
END LOOP;
END save_clob;

Below is the function definition
create or replace function getclobastable (id IN VARCHAR2)
return clob_table
is
l_length INTEGER;
l_start INTEGER := 1;
l_recsize CONSTANT INTEGER := 4000;
i_clob CLOB;
n BINARY_INTEGER := 0;
save_table clob_table := clob_table();
BEGIN
save_table := clob_table();
-- Get the CLOB data into i_clob
l_length := DBMS_LOB.getlength (i_clob);
WHILE l_start <= l_length
LOOP
n := n + 1;
save_table.EXTEND();
save_table(n) := DBMS_LOB.SUBSTR (i_clob, l_recsize, l_start);
l_start := l_start + l_recsize;
END LOOP;
RETURN save_table;
END;

Related

How to pass a parameter of CLOB type to Oracle stored procedure which is having 100k+ length string?

Create procedure p(p1 clob) as
(
##code goes here..
);
exec p('100k+ length string...');
When I tried above procedure with 100k+ length string it is throwing ORA-20002: -20002:ORA-20002: -6502:ORA-06502: PL/SQL: numeric or value error\nORA-06512: at
How can we pass the value to the stored procedure?
Do we need to increase the db_block_size to increase the capacity of CLOB datatype?
You can pass the clob to the procedure just like other data types (on db<>fiddle):
create or replace procedure p (p1 clob) as
begin
dbms_output.put_line ('clob len='||length (p1));
end;
/
declare
c clob := '123';
begin
for i in 1..4 loop
dbms_lob.append (c, rpad ('A', 32767, 'A')); end loop;
p (c);
end;
/
clob len=131071
I think you are mistaken what a CLOB datatype can store with the procedure put_line of dbms_output
DBMS_OUTPUT.PUT_LINE ( item IN VARCHAR2);
The item is a varchar2 object. So, if you want to print the output of a clob greater than the limit of a varchar, you need to create a different kind of code. In my case, I use always the below code to print a clob column:
create or replace procedure print_clob_to_output (p_clob in clob)
is
l_offset pls_integer := 1;
l_chars pls_integer;
begin
loop
exit when l_offset > dbms_lob.getlength(p_clob);
l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
if l_chars is null or l_chars = 0 then
l_chars := dbms_lob.getlength(p_clob) + 1;
end if;
dbms_output.put_line(dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
l_offset := l_chars + 1;
end loop;
end print_clob_to_output;

Oracle - extract images from BLOB

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;

custom split function not working in pl/sql

I have written a custom function in pl/sql which splits a clob variable into set of strings on the basis of the separator provided but it is not working as intended please help me out in figuring the problem with the code.
create or replace
FUNCTION SPLITCLOB (p_in_string clob, p_delim VARCHAR2) RETURN t_array
IS
i number :=0;
pos number :=0;
lv_str clob := p_in_string;
Strings t_array:=t_array ();
Begin
-- determine first chuck of string
pos := DBMS_LOB.INSTR(lv_str,p_delim,1,1);
If ( pos = 0) Then
i := i + 1;
strings.Extend();
strings(i) := DBMS_LOB.SUBSTR(lv_str,1);
RETURN strings;
End If;
-- while there are chunks left, loop
WHILE ( pos != 0) LOOP
-- increment counter
i := i + 1;
-- create array element for chuck of string
strings.EXTEND();
strings(i) := DBMS_LOB.SUBSTR(lv_str,1,pos-1);
-- remove chunk from string
lv_str := DBMS_LOB.SUBSTR(lv_str,pos+1,dbms_lob.getLength(lv_str));
-- determine next chunk
pos := DBMS_LOB.INSTR(lv_str,p_delim,1,1);
-- no last chunk, add to array
IF pos = 0 THEN
strings.extend();
strings(i+1) := lv_str;
END IF;
End Loop;
-- return array
RETURN strings;
End Splitclob;
here t_array() is custom type defiition of which is provided below
create or replace
TYPE "T_ARRAY"
AS TABLE OF VARCHAR2(500);
thanks in advance
I've changed a piece of code I wrote not a long time ago and it seems it works as you want. Note: it will also work if there is only a single item in the input parameter (I mean, the situation when there is no separator in the input is covered).
CREATE OR REPLACE
TYPE T_ARRAY
AS TABLE OF VARCHAR2(500);
/
CREATE OR REPLACE FUNCTION splitclob (p_clob_in CLOB, p_delim VARCHAR2) RETURN t_array
AS
v_buffer VARCHAR2(500);
v_len NUMBER;
v_offset NUMBER := 1;
v_delim_pos NUMBER;
v_amount NUMBER;
v_result_array t_array := t_array();
BEGIN
IF p_clob_in IS NOT NULL THEN
v_len := dbms_lob.getlength(p_clob_in);
WHILE v_offset < v_len
LOOP
v_delim_pos := instr(p_clob_in, p_delim, v_offset);
IF v_delim_pos = 0 THEN
v_amount := v_len - v_offset + 1;
ELSE
v_amount := v_delim_pos - v_offset;
END IF;
dbms_lob.read(p_clob_in, v_amount, v_offset, v_buffer);
v_offset := v_offset + v_amount + 1;
v_result_array.EXTEND;
v_result_array(v_result_array.LAST) := v_buffer;
END LOOP;
END IF;
RETURN v_result_array;
END;
/
DECLARE
v_array t_array;
BEGIN
v_array := splitclob('order_id=383325; order_line_item=59; order_class_id=5749; subscription_code=5U12PFNCAU; start_date=01/12/2012; end_date=30/11/2013; date_override=null; license_available=-1; license_consumed=1; license_override=-1; order_class_status=0', ';');
FOR v_i IN v_array.first..v_array.last
LOOP
dbms_output.put_line(v_i || ' ' || v_array(v_i));
END LOOP;
END;
/
Output:
1 order_id=383325
2 order_line_item=59
3 order_class_id=5749
4 subscription_code=5U12PFNCAU
5 start_date=01/12/2012
6 end_date=30/11/2013
7 date_override=null
8 license_available=-1
9 license_consumed=1
10 license_override=-1
11 order_class_status=0
You have to take into account a situation when one of the tokens will be longer than 500 characters. Remember that VARCHAR2 datatype in SQL context has a 4000 bytes limitation. If you know there won't be tokens longer than that, then you don't have to change anything.

Procedure and function. Return one big string

I writing this procedure and I have question how can I overwrite old value on new Value and return the new line with new big one string with new mails.
Procedure split one big email which have got emails on few single mails and change domain.
Perception: I got one table with atributes example Values which have one big string with emails. I must change this emails to domain NewDomain.pl when its diffrent from aaa.pl and bbb.pl when its the same I leave this emails. example:
Old Value: 'zamowienia#kicius.pl mickey.mouse#aaa.pl kimus.walus#domek.pl'
and result I want update:
**New Value: 'zamowienia#NewDomain.pl mickey.mouse#aaa.pl kimus.walus#NewDomain.pl'
First procedure:
CREATE OR REPLACE PROCEDURE changeMailAll
AS
BEGIN
DECLARE delim char(3);
cur_position INTEGER(11) DEFAULT 1;
r_remainder VARCHAR(250);
cur_string VARCHAR(1000);
delim_length INTEGER;
length_remainder INTEGER;
mail VARCHAR(255);
MAILs VARCHAR(20000);
v_value VARCHAR2(255);
v_valueNew VARCHAR2(255);
v_customerId VARCHAR(20);
c INTEGER;
d INTEGER;
positionMonkey INTEGER;
v_identity VARCHAR(50);
domena VARCHAR2(50);
v_loop VARCHAR(100);
adres VARCHAR(255);
**str PKT_StringFnc.t_array;**
CURSOR cursorMails IS
SELECT Customer_Id, Value FROM PKT_userTrue where method_id = 'E_MAIL';
BEGIN
OPEN cursorMails;
LOOP
FETCH cursorMails INTO v_customerId, v_value;
**str := PKT_StringFnc.SPLIT(v_value,' ');
FOR i IN 1..str.COUNT LOOP
dbms_output.put_line('XXX1' || str(i));
END LOOP;**
EXIT WHEN cursorMails%NOTFOUND;
END LOOP;
CLOSE cursorMails;
END;
END;
End Second procedure where I split mail from first procedure
CREATE OR REPLACE PACKAGE BODY PKT_StringFnc
IS
FUNCTION SPLIT (p_in_string VARCHAR2, p_delim VARCHAR2) RETURN t_array
IS
i number :=0;
pos number :=0;
lv_str varchar2(255) := p_in_string;
positionMonkey INTEGER;
domena VARCHAR2(50);
adres VARCHAR(255);
lv_str_new VARCHAR2(255);
aaa VARCHAR(20) := '#aaa.pl ';
bbb VARCHAR(30) := '#bbb.pl ';
result VARCHAR(1000);
strings t_array;
BEGIN
pos := instr(lv_str,p_delim,1,1);
WHILE ( pos != 0) LOOP
i := i + 1;
strings(i) := substr(lv_str,1,pos);
positionMonkey := INSTR(strings(i),'#');
domena := SUBSTR(strings(i), positionMonkey);
adres := RTRIM(strings(i),domena);
lv_str := substr(lv_str,pos+1,length(lv_str));
pos := instr(lv_str,p_delim,1,1);
IF pos = 0 THEN
strings(i+1) := lv_str;
ELSE
strings(i+1) := lv_str_new;
END IF;
IF domena = aaa OR domena = bbb THEN
lv_str_new := REPLACE(strings(i),domena,'#NewDomain.com');
END IF;
DBMS_OUTPUT.PUT_LINE('lv_str_newREPLACE:'|| lv_str_new);
END LOOP;
RETURN strings;
END SPLIT;
END;
/
When I return one big string I want update in table and where I can do it ?
Thanks for help
Maybe somebody can rewrite easiest procedure from two to one procedure
I wonder if something like
UPDATE pktTrue
SET Value = REGEXP_REPLACE(Value, '(#aaa.pl)|(#bbb.pl)|(#[a-zA-Z0-9._%-]+\.[a-zA-Z]{2,4})', '\1\2#NewDomain.pl', 1, 0, 'c')
WHERE method_id = 'E_MAIL';
will work for you?

Base64 encoding and decoding in oracle

How can I do Base64 encode/decode a value in Oracle?
I've implemented this to send Cyrillic e-mails through my MS Exchange server.
function to_base64(t in varchar2) return varchar2 is
begin
return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
end to_base64;
Try it.
upd: after a minor adjustment I came up with this, so it works both ways now:
function from_base64(t in varchar2) return varchar2 is
begin
return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
end from_base64;
You can check it:
SQL> set serveroutput on
SQL>
SQL> declare
2 function to_base64(t in varchar2) return varchar2 is
3 begin
4 return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
5 end to_base64;
6
7 function from_base64(t in varchar2) return varchar2 is
8 begin
9 return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw (t)));
10 end from_base64;
11
12 begin
13 dbms_output.put_line(from_base64(to_base64('asdf')));
14 end;
15 /
asdf
PL/SQL procedure successfully completed
upd2: Ok, here's a sample conversion that works for CLOB I just came up with. Try to work it out for your blobs. :)
declare
clobOriginal clob;
clobInBase64 clob;
substring varchar2(2000);
n pls_integer := 0;
substring_length pls_integer := 2000;
function to_base64(t in varchar2) return varchar2 is
begin
return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
end to_base64;
function from_base64(t in varchar2) return varchar2 is
begin
return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
end from_base64;
begin
select clobField into clobOriginal from clobTable where id = 1;
while true loop
/*we substract pieces of substring_length*/
substring := dbms_lob.substr(clobOriginal,
least(substring_length, substring_length * n + 1 - length(clobOriginal)),
substring_length * n + 1);
/*if no substring is found - then we've reached the end of blob*/
if substring is null then
exit;
end if;
/*convert them to base64 encoding and stack it in new clob vadriable*/
clobInBase64 := clobInBase64 || to_base64(substring);
n := n + 1;
end loop;
n := 0;
clobOriginal := null;
/*then we do the very same thing backwards - decode base64*/
while true loop
substring := dbms_lob.substr(clobInBase64,
least(substring_length, substring_length * n + 1 - length(clobInBase64)),
substring_length * n + 1);
if substring is null then
exit;
end if;
clobOriginal := clobOriginal || from_base64(substring);
n := n + 1;
end loop;
/*and insert the data in our sample table - to ensure it's the same*/
insert into clobTable (id, anotherClobField) values (1, clobOriginal);
end;
Solution with utl_encode.base64_encode and utl_encode.base64_decode have one limitation, they work only with strings up to 32,767 characters/bytes.
In case you have to convert bigger strings you will face several obstacles.
For BASE64_ENCODE the function has to read 3 Bytes and transform them. In case of Multi-Byte characters (e.g. öäüè€ stored at UTF-8, aka AL32UTF8) 3 Character are not necessarily also 3 Bytes. In order to read always 3 Bytes you have to convert your CLOB into BLOB first.
The same problem applies for BASE64_DECODE. The function has to read 4 Bytes and transform them into 3 Bytes. Those 3 Bytes are not necessarily also 3 Characters
Typically a BASE64-String has NEW_LINE (CR and/or LF) character each 64 characters. Such new-line characters have to be ignored while decoding.
Taking all this into consideration the full featured solution could be this one:
CREATE OR REPLACE FUNCTION DecodeBASE64(InBase64Char IN OUT NOCOPY CLOB) RETURN CLOB IS
blob_loc BLOB;
clob_trim CLOB;
res CLOB;
lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
dest_offset INTEGER := 1;
src_offset INTEGER := 1;
read_offset INTEGER := 1;
warning INTEGER;
ClobLen INTEGER := DBMS_LOB.GETLENGTH(InBase64Char);
amount INTEGER := 1440; -- must be a whole multiple of 4
buffer RAW(1440);
stringBuffer VARCHAR2(1440);
-- BASE64 characters are always simple ASCII. Thus you get never any Mulit-Byte character and having the same size as 'amount' is sufficient
BEGIN
IF InBase64Char IS NULL OR NVL(ClobLen, 0) = 0 THEN
RETURN NULL;
ELSIF ClobLen<= 32000 THEN
RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char)));
END IF;
-- UTL_ENCODE.BASE64_DECODE is limited to 32k, process in chunks if bigger
-- Remove all NEW_LINE from base64 string
ClobLen := DBMS_LOB.GETLENGTH(InBase64Char);
DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL);
DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer);
read_offset := read_offset + amount;
END LOOP;
read_offset := 1;
ClobLen := DBMS_LOB.GETLENGTH(clob_trim);
DBMS_LOB.CREATETEMPORARY(blob_loc, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset)));
DBMS_LOB.WRITEAPPEND(blob_loc, DBMS_LOB.GETLENGTH(buffer), buffer);
read_offset := read_offset + amount;
END LOOP;
DBMS_LOB.CREATETEMPORARY(res, TRUE);
DBMS_LOB.CONVERTTOCLOB(res, blob_loc, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning);
DBMS_LOB.FREETEMPORARY(blob_loc);
DBMS_LOB.FREETEMPORARY(clob_trim);
RETURN res;
END DecodeBASE64;
CREATE OR REPLACE FUNCTION EncodeBASE64(InClearChar IN OUT NOCOPY CLOB) RETURN CLOB IS
dest_lob BLOB;
lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
dest_offset INTEGER := 1;
src_offset INTEGER := 1;
read_offset INTEGER := 1;
warning INTEGER;
ClobLen INTEGER := DBMS_LOB.GETLENGTH(InClearChar);
amount INTEGER := 1440; -- must be a whole multiple of 3
-- size of a whole multiple of 48 is beneficial to get NEW_LINE after each 64 characters
buffer RAW(1440);
res CLOB := EMPTY_CLOB();
BEGIN
IF InClearChar IS NULL OR NVL(ClobLen, 0) = 0 THEN
RETURN NULL;
ELSIF ClobLen <= 24000 THEN
RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(InClearChar)));
END IF;
-- UTL_ENCODE.BASE64_ENCODE is limited to 32k/(3/4), process in chunks if bigger
DBMS_LOB.CREATETEMPORARY(dest_lob, TRUE);
DBMS_LOB.CONVERTTOBLOB(dest_lob, InClearChar, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning);
LOOP
EXIT WHEN read_offset >= dest_offset;
DBMS_LOB.READ(dest_lob, amount, read_offset, buffer);
res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));
read_offset := read_offset + amount;
END LOOP;
DBMS_LOB.FREETEMPORARY(dest_lob);
RETURN res;
END EncodeBASE64;
All the previous posts are correct. There's more than one way to skin a cat. Here is another way to do the same thing: (just replace "what_ever_you_want_to_convert" with your string and run it in Oracle:
set serveroutput on;
DECLARE
v_str VARCHAR2(1000);
BEGIN
--Create encoded value
v_str := utl_encode.text_encode
('what_ever_you_want_to_convert','WE8ISO8859P1', UTL_ENCODE.BASE64);
dbms_output.put_line(v_str);
--Decode the value..
v_str := utl_encode.text_decode
(v_str,'WE8ISO8859P1', UTL_ENCODE.BASE64);
dbms_output.put_line(v_str);
END;
/
source
do url_raw.cast_to_raw() support in oracle 6

Resources