node-firebird 2.5.0 → 2.7.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.
- package/README.md +101 -4
- package/lib/types.d.ts +52 -0
- package/lib/wire/connection.d.ts +22 -0
- package/lib/wire/connection.js +487 -0
- package/lib/wire/const.d.ts +19 -0
- package/lib/wire/const.js +29 -0
- package/lib/wire/database.d.ts +20 -0
- package/lib/wire/database.js +65 -0
- package/lib/wire/serialize.d.ts +2 -1
- package/lib/wire/serialize.js +9 -4
- package/lib/wire/statement.d.ts +6 -0
- package/lib/wire/statement.js +11 -0
- package/lib/wire/transaction.d.ts +11 -5
- package/lib/wire/transaction.js +65 -0
- package/lib/wire/xsqlvar.d.ts +9 -0
- package/lib/wire/xsqlvar.js +22 -11
- package/package.json +1 -1
- package/src/types.ts +52 -0
- package/src/wire/connection.ts +530 -0
- package/src/wire/const.ts +31 -0
- package/src/wire/database.ts +74 -0
- package/src/wire/serialize.ts +11 -5
- package/src/wire/statement.ts +13 -0
- package/src/wire/transaction.ts +71 -0
- package/src/wire/xsqlvar.ts +25 -14
package/src/wire/database.ts
CHANGED
|
@@ -229,6 +229,54 @@ class Database extends Events.EventEmitter {
|
|
|
229
229
|
return self;
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Bulk-execute `query` once per row via the Firebird 4 batch API
|
|
234
|
+
* (protocol 16+) with all-or-nothing semantics: the batch runs in its
|
|
235
|
+
* own transaction, committed only when every record succeeded and
|
|
236
|
+
* rolled back otherwise. On failure the error of the first failed
|
|
237
|
+
* record is reported, with the full completion attached as
|
|
238
|
+
* err.batchCompletion. Use transaction.executeBatch for partial-success
|
|
239
|
+
* handling.
|
|
240
|
+
*/
|
|
241
|
+
executeBatch(query: string, rows: any[][], callback?: any, options?: any): this {
|
|
242
|
+
var self = this;
|
|
243
|
+
|
|
244
|
+
self.connection.startTransaction(function(err: any, transaction: any) {
|
|
245
|
+
if (err) {
|
|
246
|
+
doError(err, callback);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
transaction.executeBatch(query, rows, function(err: any, result: any) {
|
|
251
|
+
if (err) {
|
|
252
|
+
transaction.rollback(function() {
|
|
253
|
+
doError(err, callback);
|
|
254
|
+
});
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!result.success) {
|
|
259
|
+
transaction.rollback(function() {
|
|
260
|
+
var first = result.errors.length ? result.errors[0] : null;
|
|
261
|
+
var batchError: any = first
|
|
262
|
+
? first.error
|
|
263
|
+
: new Error('Batch failed for record(s) ' + result.errorRecordNumbers.join(', '));
|
|
264
|
+
batchError.batchCompletion = result;
|
|
265
|
+
doError(batchError, callback);
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
transaction.commit(function(err: any) {
|
|
271
|
+
if (callback)
|
|
272
|
+
callback(err, result);
|
|
273
|
+
});
|
|
274
|
+
}, options);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return self;
|
|
278
|
+
}
|
|
279
|
+
|
|
232
280
|
sequentially(query: string, params?: any, on?: any, callback?: any, options: any = {}): this {
|
|
233
281
|
if (params instanceof Function) {
|
|
234
282
|
options = callback;
|
|
@@ -322,6 +370,22 @@ class Database extends Events.EventEmitter {
|
|
|
322
370
|
return this.connection.dropDatabase(callback);
|
|
323
371
|
}
|
|
324
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Cancel the operation currently executing on this connection by sending
|
|
375
|
+
* an out-of-band op_cancel (Firebird 2.5+ / protocol 12+). The cancelled
|
|
376
|
+
* operation fails through its own callback with err.gdscode ===
|
|
377
|
+
* GDSCode.CANCELLED. `kind` defaults to fb_cancel_raise; cancellation is
|
|
378
|
+
* per-attachment, not per-statement.
|
|
379
|
+
*/
|
|
380
|
+
cancel(kind?: number | ((err?: any) => void), callback?: (err?: any) => void): this {
|
|
381
|
+
if (typeof kind === 'function') {
|
|
382
|
+
callback = kind;
|
|
383
|
+
kind = undefined;
|
|
384
|
+
}
|
|
385
|
+
this.connection.cancelOperation(kind, callback);
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
|
|
325
389
|
attachEvent(callback: (err: any, evt?: any) => void): this {
|
|
326
390
|
var self = this;
|
|
327
391
|
const eventid = self.eventid++;
|
|
@@ -457,6 +521,11 @@ class Database extends Events.EventEmitter {
|
|
|
457
521
|
return fromCallback(function(cb) { self.execute(query, params, cb, options); });
|
|
458
522
|
}
|
|
459
523
|
|
|
524
|
+
executeBatchAsync(query: string, rows: any[][], options?: any): Promise<any> {
|
|
525
|
+
var self = this;
|
|
526
|
+
return fromCallback(function(cb) { self.executeBatch(query, rows, cb, options); });
|
|
527
|
+
}
|
|
528
|
+
|
|
460
529
|
sequentiallyAsync(query: string, params?: any, on?: any, options?: any): Promise<void> {
|
|
461
530
|
if (params instanceof Function) {
|
|
462
531
|
options = on;
|
|
@@ -496,6 +565,11 @@ class Database extends Events.EventEmitter {
|
|
|
496
565
|
return fromCallback(function(cb) { self.attachEvent(cb); });
|
|
497
566
|
}
|
|
498
567
|
|
|
568
|
+
cancelAsync(kind?: number): Promise<void> {
|
|
569
|
+
var self = this;
|
|
570
|
+
return fromCallback(function(cb) { self.cancel(kind, cb); });
|
|
571
|
+
}
|
|
572
|
+
|
|
499
573
|
/**
|
|
500
574
|
* Run `work` inside a transaction: commits when the returned promise
|
|
501
575
|
* resolves, rolls back when it rejects (the original error is rethrown,
|
package/src/wire/serialize.ts
CHANGED
|
@@ -282,12 +282,12 @@ export class XdrWriter {
|
|
|
282
282
|
this.pos += 4;
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
addInt64(value: number): void {
|
|
285
|
+
addInt64(value: number | bigint): void {
|
|
286
286
|
this.ensure(8);
|
|
287
|
-
// Note: precision is limited to Number.MAX_SAFE_INTEGER
|
|
288
|
-
//
|
|
289
|
-
// Long.fromNumber() behaviour.
|
|
290
|
-
this.buffer.writeBigInt64BE(BigInt(Math.trunc(value)), this.pos);
|
|
287
|
+
// Note: for numbers, precision is limited to Number.MAX_SAFE_INTEGER
|
|
288
|
+
// (±2^53-1); values outside this range lose precision, which matches
|
|
289
|
+
// the previous Long.fromNumber() behaviour. BigInts keep full precision.
|
|
290
|
+
this.buffer.writeBigInt64BE(typeof value === 'bigint' ? value : BigInt(Math.trunc(value)), this.pos);
|
|
291
291
|
this.pos += 8;
|
|
292
292
|
}
|
|
293
293
|
|
|
@@ -381,6 +381,12 @@ export class XdrWriter {
|
|
|
381
381
|
this.pos += 8;
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
+
addFloat(value: number): void {
|
|
385
|
+
this.ensure(4);
|
|
386
|
+
this.buffer.writeFloatBE(value, this.pos);
|
|
387
|
+
this.pos += 4;
|
|
388
|
+
}
|
|
389
|
+
|
|
384
390
|
addQuad(quad: { low: number; high: number }): void {
|
|
385
391
|
this.ensure(8);
|
|
386
392
|
var b = this.buffer;
|
package/src/wire/statement.ts
CHANGED
|
@@ -69,6 +69,14 @@ class Statement {
|
|
|
69
69
|
this.connection.fetchAll(this, transaction, callback);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Execute this statement once per row via the Firebird 4 batch API
|
|
74
|
+
* (protocol 16+). `rows` is an array of parameter arrays.
|
|
75
|
+
*/
|
|
76
|
+
executeBatch(transaction: any, rows: any[][], callback?: any, options?: any): void {
|
|
77
|
+
this.connection.executeBatch(transaction, this, rows, callback, options);
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
/* Promise / async-await API — wrappers over the callback methods above. */
|
|
73
81
|
|
|
74
82
|
executeAsync(transaction: any, params?: any, options?: any): Promise<any> {
|
|
@@ -76,6 +84,11 @@ class Statement {
|
|
|
76
84
|
return fromCallback(function(cb) { self.execute(transaction, params, cb, options); });
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
executeBatchAsync(transaction: any, rows: any[][], options?: any): Promise<any> {
|
|
88
|
+
var self = this;
|
|
89
|
+
return fromCallback(function(cb) { self.executeBatch(transaction, rows, cb, options); });
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
fetchAsync(transaction: any, count: number | string): Promise<any> {
|
|
80
93
|
var self = this;
|
|
81
94
|
return fromCallback(function(cb) { self.fetch(transaction, count, cb); });
|
package/src/wire/transaction.ts
CHANGED
|
@@ -8,6 +8,38 @@ import Const from './const';
|
|
|
8
8
|
*
|
|
9
9
|
***************************************/
|
|
10
10
|
|
|
11
|
+
/** The error delivered when options.signal was already aborted on entry. */
|
|
12
|
+
function abortError(signal: any): Error {
|
|
13
|
+
if (signal && signal.reason instanceof Error)
|
|
14
|
+
return signal.reason;
|
|
15
|
+
var err: any = new Error('The operation was aborted');
|
|
16
|
+
err.name = 'AbortError';
|
|
17
|
+
err.code = 'ABORT_ERR';
|
|
18
|
+
return err;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Wire an AbortSignal to a running statement: on abort, send an out-of-band
|
|
23
|
+
* op_cancel so the server fails the executing operation with isc_cancelled
|
|
24
|
+
* (surfaced through the statement's own callback as err.gdscode ===
|
|
25
|
+
* GDSCode.CANCELLED). Returns the wrapped callback that detaches the
|
|
26
|
+
* listener once the operation settles.
|
|
27
|
+
*/
|
|
28
|
+
function hookAbortSignal(connection: any, signal: any, callback: any): any {
|
|
29
|
+
var settled = false;
|
|
30
|
+
var onAbort = function() {
|
|
31
|
+
if (!settled)
|
|
32
|
+
connection.cancelOperation(Const.fb_cancel_raise);
|
|
33
|
+
};
|
|
34
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
35
|
+
return function(err?: any, result?: any, meta?: any, isSelect?: boolean) {
|
|
36
|
+
settled = true;
|
|
37
|
+
signal.removeEventListener('abort', onAbort);
|
|
38
|
+
if (callback)
|
|
39
|
+
callback(err, result, meta, isSelect);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
11
43
|
class Transaction {
|
|
12
44
|
connection: any;
|
|
13
45
|
db: any;
|
|
@@ -38,6 +70,15 @@ class Transaction {
|
|
|
38
70
|
params = undefined;
|
|
39
71
|
}
|
|
40
72
|
|
|
73
|
+
var signal = options && options.signal;
|
|
74
|
+
if (signal) {
|
|
75
|
+
if (signal.aborted) {
|
|
76
|
+
doError(abortError(signal), callback);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
callback = hookAbortSignal(this.connection, signal, callback);
|
|
80
|
+
}
|
|
81
|
+
|
|
41
82
|
var self = this;
|
|
42
83
|
this.newStatement(query, function(err: any, statement: any) {
|
|
43
84
|
|
|
@@ -192,6 +233,36 @@ class Transaction {
|
|
|
192
233
|
this.execute(query, params, callback, options);
|
|
193
234
|
}
|
|
194
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Execute `query` once per row in `rows` using the Firebird 4 batch API
|
|
238
|
+
* (protocol 16+, single network flush). The callback receives a
|
|
239
|
+
* completion object: { recordCount, updateCounts, errors:
|
|
240
|
+
* [{recordNumber, error}], errorRecordNumbers, success }. Per-record
|
|
241
|
+
* failures do NOT roll anything back here — inspect the completion and
|
|
242
|
+
* commit or roll back yourself (or use db.executeBatch for
|
|
243
|
+
* all-or-nothing semantics).
|
|
244
|
+
*/
|
|
245
|
+
executeBatch(query: string, rows: any[][], callback?: any, options?: any): void {
|
|
246
|
+
var self = this;
|
|
247
|
+
this.newStatement(query, function(err: any, statement: any) {
|
|
248
|
+
if (err) {
|
|
249
|
+
doError(err, callback);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
statement.executeBatch(self, rows, function(err: any, result: any) {
|
|
254
|
+
statement.release();
|
|
255
|
+
if (callback)
|
|
256
|
+
callback(err, result);
|
|
257
|
+
}, options);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
executeBatchAsync(query: string, rows: any[][], options?: any): Promise<any> {
|
|
262
|
+
var self = this;
|
|
263
|
+
return fromCallback(function(cb) { self.executeBatch(query, rows, cb, options); });
|
|
264
|
+
}
|
|
265
|
+
|
|
195
266
|
commit(callback?: (err?: any) => void): void {
|
|
196
267
|
this.connection.commit(this, callback);
|
|
197
268
|
}
|
package/src/wire/xsqlvar.ts
CHANGED
|
@@ -718,6 +718,28 @@ export class SQLParamBuffer {
|
|
|
718
718
|
|
|
719
719
|
//------------------------------------------------------
|
|
720
720
|
|
|
721
|
+
/**
|
|
722
|
+
* Split a JS Date into the Firebird wire representation used by
|
|
723
|
+
* TIMESTAMP/DATE/TIME columns: `date` is the modified-Julian day number and
|
|
724
|
+
* `time` the count of 100-microsecond units since midnight (local time).
|
|
725
|
+
*/
|
|
726
|
+
export function encodeDateTimeParts(value: Date): { date: number; time: number } {
|
|
727
|
+
var ms = value.getTime() - value.getTimezoneOffset() * MsPerMinute;
|
|
728
|
+
var time = ms % TimeCoeff;
|
|
729
|
+
var date = (ms - time) / TimeCoeff + DateOffset;
|
|
730
|
+
time *= 10;
|
|
731
|
+
|
|
732
|
+
// check overflow (dates before the epoch)
|
|
733
|
+
if (time < 0) {
|
|
734
|
+
date--;
|
|
735
|
+
time = TimeCoeff * 10 + time;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
return { date: date, time: time };
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
//------------------------------------------------------
|
|
742
|
+
|
|
721
743
|
export class SQLParamQuad {
|
|
722
744
|
value: any;
|
|
723
745
|
|
|
@@ -753,20 +775,9 @@ export class SQLParamDate {
|
|
|
753
775
|
|
|
754
776
|
encode(data: XdrWriter): void {
|
|
755
777
|
if (this.value != null) {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
var date = (value - time) / TimeCoeff + DateOffset;
|
|
760
|
-
time *= 10;
|
|
761
|
-
|
|
762
|
-
// check overflow
|
|
763
|
-
if (time < 0) {
|
|
764
|
-
date--;
|
|
765
|
-
time = TimeCoeff*10 + time;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
data.addInt(date);
|
|
769
|
-
data.addUInt(time);
|
|
778
|
+
var parts = encodeDateTimeParts(this.value);
|
|
779
|
+
data.addInt(parts.date);
|
|
780
|
+
data.addUInt(parts.time);
|
|
770
781
|
} else {
|
|
771
782
|
data.addInt(0);
|
|
772
783
|
data.addUInt(0);
|