RDB$BLOB_UTIL
package
Adriano dos Santos Fernandes
Tracker ticket: #281
This package provides procedures and functions to manipulate BLOBs in a way that standard Firebird functions, like BLOB_APPEND
and SUBSTRING
, cannot do or are very slow.
These routines operate on binary data directly, even for text BLOBs.
Package routines
Function NEW_BLOB
RDB$BLOB_UTIL.NEW_BLOB
creates a new BLOB SUB_TYPE BINARY.It returns a BLOB suitable for data appending, similar to BLOB_APPEND
.
The advantage over BLOB_APPEND
is that it’s possible to set custom SEGMENTED
and TEMP_STORAGE
options.
BLOB_APPEND
always creates BLOBs in temporary storage, which may not always be the best approach if the created BLOB is going to be stored in a permanent table, as this will require a copy operation.
The BLOB returned from this function, even when TEMP_STORAGE = FALSE
, may be used with BLOB_APPEND
for appending data.
-
SEGMENTED
typeBOOLEAN NOT NULL
-
TEMP_STORAGE
typeBOOLEAN NOT NULL
BLOB SUB_TYPE BINARY NOT NULL
Function OPEN_BLOB
RDB$BLOB_UTIL.OPEN_BLOB
opens an existing BLOB for reading.It returns a handle (an integer bound to the transaction) suitable for use with other functions of this package, like SEEK
, READ_DATA
and CLOSE_HANDLE
.
Handles which are not explicitly closed are closed automatically when the transaction ends.
-
BLOB
typeBLOB NOT NULL
INTEGER NOT NULL
Function IS_WRITABLE
RDB$BLOB_UTIL.IS_WRITABLE
returns TRUE
when a BLOB is suitable for data appending using BLOB_APPEND
without copying.
-
BLOB
typeBLOB NOT NULL
BOOLEAN NOT NULL
Function READ_DATA
RDB$BLOB_UTIL.READ_DATA
reads chunks of data of a BLOB handle opened with RDB$BLOB_UTIL.OPEN_BLOB
.When the BLOB is fully read and there is no more data, it returns NULL
.
If LENGTH
is passed with a positive number, it returns a VARBINARY with its maximum length.
If LENGTH
is NULL
it returns just a segment of the BLOB with a maximum length of 32765.
-
HANDLE
typeINTEGER NOT NULL
-
LENGTH
typeINTEGER
VARBINARY(32765)
Function SEEK
RDB$BLOB_UTIL.SEEK
sets the position for the next READ_DATA
, it returns the new position.
MODE
may be 0
(from the start), 1
(from current position) or 2
(from end).
When MODE
is 2
, OFFSET
should be zero or negative.
-
HANDLE
typeINTEGER NOT NULL
-
MODE
typeINTEGER NOT NULL
-
OFFSET
typeINTEGER NOT NULL
INTEGER NOT NULL
Note
|
|
Procedure CANCEL_BLOB
RDB$BLOB_UTIL.CANCEL_BLOB
immediately releases a temporary BLOB, like one created with BLOB_APPEND
.
If the same BLOB is used after cancel, an “invalid blob id” error will be raised.
-
BLOB
typeBLOB
Procedure CLOSE_HANDLE
RDB$BLOB_UTIL.CLOSE_HANDLE
closes a BLOB handle opened with RDB$BLOB_UTIL.OPEN_BLOB
.
Handles which are not explicitly closed are closed automatically when the transaction ends.
-
HANDLE
typeINTEGER NOT NULL
Examples
EXECUTE BLOCK
execute block returns (b blob) as begin -- Create a BLOB handle in the temporary space. b = rdb$blob_util.new_blob(false, true); -- Add chunks of data. b = blob_append(b, '12345'); b = blob_append(b, '67'); suspend; end
EXECUTE BLOCK
execute block returns (s varchar(10)) as declare b blob = '1234567'; declare bhandle integer; begin -- Open the BLOB and get a BLOB handle. bhandle = rdb$blob_util.open_blob(b); -- Get chunks of data as string and return. s = rdb$blob_util.read_data(bhandle, 3); suspend; s = rdb$blob_util.read_data(bhandle, 3); suspend; s = rdb$blob_util.read_data(bhandle, 3); suspend; -- Here EOF is found, so it returns NULL. s = rdb$blob_util.read_data(bhandle, 3); suspend; -- Close the BLOB handle. execute procedure rdb$blob_util.close_handle(bhandle); end
set term !; execute block returns (s varchar(10)) as declare b blob; declare bhandle integer; begin -- Create a stream BLOB handle. b = rdb$blob_util.new_blob(false, true); -- Add data. b = blob_append(b, '0123456789'); -- Open the BLOB. bhandle = rdb$blob_util.open_blob(b); -- Seek to 5 since the start. rdb$blob_util.seek(bhandle, 0, 5); s = rdb$blob_util.read_data(bhandle, 3); suspend; -- Seek to 2 since the start. rdb$blob_util.seek(bhandle, 0, 2); s = rdb$blob_util.read_data(bhandle, 3); suspend; -- Advance 2. rdb$blob_util.seek(bhandle, 1, 2); s = rdb$blob_util.read_data(bhandle, 3); suspend; -- Seek to -1 since the end. rdb$blob_util.seek(bhandle, 2, -1); s = rdb$blob_util.read_data(bhandle, 3); suspend; end! set term ;!
create table t(b blob); set term !; execute block returns (bool boolean) as declare b blob; begin b = blob_append(null, 'writable'); bool = rdb$blob_util.is_writable(b); suspend; insert into t (b) values ('not writable') returning b into b; bool = rdb$blob_util.is_writable(b); suspend; end! set term ;!