====== IBPP::Blob ===== Firebird and Interbase do support the storage of arbitrary binary data in a single column, the type of such a column is BLOB. This feature is not widely available at the Dynamic SQL interface level (except some simple text BLOBs extractions), and best require some C-API programming to be used. IBPP allows you to read and write those blob columns easily through a file I/O analogy. ===== Overview ===== Writing blob data to a blob column involves 3 steps. * Allocate a Blob object. * Describe it (gets its description from the system tables based on the table and column names). * Write the data to the blob. * Write the blob reference to the database, through an INSERT or UPDATE statement. Similarly, reading data from a blob column involves 3 steps. * Allocate a Blob object. * Read the blob reference from the database through a SELECT statement. * Read the data out of the blob. ===== BlobFactory ===== BlobFactory is used to create and get access to a Blob object. Blob BlobFactory(Database db, Transaction tr) Blobs objects have a lifetime strictly limited by the lifetime of the [[transaction]] and [[database]] they depend on. You can only call BlobFactory with a connected database and a started transaction. The blob reference (a kind of internal ID) will be invalid as soon as the transaction is committed or rolled-back or the database disconnected. ===== Methods ===== ==== void Create() ==== Create is used when you need to write data to a Blob. Wether this is a blob you retrieved from the database or a new blob which you will write to the first time, you use Create() upon you Blob object to open it for writing, much like when you create a disk file through some file I/O mechanism. The action of writing a blob always starts with such a Create(), effectively creating a new blob reference. There is no such thing as opening an existing blob for incrementally writing inside the blob. It is always a game of real-all / write-all when it comes to updating a blob (replacing one instance by another one if you prefer). After your call to Create() your blob is ready for calls to Write() / Close() and Cancel(). You cannot Read() from a blob after calling Create(). ==== void Cancel() ==== Cancel() is only used when you called Create(), then decide you don't want to continue. Instead of calling Close(), do use Cancel() in such cases. ==== void Open() ==== Opens a blob for reading, that is readies it for calls to Read(). You can only open a blob for reading when you actually got the blob reference from the database. That is you cannot simply get a blob object through the BlobFactory then Open() it. You really need first to run a query, selecting the blob columns and assigning it to your blob object through the Get() methods of the [[Statement]]. Once opened, you can call Read() and Close(). Cancel() is unrelated to read operations and would be an error. ==== void Close() ==== After writing to a new blob, opened by Create(), or reading from an existing blob, opened by Open(), you should Close() the blob. Note that a blob that you retrieved from the database can be opened, read, closed and reopened multiple times as long as the [[database]] connection and [[transaction]] it depends on are still connected and started. ==== int Read(void* dest, int size) ==== Read() mimics some simple file I/O. The parameter dest is a pointer to some memory location where you will read a 'chunk' of the blob. The parameter size is the maximum number of bytes you want to read at once. Typically this will be the size of the buffer 'dest' is pointing to. Read() returns you the actual number of bytes read out of the blob. At any time, it can be less than your 'size' parameter, even though the blob is not completely read. This very important to note and remember. If the return value is 0 (zero bytes read), this means you have already read all the bytes out of the blob, you reached the end of blob. Just Close() the blob now. ==== void Write(const void* source, int size) ==== Write() mimics some simple file I/O. The parameter 'source' is a pointer to some memory location from which you will write a 'chunk' to the blob. The parameter size is the number of bytes that you want to write. There is a limit of 32767 bytes, this limit comes out of Firebird API itself. ==== void Info(int* size, int* largest, int* segments) ==== Info() can be called on an allocated blob (one that got read from the database or one that you created and closed even though you did not write it yet to the database. * size : is the total size of the blob, in bytes * largest : is the largest segment of the blob (hint: before reading a blob, you can benefit from this information to allocate a read buffer of the correct size) * segments : is the number of segments (the minimal number of times Read() will return, if the buffer is large enough, before returning 0 - end of blob) ==== void Save(const std::string& data) ==== Save() is a special shortcut to help manage blob contents through std::string. It builds upon the fact that std::string can hold arbitrary binary data. It is also much useful when the blob data is actually text. Save() is a shortcut in such that it takes the blob, calls Create(), takes the std::string, Write() the string data in multiple chunks if needed and then Close() the blob, ready to be written to the database. ==== void Load(std::string& data) ==== Load() is a special shortcut to help manage blob contents through std::string. It builds upon the fact that std::string can hold arbitrary binary data. It is also much useful when the blob data is actually text. Load() is a shortcut in such that it takes the blob, calls Open(), Read() in multiple chunks if required, copying to the std::string, and then Close() the blob. ==== IBPP::Database DatabasePtr() and IBPP::Transaction TransactionPtr() ==== Used to get easy access to the [[Database]] and [[Transaction]] this Blob is linked to.