Delphi Programming

This is a for now unstructured collection of tips for Firebird, the open source branch of CodeGear's Interbase. Some of them might also work for Interbase.

Open a database readonly[]

If you read a .gdb file from a cdrom it is normally not possible to open it in Firebird because the server tries to write to the file when it starts a transaction. You must use gfix mark the database as readonly

gfix -mode read_only <databasename>

Of course you must do that before writing the file to the cdrom.

Open a database readonly from multiple servers[]

A firebird server (including the embedded server) normally opens a database exclusively. So no two instances of Firebird can open the same database. This of course makes perfect sense for a normal database because there is no way two servers can synchronize their changes. For a read only database this is different because there are no changes, but there seems to be no configuration option to allow concurrent access to a database from multiple servers.

I found a hack for allowing this with the embedded Firebird: Before opening the database with Firebird, open the file in readonly mode with fmShareDenyWrite for your application:

 // this forces the database to be opened readonly:
 FileOpen(IBDatabase.DatabaseName, fmOpenRead or fmShareDenyWrite);
 IBTable.Active := true;

Open a database on a network share[]

Firebird does not allow a database to reside on a network share even if it is mapped to a drive letter. This probably is to prevent data loss and performance problems. Again, this makes quite a lot sense for normal databases but for the aforementioned read only database there is at least no danger of losing data.

Again, the embedded version can be hacked to open a database on a network drive. (Be warned, this hack is definitely ugly!):

  1. Assign a local filename to your IBDatabase.DatabaseName, preferably one that does not exist (e.g. "c:\nonexisting-dir\server\share\filename.gdb")
  2. Hook the Windows API function CreateFileW and in this hook check for the assigned filename. If it matches (use case insensitive compare!) change the filename to the network filename e.g. "c:\nonexisting-dir\server\share\filename.gdb" -> "\\server\share\filename.gdb" and call the original API function. If the filename does not match, just call the original function.

This tricks Firebird into opening a database on a network share because all the checks originally are done on a local filename. (I said it's ugly, didn't I?)