node-firebird 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -135,102 +135,110 @@ class ServiceManager extends Events.EventEmitter {
135
135
  }
136
136
 
137
137
  _processquery(buffer, callback) {
138
- //console.log(buffer);
139
- var br = new BlrReader(buffer);
140
- var tinfo = br.readByteCode();
141
- var res = {};
142
- res.result = 0;
143
- for (; tinfo !== Const.isc_info_end; tinfo = br.readByteCode()) {
144
- switch (tinfo) {
145
- case Const.isc_info_svc_server_version:
146
- case Const.isc_info_svc_implementation:
147
- case Const.isc_info_svc_user_dbpath:
148
- case Const.isc_info_svc_get_env:
149
- case Const.isc_info_svc_get_env_lock:
150
- case Const.isc_info_svc_get_env_msg:
151
- res[this._infosmapping[tinfo]] = br.readString();
152
- break;
153
- case Const.isc_info_svc_version:
154
- res[this._infosmapping[tinfo]] = br.readInt32();
155
- break;
156
- case Const.isc_info_svc_svr_db_info:
157
- this._processdbinfo(br, res);
158
- break;
159
- case Const.isc_info_svc_limbo_trans:
160
- // not implemented
161
- for (; tinfo !== isc_info_flag_end; tinfo = br.readByteCode())
138
+ if (!Buffer.isBuffer(buffer)) {
139
+ doError(new Error('Malformed service-manager response: missing BLR buffer'), callback);
140
+ return;
141
+ }
142
+
143
+ try {
144
+ var br = new BlrReader(buffer);
145
+ var tinfo = br.readByteCode();
146
+ var res = {};
147
+ res.result = 0;
148
+ for (; tinfo !== Const.isc_info_end; tinfo = br.readByteCode()) {
149
+ switch (tinfo) {
150
+ case Const.isc_info_svc_server_version:
151
+ case Const.isc_info_svc_implementation:
152
+ case Const.isc_info_svc_user_dbpath:
153
+ case Const.isc_info_svc_get_env:
154
+ case Const.isc_info_svc_get_env_lock:
155
+ case Const.isc_info_svc_get_env_msg:
156
+ res[this._infosmapping[tinfo]] = br.readString();
162
157
  break;
163
- case Const.isc_info_svc_get_users:
164
- br.pos += 2
165
- res[this._infosmapping[tinfo]] = [];
166
- break;
167
- case Const.isc_spb_sec_username:
168
- var tuser = res[this._infosmapping[68]];
169
- tuser.push({});
170
- tuser[tuser.length - 1].username = br.readString();
171
- break;
172
- case Const.isc_spb_sec_firstname:
173
- var tuser = res[this._infosmapping[68]];
174
- var user = tuser[tuser.length-1];
175
- user.firstname = br.readString();
176
- break;
177
- case Const.isc_spb_sec_middlename:
178
- var tuser = res[this._infosmapping[68]];
179
- var user = tuser[tuser.length-1];
180
- user.middlename = br.readString();
181
- break;
182
- case Const.isc_spb_sec_lastname:
183
- var tuser = res[this._infosmapping[68]];
184
- var user = tuser[tuser.length-1];
185
- user.lastname = br.readString();
186
- break;
187
- case Const.isc_spb_sec_groupid:
188
- var tuser = res[this._infosmapping[68]];
189
- var user = tuser[tuser.length-1];
190
- user.groupid = br.readInt32();
191
- break;
192
- case Const.isc_spb_sec_userid:
193
- var tuser = res[this._infosmapping[68]];
194
- var user = tuser[tuser.length-1];
195
- user.userid = br.readInt32();
196
-
197
- break;
198
- case Const.isc_spb_sec_admin:
199
- var tuser = res[this._infosmapping[68]];
200
- var user = tuser[tuser.length-1];
201
- user.admin = br.readInt32();
202
- break;
203
-
204
- case Const.isc_info_svc_line:
205
- res.line = br.readString();
206
- break;
207
-
208
- case Const.isc_info_svc_to_eof:
209
- res.line = br.readString();
210
- break;
211
-
212
- case Const.isc_info_truncated:
213
- res.result = 1; // too much data for the result buffer increase size of it (buffersize parameter))
214
- break;
215
-
216
- case Const.isc_info_data_not_ready:
217
- res.result = 2;
218
- break;
219
-
220
- case Const.isc_info_svc_timeout:
221
- res.result = 3;
222
- break;
223
-
224
- case Const.isc_info_svc_stdin:
225
-
226
- break;
227
-
228
- case Const.isc_info_svc_capabilities:
229
- this._processcapabilities(br, res);
230
- break;
158
+ case Const.isc_info_svc_version:
159
+ res[this._infosmapping[tinfo]] = br.readInt32();
160
+ break;
161
+ case Const.isc_info_svc_svr_db_info:
162
+ this._processdbinfo(br, res);
163
+ break;
164
+ case Const.isc_info_svc_limbo_trans:
165
+ // not implemented
166
+ for (; tinfo !== isc_info_flag_end; tinfo = br.readByteCode())
167
+ break;
168
+ case Const.isc_info_svc_get_users:
169
+ br.pos += 2
170
+ res[this._infosmapping[tinfo]] = [];
171
+ break;
172
+ case Const.isc_spb_sec_username:
173
+ var tuser = res[this._infosmapping[68]];
174
+ tuser.push({});
175
+ tuser[tuser.length - 1].username = br.readString();
176
+ break;
177
+ case Const.isc_spb_sec_firstname:
178
+ var tuser = res[this._infosmapping[68]];
179
+ var user = tuser[tuser.length-1];
180
+ user.firstname = br.readString();
181
+ break;
182
+ case Const.isc_spb_sec_middlename:
183
+ var tuser = res[this._infosmapping[68]];
184
+ var user = tuser[tuser.length-1];
185
+ user.middlename = br.readString();
186
+ break;
187
+ case Const.isc_spb_sec_lastname:
188
+ var tuser = res[this._infosmapping[68]];
189
+ var user = tuser[tuser.length-1];
190
+ user.lastname = br.readString();
191
+ break;
192
+ case Const.isc_spb_sec_groupid:
193
+ var tuser = res[this._infosmapping[68]];
194
+ var user = tuser[tuser.length-1];
195
+ user.groupid = br.readInt32();
196
+ break;
197
+ case Const.isc_spb_sec_userid:
198
+ var tuser = res[this._infosmapping[68]];
199
+ var user = tuser[tuser.length-1];
200
+ user.userid = br.readInt32();
201
+
202
+ break;
203
+ case Const.isc_spb_sec_admin:
204
+ var tuser = res[this._infosmapping[68]];
205
+ var user = tuser[tuser.length-1];
206
+ user.admin = br.readInt32();
207
+ break;
208
+
209
+ case Const.isc_info_svc_line:
210
+ res.line = br.readString();
211
+ break;
212
+
213
+ case Const.isc_info_svc_to_eof:
214
+ res.line = br.readString();
215
+ break;
216
+
217
+ case Const.isc_info_truncated:
218
+ res.result = 1; // too much data for the result buffer increase size of it (buffersize parameter))
219
+ break;
220
+
221
+ case Const.isc_info_data_not_ready:
222
+ res.result = 2;
223
+ break;
224
+
225
+ case Const.isc_info_svc_timeout:
226
+ res.result = 3;
227
+ break;
228
+
229
+ case Const.isc_info_svc_stdin:
230
+
231
+ break;
232
+
233
+ case Const.isc_info_svc_capabilities:
234
+ this._processcapabilities(br, res);
235
+ break;
236
+ }
231
237
  }
238
+ callback(null, res);
239
+ } catch (err) {
240
+ doError(new Error('Malformed service-manager response: ' + err.message), callback);
232
241
  }
233
- callback(null, res);
234
242
  }
235
243
 
236
244
  detach(callback, force) {
@@ -1047,4 +1055,4 @@ class ServiceManager extends Events.EventEmitter {
1047
1055
  ServiceManager.ShutdownMode = ShutdownMode;
1048
1056
  ServiceManager.ShutdownKind = ShutdownKind;
1049
1057
 
1050
- module.exports = ServiceManager;
1058
+ module.exports = ServiceManager;
@@ -25,15 +25,15 @@ class Statement {
25
25
  this.connection.dropStatement(this, callback);
26
26
  }
27
27
 
28
- execute(transaction, params, callback, custom) {
28
+ execute(transaction, params, callback, options) {
29
29
  if (params instanceof Function) {
30
- custom = callback;
30
+ options = callback;
31
31
  callback = params;
32
32
  params = undefined;
33
33
  }
34
34
 
35
- this.custom = custom;
36
- this.connection.executeStatement(transaction, this, params, callback, custom);
35
+ this.options = options;
36
+ this.connection.executeStatement(transaction, this, params, callback, options);
37
37
  }
38
38
 
39
39
  fetch(transaction, count, callback) {
@@ -25,9 +25,9 @@ class Transaction {
25
25
  }
26
26
  }
27
27
 
28
- execute(query, params, callback, custom) {
28
+ execute(query, params, callback, options) {
29
29
  if (params instanceof Function) {
30
- custom = callback;
30
+ options = callback;
31
31
  callback = params;
32
32
  params = undefined;
33
33
  }
@@ -100,13 +100,13 @@ class Transaction {
100
100
  break;
101
101
  }
102
102
 
103
- }, custom);
103
+ }, options);
104
104
  });
105
105
  }
