Firebird Odbc Driver 20 Manual
Firebird Odbc Driver 20 Manual
0
Manual
Alexander Potapchenko, Vladimir Tsvigun, Pavel Cisar, Jim Starkey, others
• Compiling for both 32-bit and 64-bit Windows clients on the Microsoft SDK base
• Unicode
• Multiple simultaneous transactions per connection, with varying transaction attributes if need
be. For example, one read-only transaction, one or more simultaneous read/write transactions.
• Firebird Services API (backup & restore, statistics, repair) by way of the function
SQLConfigDataSource
• The schemas SCHEMA or OWNER for cases where a schema is required for cross-DBMS compatibility
in SQL queries
• Fully functioning SQL syntax support for Services transactions via Firebird’s gpre pre-compiler
language (“EmbedSQL”)
• Use of the COM interface for Microsoft Distributed Transaction Coordinator (DTC)
1
Chapter 2. Installing the Driver
Installation is similar for both options. You can install both the 32-bit and the 64-bit driver on the
same machine if the user is going to access Firebird from multiple applications of mixed bitness.
Care will be needed to ensure that each application will connect using the correct DSN for the
required driver.
2
Chapter 2. Installing the Driver
Make sure you get the fbclient library that has the same major version number as
the server it is going to connect with.
• On a 64-bit Windows installation, the version of fbclient.dll in Firebird’s bin folder (or
Firebird’s root folder for version 3.0 and higher) is the 64-bit one. In some builds, the 32-bit
client is located in a folder, named either WOW64 or system32, that is beneath Firebird’s root.
If your ODBC DSN setup is going to need the 32-bit fbclient.dll and it is not there, you will need
to download the 32-bit Windows .zip kit from the main Firebird download page, extract the 32-
bit client from it and place it in the same folder as your application. An alternative is to
download the 32-bit installer instead and perform a client-only install, configuring the installer
to place it where you want it to be.
• The POSIX server kits always come with only the matching libfbclient.so. You will need to
extract it from an .i686 kit if your POSIX client application is 32-bit.
Have the client library in its proper place before installing the driver and configuring the DSN.
3
Chapter 2. Installing the Driver
Download or move the executable installer kit to the desktop. Right-click on it and select Run as
Administrator.
Click your way through the screens until you reach the one in which you configure your
preferences for the installation:
If you want or need to, you can have the driver installed in some other location than the one
offered by the installer as the default. Use the [ Browse ] button to find the location where you want
4
Chapter 2. Installing the Driver
The installer will create the \Firebird_ODBC subfolder if it does not exist already.
Lastly, the installer will display the configuration you have chosen. If you happy with it, just click
[ Install ] and it is done.
You might observe here that, on our system, we keep our own dedicated
“Programs64” and “Programs32” folders under C:\Windows. That is simply
preference as to how we organise our server and monitor the volume of stuff
installed by Windows updates into its own program folders.
The .chm and .html documents noted on that screen are older evolutions of this
document that are still built in with the kits at the point of this writing.
There are two prerequisites for installing the ODBC/JDBC driver on Linux:
The ODBC/JDBC driver packages for Linux are gzipped tar files. After gunzip they should be
processed by tar, or you can rename them to .tar.gz and use a tool such as Midnight Commander
to unpack them.
5
Chapter 2. Installing the Driver
Building from source code (recommended), requires the development package for unixODBC.
Proceed with the following steps:
3. Set the evironment variables FBINCDIR (Firebird include directory) and FBLIBDIR (Firebird lib
directory) if necessary.
5. It is possible to copy the library to /usr/local/lib64 or any preferred directory; or run make
install to symlink the library from the unixODBC directory
To install from the binary package, copy libOdbcFb.so to /usr/local/lib64, /usr/local/lib32 or any
other desired destination directory, as appropriate.
6
Chapter 3. Firebird ODBC Configuration
For the purpose of our example, we want to pick the item ODBC Data Sources (32-bit). Obviously, if
we had installed the 64-bit driver with the intention of using it for a 64-bit application, we would
pick the 64-bit item from this menu instead.
Run as Administrator!
Don’t left-click the item: right-click and, from the context menu, select Run as
Administrator. This is necessary because you are about to set up a System DSN.
Click on the tab labelled System DSN, where you will begin setting up your DSN.
7
Chapter 3. Firebird ODBC Configuration
Click [ Add… ] on the first screen to bring up the list of drivers on the next. Select the
Firebird/InterBase(r) driver, then click [ Finish ].
After clicking [ Finish ] on the previous screen, you are presented with a form into which you will
enter the parameters for a connection and will be able to test that they all work.
8
Chapter 3. Firebird ODBC Configuration
Parameter Entry
Data Source Name (DSN) REQUIRED. A unique, meaningful name indicating the type of
connection or its use. Make it brief as you can expand the
narrative elsewhere. Examples: “Connect from FbEmbed” or
“ConnectFbServer”
Description Optional. Can be used to provide more details about the data
source.
Client May be required. Local path to the Firebird client library. For
embedded connections to a sub-V.3 Windows server, it can point
to the copy of fbembed.dll in the application directory; otherwise,
point it to where you have located the bitness-compatible
Firebird remote client library unless you are certain the correct
library will be found automatically in a system location.
Character Set May be blank. Sets the default character set of the client.
Transaction parameters
Nowait (default wait) The transaction will wait if it encounters a lock conflict. Check to
have the transaction return an error immediately upon
encountering a lock conflict.
9
Chapter 3. Firebird ODBC Configuration
Parameter Entry
Lock timeout When a transaction is set for WAIT conflict resolution, express
the length of time in seconds until the lock times out and a lock
conflict error is returned (isc_lock_timeout).
Dialect SQL dialect for the client to use in accessing the database. The
only valid options for Firebird are 1 or 3. Note, Dialect 1 is not
compatible with quoted identifiers; Dialect 3 will not accept
strings delimited by double quotes.
Sensitive Identifier This option affects the way the client treats the property
SQL_IDENTIFIER_CASE. SQL_IC_UPPER (value=1) is the default,
treating all identifiers as stored in upper case characters. Check
to select SQL_IC_SENSITIVE (value=3) to have the interface treat all
identifiers that are not in all upper case as though they were
case-sensitive. This is not recommended! For an explanation, see
Note (1) below.
Autoquoted Identifier Default is NO. The effect of checking this is to change the setting to
YES. In that case, every identifier in every statement will be
double-quoted automatically. The need to set this on would be
highly unusual and would need to be well understood to avoid
non-stop errors.
SCHEMA options Drop-down list offering three options for treatment of SQL
schemas, which Firebird does not support. Normally, leave this at
the default setting Set null field SCHEMA. For some details, see
Note (2) below.
10
Chapter 3. Firebird ODBC Configuration
to be converted to
gets converted to
11
Chapter 3. Firebird ODBC Configuration
or
This selection of schema settings attempts to prevent clashes with applications that
do this kind of thing. The drop-down list offers the three variants:
Set null field SCHEMA is the default, causing the SCHEMA element to be set NULL
whenever it is specified as part of a query. The result is a query that Firebird can
process.
Remove SCHEMA from SQL query filters the namespace references from the
statement whenever the SQLExecDirect command receives a request such as
Use full SCHEMA] is reserved for a future in which Firebird has the capability to
process these concepts itself — perhaps in Firebird 4. In that event, the driver will
have no need to screen out these constructions.
Click on the [ Test connection ] button to confirm that your configuration is good:
12
Chapter 3. Firebird ODBC Configuration
If all is well, click [ OK ], return to the main form and save the configuration by clicking [ OK ]
there, too.
The Services button launches a number of server management utilities through a GUI management
console. It is described later in The Services Interface.
Configuration depends on the Linux distribution but, somewhere in /etc or /etc/unixODBC, should
be two files named odbc.ini and odbcinst.ini.
Add to odbcinst.ini:
[Firebird]
Description = InterBase/Firebird ODBC Driver
Driver = /usr/local/lib64/libOdbcFb.so
Setup = /usr/local/lib64/libOdbcFb.so
Threading = 1
FileUsage = 1
CPTimeout =
CPReuse =
Add to odbc.ini:
13
Chapter 3. Firebird ODBC Configuration
[employee]
Description = Firebird
Driver = Firebird
Dbname = localhost:/opt/firebird/examples/empbuild/employee.fdb
User = SYSDBA
Password = masterkey
Role =
CharacterSet =
ReadOnly = No
NoWait = No
UnixODBC has a tool named ISQL (not to be confused with Firebird’s tool of the same name!) that
you can use to test the connection, as follows:
isql -v employee
If you have connection problems, make sure the directory where you placed the Firebird ODBC
shared library, e.g. /usr/local/lib64/libOdbcFb.so, is on the system loadable library path. If not you
could set:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/odbc
export LD_LIBRARY_PATH=/usr/lib/odbc
If you still have problems, the next thing is to try an strace to try to identify them:
14
Chapter 4. Connecting to Firebird from Applications
PWD Password
PASSWORD
ROLE Role
DSN Data source name
DRIVER Driver name e.g., the string Firebird/InterBase(r) driver. Defaults to
the driver defined in the DSN.
DBNAME Database Full path to the database as seen by the server, including
IP address | server name[/port] for a remote connection.
DATABASE
Defaults to the database defined in the DSN.
CLIENT Local path to the May be needed if the connection is to be via an embedded
required fbclient server library located in an application folder.
library
CHARSET Client-side default Should be the same as the default character set of the
character set database, if possible; or one that is known to be codepage-
CHARACTERSET
compatible.
READONLY Read-only Set transactions in this connection to be read-only. The
default is read/write.
NOWAIT No wait Set transactions in this connection to have NO WAIT lock
resolution. The default is WAIT.
LOCKTIMEOUT Set the lock Pass the number of seconds to elapse after encountering a
timeout on WAIT lock conflict until a transaction is to return an error. Not
transaction valid if the transaction is set for NO WAIT resolution.
15
Chapter 4. Connecting to Firebird from Applications
The ODBC function SQLDriverConnect gives priority to the attributes defined in the connection
string, only fetching those stored in the DSN, or in a cited FILEDSN, to fill in any gaps.
Some examples of connection strings for applications that use the ODBC function SQLDriverConnect:
Open("DSN=myDb;")
Here, the function is expected to read everything it needs from the DSN. User name and password
are not supplied in the string. If they are not present in the DSN, either
1. it will use the environment variables ISC_PASSWORD and ISC_USER if they are are set; otherwise
The function should have what it needs to make this connection, provided the user name and
password are authenticated by the server.
16
Chapter 4. Connecting to Firebird from Applications
The DBNAME key points to the server IP address in the first example, with the path to the database file
in the POSIX format. The second example is making the same connection, using the server’s host
name instead of the IP address.
Open("DRIVER=Firebird/InterBase(r) driver;
DBNAME=172.17.2.10:/usr/local/db/myDb.fdb;")
In the last example, a local connection using a database alias in place of the database file path. Of
course, the alias must be present in aliases.conf in the root directory of the Firebird server (or, for
Firebird 3 and up, in databases.conf).
Using the server IP address and specifying an alternative port, with the target database on a POSIX
server; and the same using the server’s host name instead:
172.17.2.10/3051:/usr/local/db/myDb.fdb
myserver/3051:/usr/local/db/myDb.fdb
Using the server IP address, with the target database on a Windows server; and the same using the
server’s host name instead:
172.17.2.10:c:\db\myDb.fdb
myserver:c:\db\myDb.fdb
Using the server IP address and specifying an alternative port, with the target database on a
Windows server; and the same using the server’s host name instead:
172.17.2.10/3051:c:\db\myDb.fdb
myserver/3051:c:\db\myDb.fdb
Using TCP/IP local loopback, using the local loopback IP address on a POSIX server; and the same
17
Chapter 4. Connecting to Firebird from Applications
127.0.0.1:/usr/local/db/myDb.fdb
localhost:/usr/local/db/myDb.fdb
127.0.0.1:c:\db\myDb.fdb
localhost:c:\db\myDb.fdb
The DBNAME value for embedded connections and for the “Windows Local” (XNET) style of
connection uses just the file path or alias, without host name, IP address or any port number.
Local connection on a Windows server using first the file path and next an alias:
DBNAME=C:\db\myDb.fdb
DBNAME=C:dummy
On a POSIX server:
DBNAME=/usr/local/db/myDb.fdb
DBNAME=dummy
It is strongly recommended to define and use aliases to simplify life for you and your users. It
makes your DBNAME values completely neutral to the filesystem and so much less cumbersome. In
our last pairs of examples, the same alias was used on both Windows and POSIX. The one on the
Windows server would be defined thus:
dummy = C:\db\myDb.fdb
18
Chapter 4. Connecting to Firebird from Applications
dummy = /usr/local/db/myDb.fdb
19
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
5.1. Multithreading
Thread protection can be specified at two levels:
The default setting is reflected in the initial setup of the DSN on Windows: SAFETHREAD=Y.
then the driver is built without multi-threading support and responsibility for threading control is
transferred to the Firebird client library. This provides for fastest performance.
If you have a build that was made with this define, you should make it the default thread behaviour
for the DSN by configuring SAFETHREAD=N in its interface.
5.2. Transactions
Firebird supports three transaction isolation levels:
• READ COMMITTED
20
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
The default isolation level of the ODBC/JDBC driver is READ COMMITTED, which maps with read
committed in other database systems. Firebird’s other isolation levels do not map so easily. In the
ODBC/JDBC driver, SNAPSHOT maps to REPEATABLE READ and SNAPSHOT TABLE STABILITY maps
to SERIALIZABLE, with some tweaks.
Since version 2.0, the driver has been able to support every transaction configuration that Firebird
can support, including table reservation (“table blocking”). That was achieved by incorporating the
so-called “EmbeddedSQL” syntax that is native to the old pre-compiler, gpre, to prepare calls to the
ODBC API by the function SQLExecDirect.
5.2.1. Locking
Firebird implements optimistic row-level locking under all conditions. A transaction does not
attempt to lock a record until it is ready to post an update operation affecting that record. It can
happen, though rarely, for an update to fail because another client has a lock on the record, even if
the transaction that fails started before the one which secured the lock.
Firebird’s record versioning engine is able to achieve a granularity finer than that provided by
traditional row-level locking. Versioning allows any number of transactions to read a consistent
copy of any given record, even if other transactions are updating the same row simultaneously.
Readers and writers never block one another and Firebird’s maintenance of record versions is
totally transparent to the user.
DECLARE TRANSACTION… declares the described transaction, without activating it. SET TRANSACTION…,
on the other hand, activates the transaction, temporarily switching the SQL_ATTR_AUTOCOMMIT global
attribute of the ODBC API to SQL_AUTOCOMMIT_OFF. The transaction will have to be finished explicitly;
when it ends, the abiding rule of the API resumes.
21
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
LOCAL limits a transaction to acting only within the context of the current connection.
NAME transaction-name is a uniquely-named transaction, prepared for use by any connections in the
global environment.
or
or
or
The form SET TRANSACTION … NAME transaction-name [USING namedUniqueWorkspace] differs from
earlier implementations whereby the configuration set by the SET command would be repeated for
the next transaction. The inclusion of the NAME and/or USING clauses makes the configuration
repeatable on demand by use of the name.
22
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
In SQL, a transaction is completed by a COMMIT or ROLLBACK request. ODBC has methods that do one
or the other, such as SQLEndTran. Some programs are able to invoke SQLExecDirect but cannot call
SQLEndTran. For those programs it is necessary to call an explicit
If a transaction is initiated locally, the driver will execute SQLEndTran for the local
hStmt.
The ODBC/JDBC driver supports two-phase commit transactions, that is, a single transaction across
different Firebird databases. Up to 16 databases can be accessed simultaneously in one such
transaction — that is an absolute limit.
Firebird ODBC by default uses one transaction per connection. Programmatically you can use a
more flexible transaction structure. For example, you can use multiple transactions within one
connection, whereby a single connection can be using a number of read/write transactions
simultaneously.
23
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
An Example
HSTMT stmtRd;
HSTMT stmtWr;
SQLAllocHandle( SQL_HANDLE_STMT, connection, &stmtRd );
SQLAllocHandle( SQL_HANDLE_STMT, connection, &stmtWr );
SQLExecDirect( stmtRd, (UCHAR*)
"SET TRANSACTION LOCAL\n"
"READ ONLY\n"
"ISOLATION LEVEL\n"
"READ COMMITTED NO RECORD_VERSION WAIT\n",
SQL_NTS );
SQLExecDirect( stmtWr, (UCHAR*)
"SET TRANSACTION LOCAL\n"
"READ WRITE\n"
"ISOLATION LEVEL\n"
"READ COMMITTED NO RECORD_VERSION WAIT\n",
SQL_NTS );
SQLExecDirect( stmtRd,(UCHAR*)
"SELECT CURRENCY FROM COUNTRY"
" WHERE country = 'Canada'"
" FOR UPDATE OF CURRENCY",
SQL_NTS );
SQLFetch( stmtRd );
SQLPrepare( stmtWr, (UCHAR*)
"update COUNTRY\n"
"set CURRENCY = 'CndDlr'\n"
"where COUNTRY = 'Canada'\n",
SQL_NTS );
SQLExecute( stmtWr );
SQLExecDirect( stmtWr, (UCHAR*)"COMMIT", SQL_NTS );
The Microsoft Distributed Transaction Coordinator (MS DTC) service is a Windows component that
is responsible for coordinating transactions that span multiple resource managers, such as
database systems, message queues, and file systems. It can perform global, single-phase or two-
phase commit transactions involving Microsoft SQL Server, Sybase and other servers that are able
to work with it. Our ODBC/JDBC driver provides that capability for Firebird servers.
24
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
ITransactionDispenser *pTransactionDispenser;
ITransaction *pTransaction;
// Obtain the ITransactionDispenser Interface pointer
// by calling DtcGetTransactionManager()
DtcGetTransactionManager( NULL,// [in] LPTSTR pszHost,
NULL,// [in] LPTSTR pszTmName,
IID_ITransactionDispenser,// [in] REFIID rid,
0,// [in] DWORDdwReserved1,
0, // [in] WORDwcbReserved2,
NULL,// [in] void FAR * pvReserved2,
(void **)&pTransactionDispenser // [out] void** ppvObject
);
// Establish connection to database on server#1
LogonToDB( &gSrv1 );
// Establish connection to database on server#2
LogonToDB( &gSrv2 );
// Initiate an MS DTC transaction
pTransactionDispenser->BeginTransaction(
NULL,// [in] IUnknown __RPC_FAR *punkOuter,
ISOLATIONLEVEL_ISOLATED,// [in] ISOLEVEL isoLevel,
ISOFLAG_RETAIN_DONTCARE,// [in] ULONG isoFlags,
NULL,// [in] ITransactionOptions *pOptions
&pTransaction// [out] ITransaction **ppTransaction
);
// Enlist each of the data sources in the transaction
SQLSetConnectOption( gSrv1->hdbc, SQL_COPT_SS_ENLIST_IN_DTC, (UDWORD)pTransaction );
SQLSetConnectOption( gSrv2->hdbc, SQL_COPT_SS_ENLIST_IN_DTC, (UDWORD)pTransaction );
// Generate the SQL statement to execute on each of the databases
sprintf( SqlStatement,
"update authors set address = '%s_%d' where au_id = '%s'",
gNewAddress, i, gAuthorID );
// Perform updates on both of the DBs participating in the transaction
ExecuteStatement( &gSrv1, SqlStatement );
ExecuteStatement( &gSrv2, SqlStatement );
// Commit the transaction
hr = pTransaction->Commit( 0, 0, 0 );
// or roll back the transaction
//hr = pTransaction->Abort( 0, 0, 0 );
25
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
5.4. Cursors
In the current Firebird ODBC/JDBC driver, the Dynamic and Keyset cursors are modified to use the
Static cursor, through which it is not possible to update sets.
The read operators SQLFetch, SQLExtendedFetch and SQLScrollFetch use SQL_ROWSET_SIZE and
SQL_ATTR_ROW_ARRAY_SIZE.
For best performance using BLOB fields, use the operator SQLBindParameter, regardless of the size of
the BLOB field, as this will work much faster than using SQLPutData/SQLGetData.
// Specify that the Firebird ODBC Cursor is always used, then connect.
SQLSetConnectAttr( hdbc, SQL_ATTR_ODBC_CURSORS, (SQLPOINTER)SQL_CUR_USE_DRIVER, 0 );
SQLConnect( hdbc, (UCHAR*)connectString, SQL_NTS, NULL, 0, NULL, 0 );
This topic is well documented in MSDN. However, we must stress the absolute requirement to use
these statements before connecting:
// Specify that the ODBC Cursor Library is always used, then connect.
SQLSetConnectAttr( hdbc, SQL_ATTR_ODBC_CURSORS, (SQLPOINTER)SQL_CUR_USE_ODBC, 0 );
SQLConnect( hdbc, (UCHAR*)connectString, SQL_NTS, NULL, 0, NULL, 0 );
That data sets keys (?) in the rowset buffers. Updating the buffers requires this statement:
• Output from an executable procedure is optional and any output returned is a set of not more
26
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
than one “row” of values. If output is defined and none is produced, the output is null.
Returning data is not the primary goal of an executable procedure. Its purpose is to perform
data operations that are invisible to the user.
The mechanism for calling an executable procedure is the SQL statement EXECUTE PROCEDURE. For
example,
• A selectable procedure is written with the objective of returning a set of zero, one or many rows
of data. It can be used to change data, but it should not be written to do that. The PSQL
statement SUSPEND is used in this style of procedure to pass a row of output that has been
collected inside an iteration of a FOR SELECT.. loop out to a buffer.
The mechanism for calling a selectable procedure is the SQL statement SELECT.
In this example we have a selectable procedure from which we expect to receive a set of zero or
more rows based on the input parameters:
Microsoft Excel and some other applications use this statement to call a stored procedure:
The Firebird ODBC/JDBC driver determines what call to use when executing a stored procedure,
from the metadata obtained from the Firebird engine. Firebird flags a procedure as ‘executable’ or
‘selectable’ according to count of SUSPEND statements in the assembled (BLR) code of its definition.
For a trivial example:
Because the procedure has no SUSPEND statements, the ODBC driver knows to pass the call as execute
procedure TEST.
27
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
the BLR code for the stored procedure contains more than zero SUSPEND statements, so the ODBC
Driver will use select * from "ALL_LANGS".
TRAPS!
If you edit an element of the array e.g. element 1, 2 and 5, and do not specify the
other elements of the array, e.g. 3 and 4, then the other elements of the array will
be zeroed (integer), or blank (string).
With some programs where columns are dependent on array data, it is possible to
enter array data into a currently NULL array column without a validity check being
made on the various array elements. Under these circumstances it is essential to
enter the array elements before entering the column data.
28
Chapter 5. Developing with the Firebird ODBC/JDBC Driver
1. Create your database in Firebird. You can use table names like "Pending_Invoices" and fields
like "Order_Number".
2. Create the DSN for the Database, making sure to check all options in “Extended Identifier
Properties”
3. Open your dictionary, and import multiple tables as normal from the odbc source. It will work,
but do not try to browse or use the files in an application yet.
4. For every field, type in the “External Name” the name of the field surrounded by quotes (for
example, type "Order_Number" in the external name).
That’s it! Now use your dictionary with mixed case identifiers, without problems. But
remember — you must use double quotes around object names in all SQL statements from inside
Clarion.
29
Chapter 6. Firebird Events
Let us suppose that the table has also a BEFORE UPDATE trigger that posts an event 'change_order' in
subsequent operations when the field ORDER_STATUS is changed.
The trigger BEFORE UPDATE does not exist: this scenario is just for illustration
purposes, but you could create it if you like:
For our demo, we need to insert a new record into SALES. The field ORDER_STATUS on the newly-
inserted record contains the default value 'new'. After it commits, posting the event 'new_order', we
want to go back and change something in the new record. When we do so, our BEFORE UPDATE
trigger, BI_SALES will check whether the value of ORDER_STATUS is still 'new' and, if so, it will change it
to 'open' and post the event 'change_order'.
We are not really interested in how inserting and changing the record affects the
database state. The idea here is to show how to prime the driver to manage
listening for multiple events.
#include "OdbcUserEvents.h"
Next, in the table eventInfo, we specify the events that we are interested in. For our example, the
event 'new_order' is the only one we are interested in at this stage. The event 'change_order' is in
the picture only to demonstrate the driver’s ability to manage multiple events.
30
Chapter 6. Firebird Events
ODBC_EVENT_INFO eventInfo[] =
{
INIT_ODBC_EVENT("new_order"),
INIT_ODBC_EVENT("change_order")
};
Now, we need to create a structure — which we will name MyUniqueData — to store the data tasks
involved in our operation. In our example, a field event_flag will signal an event delivered from the
server. Our job starts from there.
struct MyUniqueData
{
int event_flag;
//... other define for use into astRoutine
};
We need to create a callback function, astRoutine, which will be activated when events defined in
the eventInfo table are flagged:
SQLSetConnectAttr( userInterfase->hdbc,
SQL_FB_UPDATECOUNT_EVENTS,
(SQLPOINTER)updated,
SQL_LEN_BINARY_ATTR( length ) );
This call is needed for updating the state of events in our structure eventInfo. That structure has a
field countEvents that maintains a total of event operations and a Boolean field changed that is set
True when the 'before' and 'after' values of countEvents are different.
When we want to flag an event that we are interested in, we issue the command:
myData.event_flag++;
31
Chapter 6. Firebird Events
It provides a fairly primitive mechanism for synchronizing workflow, but it is sufficient for our
needs. Its setup is as follows:
• At connection time or when the DSN is being constructed, the NOWAIT option must be set to OFF
// Specify that the Firebird ODBC Cursor is always used, then connect.
SQLSetConnectAttr( hdbc, SQL_ATTR_ODBC_CURSORS, (SQLPOINTER)SQL_CUR_USE_DRIVER, 0
);
SQLConnect( hdbc, (UCHAR*)connectString, SQL_NTS, NULL, 0, NULL, 0 );
• For the purpose of our demonstration we need to prepare an SQL cursor request. Your own,
real-life scenario would be less trivial, of course.
• We’ll construct the cursor query for our demo, naming it 'C':
• Initialize the structure ODBC_EVENTS_BLOCK_INFO as the events interface that is passed to the
driver:
myData.event_flag = 0;
ODBC_EVENTS_BLOCK_INFO eventsBlockInfo = INIT_EVENTS_BLOCK_INFO(
hdbc, eventInfo, astRoutine, &myData );
SQLSetConnectAttr(
hdbc, SQL_FB_INIT_EVENTS,
(SQLPOINTER)&eventsBlockInfo,
SQL_LEN_BINARY_ATTR((int)sizeof( eventsBlockInfo )) );
- to inform connection, that we are ready to accept events.
SQLSetConnectAttr( hdbc, SQL_FB_REQUEUE_EVENTS, (SQLPOINTER)NULL, 0 );
• Events begin …
32
Chapter 6. Firebird Events
while ( !iret )
{
// If the event was triggered, reset the buffer and re-queue
if ( myData.event_flag )
{
myData.event_flag = 0;
// Check for first ast_call. isc_que_events fires
// each event to get processing started
if ( first )
first = 0;
else
{
// Select query to look at triggered events
ret = SQLExecute( stmtSel );
for (;;)
{
ret = SQLFetch( stmtSel );
if ( ret == SQL_NO_DATA_FOUND )
break;
ret = SQLExecute( stmtUpd );
}
}
/* Re-queue for the next event */
SQLSetConnectAttr( hdbc, SQL_FB_REQUEUE_EVENTS, (SQLPOINTER)NULL, 0 );
/* This does not block, but as a sample program there is nothing
* else for us to do, so we will take a nap
*/
Sleep(1000);
}
}
33
Chapter 7. The Services Interface
The console is a tabbed display providing access to many of the Services API functions, with the
Backup tab on top.
34
Chapter 7. The Services Interface
35
Chapter 7. The Services Interface
We selected Header pages, which produced the gstat -h report for our database. Clicking on the
[ View Log ] button delivers the output to the browser:
Of course, you can have any statistics report, the Firebird log, metadata reports and more.
The Repair tab gives easy access to most of the gfix housekeeping functions:
36
Chapter 7. The Services Interface
The Users tab could be used to maintain accounts in the security database of any version of
Firebird prior to version 3.0, although the Services API method was discouraged from V.2.5 onward.
The Services API method is still available to maintain users in Firebird 3 databases if they were
defined using Legacy_Auth authentication management. It will not work with users defined with the
default SRP authentication manager.
Click on the appropriate button to add, modify or delete a user. Remember, the user performing
37
Chapter 7. The Services Interface
these tasks must be SYSDBA or a user with elevated server privileges. The role RDB$ADMIN is not
sufficiently elevated.
If a log file is available from the execution of a Service API function, the [ View Log ] button will
become active. The UI provides it on demand in HTML format and opens it in your default browser.
If you wonder how to go about coding this into your own ODBC application, the source code is a
resource that is freely available to you.
In the Connection chapter is a table of the keywords available to signify the values for attachments
38
Chapter 7. The Services Interface
via Firebird’s “regular” API. The table below provides the keywords for the KEYWORD=value
parameters for connecting to the server and launching a service request. These are additional to
the relevant connection parameters. For some cases, the default settings from the DSN, if used, will
be correct for Service requests.
The following samples show how to configure the various service requests.
39
Chapter 7. The Services Interface
Creating a Database
SQLConfigDataSource( NULL,
ODBC_ADD_DSN,
"Firebird/InterBase(r) driver",
"ODBC\0"
"CREATE_DB = D:\\TestService\\test.fdb\0"
"DESCRIPTION = My Firebird database\0"
"UID = SYSDBA\0"
"PWD = masterkey\0"
"CHARSET = NONE\0"
"PAGESIZE = 8192\0"
"DIALECT = 3\0" );
More alternative examples for creating databases are at the end of this chapter.
Backing Up a Database
SQLConfigDataSource( NULL,
ODBC_ADD_DSN,
"Firebird/InterBase(r) driver",
"ODBC\0"
"BACKUP_DB = D:\\TestService\\test.fdb\0"
"BACKUPFILE = D:\\TestService\\test.fbk\0"
"UID = SYSDBA\0"
"PWD = masterkey\0" );
Restoring a Database
SQLConfigDataSource( NULL,
ODBC_ADD_DSN,
"Firebird/InterBase(r) driver",
"ODBC\0"
"RESTORE_DB = D:\\TestService\\testNew.fdb\0"
"BACKUPFILE = D:\\TestService\\test.fbk\0"
"LOGFILE = D:\\TestService\\test.log\0"
"UID = SYSDBA\0"
"PWD = masterkey\0" );
Repairing a Database
SQLConfigDataSource( NULL,
ODBC_ADD_DSN,
"Firebird/InterBase(r) driver",
"ODBC\0"
"REPAIR_DB = D:\\TestService\\test.fdb\0"
"UID = SYSDBA\0"
"PWD = masterkey\0" );
40
Chapter 7. The Services Interface
Create a database using the ODBC API function SQLConfigDataSource. A convenient method for
creating a database that is going to be managed by someone else.
SQLConfigDataSource( NULL,
ODBC_ADD_DSN,
"Firebird/InterBase(r) driver",
"ODBC\0"
"CREATE_DB = D:\\TestService\\test.fdb\0"
"DESCRIPTION = My Firebird database\0"
"UID = SYSDBA\0"
"PWD = masterkey\0"
"CHARSET = NONE\0"
"PAGESIZE = 8192\0"
"DIALECT = 3\0" );
Create a database using the ODBC API function SQLDriverConnect. Convenient when the job is going
to be performed from a user application. The driver will handle errors and continue attempting to
create the database until it eventually succeeds in connecting to it. Access is passed to the client
upon success.
UCHAR buffer[1024];
SWORD bufferLength;
SQLDriverConnect( connection, hWnd,
(UCHAR*)"DRIVER=Firebird/InterBase(r) driver;"
"UID=SYSDBA;"
"PWD=masterkey;"
"PAGESIZE=8192;"
"DBNAMEALWAYS=C:\\Temp\\NewDB.fdb", SQL_NTS,
buffer, sizeof (buffer), &bufferLength,
SQL_DRIVER_NOPROMPT );
Create a database using the ODBC API function SQLExecDirect. This scenario is interesting in that the
database is created within the context of an existing client connection. It is not necessary therefore
to include "DRIVER=Firebird/InterBase (r) driver;" in the call, since it will be taken from the
current connection.
As with the first method that used SQLConfigDataSource, the current user does not get management
rights on the database created. For that requirement, SQLDriverConnect should be used instead.
41
Chapter 7. The Services Interface
SQLExecDirect( hStmt,
"CREATE DATABASE \'C:/TEMP/NEWDB00.FDB\'"
" PAGE_SIZE 8192"
" SET NAMES \'NONE\'"
" USER \'SYSDBA\'"
" PASSWORD \'masterkey\';",
SQL_NTS );
42
Chapter 8. Examples
Chapter 8. Examples
This page is optimistically left (almost) blank.
If you have something to offer, please feel free to zip it up and drop it into the Tracker, as an
improvement, in either the ODBC or the DOC section.
We would welcome a short description saying what your example demonstrates, in what
programming or scripting language and on what OS platform you tested it.
43
Appendix A: Licence Notices
The Initial Writers of the Original Documentation are Alexander Potapchenko, Vladimir Tsvigun,
James Starkey and others.
Copyright © 2017. All Rights Reserved. Initial Writers contact: paul at vinkenoog dot nl.
Included portions are Copyright © 2001-2020 by the authors. All Rights Reserved.
Software Licence
The contents of this manual refer to the Firebird ODBC/JDBC driver contributed originally to the
Firebird Project by James Starkey and developed since then by Vladimir Tsvigun, Alexander
Potapchenko and others under the Initial Developer’s Public License V.1.0.
44
Appendix B: Document History
Revision History
1.0. ?? ?? ??
x
0.2 27 Nov H.E.M.B. Picked up missing info about multi-threading at the beginning of Ch.
2017 5
0.1 25 Nov H.E.M.B. Tidied up old .chm help file and converted to Firebird
2017 documentation format.
45