Firebird interfaces.
Firebird's OO API is based on use of interfaces. That interfaces, though looking in some aspects like OLE2 interfaces (some of them have addRef() and release() methods) are non standard and have features, missing in ither widely used types of interfaces. First of all Firebird interfaces are language independent – that means that to define/use them one need not use language specific constructions like class in C++, interface may be defined using any language having concepts of array and pointer to procedure/function. Next interfaces are versioned – i.e. we support different versions of same interface. Binary layout of interfaces is designed to support that features very efficient (there is no need in additional virtual calls like in OLE2/COM with it's QueryInterface) but it's not convenient for direct use from most languages. Therefore language-specific wrappers should better be designed for different languages making use of API easier. Currently we have wrappers for C++ and Pascal, Java is coming soon. From end-user POV calls from C++ and Pascal have absolutely no difference, though some additional language-specific features present in C++ (like automatic status check after API calls) are missing in Pascal.
Typically database API is used to access data stored in database. Firebird OO API certainly performs this task but in addition it supports writing your own plugins – modules, making it possible to enhance Firebird capabilities according to your needs. Therefore this document contains 2 big parts – accessing databases and writing plugins. Certainly some interfaces (like status vector) are used in both parts of API, they will be discussed in data access part and freely referenced later when discussing plugins. Therefore even if you plan to write some plugin you should better start with the first part of this document. Moreover a lot of plugins need to access databases themselves and data access API is typically needed for it.
Firebird installation package contains a number of live samples of use of OO API – they are in examples/interfaces (database access) and examples/dbcrypt (plugin performing fictitious database encryption) directories. It's supposed that the reader is familiar with ISC API used in Firebird since interbase times.
Accessing databases.
First of all we need to get access to IMaster interface. IMaster is primary Firebird interface, required to access all the rest of interfaces. Therefore there is a special way of accessing it – the only one needed to use OO API plain function called fb_get_master_interface(). This function has no parameters and always succeeds. There is one and only one instance of IMaster per Firebird client library, therefore one need not care about releasing memory, used by master interface. A simplest way to access it from your program is to have appropriate global or static variable:
static IMaster* master = fb_get_master_interface();
For a lot of methods, used in Firebird API, first parameter is IStatus interface. It's a logical replacement of ISC_STATUS_ARRAY, but works separately with errors and warnings (not mixing them in same array), can contain unlimited number of errors inside and (this will be important if you plan to implement IStatus yourself) always keeps strings, referenced by it, inside interface. Typically you need at least one instance of IStatus to call other methods. You obtain it from IMaster:
IStatus* st = master->getStatus();
If method getStatus() fails for some reason (OOM for example) it returns NULL – obviously we can't use generic error reporting method which is based on use of IStatus here.
Now we are going to deal with first interface, directly related to database calls. This is IProvider – interface called this way cause it's exactly that interface that must be implemented by any provider in Firebird. Firebird client library also has it's own implementation of IProvider, which must be used to start any database activity. To obtain it we call IMaster's method:
IProvider* prov = master->getDispatcher();
The following is C++ specific: We are almost ready to call attachDatabase() method of IProvider, but before it a few words about concept of Status Wrapper should be said. Status wrapper is not an interface, it's very thin envelope for IStatus interface. It helps to customize behavior of C++ API (change a way how errors, returned in IStatus interface, are processed). For the first time we recommend use of ThrowStatusWrapper, which raises C++ exception each time an error is returned in IStatus.
ThrowStatusWrapper status(st);
IStatus* getStatus()
IProvider* getDispatcher()
IPluginManager* getPluginManager()
ITimerControl* getTimerControl()
IDtc* getDtc()
IUtil* getUtilInterface()
IConfigManager* getConfigManager()
void init()
unsigned getState()
void setErrors2(unsigned length, const intptr_t* value)
void setWarnings2(unsigned length, const intptr_t* value)
void setErrors(const intptr_t* value)
void setWarnings(const intptr_t* value)
const intptr_t* getErrors()
const intptr_t* getWarnings()
IStatus* clone()
Constants defined by Status interface:
STATE_WARNINGS -
STATE_ERRORS
RESULT_ERROR = -1;
RESULT_OK = 0;
RESULT_NO_DATA = 1;
RESULT_SEGMENT = 2;
IAttachment* attachDatabase(StatusType* status, const char* fileName, unsigned dpbLength, const unsigned char* dpb)
IAttachment* createDatabase(StatusType* status, const char* fileName, unsigned dpbLength, const unsigned char* dpb)
IService* attachServiceManager(StatusType* status, const char* service, unsigned spbLength, const unsigned char* spb)
void shutdown(StatusType* status, unsigned timeout, const int reason)
void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback)