Using Stream Blobs

by Ann Harrison

Firebird supports two types of blobs, stream and segmented. The database stores segmented blobs in chunks. Each chunk starts with a two byte length indicator followed by however many bytes of data were passed as a segment. Stream blobs are stored as a continuous array of data bytes with no length indicators included.

The stream blob interface is modeled on C library I/O routines. The structure equivalent to a FILE is a BSTREAM. In general, you don't need to look inside the BSTREAM, but to seek within a blob you must reference the blob handle stored in the structure.

typedef struct bstream {
        void *bstr_blob; /* Blob handle */
         char *bstr_buffer; /* Address of buffer */
         char *bstr_ptr; /* Next character */
         short bstr_length; /* Length of buffer */
         short bstr_cnt; /* Characters in buffer */
         char bstr_mode; /*(mode) ? OUTPUT : INPUT */
        } BSTREAM;

To open a stream blob, call Bopen . In addition to opening or creating a blob, Bopen allocates a buffer for transferring data between the program and database.

        char *);

The first argument is the blob id. If you are creating a new blob, pass that value to the insert or update statement. If you are opening an existing blob, use the value returned for the blob field in the select statement.

The second and third arguments are the database handle and transaction handle.

The fourth argument is either a "w", "W", "r", or "R". These indicate whether the blob is to be opened for write or read.

The return value is a structure that describes the state of the blob.

To write to a blob, use the macro putb or putbx.

putb (char, BSTREAM);
putbx (char, BSTREAM);

Each accumulates a buffer of data and calls BLOB_put to write the data to the blob. The difference between the two is that putb is sensitive to new lines and will write out the data whenever it encounters a new line.

To read a blob, use the macro getb

c = getb (BSTREAM);

getb returns EOF at the end of blob. It reads a buffer from the database and feeds it back to the program one character at a time.

Stream blobs support a seek operation. The seek can be from the beginning of the blob, from the current position, or from the end. The call to position the blob pointer is isc_seek_blob and is much more like other API calls than the open/close/get/put routines. It requires a blob handle. The blob handle is available in the BSTREAM structure.

ISC_STATUS isc_seek_blob (ISC_STATUS *,
       isc_blob_handle *,
        ISC_LONG *);

The first parameter is a status vector.

The second is the blob handle ( blob_stream->bstr_blob ).

The third is the mode which is one of:

0, blb_seek_relative = 1, blb_seek_from_tail = 2

Zero indicates seek from the beginning. The other two are reasonably self explanatory.

The fourth parameter is the offset you want. The fifth is the offset you got – which may be different if your seek exceeded the limits of the blob.

To close a blob stream use Bclose. A return value of 1 indicates success, 0 failure.

int BLOB_close (BSTREAM *);

Here is a very simple routine that translates a status vector and stores the result in a stream blob. The variables LOG_DB and log_trans are the database handle and transaction respectively and are assumed to have been established elsewhere.

char s[1024], *p;
ISC_QUAD blob_id;

if (!(blob_stream = Bopen (&blob_id, LOG_DB, log_trans, "w")))
        fprintf (log, "%d %d blob open failedn", id, iteration);

while (isc_interprete (s, &in_vector))
        for (p = s; *p; p++)
                putb (*p, blob_stream);
if (!(BLOB_close (blob_stream)))
        fprintf (log, "%d %d blob close errorn", id, iteration);

Really very simple....

This paper was written by Ann Harrison in June 2003, and is copyright Ms. Harrison and IBPhoenix Inc. You may republish it verbatim, including this notation. You may update, correct, or expand the material, provided that you include a notation that the original work was produced by Ms. Harrison and IBPhoenix.