Related
I'm trying to encrypt and decrypt a CLOB. I have a test CASE below, which utilizes functions to accomplish this task and was taken from the following link.
Error while using DBMS_CRYPTO function to decrypt CLOB data
Once the anonymous block creates the encrypted CLOB I am using an update statement, which calls a decrypt function to ensure it matches the original string.
I've tried initializing the CLOB before encryption with a call to empty_clob() but I can't seem to get this test CASE to decrypt the CLOB and return back the original value, which I started with.
The string being generated to encrypt is small but the test CASE is a little lengthy so I can provide a step by step guide on what I'm doing.
The last step in the test is a dump() of the decrypted CLOB, which shows some unusual characters in the middle of the CLOB that weren't in the input.
While looking at the documentation I did see an example using RANDOMBYTES on a string bur that will not work for me as it would be very unlikely I will get the same random bytes for the encryption and decryption.
I'm testing this in livesql for those who want to emulate my testing environment.
I was hoping someone could tell me where the problem is and provide the necessary fixes I need to get this functioning properly.
Thanks in advance to all who respond and for your time, patience and expertise.
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE TABLE encryption_values
(
NAME VARCHAR2(100 BYTE),
VALUE NVARCHAR2(100)
);
INSERT INTO encryption_values
SELECT 'key' NAME,
RAWTOHEX ('52AB32;^$!ER94988OPS3W21') VALUE
FROM DUAL
UNION
SELECT 'iv' NAME, RAWTOHEX ('TY54ABCX') VALUE FROM DUAL;
/
CREATE OR REPLACE FUNCTION encrypt_clob (p_clob IN CLOB) return CLOB is
l_clob CLOB;
lb_variable BLOB;
v_key RAW (320);
v_encryption_type PLS_INTEGER := DBMS_CRYPTO.AES_CBC_PKCS5;
v_iv RAW (320);
l_dest_offset PLS_INTEGER := 1;
l_src_offset PLS_INTEGER := 1;
l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx;
l_warning PLS_INTEGER;
l_step PLS_INTEGER := 1998;
begin
SELECT VALUE
INTO v_key
FROM encryption_values
WHERE name = 'key';
SELECT VALUE
INTO v_iv
FROM encryption_values
WHERE name = 'iv';
dbms_lob.createtemporary(lb_variable, true);
DBMS_CRYPTO.ENCRYPT(
dst => lb_variable,
src => p_clob,
typ => v_encryption_type,
key => v_key,
iv => v_iv
);
DBMS_LOB.createTemporary(
lob_loc => l_clob,
cache => TRUE);
FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(lb_variable) - 1 )/l_step) LOOP
l_clob := l_clob || UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(DBMS_LOB.substr(lb_variable, l_step, i * l_step + 1)));
END LOOP;
RETURN l_clob;
end encrypt_clob;
/
CREATE OR REPLACE FUNCTION decrypt_clob (p_clob IN CLOB) return CLOB is
lb_variable CLOB;
l_clob CLOB;
l_blob BLOB;
v_key RAW (320);
v_encryption_type PLS_INTEGER := DBMS_CRYPTO.AES_CBC_PKCS5;
v_iv RAW (320);
l_dest_offset PLS_INTEGER := 1;
l_src_offset PLS_INTEGER := 1;
l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx;
l_warning PLS_INTEGER;
l_raw RAW(32767);
l_amt NUMBER := 16;
l_offset NUMBER := 1;
l_temp VARCHAR2(32767);
begin
SELECT VALUE
INTO v_key
FROM encryption_values
WHERE name = 'key';
SELECT VALUE
INTO v_iv
FROM encryption_values
WHERE name = 'iv';
dbms_lob.createtemporary(l_blob, true);
-- base-64 string has line breaks; those could give an inaccurate result to the decode function below, so they are replaced with NULL.
l_clob := replace(replace(p_clob, chr(13), null), chr(10), null);
FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(l_clob) - 1 )/l_amt) LOOP
DBMS_LOB.read(l_clob, l_amt, l_offset, l_temp);
l_offset := l_offset + l_amt;
l_raw := UTL_ENCODE.base64_decode(utl_raw.cast_to_raw(l_temp));
DBMS_LOB.append (l_blob, TO_BLOB(l_raw));
END LOOP;
dbms_lob.createtemporary(lb_variable, true);
DBMS_CRYPTO.DECRYPT(
dst => lb_variable,
src => l_blob,
typ => v_encryption_type,--dbms_crypto.des_cbc_pkcs5,
key => v_key,
iv => v_iv
);
return lb_variable;
end decrypt_clob;
/
CREATE table t(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
hash_pk VARCHAR2(1000) not NULL PRIMARY KEY,
c CLOB,
encrypted VARCHAR2(1) DEFAULT 'N',
create_date DATE DEFAULT SYSDATE
);
/
CREATE or REPLACE FUNCTION HASH_SHA512 (
psINPUT IN VARCHAR2
) RETURN VARCHAR2 AS
rHash RAW (512);
BEGIN
rHash := DBMS_CRYPTO.HASH (TO_CLOB (psINPUT),
dbms_crypto.HASH_SH512);
RETURN (LOWER (RAWTOHEX (rHash)));
END HASH_SHA512;
/
CREATE OR REPLACE PROCEDURE insert_clob(
p_clob IN CLOB,
p_encrypted VARCHAR2
) AS
l_hash_pk VARCHAR2(1000);
BEGIN
SELECT HASH_SHA512(p_clob) INTO l_hash_pk from dual;
IF (p_encrypted = 'N')
THEN
insert into t (hash_pk, c, encrypted)
select l_hash_pk, p_clob, p_encrypted from dual
where not exists(select 1
from t
where (hash_pk = l_hash_pk));
ELSE
insert into t (hash_pk, c, encrypted)
select l_hash_pk, encrypt_clob (p_clob), p_encrypted from dual
where not exists(select 1
from t
where (hash_pk = l_hash_pk));
END IF;
END;
declare
c1 clob := empty_clob();
c2 varchar2(32000);
BEGIN
for i in 1 .. 3
loop
c2 := 'abcdefghijklmnopqrstuvwxyz ' || i;
dbms_output.put_line(c2);
SELECT CONCAT(c1, c2) INTO c1 FROM DUAL;
insert_clob (c1, 'Y');
c1 := empty_clob();
c2 := NULL;
end loop;
END;
UPDATE t
set c = decrypt_clob(c),encrypted = 'N' where encrypted ='Y';
-- As you can see from the dump() the decrypted CLOB doesn't match the original CLOB.
SELECT c, dump(to_char(c)) from t;
/
C DUMP(TO_CHAR(C))
abcdefgh0QKEmnopqrstuvwxyz 1 Typ=1 Len=28: 97,98,99,100,101,102,103,104,48,81,75,69,109,110,111,112,113,114,115,116,117,118,119,120,121,122,32,49
abcdefgh�klmnopqrstuvwxyz 2 Typ=1 Len=30: 97,98,99,100,101,102,103,104,239,191,189,22,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,32,50
abcdefgh�klmnopqrstuvwxyz 3 Typ=1 Len=30: 97,98,99,100,101,102,103,104,239,191,189,22,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,32,51
Attempting to update pictures in a blob column for multiple rows, I receive successful messages with no error and yet changes have not been rendered. I restarted Oracle service and machine and still nothing propagated. Yes, as shown I am committing and I have tried only one blob to no avail.
Is it the temporary dest_lob object? The readonly type? Do I have to release the temp blob?
Is it the appropriate schema not set? I am calling it with schema user.
Do previous blob content have to be NULL? The Hamlet.jpg attempt (ID = 101) maintains NULL in Picture blob column.
Is it a caching issue with Oracle? Do I have to refresh something like the tablespace file?
Is it the multiple BEGIN ... END calls?
Table
SQL > desc Characters;
Name Null? Type
----------------------------------------------------------------
ID NOT NULL NUMBER(5)
CHARACTER VARCHAR2(255 CHAR)
DESCRIPTION VARCHAR2(1000 CHAR)
SOURCE VARCHAR2(255 CHAR)
QUOTE VARCHAR2(1500 CHAR)
PICTURE BLOB
LINKIMAGE VARCHAR2(255 CHAR)
PL-SQL
CREATE OR REPLACE DIRECTORY MY_DIR AS '/path/to/pictures';
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'HenryCorwin.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 44;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'Hamlet.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 101;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'CGreen.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 15;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'SevenOfNine.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 82;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
sqlplus command line call (of above script)
SQL> #/path/to/script.sql
Console Output
Directory created.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
SQL Blob data check
SELECT ID FROM Characters
WHERE DBMS_LOB.GETLENGTH(Picture) = 0 OR
DBMS_LOB.GETLENGTH(Picture) IS NULL;
Output
ID
----------
15
44
82
101
Environment
Ubuntu 16.04 LTS, 64-bit
Intel Celeron, 4-processor, 64-GB HD, 2-GB RAM
Oracle 11g Express:
SQL > select * from v$version
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
With help from this other forum thread, I found my issue. Instead of using the following LOB methods:
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
Simply replace with the FILE version and remove the CREATETEMPORARY():
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
And in hindsight this makes somewhat sense since I am reading form a file object, src_bfile, and not an actual blob object.
With the following updated PL/SQL routine, blob columns successfully render.
CREATE OR REPLACE DIRECTORY MY_DIR AS '/path/to/pictures';
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'HenryCorwin.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 44 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'CGreen.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 15 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'SevenOfNine.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 82 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
Also, if blob column is NULL like my Hamlet.jpg attempt the above procedure will fail with
ORA-06502: PL/SQL: numeric or value error: invalid LOB locator
specified:
ORA-22275 ORA-06512: at "SYS.DBMS_LOB", line 928 ORA-06512:
at line 7
To resolve, update with EMPTY_BLOB() prior to updating the blob with the intended object.
UPDATE CHARACTERS SET Picture = EMPTY_BLOB() WHERE ID = 101;
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'Hamlet.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 101 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
Successful messages render and final query returns a sight to sore eyes:
SQL > SELECT ID FROM Characters WHERE DBMS_LOB.GETLENGTH(Picture) = 0 OR DBMS_LOB.GETLENGTH(Picture) IS NULL;
no rows selected
SQL > SQL> SELECT DBMS_LOB.GETLENGTH(Picture) FROM Characters WHERE ID IN (15, 44, 82, 101);
DBMS_LOB.GETLENGTH(PICTURE)
---------------------------
365256
412300
381586
404241
I'll suggest you do an dbms_lob.erase, which seems to be necessary:
SELECT PICTURE INTO dest_blob FROM CHARACTERS WHERE ID = 15
FOR UPDATE;
dest_length := DBMS_LOB.GETLENGTH(dest_blob);
IF dest_length <> 0 THEN
DBMS_LOB.ERASE(dest_blob,dest_length,1);
END IF;
-- then do as you wrote:
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
Hope this helps (stolen from here)
Recently I am trying to expand my knowledge about communication between databases in Oracle and I would like to get answer for few questions:
Problem
I am sending query through one database to another via LINK, for instance:
insert into testme#linkme values (1, ‘Hello World’);
where testme is destination table in second database and linkme is my link.
Questions
When sending query, are my data vulnerable (are they encrypted somehow during this process)?
If yes, could you briefly tell me more?
If no, is there any way to make this process safe?
Also, do you know any tools that I could use to test what happens with my data during sending process?
create or replace PACKAGE BODY "PKG_LOGI_PWD_REG"
as
FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2
IS
l_decrypted RAW(32);
l_decrypted_string VARCHAR2(32);
L_USER varchar2(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY raw(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
BEGIN
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
l_decrypted := dbms_crypto.decrypt
( SRC => P_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
l_decrypted_string := utl_i18n.raw_to_char
( data => l_decrypted ,
src_charset => 'AL32UTF8' );
RETURN l_decrypted_string;
end DECRYPT_VAL;
FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN VARCHAR2
is
L_VAL RAW(32);
L_ENCRYPTED raw(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY RAW(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
begin
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
L_VAL := utl_i18n.string_to_raw
( data => p_val,
dst_charset => 'AL32UTF8' );
L_ENCRYPTED := dbms_crypto.encrypt
( SRC => L_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
return L_ENCRYPTED;
EXCEPTION when OTHERS then
RETURN SQLCODE||'-'||SQLERRM;
end ENCRYPT_VAL;
end PKG_LOGI_PWD_REG;
..
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;
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;
/