Pure JavaScript and Asynchronous Firebird client for Node.js

Firebird forum on Google Groups.
Firebird database on social networks
Changelog for version v0.2.x
- added auto-reconnect
- added sequentially selects
- events for connection (attach, detach, row, result, transaction, commit, rollback, error, etc.)
- performance improvements
- supports inserting/updating buffers and streams
- reading blobs (sequentially)
- pooling
database.detach()waits for last command- better unit-test
Installation
npm install node-firebirdUsage
var Firebird = require('node-firebird');Methods
Firebird.escape(value) -> return {String}- prevent for SQL InjectionsFirebird.attach(options, function(err, db))attach a databaseFirebird.create(options, function(err, db))create a databaseFirebird.attachOrCreate(options, function(err, db))attach or create databaseFirebird.pool(max, options) -> return {Object}create a connection pooling
Connection types
Connection options
var options = {};
options.host = '127.0.0.1';
options.port = 3050;
options.database = 'database.fdb';
options.user = 'SYSDBA';
options.password = 'masterkey';
options.lowercase_keys = false; // set to true to lowercase keys
options.role = null; // default
options.pageSize = 4096; // default when creating database
options.retryConnectionInterval = 1000; // reconnect interval in case of connection drop
options.blobAsText = false; // set to true to get blob as text, only affects blob subtype 1
options.blobChunkSize = 1024; // segment size in bytes used when WRITING blobs (default 1024, max 65535)
options.blobReadChunkSize = 1024; // buffer size in bytes requested per op_get_segment when READING blobs (default 1024, max 65535)
options.encoding = 'UTF8'; // default encoding for connection is UTF-8
options.wireCompression = false; // set to true to enable firebird compression on the wire (works only on FB >= 3 and compression is enabled on server (WireCompression = true in firebird.conf))
options.wireCrypt = Firebird.WIRE_CRYPT_ENABLE; // default; set to Firebird.WIRE_CRYPT_DISABLE to disable wire encryption (FB >= 3)
options.pluginName = undefined; // optional, auto-negotiated; can be set to Firebird.AUTH_PLUGIN_SRP256, Firebird.AUTH_PLUGIN_SRP, or Firebird.AUTH_PLUGIN_LEGACY
options.dbCryptConfig = undefined; // optional; database encryption key for encrypted databases. Use 'base64:<value>' for base64-encoded keys or plain text
options.connectTimeout = 10000; // optional; timeout in ms for a single pool.get() attach operation (default: no timeout)Classic
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
db.query('SELECT * FROM TABLE', function (err, result) {
// IMPORTANT: close the connection
db.detach();
});
});Pooling
// 5 = the number is count of opened sockets
var pool = Firebird.pool(5, options);
// Get a free pool
pool.get(function (err, db) {
if (err) throw err;
// db = DATABASE
db.query('SELECT * FROM TABLE', function (err, result) {
// IMPORTANT: release the pool connection
db.detach();
});
});
// Destroy pool
pool.destroy();Advanced Pooling Features
The pool implementation includes several safeguards for reliability:
- Connection Timeout: Use
options.connectTimeoutto prevent the pool from hanging if a server accepts the TCP connection but fails to respond to the Firebird wire protocol (e.g., during high load or authentication stalls). - Pool Destruction: Calling
pool.destroy()now immediately drains thependingqueue, notifying all waiting callers with an error. It also prevents any furtherpool.get()calls. - Slot Recovery: If a connection attempt times out, the pool slot is correctly freed so subsequent requests can be served. Late-arriving connections are automatically discarded to prevent resource leaks.
Pool Lifecycle State Diagram
stateDiagram-v2
[*] --> Active
Active --> Destroying: pool.destroy()
Destroying --> Destroyed: all connections detached
Destroyed --> [*]
state Active {
[*] --> Idle
Idle --> Creating: pool.get() [no idle db]
Creating --> InUse: attach() success
Creating --> Idle: attach() failure/timeout
Idle --> InUse: pool.get() [idle db exists]
InUse --> Idle: db.detach()
}
state Destroying {
[*] --> DrainingPending
DrainingPending --> DetachingIdle
DetachingIdle --> WaitingForInUse
WaitingForInUse --> [*]
}
Connect Timeout Sequence
sequenceDiagram
participant User
participant Pool
participant Firebird
User->>Pool: pool.get()
Pool->>Pool: increment _creating
Pool->>Pool: start timer (connectTimeout)
Pool->>Firebird: attach(options)
Note over Firebird: Server accepts TCP but hangs
Pool-->>Pool: timer expires
Pool->>Pool: decrement _creating
Pool-->>User: callback(Error: Connection timeout)
Note over Firebird: Server eventually responds
Firebird-->>Pool: attach callback(db)
Pool->>Firebird: db.detach() (discard late connection)
Database object (db)
Database Methods
db.query(query, [params], function(err, result), options)- classic query, returns Array of Objectdb.execute(query, [params], function(err, result), options)- classic query, returns Array of Arraydb.sequentially(query, [params], function(row, index), function(err), options)- sequentially querydb.detach(function(err))detach a databasedb.transaction(options, function(err, transaction))create transaction
Transaction options
const options = {
autoCommit: false,
autoUndo: true,
isolation: Firebird.ISOLATION_READ_COMMITTED,
ignoreLimbo: false,
readOnly: false,
wait: true,
waitTimeout: 0,
};Transaction methods
transaction.query(query, [params], function(err, result), options)- classic query, returns Array of Objecttransaction.execute(query, [params], function(err, result), options)- classic query, returns Array of Arraytransaction.sequentially(query, [params], function(row, index), function(err), options)- sequentially querytransaction.commit(function(err))commit current transactiontransaction.rollback(function(err))rollback current transaction
Statement options
const options = {
timeout: 1000, // Statement timeout in ms, default is 0 (no timeout)
}Examples
Parametrized Queries
Parameters
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
db.query(
'INSERT INTO USERS (ID, ALIAS, CREATED) VALUES(?, ?, ?) RETURNING ID',
[1, "Pe'ter", new Date()],
function (err, result) {
console.log(result[0].id);
db.query(
'SELECT * FROM USERS WHERE Alias=?',
['Peter'],
function (err, result) {
console.log(result);
db.detach();
}
);
}
);
});BLOB (stream)
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
// INSERT STREAM as BLOB
db.query(
'INSERT INTO USERS (ID, ALIAS, FILE) VALUES(?, ?, ?)',
[1, 'Peter', fs.createReadStream('/users/image.jpg')],
function (err, result) {
// IMPORTANT: close the connection
db.detach();
}
);
});BLOB (buffer)
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
// INSERT BUFFER as BLOB
db.query(
'INSERT INTO USERS (ID, ALIAS, FILE) VALUES(?, ?, ?)',
[1, 'Peter', fs.readFileSync('/users/image.jpg')],
function (err, result) {
// IMPORTANT: close the connection
db.detach();
}
);
});Reading Blobs (Asynchronous)
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
db.query('SELECT ID, ALIAS, USERPICTURE FROM USER', function (err, rows) {
if (err) throw err;
// first row
rows[0].userpicture(function (err, name, e) {
if (err) throw err;
// +v0.2.4
// e.pipe(writeStream/Response);
// e === EventEmitter
e.on('data', function (chunk) {
// reading data
});
e.on('end', function () {
// end reading
// IMPORTANT: close the connection
db.detach();
});
});
});
});Reading Multiples Blobs (Asynchronous)
Firebird.attach(options, (err, db) => {
if (err) throw err;
db.transaction(Firebird.ISOLATION_READ_COMMITTED, (err, transaction) => {
if (err) {
throw err;
}
transaction.query('SELECT FIRST 10 * FROM JOB', (err, result) => {
if (err) {
transaction.rollback();
return;
}
const arrBlob = [];
for (const item of result) {
const fields = Object.keys(item);
for (const key of fields) {
if (typeof item[key] === 'function') {
item[key] = new Promise((resolve, reject) => {
// the same transaction is used (better performance)
// this is optional
item[key](transaction, (error, name, event, row) => {
if (error) {
return reject(error);
}
// reading data
let value = '';
event.on('data', (chunk) => {
value += chunk.toString('binary');
});
event.on('end', () => {
resolve({ value, column: name, row });
});
});
});
arrBlob.push(item[key]);
}
}
}
Promise.all(arrBlob)
.then((blobs) => {
for (const blob of blobs) {
result[blob.row][blob.column] = blob.value;
}
transaction.commit((err) => {
if (err) {
transaction.rollback();
return;
}
db.detach();
console.log(result);
});
})
.catch((err) => {
transaction.rollback();
});
});
});
});Optimizing BLOB Read/Write Chunk Sizes
When working with large blobs (especially over remote or high-latency connections), you can configure the chunk/segment sizes to minimize the number of network round-trips:
- blobChunkSize: The segment size in bytes used when writing blobs (default:
1024, maximum:65535). - blobReadChunkSize: The buffer size in bytes requested per segment read operation when reading blobs (default:
1024, maximum:65535).
For example, setting blobReadChunkSize: 65535 requests 64KB segments at a time, resulting in up to 64x fewer network packets/round-trips when reading large blobs.
var options = {
host: '127.0.0.1',
port: 3050,
database: 'database.fdb',
user: 'SYSDBA',
password: 'masterkey',
blobChunkSize: 65535, // Minimize write round-trips
blobReadChunkSize: 65535 // Minimize read round-trips
};
Firebird.attach(options, function (err, db) {
if (err) throw err;
// Insert/Read operations will use the configured 64KB chunk sizes
db.detach();
});Streaming a big data
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
db.sequentially(
'SELECT * FROM BIGTABLE',
function (row, index) {
// EXAMPLE
stream.write(JSON.stringify(row));
},
function (err) {
// END
// IMPORTANT: close the connection
db.detach();
}
);
});Transactions
Transaction types:
Firebird.ISOLATION_READ_UNCOMMITTEDFirebird.ISOLATION_READ_COMMITTEDFirebird.ISOLATION_REPEATABLE_READFirebird.ISOLATION_SERIALIZABLEFirebird.ISOLATION_READ_COMMITTED_READ_ONLY
Firebird.attach(options, function (err, db) {
if (err) throw err;
// db = DATABASE
db.transaction(
Firebird.ISOLATION_READ_COMMITTED,
function (err, transaction) {
transaction.query(
'INSERT INTO users VALUE(?,?)',
[1, 'Janko'],
function (err, result) {
if (err) {
transaction.rollback();
return;
}
transaction.commit(function (err) {
if (err) transaction.rollback();
else db.detach();
});
}
);
}
);
});Driver Events
Driver events are synchronous notifications emitted on the Database object for connection-level operations. Subscribe with db.on(eventName, handler).
Firebird.attach(options, function (err, db) {
if (err) throw err;
db.on('attach', function () {
// fired once the database is attached
});
db.on('detach', function (isPoolConnection) {
// isPoolConnection === Boolean
});
db.on('reconnect', function () {
// fired after the driver reconnects a dropped socket
});
db.on('error', function (err) {
// connection-level errors (socket errors, closed connection, etc.)
});
db.on('transaction', function (options) {
// fired when a transaction is started (before server response)
// options === resolved transaction options object
});
db.on('commit', function () {
// fired when a transaction commit is sent
});
db.on('rollback', function () {
// fired when a transaction rollback is sent
});
db.on('query', function (sql) {
// fired with the SQL string when a statement is prepared
});
db.on('row', function (row, index, isObject) {
// fired for each row decoded during a fetch
// index === Number, isObject === Boolean
});
db.on('result', function (rows) {
// fired with the full rows array once all rows are fetched
// rows === Array
});
db.detach();
});Firebird Database Events (POST_EVENT)
Firebird database events are asynchronous notifications triggered by POST_EVENT inside PSQL triggers or stored procedures. They travel over a separate aux connection and are handled through FbEventManager.
Note: Full POST_EVENT reception is not yet implemented.
attachEventandregisterEventare available, but actual event delivery requires completing theop_que_events/op_eventwire-protocol implementation.
Firebird.attach(options, function (err, db) {
if (err) throw err;
// 1. Open the aux event connection and get a FbEventManager
db.attachEvent(function (err, evtmgr) {
if (err) throw err;
// 2. Subscribe to one or more named events
evtmgr.registerEvent(['MY_EVENT'], function (err) {
if (err) throw err;
// 3. Listen for POST_EVENT notifications
evtmgr.on('post_event', function (name, count) {
// name === event name string (e.g. 'MY_EVENT')
// count === cumulative trigger count since last notification
});
});
// 4. Unsubscribe from events when no longer needed
// evtmgr.unregisterEvent(['MY_EVENT'], function (err) { ... });
// 5. Release the aux connection when done
// evtmgr.close(function (err) { ... });
});
});Escaping Query values
var sql1 = 'SELECT * FROM TBL_USER WHERE ID>' + Firebird.escape(1);
var sql2 = 'SELECT * FROM TBL_USER WHERE NAME=' + Firebird.escape("Pe'er");
var sql3 =
'SELECT * FROM TBL_USER WHERE CREATED<=' + Firebird.escape(new Date());
var sql4 = 'SELECT * FROM TBL_USER WHERE NEWSLETTER=' + Firebird.escape(true);
// or db.escape()
console.log(sql1);
console.log(sql2);
console.log(sql3);
console.log(sql4);Using GDS codes
var { GDSCode } = require('node-firebird/lib/gdscodes');
/*...*/
db.query(
'insert into my_table(id, name) values (?, ?)',
[1, 'John Doe'],
function (err) {
if (err.gdscode == GDSCode.UNIQUE_KEY_VIOLATION) {
console.log('constraint name:' + err.gdsparams[0]);
console.log('table name:' + err.gdsparams[0]);
/*...*/
}
/*...*/
}
);Service Manager functions
- backup
- restore
- fixproperties
- serverinfo
- database validation
- commit transaction
- rollback transaction
- recover transaction
- database stats
- users infos
- user actions (add modify remove)
- get firebird file log
- tracing
// each row : fctname : [params], typeofreturn
var fbsvc = {
"backup" : { [ "options"], "stream" },
"nbackup" : { [ "options"], "stream" },
"restore" : { [ "options"], "stream" },
"nrestore" : { [ "options"], "stream" },
"setDialect": { [ "database","dialect"], "stream" },
"setSweepinterval": { [ "database","sweepinterval"], "stream" },
"setCachebuffer" : { [ "database","nbpagebuffers"], "stream" },
"BringOnline" : { [ "database"], "stream" },
"Shutdown" : { [ "database","shutdown","shutdowndelay","shutdownmode"], "stream" },
"setShadow" : { [ "database","activateshadow"], "stream" },
"setForcewrite" : { [ "database","forcewrite"], "stream" },
"setReservespace" : { [ "database","reservespace"], "stream" },
"setReadonlyMode" : { [ "database"], "stream" },
"setReadwriteMode" : { [ "database"], "stream" },
"validate" : { [ "options"], "stream" },
"commit" : { [ "database", "transactid"], "stream" },
"rollback" : { [ "database", "transactid"], "stream" },
"recover" : { [ "database", "transactid"], "stream" },
"getStats" : { [ "options"], "stream" },
"getLog" : { [ "options"], "stream" },
"getUsers" : { [ "username"], "object" },
"addUser" : { [ "username", "password", "options"], "stream" },
"editUser" : { [ "username", "options"], "stream" },
"removeUser" : { [ "username","rolename"], "stream" },
"getFbserverInfos" : { [ "options", "options"], "object" },
"startTrace" : { [ "options"], "stream" },
"suspendTrace" : { [ "options"], "stream" },
"resumeTrace" : { [ "options"], "stream" },
"stopTrace" : { [ "options"], "stream" },
"getTraceList" : { [ "options"], "stream" },
"hasActionRunning" : { [ "options"], "object"}
}
Backup Service example
const options = {...}; // Classic configuration with manager = true
Firebird.attach(options, function(err, svc) {
if (err)
return;
svc.backup(
{
database:'/DB/MYDB.FDB',
files: [
{
filename:'/DB/MYDB.FBK',
sizefile:'0'
}
]
},
function(err, data) {
data.on('data', line => console.log(line));
data.on('end', () => svc.detach());
}
);
});Restore Service example
const config = {...}; // Classic configuration with manager = true
const RESTORE_OPTS = {
database: 'database.fdb',
files: ['backup.fbk']
};
Firebird.attach(config, (err, srv) => {
srv.restore(RESTORE_OPTS, (err, data) => {
data.on('data', () => {});
data.on('end', () =>{
srv.detach();})
});
});getLog and getFbserverInfos Service examples with use of stream and object return
fb.attach(_connection, function (err, svc) {
if (err) return;
// all function that return a stream take two optional parameter
// optread => byline or buffer byline use isc_info_svc_line and buffer use isc_info_svc_to_eof
// buffersize => is the buffer for service manager it can't exceed 8ko (i'm not sure)
svc.getLog({ optread: 'buffer', buffersize: 2048 }, function (err, data) {
// data is a readablestream that contain the firebird.log file
console.log(err);
data.on('data', function (data) {
console.log(data.toString());
});
data.on('end', function () {
console.log('finish');
});
});
// an other exemple to use function that return object
svc.getFbserverInfos(
{
dbinfo: true,
fbconfig: true,
svcversion: true,
fbversion: true,
fbimplementation: true,
fbcapatibilities: true,
pathsecuritydb: true,
fbenv: true,
fbenvlock: true,
fbenvmsg: true,
},
{},
function (err, data) {
console.log(err);
console.log(data);
}
);
});Character Set & Encoding Support
Node-Firebird defaults to UTF-8 for database connections, but fully supports custom client character sets. You can set the connection encoding by specifying options.encoding (e.g. 'UTF8', 'WIN1252', 'ISO8859_1', 'LATIN1', 'ASCII', or 'NONE').
Commonly used Firebird character sets are automatically mapped to their corresponding Node.js Buffer encodings:
| Firebird Character Set | Node.js Buffer Encoding | Description / Notes |
|---|---|---|
UTF8, UNICODE_FSS |
utf8 |
Unicode. Handles character-level truncation automatically based on charset width. |
WIN1252, ISO8859_1, LATIN1 |
latin1 |
8-bit European encodings. Safely decodes special accented characters. |
ASCII |
ascii |
7-bit ASCII. |
NONE |
latin1 |
Raw/unspecified character set. Treated as binary-safe 8-bit characters. |
Accented characters and fixed-length CHAR(N) column whitespace/truncation are handled automatically matching the connection character set width definitions.
Custom Charset Connection Example
var options = {
host: '127.0.0.1',
port: 3050,
database: 'win1252_db.fdb',
user: 'SYSDBA',
password: 'masterkey',
encoding: 'WIN1252' // Automatically maps to 'latin1' under the hood
};
Firebird.attach(options, function (err, db) {
if (err) throw err;
// Writes 'Ç Ã É Ú Ñ' correctly using Windows-1252 encoding
db.query('INSERT INTO ACCENTED_TEST (ID, NAME) VALUES (?, ?)', [1, 'Ç Ã É Ú Ñ'], function (err) {
if (err) throw err;
db.query('SELECT NAME FROM ACCENTED_TEST WHERE ID = 1', function (err, rows) {
if (err) throw err;
console.log(rows[0].name); // 'Ç Ã É Ú Ñ' (perfectly decoded)
db.detach();
});
});
});Firebird 3.0+ Support
Firebird 3.0 wire protocol versions 14 and 15 are now supported, including:
- Srp256 authentication (SHA-256) — preferred by default, alongside Srp (SHA-1) and Legacy_Auth
- Wire encryption (Arc4/RC4) — enabled by default via
wireCrypt - Wire compression — supported for protocol version 13+ (set
wireCompression: true) - Database encryption callback — support for encrypted databases via
dbCryptConfigoption
No server-side configuration changes are required for Firebird 3.0 with default settings.
Firebird.attach({
host: '127.0.0.1',
port: 3050,
database: '/path/to/db.fdb',
user: 'SYSDBA',
password: 'masterkey',
wireCrypt: Firebird.WIRE_CRYPT_ENABLE, // default, can set WIRE_CRYPT_DISABLE
pluginName: Firebird.AUTH_PLUGIN_SRP256, // optional, auto-negotiated
}, function(err, db) {
if (err) throw err;
// ...
db.detach();
});Database Encryption Support
For encrypted databases, provide the encryption key via the dbCryptConfig option:
Firebird.attach({
host: '127.0.0.1',
database: '/path/to/encrypted.fdb',
user: 'SYSDBA',
password: 'masterkey',
dbCryptConfig: 'base64:bXlTZWNyZXRLZXkxMjM0NTY=', // base64-encoded key
// or dbCryptConfig: 'myPlainTextKey' // plain text key (UTF-8 encoded)
}, function(err, db) {
if (err) throw err;
// ...
db.detach();
});Notes:
- The
dbCryptConfigvalue can be prefixed withbase64:for base64-encoded keys - Plain text values are encoded as UTF-8
- Empty or undefined values send an empty response to the callback
- This feature requires Firebird 3.0.1+ (protocol 14/15) for encrypted databases
Firebird 4.0 and 5.0 Support
Firebird 4.0+ wire protocol (versions 16 and 17) is fully supported, including:
- Protocol versions 16 and 17 — Full support for Firebird 4.0+ and 5.0+ wire protocols (automatic fallback/negotiation).
- DECFLOAT data types — Production-ready support for
DECFLOAT(16)(Decimal64, 8 bytes) andDECFLOAT(34)(Decimal128, 16 bytes) complying with the full IEEE 754-2008 standard using BID (Binary Integer Decimal) encoding. Supports special values such asNaN,+Infinity,-Infinity,+0, and-0. - INT128 data type — Native support for 128-bit integers using Node.js
BigInt. - Statement Timeout — Support for query and statement-level execution timeouts (Protocol 16+).
- Time Zone Support — Native support for
TIME WITH TIME ZONEandTIMESTAMP WITH TIME ZONE(represented as JavaScriptDateobjects). - Extended metadata identifiers — Support for identifiers up to 63 characters.
No configuration changes are required for Firebird 4.0 or 5.0 servers. The driver will automatically negotiate the best protocol version supported by both the client and server.
Firebird.attach({
host: '127.0.0.1',
port: 3050,
database: '/path/to/fb4.fdb',
user: 'SYSDBA',
password: 'masterkey',
}, function(err, db) {
if (err) throw err;
// DECFLOAT and INT128 types are automatically supported
db.query('SELECT CAST(123.456 AS DECFLOAT(16)) AS df16, CAST(9876543210 AS INT128) AS i128 FROM RDB$DATABASE', function(err, result) {
console.log(result); // { df16: 123.456, i128: 9876543210n }
db.detach();
});
});Using Timezones (FB 4.0+)
Columns of type TIMESTAMP WITH TIME ZONE and TIME WITH TIME ZONE are automatically mapped to JavaScript Date objects. Values are read as UTC and represented in the local timezone of the Node.js process.
// Select timezone columns
db.query('SELECT TS_TZ_COL, T_TZ_COL FROM FB4_TABLE', function(err, result) {
console.log(result[0].ts_tz_col); // JavaScript Date object
});
// Insert using Date objects
db.query('INSERT INTO FB4_TABLE (TS_TZ_COL) VALUES (?)', [new Date()], function(err) {
// ...
});For legacy Firebird 4 servers with SRP authentication only, use the following configuration in firebird.conf:
AuthServer = Srp256, Srp
WireCrypt = EnabledFor more details see:
- Firebird 3 release notes — new authentication
- Firebird 4 release notes — Srp256
- Firebird 4 release notes — DECFLOAT
- Firebird 4 migration guide — authorization
- Firebird 5 migration guide — authorization
Extensive Examples
Firebird 4.0+ DECFLOAT & INT128 Usage
Firebird.attach({
host: '127.0.0.1',
database: '/path/to/fb4.fdb',
user: 'SYSDBA',
password: 'masterkey',
}, function(err, db) {
if (err) throw err;
// Insert DECFLOAT and INT128 types
db.query(
'INSERT INTO INVENTORY (ID, PRICE, SERIAL_NUMBER) VALUES (?, ?, ?)',
[1n, '12.34567890123456', 987654321098765432109876543210n],
function(err) {
if (err) throw err;
// Select them back
db.query('SELECT PRICE, SERIAL_NUMBER FROM INVENTORY WHERE ID = 1', function(err, result) {
if (err) throw err;
console.log(typeof result[0].price); // 'string' (e.g. '12.34567890123456')
console.log(typeof result[0].serial_number); // 'bigint' (e.g. 987654321098765432109876543210n)
db.detach();
});
}
);
});Statement Timeouts (Firebird 4.0+)
Setting a statement timeout allows the client to automatically abort queries that take too long on the server.
Firebird.attach(options, function(err, db) {
if (err) throw err;
// Specify a statement-level execution timeout of 1000ms
db.query(
'SELECT * FROM MY_LARGE_TABLE',
[],
function(err, result) {
if (err) {
if (err.message.includes('timeout')) {
console.error('Query timed out!');
} else {
console.error('Error:', err);
}
}
db.detach();
},
{ timeout: 1000 } // timeout option passed to query/execute
);
});Advanced Connection Pooling & Life-cycle
var pool = Firebird.pool(10, {
host: '127.0.0.1',
database: 'db.fdb',
user: 'SYSDBA',
password: 'masterkey',
connectTimeout: 5000 // 5 seconds connect timeout for pool.get()
});
// Retrieve a connection
pool.get(function(err, db) {
if (err) {
console.error('Could not get connection from pool:', err);
return;
}
db.query('SELECT * FROM TABLE', function(err, result) {
// Return connection back to the pool
db.detach();
});
});
// Close all pool connections and reject pending requests
process.on('SIGTERM', function() {
pool.destroy();
});Contributors
- Henri Gourvest, https://github.com/hgourvest
- Popa Marius Adrian, https://github.com/mariuz
- Peter Širka, https://github.com/petersirka
