ACE Director Alum Daniel Morgan, founder of Morgan's Library, is scheduling
complimentary technical Workshops on Database Security for the first 30
Oracle Database customers located anywhere in North America, EMEA, LATAM, or
APAC that send an email to
asra_us@oracle.com. Request a Workshop for
your organization today.
Purpose
Provides APIs to access and manipulate specific parts of a LOB or complete LOBs.
The two STANDARD package functions EMPTY_BLOB and EMPTY_CLOB are
demonstrated on this page as this is the part of the library where they
will most likely find use.
AUTHID
DEFINER
Constants
Name
Data Type
Value
Miscellaneous
archive_path_max_size
PLS_INTEGER
32767
call
PLS_INTEGER
12
contenttype_max_size
PLS_INTEGER
128
default_csid
INTEGER
0
default_lang_ctx
INTEGER
0
file_readonly
BINARY_INTEGER
0
lob_readonly
BINARY_INTEGER
0
lob_readwrite
BINARY_INTEGER
1
lobmaxsize
INTEGER
18446744073709551615
no_warning
INTEGER
0
session
PLS_INTEGER
10
transaction
PLS_INTEGER
11
warn_inconvertible_char
INTEGER
1
Archive Put Flags
archive_put_nocache
PLS_INTEGER
0
archive_put_cache
PLS_INTEGER
1
Archive Reference Flags
archive_copy_ref
PLS_INTEGER
0
archive_copy_cache
PLS_INTEGER
1
Archive State
archive_never
PLS_INTEGER
0
archive_yes
PLS_INTEGER
1
archive_no
PLS_INTEGER
2
Option Types
opt_compress
PLS_INTEGER
1
opt_encrypt
PLS_INTEGER
2
opt_deduplicate
PLS_INTEGER
4
Option Values
compress_off
PLS_INTEGER
0
compress_on
PLS_INTEGER
1
encrypt_off
PLS_INTEGER
0
encrypt_on
PLS_INTEGER
2
deduplicate_off
PLS_INTEGER
0
deduplicate_on
PLS_INTEGER
4
Data Types
TYPE blob_deduplicate_region IS RECORD (
lob_offset INTEGER,
len INTEGER,
primary_lob BLOB,
primary_lob_offset NUMBER,
mime_type VARCHAR2(80));
TYPE blob_deduplicate_region_tab
IS TABLE OF blob_deduplicate_region
INDEX BY PLS_INTEGER;
TYPE clob_deduplicate_region IS RECORD (
lob_offset INTEGER,
len INTEGER,
primary_lob CLOB,
primary_lob_offset NUMBER,
mime_type VARCHAR2(80));
TYPE clob_deduplicate_region_tab
IS TABLE OF clob_deduplicate_region;
INDEX BY PLS_INTEGER;
Demo Table
Some of the demos require a table with the LOB stored in a SECUREFILE in an ASSM tablespace.
This tablespace and table will make those demos will reference use the table secure_file_tab.
CREATE TABLESPACE securefiletbs
DATAFILE 'c:\temp\securefile01.dbf' SIZE 25M
EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;
CREATE TABLE secure_file_tab (
rid NUMBER(5),
clobcol CLOB)
LOB (clobcol) STORE AS SECUREFILE clobcol (
TABLESPACE securefiletbs
RETENTION MIN 3600
DEDUPLICATE NOCOMPRESS);
INSERT INTO secure_file_tab VALUES (1, 'AbCdEfGhIjKlMnOpQrStUvWxYz');
INSERT INTO secure_file_tab VALUES (2, 'AAAAAAAAAAAAAAAAAAAAA');
COMMIT;
Dependencies
SELECT name FROM dba_dependencies
WHERE referenced_name = 'DBMS_LOB'
UNION
SELECT referenced_name FROM dba_dependencies WHERE name = 'DBMS_LOB';
Appends the contents of a source internal LOB to a destination LOB
Overload 1
dbms_lob.append(
dest_lob IN OUT NOCOPY BLOB,
src_lob IN BLOB);
CREATE OR REPLACE PROCEDURE example_1a AUTHID DEFINER IS
dest_lob BLOB;
src_lob BLOB;
BEGIN
-- get the LOB locators
-- note that the FOR UPDATE clause locks the row
SELECT b_lob INTO dest_lob
FROM lob_table
WHERE key_value = 12
FOR UPDATE;
SELECT b_lob INTO src_lob
FROM lob_table
WHERE key_value = 21;
dbms_lob.append(dest_lob, src_lob);
COMMIT;
END example_1a;
/
Overload 2
dbms_lob.append(
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
src_lob IN CLOB CHARACTER SET dest_lob%CHARSET);
CREATE OR REPLACE PROCEDURE example_1b AUTHID DEFINER IS
dest_lob, src_lob BLOB;
BEGIN
-- get the LOB locators
SELECT b_lob INTO dest_lob
FROM lob_table
WHERE key_value = 12
FOR UPDATE;
SELECT b_lob INTO src_lob
FROM lob_table
WHERE key_value = 12;
dbms_lob.append(dest_lob, src_lob);
COMMIT;
END example_1b;
/
Writes a CLOB to a file with given character encoding: Defaults to the db charset
dbms_lob.clob2file(
cl IN CLOB,
flocation IN VARCHAR2,
fname IN VARCHAR2,
csid IN NUMBER := 0,
openmode IN VARCHAR2 := 'wb');
DECLARE
cVal CLOB := 'This is a test of new DBMS_LOB functionality';
fLoc dba_directories.directory_name%TYPE := 'ORACLE_HOME'; -- from dba_directories
BEGIN
dbms_lob.clob2file(cVal, fLoc, 'morgan.txt'
);
END;
/
dbms_lob.compare(
lob_1 IN BLOB,
lob_2 IN BLOB,
amount IN INTEGER := 18446744073709551615,
offset_1 IN INTEGER := 1,
offset_2 IN INTEGER := 1)
RETURN INTEGER;
TBD
Overload 2
dbms_lob.compare(
lob_1 IN CLOB CHARACTER SET ANY_CS,
lob_2 IN CLOB CHARACTER SET lob_1%CHARSET,
amount IN INTEGER := 18446744073709551615,
offset_1 IN INTEGER := 1,;
offset_2 IN INTEGER := 1)
RETURN INTEGER;
TBD
Overload 3
dbms_lob.compare(
file_1 IN BFILE,
file_2 IN BFILE,
amount IN INTEGER,
offset_1 IN INTEGER := 1,
offset_2 IN INTEGER := 1)
RETURN INTEGER;
Reads character data from a source CLOB or NCLOB instance, converts the character data to the specified character, writes the converted data to a destination BLOB instance in binary format, and returns the new offsets
dbms_lob.convertToBlob(
dest_lob IN OUT NOCOPY BLOB,
src_clob IN CLOB CHARACTER SET ANY_CS,
amount IN INTEGER,
dest_offset IN OUT INTEGER,
src_offset IN OUT INTEGER,
blob_csid IN NUMBER,
lang_context IN OUT INTEGER,
warning OUT INTEGER);
Takes a source BLOB instance, converts the binary data in the source instance to character data using the specified character, writes the character data to a destination CLOB or NCLOB instance, and returns the new offsets
dbms_lob.convertToClob(
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
src_blob IN BLOB,
amount IN INTEGER,
dest_offset IN OUT INTEGER,
src_offset IN OUT INTEGER,
blob_csid IN NUMBER,
lang_context IN OUT INTEGER,
warning OUT INTEGER);
Copies all, or part, of the source LOB to the destination LOB
Overload 1
dbms_lob.copy(
dest_lob IN OUT NOCOPY BLOB,
src_lob IN BLOB,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1);
TBD
Overload 2
dbms_lob.copy(
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
src_lob IN CLOB CHARACTER SET dest_lob%CHARSET,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1);
Creates a temporary BLOB or CLOB and its corresponding index in the user's default temporary tablespace
Overload 1
dbms_lob.createTemporary(
lob_loc IN OUT NOCOPY BLOB,
cache IN BOOLEAN,
dur IN PLS_INTEGER := 10);
TBD
Overload 2
dbms_lob.createTemporary(
lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
cache IN BOOLEAN,
dur IN PLS_INTEGER := 10);
DECLARE
clobVar CLOB := EMPTY_CLOB;
len BINARY_INTEGER;
retVal PLS_INTEGER;
x VARCHAR2(80);
BEGIN
dbms_lob.createTemporary(clobVar, TRUE);
dbms_lob.open(clobvar,
dbms_lob.lob_readwrite);
x := 'before line break' || CHR(10) || 'after line break';
len := LENGTH(x);
dbms_lob.dbfs_link_generate_path(
lob_loc IN BLOB,
storage_dir IN VARCHAR2)
RETURN VARCHAR2;
PRAGMA RESTRICT_REFERENCES(dbfs_link_generate_path, WNDS, RNDS, WNPS, RNPS);
TBD
Overload 2
dbms_lob.dbfs_link_generate_path(
lob_loc IN CLOB CHARACTER SET ANY_CS,
storage_dir IN VARCHAR2)
RETURN VARCHAR2;
PRAGMA RESTRICT_REFERENCES(dbfs_link_generate_path, WNDS, RNDS, WNPS, RNPS);
Deletes the data at the given offset for the given length from the LOB
Overload 1
dbms_lob.fragment_delete(
lob_loc IN OUT NOCOPY BLOB,
amount IN INTEGER,
offset IN INTEGER);
TBD
Overload 2
Clearly there is an issue here so I am opening an SR at MOS (5 Feb, 2014)
dbms_lob.fragment_delete(
lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
amount IN INTEGER,
offset IN INTEGER);
DECLARE
dest_lob CLOB;
BEGIN
SELECT clobcol
INTO dest_lob
FROM secure_file_tab
WHERE rid = 1
FOR UPDATE;
dbms_output.put_line(dest_lob);
dbms_lob.fragment_delete(dest_lob, 2, 2);
dbms_output.put_line(dest_lob);
END;
/
AbCdEfGhIjKlMnOp
DECLARE
*
ERROR at line 1:
ORA-43856: Unsupported LOB type for SECUREFILE LOB operation
ORA-06512: at "SYS.DBMS_LOB", line 1187
ORA-06512: at line 11
Inserts the given data (limited to 32K) into the LOB at the given offset
Overload 1
dbms_lob.fragment_insert(
lob_loc IN OUT NOCOPY BLOB,
amount IN INTEGER,
offset IN INTEGER,
buffer IN RAW);
TBD
Overload 2
Clearly there is the issue here so I am opening an SR at MOS (5 Feb, 2014)
dbms_lob.fragment_insert(
lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
amount IN INTEGER,
offset IN INTEGER,
buffer IN VARCHAR2 CHARACTER SET lob_loc%CHARSET);
DECLARE
dest_lob CLOB;
BEGIN
SELECT clobcol
INTO dest_lob
FROM secure_file_tab
WHERE rid = 1
FOR UPDATE;
dbms_output.put_line(dest_lob);
dbms_lob.fragment_insert(dest_lob, 2, 3, 'Zz');
dbms_output.put_line(dest_lob);
END;
/
AbCdEfGhIjKlMnOp
DECLARE
*
ERROR at line 1:
ORA-43856: Unsupported LOB type for SECUREFILE LOB operation
ORA-06512: at "SYS.DBMS_LOB", line 1169
ORA-06512: at line 11
Moves the amount of bytes (BLOB) or characters (CLOB/NCLOB) from the given offset to the new offset specified
Overload 1
dbms_lob.fragment_move(
lob_loc IN OUT NOCOPY BLOB,
amount IN INTEGER,
src_offset IN INTEGER,
dest_offset IN INTEGER);
TBD
Overload 2
Clearly there is the issue here so I am opening an SR at MOS (5 Feb, 2014)
dbms_lob.fragment_move(
lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
amount IN INTEGER,
src_offset IN INTEGER,
dest_offset IN INTEGER);
DECLARE
dest_lob CLOB;
BEGIN
SELECT clobcol
INTO dest_lob
FROM secure_file_tab
WHERE rid = 1
FOR UPDATE;
dbms_output.put_line(dest_lob);
dbms_lob.fragment_move(dest_lob, 1, 1, 1);
dbms_output.put_line(dest_lob);
END;
/
AbCdEfGhIjKlMnOp
DECLARE
*
ERROR at line 1:
ORA-43856: Unsupported LOB type for SECUREFILE LOB operation
ORA-06512: at "SYS.DBMS_LOB", line 1207
ORA-06512: at line 11
Replaces the data at the given offset with the given data (not to exceed 32k)
Overload 1
dbms_lob.fragment_replace(
lob_loc IN OUT NOCOPY BLOB,
old_amount IN INTEGER,
new_amount IN INTEGER,
offset IN INTEGER,
buffer IN RAW);
TBD
Overload 2
dbms_lob.fragment_replace(
lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
old_amount IN INTEGER,
new_amount IN INTEGER,
offset IN INTEGER,
buffer IN VARCHAR2 CHARACTER SET lob_loc%CHARSET);
DECLARE
dest_lob CLOB;
BEGIN
SELECT clobcol
INTO dest_lob
FROM secure_file_tab
WHERE rid = 1
FOR UPDATE;
dbms_output.put_line(dest_lob);
dbms_lob.fragment_replace(dest_lob, 1, 1, 1, 'Zz');
dbms_output.put_line(dest_lob);
END;
/
AbCdEfGhIjKlMnOp
DECLARE
*
ERROR at line 1:
ORA-43856: Unsupported LOB type for SECUREFILE LOB operation
ORA-06512: at "SYS.DBMS_LOB", line 1229
ORA-06512: at line 11
Returns the matching position of the nth occurrence of the pattern in the LOB
Overload 1
dbms_lob.instr(
lob_loc IN BLOB,
pattern IN RAW,
offset IN INTEGER := 1,
nth IN INTEGER := 1)
RETURN INTEGER;
TBD
Overload 2
dbms_lob.instr(
lob_loc IN CLOB CHARACTER SET ANY_CS,
pattern IN VARCHAR2 CHARACTER SET lob_loc%CHARSET,
offset IN INTEGER := 1,
nth IN INTEGER := 1)
RETURN INTEGER;
conn pm/pm@pdbdev
SELECT dbms_lob.getlength(ad_sourcetext), dbms_lob.instr(ad_sourcetext, 'A')
FROM print_media;
SELECT dbms_lob.getlength(ad_sourcetext), dbms_lob.instr(ad_sourcetext, 'E')
FROM print_media;
Overload 3
dbms_lob.instr(
file_loc IN BFILE,
pattern IN RAW,
offset IN INTEGER := 1,
nth IN INTEGER := 1)
RETURN INTEGER;
dbms_lob.isremote(lob_loc IN CLOB CHARACTER
SET ANY_CS)
RETURN BOOLEAN;
PRAGMA RESTRICT_REFERENCES(isremote, WNDS, RNDS, WNPS, RNPS);
DECLARE
cVal CLOB := 'This is a test of ISREMOTE';
BEGIN
IF dbms_lob.isRemote(cVal) THEN
dbms_output.put_line('Is Remote');
ELSE
dbms_output.put_line('Is Not Remote');
END IF;
END;
/
dbms_lob.loadclobfromfile(
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
src_bfile IN BFILE,
amount IN INTEGER,
dest_offset IN OUT INTEGER,
src_offset IN OUT INTEGER,
bfile_csid IN NUMBER,
lang_context IN OUT INTEGER,
warning OUT INTEGER);
dbms_lob.loadfromfile(
dest_lob IN OUT NOCOPY BLOB,
src_lob IN BFILE,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1);
See SETCONTENTTYPE Demo Below
Overload 2
dbms_lob.loadfromfile(
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
src_lob IN BFILE,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1);
LOOP
dbms_lob.read(l_uncompressed_blob, l_blob_amount, l_blob_pos, l_blob_buffer);
dbms_output.put_line(utl_raw.cast_to_varchar2(l_blob_buffer));
l_blob_pos := l_blob_pos + l_blob_amount;
END LOOP;
dbms_sql.close_cursor(cur);
EXCEPTION
WHEN no_data_found THEN
dbms_sql.close_cursor(cur);
dbms_output.put_line(' ===========================================');
dbms_output.put_line('End of BLOB');
dbms_output.put_line(' ===========================================');
-- display lengths
dbms_output.put_line('Compressed Length : ' || LENGTH(l_compressed_blob));
dbms_output.put_line('Uncompressed Length: ' || LENGTH(l_uncompressed_blob));
dbms_output.put_line('Note that the BLOB above is split at 2000 byte boundries');
END;
/
Overload 2
dbms_lob.read(
lob_loc IN CLOB CHARACTER SET ANY_CS,
amount IN OUT NOCOPY INTEGER,
offset IN INTEGER,
buffer OUT VARCHAR2 CHARACTER SET lob_loc%CHARSET);
TBD
Overload 3
dbms_lob.read(
file_loc IN BFILE,
amount IN OUT NOCOPY INTEGER,
offset IN INTEGER,
buffer OUT RAW);
Returns part of the LOB value starting at the specified offset
Overload 1
dbms_lob.substr(
lob_loc IN BLOB,
amount IN INTEGER := 32767,
offset IN INTEGER := 1)
RETURN RAW;
TBD
Overload 2
dbms_lob.substr(
lob_loc IN CLOB CHARACTER SET ANY_CS,
amount IN INTEGER := 32767,
offset IN INTEGER := 1)
RETURN VARCHAR2 CHARACTER SET lob_loc%CHARSET;
DECLARE
dest_lob CLOB;
BEGIN
SELECT clobcol
INTO dest_lob
FROM secure_file_tab
WHERE rid = 1
FOR UPDATE;
dbm_lob.write(
lob_loc IN OUT NOCOPY BLOB,
amount IN INTEGER,
offset IN INTEGER,
buffer IN RAW);
TBD
Overload 2
dbm_lob.write(
lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
amount IN INTEGER,
offset IN INTEGER,
buffer IN VARCHAR2 CHARACTER SET lob_loc%CHARSET);
DECLARE
dest_lob CLOB;
BEGIN
SELECT clobcol
INTO dest_lob
FROM secure_file_tab
WHERE rid = 2
FOR UPDATE;
INSERT INTO book_author_ie
SELECT bookid, authorid
FROM book, author;
CREATE OR REPLACE PROCEDURE xml_gen(cvar IN OUT NOCOPY CLOB) AUTHID DEFINER AS
CURSOR c IS
SELECT b.title, b.description, a.author_name
FROM book b, author a, book_author_ie ie
WHERE b.bookid = ie.bookid
AND a.authorid = ie.authorid;
BEGIN
FOR r IN c LOOP
dbms_lob.writeappend(cvar, 19, '<root><book><title>');
dbms_lob.writeappend(cvar, length(r.title), r.title);
dbms_lob.writeappend(cvar, 14, '</title><desc>');
dbms_lob.writeappend(cvar, length(r.description), r.description);
dbms_lob.writeappend(cvar, 27, '</desc></book><author_name>');
dbms_lob.writeappend(cvar, length(r.author_name), r.author_name);
dbms_lob.writeappend(cvar, 21, '</author_name></root>');
END LOOP;
END xml_gen;
/
-- insert a NULL record to lock
INSERT INTO pdm
(dname, sname, fname, iblob)
VALUES
(pdname, psname, pfname, EMPTY_BLOB())
RETURNING iblob INTO dst_file;
-- lock record
SELECT iblob
INTO dst_file
FROM pdm
WHERE dname = pdname
AND sname = psname
AND fname = pfname
FOR UPDATE;
-- open the file
dbms_lob.fileopen(src_file, dbms_lob.file_readonly);
-- read the file
dbms_lob.loadfromfile(dst_file, src_file, lgh_file);
-- update the blob field
UPDATE pdm
SET iblob = dst_file
WHERE dname = pdname
AND sname = psname
AND fname = pfname;
-- close file
dbms_lob.fileclose(src_file);
END load_file;
/
Save BLOB to File Demo
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.
There are articles on MetaLink explaining how to do and it has a C program ready for compiling and the External Procedure stuff, i'd advise a visit.
Especially, look for Note:70110.1, Subject: WRITING BLOB/CLOB/BFILE CONTENTS TO A FILE USING EXTERNAL PROCEDURES
Here is the Oracle code cut and pasted from it. The outputstring procedure is the oracle procedure interface to the External procedure.
-------------------------------------
DECLARE
i1 BLOB;
len NUMBER;
my_vr RAW(10000);
i2 NUMBER;
i3 NUMBER := 10000;
BEGIN
-- get the blob locator
SELECT c2
INTO i1
FROM lob_tab
WHERE c1 = 2;
-- find the length of the blob column
len := dbms_lob.getlength(i1);
dbms_output.put_line('Column Length: ' || TO_CHAR(len));
-- read 10000 bytes at a time
i2 := 1;
IF len < 10000 THEN
-- if the col length is < 10000
dbms_lob.read(i1, len, i2, my_vr);
-- you have to convert the data to rawtohex format.
-- directly sending the buffer data will not work
-- That is the reason why we are sending the length as
-- the double the size of the data read
dbms_output.put_line('Read ' || to_char(len) || 'Bytes');
ELSE
-- if the col length is > 10000
dbms_lob.read(i1, i3, i2, my_vr);
CREATE OR REPLACE PROCEDURE read_file AUTHID CURRENT_USER IS
src_file BFILE := bfilename('DOCUMENT_DIR', 'image.gif');
dst_file BLOB;
lgh_file BINARY_INTEGER;
BEGIN
-- lock record
SELECT bin_data
INTO dst_file
FROM db_image
FOR update;
-- open the file
dbms_lob.fileopen(src_file, dbms_lob.file_readonly);
-- read the file
dbms_lob.loadfromfile(dst_file, src_file, lgh_file);
-- update the blob field
UPDATE db_image
SET bin_data = dst_file;
COMMIT;
-- close file
dbms_lob.fileclose(src_file);
EXCEPTION
WHEN access_error THEN
RAISE;
WHEN invalid_argval THEN
RAISE;
WHEN invalid_directory THEN
RAISE;
WHEN no_data_found THEN
RAISE;
WHEN noexist_directory THEN
RAISE;
WHEN nopriv_directory THEN
RAISE;
WHEN open_toomany THEN
RAISE;
WHEN operation_failed THEN
RAISE;
WHEN unopened_file THEN
RAISE;
WHEN others THEN
RAISE;
END read_file;
/
LOB Demo by Alberto Dell'Era
/* I have already done my own tests and it doesn't.
I can only retrieve 4000 as you already mentioned as opposed to the 64000 we're used to, but I think that this is a good trade off considering that we were doing almost 5000 queries at a time.
Perhaps you could consider tuning the temp tablespace extent size to retain the ability to fetch 64000 bytes. Consider this test case (9.2.0.5, 8k block size) */
CREATE TABLE don(x CLOB);
DECLARE
l_clob clob;
BEGIN
FOR i IN 1..10
LOOP
INSERT INTO don (x) VALUES (empty_clob())
RETURNING x INTO l_clob;
-- create a 400,000 bytes clob
FOR i IN 1..100
LOOP
dbms_lob.append(l_clob, rpad ('*',4000,'*'));
END LOOP;
END LOOP;
END;
/
So by reducing the extent size we greatly reduce the space allocated to the temp lob_index.
I don't know why the lob_data that should contain 64000 bytes stays to 327,680 for an extent size of 64K. Interestingly, if we select only 1 row:
SELECT SUBSTR(x, 1, 64000) PIECE
FROM don
WHERE rownum = 1;
/* I don't know the reason for this. Perhaps temporary LOBs have a different (bigger) CHUNKSIZE and/or PCTVERSION or perhaps they are updated versus being 'truncated' and then inserted for each row fetched?
Obviously, changing the extent size may adversely affect sort-to-disk and hash-join-to-disk, etc, operations - even if, by using an LMT temp tablespace, the impact may (stress on *may*) be immaterial. */
Replaces All Code Occurrences Of A String With Another Within A CLOB
-- 1) clob src - the CLOB source to be replaced.
-- 2) replace str - the string to be replaced.
-- 3) replace with - the replacement string.
CREATE OR REPLACE FUNCTION replaceClob(
srcClob IN CLOB,
replaceStr IN VARCHAR2,
replaceWith IN VARCHAR2)
RETURN CLOB AUTHID DEFINER IS
vBuffer VARCHAR2 (32767);
l_amount BINARY_INTEGER := 32767;
l_pos PLS_INTEGER := 1;
l_clob_len PLS_INTEGER;
newClob CLOB := EMPTY_CLOB;
BEGIN
-- initalize the new clob
dbms_lob.createtemporary(newClob,TRUE);
l_clob_len := dbms_lob.getlength(srcClob);
WHILE l_pos < l_clob_len
LOOP
dbms_lob.read(srcClob, l_amount, l_pos, vBuffer);
IF vBuffer IS NOT NULL THEN
-- replace the text
vBuffer := replace(vBuffer, replaceStr, replaceWith);
-- write it to the new clob
dbms_lob.writeappend(newClob, LENGTH(vBuffer), vBuffer);
END IF;
l_pos := l_pos + l_amount;
END LOOP;
RETURN newClob;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END replace_clob;
/