Embedded Databases 3 Embedded Firebird: Michaël Van Canneyt January 28, 2006
Embedded Databases 3 Embedded Firebird: Michaël Van Canneyt January 28, 2006
Embedded Databases 3 Embedded Firebird: Michaël Van Canneyt January 28, 2006
Embedded Firebird
Michaël Van Canneyt
Abstract
In this third article about embedded database, the Embedded Firebird is tested. It
will be shown how to use set up Embedded firebird, and how to configure some database
access layers (for Delphi and Lazarus) to work with Embedded Firebird.
1 Introduction
The Firebird SQL server (currently at version 1.5.3) was started from the open source
version of Interbase (6.0). It has remained compatible to a large part to Interbase, but has
put other accents than the Interbase Developers. One of these differences is that Firebird
offers an embedded build of the Firebird server. This means essentially that the Firebird
Client Library and the Firebird Server have been built into a single library (fbembed),
which can be used directly in an application.
No separately running Firebird server is needed to use the embedded server; The sole re-
striction is that a database can be accessed by only 1 application at a time. Other than that,
all functionality of the normal server version is available. This makes Firebird an excellent
choice as a back-end for a small application which nevertheless needs a database. At any
time, the application can be upscaled to a real client-server application. No code changes
will be necessary other than perhaps specifying the new location of the database.
In the next sections, the setup of embedded firebird will be discussed. After that, it will be
explained how to configure some existing Delphi and Lazarus data-access technologies so
they use the embedded version of firebird. Finally, the pupil tracker application introduced
in the previous articles will be tested with Firebird, and the performance will be compared
with SQLite.
2 Installation on Windows
The windows version of Embedded firebird comes as a separate zip file, which contains
installation instructions. Normally, it is sufficient to unzip the contents of this file in the
directory of the application which will use the embedded Firebird engine. Strictly speaking,
only the following files are needed:
fbembed.dll
ib_util.dll
firebird.conf
firebird.msg
intl\fbintl.dll
1
udf\fbudf.dll
If the data access layer of the application needs to have the traditional name of the In-
terbase/Firebird client library, then the file fbembed.dll can be renamed to fbclient.dll or
gds32.dll.
The fbintl.dll is only needed when the application needs to support international character
sets. Similarly, the fbudf.dll is only needed when the application needs to access the
standard UDF libraries.
In principle it is possible to split out the application files and the embedded firebird files,
putting the embedded firebird files in a separate directory:
c:\embeddedfb\firebird.msg
c:\embeddedfb\intl\fbintl.dll
c:\embeddedfb\udf\fbudf.dll
In that case, the firebird.conf file located next to the application needs to have an entry
RootDirectory=c:\embeddedfb\
3 Installation on Linux
On linux the installation is similar to that on Windows, but is nevertheless slightly different.
There is no separate archive with the embedded version. Instead, the embedded version is
distributed together with the classic build of the Linux Firebird server.
The classic build contains the libfbembed.so library, which contains the embedded server.
The linux version does need the security database security.fdb, and it additionally needs
the lock manager. That means that the following files should be distributed:
lib/libfbembed.so
firebird.conf
security.fdb
intl/fbintl
udf/fbudf.so
bin/fb_lock_mgr
As can be seen from the list above, the lock manager also needs to be distributed. This is
because the embedded version is derived from the classic build of the Firebird server.
Additionally, 2 environment variables need to be set when the application is started. Sup-
posing the application is installed in /opt/myapp, then the following variables should be
set:
LD_LIBRARY_PATH=/opt/myapp/lib
FIREBIRD=/opt/myapp
The first variable allows the dynamic library loader to find the libfbembed.so library. The
second variable tells the embedded server where it can find it’s message file, configuration
file etc. It’s best to have an entry in firebird.conf which points to the application directory:
2
RootDirectory=/opt/myapp
Similar to the Windows version it’s possible to share an embedded server between vari-
ous applications by moving the above files to a directory of their own. If the 2 variables
mentioned above here point to this directory then everything should be working just fine.
Contrary to the Windows version, the security database file is needed and passwords are
checked.
4 Configuring DBExpress
The DBExpress components from Delphi offer a fast and simple way to connect to many
databases, including Interbase or Firebird. At the same time all advantages of using a
TClientDataset are available, making these components a good choice for any database
application.
The connection component TSQLConnection represents a connection to a Database.
The details of using this component will not be discussed here: mainly this means setting
the path to the database, and specifying the username and password. Note that specifying
a username and password is needed: the password will not be checked, but the username is
needed to determine the SQL permissions.
So far there is no difference with using this component for use with a regular firebird or
Interbase database. However, to use the TSQLConnection with embedded firebird, it’s
sufficient to set the vendorlib property to fbembed.dll. The DBExpress driver will then
load fbembed.dll when it establishes a connection to the database.
In the previous ’Embedded Databases’ article, a pupil track data browser application was
shown. A version of this application that uses embedded firebird can be found on the CD
accompagnying this issue. The source code will not be examined, as it’s very straightfor-
ward and simple.
IGDSLibrary = interface
[’{BCAC76DD-25EB-4261-84FE-0CB3310435E2}’]
procedure LoadIBLibrary;
procedure FreeIBLibrary;
...
end;
Not all methods are shown. Each TIBDatabase, TIBTransaction, TIBQuery com-
ponent uses a reference to this interface to execute calls. This reference is obtained using
the GetGDSLibrary call in the IBIntf unit.
The actual interface returned by the GetGDSLibrary call can be configured using the
following call:
3
Type
RegisterGDSLibrary = function : IGDSLibrary;
Procedure RegisterGDSLibraryFactory(ARegisterGDSLibrary :
TRegisterGDSLibrary);
Var
{$ifndef linux}
CustomIBXlibraryName : String = ’fbembed.dll’;
{$else}
CustomIBXlibraryName : String = ’fbembed.so’;
{$endif}
Initialization
UseEmbeddedLibrary(’c:\myapp\fbembed.dll’);
end.
One can force the use of the fbembed.dll library distributed alongside the application.
Note that it is not possible to force IBX to use a different library for different connections.
Only one library can be used. This need not be a problem, because the embedded library is
a full-fledged client library, and can hence be used to make connections to remote servers.
6 Configuring SQLDB
The SQLDB components that come with Free Pascal (or Lazarus) have been designed sim-
ilar to Delphi’s DBExpress technology. There is a TIBConnection component to con-
nect to Interbase or Firebird databases. This component makes use of the ibase60dyn
unit, distributed with Free Pascal: this unit does run-time loading of the Interbase/Firebird
client library. (The unit ibase60 links to the client library at compile-time).
The ibase60dyn unit has the following declarations in it:
Var
UseEmbeddedFirebird : Boolean = False;
const
{$IFDEF Win32}
fbembedlib = ’fbembed.dll’;
4
{$ELSE}
fbembedlib = ’libfbembed.so’;
{$endif}
If UseEmbeddedFirebird is set to True then the unit will try to load the embedded
firebird client library, instead of the normal client library. So to use the embedded firebird
library, it is sufficient to add the following code to an initialization section of a unit:
Initialization
UseEmbeddedFirebird:=True;
end.
After that, all connections will be made using the embedded firebird client library (as spec-
ified in fbembedlib).
Note that, similarly to IBExpress, only one client library can be used for all connections in
the application.
7 SQL executor
The SQL executor program introduced in the previous articles required only three functions
to be able work with any database engine:
procedure StartDatabase;
procedure StopDatabase;
procedure ExecuteStatement(SQL: String;
IgnoreError: Boolean);
These functions can easily be implemented to work with Firebird. All that is needed is
a TIBConnection component, a TSQLTransaction and TSQLQuery query. They
act together like the corresponding components from IBX: A TSQLQuery component is
connected to a TIBConnection component (called DBFB) and a TSQLTransaction
component (called TRFB).
The functions to start and stop the database are then simple:
procedure TMainForm.StartDatabase;
begin
DBFB.Connected:=True;
TRFB.StartTransaction;
end;
procedure TMainForm.StopDatabase;
begin
TRFB.Commit;
DBFB.Connected:=False;
end;
The TSQLQuery component (called FBQry) works like any TQuery or TIBQuery
would work: It has a ExecSQL method to execute the SQL statement in it’s SQL prop-
erty. This makes it easy to implement the ExecuteStatement function:
5
procedure TMainForm.ExecuteStatement(SQL : String;
IgnoreError : Boolean);
begin
Try
FBQry.SQL.Text:=SQL;
FBQry.ExecSQL;
Except
On E: Exception do
begin
MLog.Lines.add(’Error executing statement: ’+E.Message);
If Not IgnoreError then
Raise;
end;
end;
end;
This will make the program work with the default Firebird client library. To make sure
that it works with the embedded version of Firebird, the following call is added to the
initializaion section of the main form unit:
initialization
{$I frmmain.lrs}
useEmbeddedFirebird:=True;
end.
procedure TMainForm.CloseDatabase;
begin
QPupilTrackdata.Close;
QPupils.Close;
DTracker.Connected:=False;
end;
6
procedure TMainForm.OpenDatabase;
begin
DTracker.Connected:=True;
QPupils.Open;
end;
SQLDB currently does not yet have support for Master-Detail coupling of queries (although
this is planned for the near future). To make the QPupilTrackData query display the
data for the current pupil, the following handler is implemented for the AfterScroll
event of the QPupils query:
Var
ID : Integer;
begin
With QPupilTrackData do
begin
Close;
If Not Dataset.fieldByName(’PU_ID’).IsNull then
begin
ID:=Dataset.fieldByName(’PU_ID’).AsInteger;
Params.ParamByNAme(’PU_ID’).asInteger:=ID;
Open;
end;
end;
end;
Again, to make the browser application use the embedded version of Firebird, the initializa-
tion code of the mail form unit is changed in the same way as the SQL Executor program.
The end result can be seen in figure 1 on page 8
9 Performance
Exactly the same queries were run on the embedded firebird database as were run on the
SQLite version:
3. Retrieving the number of entries before 8:26h on a given date (776 pupils on Septem-
ber 6, 2005) using a left join.
4. Retrieving the number of different pupils that entered school before 8:26h on a given
date (776 pupils on September 6, 2005). This is different from the previous query.
The queries were run using the isql tool that comes with Firebird, configured so it uses the
embedded version. The queries were run a second time on a Client/Server installation of
Firebird, to determine the overhead induced by the extra transport. The result is given in
the following table:
7
Figure 1: The browser application
10 Conclusion
As can be seen from this article, using embedded Firebird is no harder than using the usual
Client/Server setup of Firebird, both in Delphi and Lazarus: All standard delivered data
access technologies are in more or less degree configurable to use various client libraries,
making a switch to embedded Firebird easy: It’s just a matter of distributing the right files
with the application. The code changes required to switch from embedded to complete
client-server are negligible. When it comes to choosing between SQLite and Firebird, the
choice will probably depend on what kind of application needs to be programmed. For
applications that need to run complicated queries, Firebird may prove a better choice than
SQLite. For applications that just need to record a lot of data, SQLite can be preferrable, as
the inserts are faster. If upscaling is an option for the future, then Firebird is better suited,
since SQLite offers no remote-access technology.