106
106
 
107
- sequentially(query, params, on, callback, asArray) {
107
+ sequentially(query, params, on, callback, options = {}) {
108
108
  if (params instanceof Function) {
109
- asArray = callback;
109
+ options = callback;
110
110
  callback = on;
111
111
  on = params;
112
112
  params = undefined;
@@ -117,7 +117,7 @@ class Transaction {
117
117
  }
118
118
 
119
119
  if (callback instanceof Boolean) {
120
- asArray = callback;
120
+ options = callback;
121
121
  callback = undefined;
122
122
  }
123
123
 
@@ -152,11 +152,23 @@ class Transaction {
152
152
  }
153
153
  };
154
154
 
155
- self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: _on });
155
+ // back compatibility - options parameter is a boolean
156
+ if (typeof options === 'boolean') {
157
+ options = { asObject: !options, asStream: true, on: _on };
158
+ } else {
159
+ options = {
160
+ asStream: true,
161
+ asObject: true,
162
+ on: _on,
163
+ ...options,
164
+ };
165
+ }
166
+
167
+ self.execute(query, params, callback, options);
156
168
  return self;
157
169
  }
158
170
 
159
- query(query, params, callback) {
171
+ query(query, params, callback, options = {}) {
160
172
  if (params instanceof Function) {
161
173
  callback = params;
162
174
  params = undefined;
@@ -165,7 +177,13 @@ class Transaction {
165
177
  if (callback === undefined)
166
178
  callback = noop;
167
179
 
168
- this.execute(query, params, callback, { asObject: true, asStream: callback === undefined || callback === null });
180
+ options = {
181
+ asObject: true,
182
+ asStream: callback === undefined || callback === null,
183
+ ...options,
184
+ };
185
+
186
+ this.execute(query, params, callback, options);
169
187
  }
170
188
 
171
189
  commit(callback) {
@@ -199,6 +199,44 @@ class SQLVarInt128 {
199
199
 
200
200
  //------------------------------------------------------
201
201
 
202
+ class SQLVarDecFloat16 {
203
+ decode(data, lowerV13) {
204
+ var ret = data.readDecFloat16();
205
+
206
+ if (!lowerV13 || !data.readInt()) {
207
+ return ret;
208
+ }
209
+
210
+ return null;
211
+ }
212
+
213
+ calcBlr(blr) {
214
+ blr.addByte(Const.blr_dec64);
215
+ blr.addShort(0);
216
+ }
217
+ }
218
+
219
+ //------------------------------------------------------
220
+
221
+ class SQLVarDecFloat34 {
222
+ decode(data, lowerV13) {
223
+ var ret = data.readDecFloat34();
224
+
225
+ if (!lowerV13 || !data.readInt()) {
226
+ return ret;
227
+ }
228
+
229
+ return null;
230
+ }
231
+
232
+ calcBlr(blr) {
233
+ blr.addByte(Const.blr_dec128);
234
+ blr.addShort(0);
235
+ }
236
+ }
237
+
238
+ //------------------------------------------------------
239
+
202
240
  class SQLVarFloat {
203
241
  decode(data, lowerV13) {
204
242
  var ret = data.readFloat();
@@ -295,6 +333,92 @@ class SQLVarTimeStamp {
295
333
 
296
334
  //------------------------------------------------------
297
335
 
336
+ class SQLVarTimeTz {
337
+ decode(data, lowerV13) {
338
+ var time = data.readUInt();
339
+ data.readInt(); // skip timezone info
340
+
341
+ if (!lowerV13 || !data.readInt()) {
342
+ var d = new Date(0);
343
+ d.setMilliseconds(Math.floor(time / 10) + d.getTimezoneOffset() * MsPerMinute);
344
+ return d;
345
+ }
346
+ return null;
347
+ }
348
+
349
+ calcBlr(blr) {
350
+ blr.addByte(Const.blr_sql_time_tz);
351
+ }
352
+ }
353
+
354
+ //------------------------------------------------------
355
+
356
+ class SQLVarTimeTzEx extends SQLVarTimeTz {
357
+ decode(data, lowerV13) {
358
+ var time = data.readUInt();
359
+ data.readInt(); // skip timezone info
360
+ data.readInt(); // skip ext_offset
361
+
362
+ if (!lowerV13 || !data.readInt()) {
363
+ var d = new Date(0);
364
+ d.setMilliseconds(Math.floor(time / 10) + d.getTimezoneOffset() * MsPerMinute);
365
+ return d;
366
+ }
367
+ return null;
368
+ }
369
+
370
+ calcBlr(blr) {
371
+ blr.addByte(Const.blr_ex_time_tz);
372
+ }
373
+ }
374
+
375
+ //------------------------------------------------------
376
+
377
+ class SQLVarTimeStampTz {
378
+ decode(data, lowerV13) {
379
+ var date = data.readInt();
380
+ var time = data.readUInt();
381
+ data.readInt(); // skip timezone info
382
+
383
+ if (!lowerV13 || !data.readInt()) {
384
+ var d = new Date(0);
385
+ d.setMilliseconds((date - DateOffset) * TimeCoeff + Math.floor(time / 10) + d.getTimezoneOffset() * MsPerMinute);
386
+ return d;
387
+ }
388
+
389
+ return null;
390
+ }
391
+
392
+ calcBlr(blr) {
393
+ blr.addByte(Const.blr_timestamp_tz);
394
+ }
395
+ }
396
+
397
+ //------------------------------------------------------
398
+
399
+ class SQLVarTimeStampTzEx extends SQLVarTimeStampTz {
400
+ decode(data, lowerV13) {
401
+ var date = data.readInt();
402
+ var time = data.readUInt();
403
+ data.readInt(); // skip timezone info
404
+ data.readInt(); // skip ext_offset
405
+
406
+ if (!lowerV13 || !data.readInt()) {
407
+ var d = new Date(0);
408
+ d.setMilliseconds((date - DateOffset) * TimeCoeff + Math.floor(time / 10) + d.getTimezoneOffset() * MsPerMinute);
409
+ return d;
410
+ }
411
+
412
+ return null;
413
+ }
414
+
415
+ calcBlr(blr) {
416
+ blr.addByte(Const.blr_ex_timestamp_tz);
417
+ }
418
+ }
419
+
420
+ //------------------------------------------------------
421
+
298
422
  class SQLVarBoolean {
299
423
  decode(data, lowerV13) {
300
424
  var ret = data.readInt();
@@ -378,6 +502,50 @@ class SQLParamInt128 {
378
502
 
379
503
  //------------------------------------------------------
380
504
 
505
+ class SQLParamDecFloat16 {
506
+ constructor(value) {
507
+ this.value = value;
508
+ }
509
+
510
+ calcBlr(blr) {
511
+ blr.addByte(Const.blr_dec64);
512
+ blr.addShort(0);
513
+ }
514
+
515
+ encode(data) {
516
+ if (this.value != null) {
517
+ data.addDecFloat16(this.value);
518
+ } else {
519
+ data.addDecFloat16(0);
520
+ data.addInt(1);
521
+ }
522
+ }
523
+ }
524
+
525
+ //------------------------------------------------------
526
+
527
+ class SQLParamDecFloat34 {
528
+ constructor(value) {
529
+ this.value = value;
530
+ }
531
+
532
+ calcBlr(blr) {
533
+ blr.addByte(Const.blr_dec128);
534
+ blr.addShort(0);
535
+ }
536
+
537
+ encode(data) {
538
+ if (this.value != null) {
539
+ data.addDecFloat34(this.value);
540
+ } else {
541
+ data.addDecFloat34(0);
542
+ data.addInt(1);
543
+ }
544
+ }
545
+ }
546
+
547
+ //------------------------------------------------------
548
+
381
549
  class SQLParamDouble {
382
550
  constructor(value) {
383
551
  this.value = value;
@@ -509,6 +677,8 @@ module.exports = {
509
677
  SQLVarInt,
510
678
  SQLVarInt64,
511
679
  SQLVarInt128,
680
+ SQLVarDecFloat16,
681
+ SQLVarDecFloat34,
512
682
  SQLVarFloat,
513
683
  SQLVarNull,
514
684
  SQLVarShort,
@@ -516,12 +686,18 @@ module.exports = {
516
686
  SQLVarText,
517
687
  SQLVarTime,
518
688
  SQLVarTimeStamp,
689
+ SQLVarTimeTz,
690
+ SQLVarTimeTzEx,
691
+ SQLVarTimeStampTz,
692
+ SQLVarTimeStampTzEx,
519
693
  SQLParamBool,
520
694
  SQLParamDate,
521
695
  SQLParamDouble,
522
696
  SQLParamInt,
523
697
  SQLParamInt64,
524
698
  SQLParamInt128,
699
+ SQLParamDecFloat16,
700
+ SQLParamDecFloat34,
525
701
  SQLParamQuad,
526
702
  SQLParamString,
527
703
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-firebird",
3
- "version": "2.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "Pure JavaScript and Asynchronous Firebird client for Node.js.",
5
5
  "keywords": [
6
6
  "firebird",
@@ -25,15 +25,16 @@
25
25
  "types": "./lib/index.d.ts",
26
26
  "license": "MPL-2.0",
27
27
  "scripts": {
28
- "test": "vitest run"
28
+ "test": "vitest run",
29
+ "lint": "oxlint"
29
30
  },
30
31
  "dependencies": {
31
32
  "big-integer": "^1.6.51",
32
33
  "long": "^5.2.3"
33
34
  },
34
35
  "devDependencies": {
35
- "coveralls-next": "^4.2.0",
36
- "nyc": "^15.0.1",
36
+ "coveralls-next": "^6.0.1",
37
+ "oxlint": "^0.15.11",
37
38
  "vitest": "^4.0.18"
38
39
  }
39
40
  }
package/vitest.config.js CHANGED
@@ -8,6 +8,17 @@ module.exports = defineConfig({
8
8
  fileParallelism: false,
9
9
  maxWorkers: 1,
10
10
  isolate: false,
11
- include: ['test/arc4.js', 'test/protocol.js', 'test/srp.js', 'test/service.js', 'test/utf8-user-identification.js', 'test/index.js', 'test/db-crypt-config.js'],
11
+ include: [
12
+ 'test/arc4.js',
13
+ 'test/protocol.js',
14
+ 'test/srp.js',
15
+ 'test/service.js',
16
+ 'test/utf8-user-identification.js',
17
+ 'test/index.js',
18
+ 'test/db-crypt-config.js',
19
+ 'test/timezone.js',
20
+ 'test/decfloat.js',
21
+ 'test/mock-server.js'
22
+ ],
12
23
  },
13
24
  });
@@ -1,72 +0,0 @@
1
- From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2
- From: Gobbo89 <gobbo89@users.noreply.github.com>
3
- Date: Thu, 19 Feb 2026 00:00:00 +0000
4
- Subject: [PATCH] fix(events): resolve event channel host from connection options
5
-
6
- When Firebird is configured with RemoteBindAddress unset (default),
7
- auxConnection() returns socket_info.host = "0.0.0.0", which is a
8
- bind-any address and not a routable destination for remote clients.
9
-
10
- This commit changes the host selection logic in attachEvent to prefer
11
- connection.options.host (the address that the user explicitly provided
12
- and that is proven reachable, since the initial DB attach succeeded).
13
-
14
- Only if options.host is absent does it fall back to socket_info.host,
15
- and even then only when that host is a concrete routable address (i.e.
16
- not "0.0.0.0" and not "::"). As a last resort it uses the socket's
17
- remoteAddress, normalizing IPv6-mapped IPv4 (::ffff:x.x.x.x → x.x.x.x).
18
-
19
- Fixes #386.
20
-
21
- ---
22
- lib/wire/database.js | 25 +++++++++++++++++++++++--
23
- 1 file changed, 23 insertions(+), 2 deletions(-)
24
-
25
- diff --git a/lib/wire/database.js b/lib/wire/database.js
26
- index xxxxxxx..yyyyyyy 100644
27
- --- a/lib/wire/database.js
28
- +++ b/lib/wire/database.js
29
- @@ -1,3 +1,18 @@
30
- +/**
31
- + * Resolves the host to use for the auxiliary event channel.
32
- + *
33
- + * Priority:
34
- + * 1. connection.options.host – explicitly provided by the caller; known reachable.
35
- + * 2. socket_info.host – only when it is a concrete routable address
36
- + * (i.e. not "0.0.0.0" and not "::").
37
- + * 3. socket.remoteAddress – the OS-level address of the main connection socket,
38
- + * with IPv6-mapped IPv4 prefixes stripped.
39
- + *
40
- + * @param {object} connection The active database connection object.
41
- + * @param {string} auxHost The host returned by the auxConnection() call.
42
- + * @returns {string} A connectable host string.
43
- + */
44
- +function resolveEventHost(connection, auxHost) {
45
- + // 1. Prefer the host the caller explicitly supplied.
46
- + if (connection.options && connection.options.host) {
47
- + return connection.options.host;
48
- + }
49
- +
50
- + // 2. Use auxConnection host only when it is a real address.
51
- + var BIND_ANY = ['0.0.0.0', '::'];
52
- + if (auxHost && BIND_ANY.indexOf(auxHost) === -1) {
53
- + return auxHost;
54
- + }
55
- +
56
- + // 3. Fall back to the OS-reported remote address of the main socket,
57
- + // normalising IPv6-mapped IPv4 (e.g. "::ffff:10.0.0.1" → "10.0.0.1").
58
- + var remoteAddress = connection._socket && connection._socket.remoteAddress;
59
- + if (remoteAddress) {
60
- + return remoteAddress.replace(/^::ffff:/, '');
61
- + }
62
- +
63
- + // Last resort: return whatever auxConnection gave us and let the caller fail
64
- + // with a meaningful socket error rather than a silent undefined.
65
- + return auxHost;
66
- +}
67
- +
68
- // ... (existing code) ...
69
-
70
- - var eventConnection = new EventConnection(socket_info.host, socket_info.port, self.connection.options, eventCallback);
71
- + var eventHost = resolveEventHost(self.connection, socket_info.host);
72
- + var eventConnection = new EventConnection(eventHost, socket_info.port, self.connection.options, eventCallback);