node-firebird 2.9.0 → 2.11.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 +211 -6
- package/lib/index.d.ts +5 -0
- package/lib/index.js +32 -1
- package/lib/pool.js +1 -1
- package/lib/srp.d.ts +3 -3
- package/lib/types.d.ts +165 -5
- package/lib/uri.js +2 -2
- package/lib/wire/connection.d.ts +92 -59
- package/lib/wire/connection.js +279 -58
- package/lib/wire/const.d.ts +9 -1
- package/lib/wire/const.js +23 -9
- package/lib/wire/database.d.ts +51 -26
- package/lib/wire/database.js +53 -20
- package/lib/wire/eventConnection.js +5 -3
- package/lib/wire/query-stream.d.ts +18 -0
- package/lib/wire/query-stream.js +73 -0
- package/lib/wire/serialize.d.ts +20 -2
- package/lib/wire/serialize.js +7 -0
- package/lib/wire/service.d.ts +42 -0
- package/lib/wire/service.js +145 -0
- package/lib/wire/socket.d.ts +3 -1
- package/lib/wire/socket.js +5 -2
- package/lib/wire/statement.d.ts +31 -19
- package/lib/wire/statement.js +1 -5
- package/lib/wire/transaction.d.ts +30 -18
- package/lib/wire/transaction.js +23 -4
- package/lib/wire/wire-types.d.ts +116 -0
- package/lib/wire/wire-types.js +10 -0
- package/lib/wire/xsqlvar.d.ts +57 -18
- package/lib/wire/xsqlvar.js +59 -0
- package/package.json +1 -1
- package/src/index.ts +36 -4
- package/src/messages.ts +1 -1
- package/src/pool.ts +1 -1
- package/src/srp.ts +6 -6
- package/src/types.ts +162 -5
- package/src/unix-crypt.ts +9 -9
- package/src/uri.ts +2 -2
- package/src/wire/connection.ts +475 -234
- package/src/wire/const.ts +23 -9
- package/src/wire/database.ts +101 -54
- package/src/wire/eventConnection.ts +8 -5
- package/src/wire/query-stream.ts +80 -0
- package/src/wire/serialize.ts +31 -0
- package/src/wire/service.ts +188 -6
- package/src/wire/socket.ts +17 -8
- package/src/wire/statement.ts +37 -29
- package/src/wire/transaction.ts +57 -32
- package/src/wire/wire-types.ts +127 -0
- package/src/wire/xsqlvar.ts +85 -7
package/src/wire/const.ts
CHANGED
|
@@ -269,7 +269,8 @@ const SUPPORTED_PROTOCOL = [
|
|
|
269
269
|
[protocol.PROTOCOL_VERSION16, connect.ARCHITECTURE_GENERIC, acceptType.ptype_lazy_send, acceptType.ptype_lazy_send, 7],
|
|
270
270
|
[protocol.PROTOCOL_VERSION17, connect.ARCHITECTURE_GENERIC, acceptType.ptype_lazy_send, acceptType.ptype_lazy_send, 8],
|
|
271
271
|
[protocol.PROTOCOL_VERSION18, connect.ARCHITECTURE_GENERIC, acceptType.ptype_lazy_send, acceptType.ptype_lazy_send, 9],
|
|
272
|
-
[protocol.PROTOCOL_VERSION19, connect.ARCHITECTURE_GENERIC, acceptType.ptype_lazy_send, acceptType.ptype_lazy_send, 10]
|
|
272
|
+
[protocol.PROTOCOL_VERSION19, connect.ARCHITECTURE_GENERIC, acceptType.ptype_lazy_send, acceptType.ptype_lazy_send, 10],
|
|
273
|
+
[protocol.PROTOCOL_VERSION20, connect.ARCHITECTURE_GENERIC, acceptType.ptype_lazy_send, acceptType.ptype_lazy_send, 11]
|
|
273
274
|
];
|
|
274
275
|
|
|
275
276
|
const authPlugin = {
|
|
@@ -472,16 +473,27 @@ const dpb = {
|
|
|
472
473
|
isc_dpb_reset_icu : 89,
|
|
473
474
|
isc_dpb_map_attach : 90,
|
|
474
475
|
isc_dpb_session_time_zone : 91,
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
// Firebird 4.0
|
|
477
|
+
isc_dpb_set_db_replica : 92,
|
|
478
|
+
isc_dpb_set_bind : 93,
|
|
479
|
+
isc_dpb_decfloat_round : 94,
|
|
480
|
+
isc_dpb_decfloat_traps : 95,
|
|
481
|
+
isc_dpb_clear_map : 96,
|
|
482
|
+
// Firebird 5.0
|
|
483
|
+
isc_dpb_upgrade_db : 97,
|
|
484
|
+
isc_dpb_parallel_workers : 100,
|
|
485
|
+
isc_dpb_worker_attach : 101,
|
|
486
|
+
// Firebird 6.0
|
|
487
|
+
// isc_dpb_owner sets the owner of a newly created database to a user
|
|
488
|
+
// other than the connecting one (create only; requires superuser).
|
|
489
|
+
isc_dpb_owner : 102,
|
|
490
|
+
isc_dpb_max_blob_cache_size : 103,
|
|
491
|
+
isc_dpb_max_inline_blob_size : 104, // Firebird 5.0.3+
|
|
478
492
|
// isc_dpb_search_path sets the comma-separated ordered list of schema
|
|
479
493
|
// names to search for unqualified object names (similar to PostgreSQL
|
|
480
|
-
// search_path).
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
// (CURRENT_SCHEMA) at connection time. Available on Protocol 20+.
|
|
484
|
-
isc_dpb_default_schema : 95,
|
|
494
|
+
// search_path). CURRENT_SCHEMA is the first existing schema of the list.
|
|
495
|
+
// Available on Protocol 20+ (Firebird 6.0).
|
|
496
|
+
isc_dpb_search_path : 105,
|
|
485
497
|
};
|
|
486
498
|
|
|
487
499
|
const cnct = {
|
|
@@ -614,6 +626,7 @@ const DESCRIBE = [
|
|
|
614
626
|
sqlInfo.isc_info_sql_length,
|
|
615
627
|
sqlInfo.isc_info_sql_field,
|
|
616
628
|
sqlInfo.isc_info_sql_relation,
|
|
629
|
+
sqlInfo.isc_info_sql_relation_alias, // FB 2.0+: query alias of the source relation (nestTables)
|
|
617
630
|
//isc_info_sql_owner,
|
|
618
631
|
sqlInfo.isc_info_sql_alias,
|
|
619
632
|
sqlInfo.isc_info_sql_describe_end,
|
|
@@ -642,6 +655,7 @@ const DESCRIBE_WITH_SCHEMA = [
|
|
|
642
655
|
sqlInfo.isc_info_sql_field,
|
|
643
656
|
sqlInfo.isc_info_sql_relation,
|
|
644
657
|
sqlInfo.isc_info_sql_relation_schema, // FB 6.0: schema of source relation
|
|
658
|
+
sqlInfo.isc_info_sql_relation_alias, // query alias of the source relation (nestTables)
|
|
645
659
|
//isc_info_sql_owner,
|
|
646
660
|
sqlInfo.isc_info_sql_alias,
|
|
647
661
|
sqlInfo.isc_info_sql_describe_end,
|
package/src/wire/database.ts
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import Events from 'events';
|
|
2
|
-
import { doError, fromCallback } from '../callback';
|
|
2
|
+
import { doError, fromCallback, type Callback, type SimpleCallback } from '../callback';
|
|
3
3
|
import { escape } from '../utils';
|
|
4
4
|
import Const from './const';
|
|
5
|
+
import { computeColumnKeys, nestCell, resolveNestTables } from './xsqlvar';
|
|
5
6
|
import EventConnection from './eventConnection';
|
|
6
7
|
import FbEventManager from './fbEventManager';
|
|
8
|
+
import makeQueryStream from './query-stream';
|
|
9
|
+
import type Connection from './connection';
|
|
10
|
+
import type Transaction from './transaction';
|
|
11
|
+
import type Statement from './statement';
|
|
12
|
+
import type { BatchCb, StatementCb, InternalQueryOptions } from './wire-types';
|
|
13
|
+
import type { BatchOptions, BatchResult, Isolation, QueryParams, QueryStreamOptions, TransactionCallback, TransactionOptions } from '../types';
|
|
14
|
+
|
|
15
|
+
/** Callback for startTransaction: the internal optional-args shape, or the
|
|
16
|
+
* public TransactionCallback (non-optional transaction) from types.ts. */
|
|
17
|
+
type TransactionCb = Callback<Transaction> | TransactionCallback;
|
|
18
|
+
|
|
19
|
+
/** startTransaction options: resolved options object, a bare isolation
|
|
20
|
+
* array, or omitted entirely (callback in the options position). */
|
|
21
|
+
type TransactionArg = TransactionOptions | Isolation | TransactionCb | undefined;
|
|
7
22
|
|
|
8
23
|
/***************************************
|
|
9
24
|
*
|
|
@@ -40,7 +55,7 @@ import FbEventManager from './fbEventManager';
|
|
|
40
55
|
*
|
|
41
56
|
***************************************/
|
|
42
57
|
|
|
43
|
-
function readblob(blob: any, callback:
|
|
58
|
+
function readblob(blob: any, callback: Callback): void {
|
|
44
59
|
if (blob === undefined || blob === null) {
|
|
45
60
|
callback(null, blob);
|
|
46
61
|
return;
|
|
@@ -80,35 +95,47 @@ function readblob(blob: any, callback: (err: any, data?: any) => void): void {
|
|
|
80
95
|
});
|
|
81
96
|
}
|
|
82
97
|
|
|
83
|
-
function fetchBlobSyncRow(row: any, meta: any[],
|
|
84
|
-
if (!row || !meta || !meta.length) {
|
|
98
|
+
function fetchBlobSyncRow(row: any, meta: any[], nestTables: boolean | string | undefined, lowercaseKeys: boolean | undefined, callback: Callback): void {
|
|
99
|
+
if (!row || !meta || !meta.length || !meta.some((m) => m && m.type === Const.SQL_BLOB)) {
|
|
85
100
|
callback(null, row);
|
|
86
101
|
return;
|
|
87
102
|
}
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
// locate blob cells by the same key computation the fetch decoder used,
|
|
105
|
+
// rather than assuming Object.keys(row) is index-aligned with meta —
|
|
106
|
+
// duplicate JOIN column names (and nested rows) break that alignment.
|
|
107
|
+
// Array rows (sequentially's legacy boolean form) are keyed by index.
|
|
108
|
+
const isArrayRow = Array.isArray(row);
|
|
109
|
+
const keys = isArrayRow ? null : computeColumnKeys(meta, nestTables, lowercaseKeys);
|
|
110
|
+
const blobCells: { target: any; key: string | number }[] = [];
|
|
91
111
|
|
|
92
112
|
for (let i = 0; i < meta.length; i++) {
|
|
93
|
-
if (meta[i]
|
|
94
|
-
|
|
113
|
+
if (!meta[i] || meta[i].type !== Const.SQL_BLOB) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const target = keys ? nestCell(row, keys[i].table) : row;
|
|
117
|
+
const key = keys ? keys[i].key : i;
|
|
118
|
+
// duplicate aliases collapse onto one cell — read it only once
|
|
119
|
+
if (typeof target[key] === 'function' &&
|
|
120
|
+
!blobCells.some((cell) => cell.target === target && cell.key === key)) {
|
|
121
|
+
blobCells.push({ target, key });
|
|
95
122
|
}
|
|
96
123
|
}
|
|
97
124
|
|
|
98
|
-
if (!
|
|
125
|
+
if (!blobCells.length) {
|
|
99
126
|
callback(null, row);
|
|
100
127
|
return;
|
|
101
128
|
}
|
|
102
129
|
|
|
103
|
-
let pending =
|
|
130
|
+
let pending = blobCells.length;
|
|
104
131
|
let blobErr: any;
|
|
105
132
|
|
|
106
|
-
|
|
107
|
-
readblob(
|
|
133
|
+
blobCells.forEach(function(cell) {
|
|
134
|
+
readblob(cell.target[cell.key], function(err: any, data: any) {
|
|
108
135
|
if (err && !blobErr) {
|
|
109
136
|
blobErr = err;
|
|
110
137
|
}
|
|
111
|
-
|
|
138
|
+
cell.target[cell.key] = data;
|
|
112
139
|
pending--;
|
|
113
140
|
if (pending === 0) {
|
|
114
141
|
callback(blobErr, row);
|
|
@@ -118,10 +145,10 @@ function fetchBlobSyncRow(row: any, meta: any[], callback: (err: any, row?: any)
|
|
|
118
145
|
}
|
|
119
146
|
|
|
120
147
|
class Database extends Events.EventEmitter {
|
|
121
|
-
connection:
|
|
148
|
+
connection: Connection;
|
|
122
149
|
eventid: number;
|
|
123
150
|
|
|
124
|
-
constructor(connection:
|
|
151
|
+
constructor(connection: Connection) {
|
|
125
152
|
super();
|
|
126
153
|
this.connection = connection;
|
|
127
154
|
connection.db = this;
|
|
@@ -132,7 +159,7 @@ class Database extends Events.EventEmitter {
|
|
|
132
159
|
return escape(value, this.connection.accept.protocolVersion);
|
|
133
160
|
}
|
|
134
161
|
|
|
135
|
-
detach(callback?:
|
|
162
|
+
detach(callback?: Callback, force?: boolean): this {
|
|
136
163
|
var self = this;
|
|
137
164
|
|
|
138
165
|
if (!force && self.connection._pending.length > 0) {
|
|
@@ -150,7 +177,7 @@ class Database extends Events.EventEmitter {
|
|
|
150
177
|
if (callback)
|
|
151
178
|
callback(err, obj);
|
|
152
179
|
|
|
153
|
-
}
|
|
180
|
+
});
|
|
154
181
|
} else {
|
|
155
182
|
self.emit('detach', false);
|
|
156
183
|
if (callback)
|
|
@@ -160,32 +187,35 @@ class Database extends Events.EventEmitter {
|
|
|
160
187
|
return self;
|
|
161
188
|
}
|
|
162
189
|
|
|
163
|
-
transaction(options:
|
|
190
|
+
transaction(options: TransactionArg, callback?: TransactionCb): this {
|
|
164
191
|
return this.startTransaction(options, callback);
|
|
165
192
|
}
|
|
166
193
|
|
|
167
|
-
startTransaction(options:
|
|
194
|
+
startTransaction(options: TransactionArg, callback?: TransactionCb): this {
|
|
168
195
|
this.connection.startTransaction(options, callback);
|
|
169
196
|
return this;
|
|
170
197
|
}
|
|
171
198
|
|
|
172
|
-
newStatement(query: string, callback:
|
|
173
|
-
|
|
199
|
+
newStatement(query: string, callback: StatementCb): this {
|
|
200
|
+
// the public strict callback shape and the internal optional-args
|
|
201
|
+
// shape only differ in optionality; treat it as the internal one
|
|
202
|
+
const cb = callback as Callback<Statement>;
|
|
203
|
+
this.startTransaction(function(err: any, transaction?: Transaction) {
|
|
174
204
|
|
|
175
|
-
if (err) {
|
|
176
|
-
|
|
205
|
+
if (err || !transaction) {
|
|
206
|
+
cb(err);
|
|
177
207
|
return;
|
|
178
208
|
}
|
|
179
209
|
|
|
180
|
-
transaction.newStatement(query, function(err: any, statement
|
|
210
|
+
transaction.newStatement(query, function(err: any, statement?: Statement) {
|
|
181
211
|
|
|
182
212
|
if (err) {
|
|
183
|
-
|
|
213
|
+
cb(err);
|
|
184
214
|
return;
|
|
185
215
|
}
|
|
186
216
|
|
|
187
217
|
transaction.commit(function(err: any) {
|
|
188
|
-
|
|
218
|
+
cb(err, statement);
|
|
189
219
|
});
|
|
190
220
|
});
|
|
191
221
|
});
|
|
@@ -193,7 +223,7 @@ class Database extends Events.EventEmitter {
|
|
|
193
223
|
return this;
|
|
194
224
|
}
|
|
195
225
|
|
|
196
|
-
execute(query: string, params?:
|
|
226
|
+
execute(query: string, params?: QueryParams | Callback, callback?: any, options?: InternalQueryOptions): this {
|
|
197
227
|
if (params instanceof Function) {
|
|
198
228
|
options = callback;
|
|
199
229
|
callback = params;
|
|
@@ -202,9 +232,9 @@ class Database extends Events.EventEmitter {
|
|
|
202
232
|
|
|
203
233
|
var self = this;
|
|
204
234
|
|
|
205
|
-
self.connection.startTransaction(function(err: any, transaction
|
|
235
|
+
self.connection.startTransaction(function(err: any, transaction?: Transaction) {
|
|
206
236
|
|
|
207
|
-
if (err) {
|
|
237
|
+
if (err || !transaction) {
|
|
208
238
|
doError(err, callback);
|
|
209
239
|
return;
|
|
210
240
|
}
|
|
@@ -238,17 +268,17 @@ class Database extends Events.EventEmitter {
|
|
|
238
268
|
* err.batchCompletion. Use transaction.executeBatch for partial-success
|
|
239
269
|
* handling.
|
|
240
270
|
*/
|
|
241
|
-
executeBatch(query: string, rows:
|
|
271
|
+
executeBatch(query: string, rows: QueryParams[], callback?: BatchCb, options?: BatchOptions): this {
|
|
242
272
|
var self = this;
|
|
243
273
|
|
|
244
|
-
self.connection.startTransaction(function(err: any, transaction
|
|
245
|
-
if (err) {
|
|
274
|
+
self.connection.startTransaction(function(err: any, transaction?: Transaction) {
|
|
275
|
+
if (err || !transaction) {
|
|
246
276
|
doError(err, callback);
|
|
247
277
|
return;
|
|
248
278
|
}
|
|
249
279
|
|
|
250
|
-
transaction.executeBatch(query, rows, function(err: any, result
|
|
251
|
-
if (err) {
|
|
280
|
+
transaction.executeBatch(query, rows, function(err: any, result?: BatchResult) {
|
|
281
|
+
if (err || !result) {
|
|
252
282
|
transaction.rollback(function() {
|
|
253
283
|
doError(err, callback);
|
|
254
284
|
});
|
|
@@ -277,7 +307,7 @@ class Database extends Events.EventEmitter {
|
|
|
277
307
|
return self;
|
|
278
308
|
}
|
|
279
309
|
|
|
280
|
-
sequentially(query: string, params?: any, on?: any, callback?: any, options:
|
|
310
|
+
sequentially(query: string, params?: any, on?: any, callback?: any, options: InternalQueryOptions | boolean = {}): this {
|
|
281
311
|
if (params instanceof Function) {
|
|
282
312
|
options = callback;
|
|
283
313
|
callback = on;
|
|
@@ -295,7 +325,7 @@ class Database extends Events.EventEmitter {
|
|
|
295
325
|
}
|
|
296
326
|
|
|
297
327
|
var self = this;
|
|
298
|
-
var _on = function(row: any, i: number, meta: any, next: (err?: any) => void) {
|
|
328
|
+
var _on = function(row: any, i: number, meta: any[], next: (err?: any) => void) {
|
|
299
329
|
var done = false;
|
|
300
330
|
var finish = function(err?: any) {
|
|
301
331
|
if (done) {
|
|
@@ -305,7 +335,9 @@ class Database extends Events.EventEmitter {
|
|
|
305
335
|
next(err);
|
|
306
336
|
};
|
|
307
337
|
|
|
308
|
-
|
|
338
|
+
// options is read at call time, after the normalization below
|
|
339
|
+
const nest = resolveNestTables(options as any, self.connection.options);
|
|
340
|
+
fetchBlobSyncRow(row, meta, nest, self.connection._lowercase_keys, function(blobErr: any) {
|
|
309
341
|
if (blobErr) {
|
|
310
342
|
finish(blobErr);
|
|
311
343
|
return;
|
|
@@ -348,7 +380,20 @@ class Database extends Events.EventEmitter {
|
|
|
348
380
|
return self;
|
|
349
381
|
}
|
|
350
382
|
|
|
351
|
-
|
|
383
|
+
/**
|
|
384
|
+
* Run `query` and return an object-mode Readable emitting one row per
|
|
385
|
+
* chunk (what pg-query-stream / mysql2 .stream() return), with real
|
|
386
|
+
* backpressure: fetching pauses while the stream buffer is full. Runs
|
|
387
|
+
* in its own transaction, like db.query. Destroying the stream early
|
|
388
|
+
* (e.g. a pipeline() teardown) aborts the fetch and releases the
|
|
389
|
+
* statement. Rows go through the regular decode path, so typeCast,
|
|
390
|
+
* blobAsText and jsonAsObject all apply.
|
|
391
|
+
*/
|
|
392
|
+
queryStream(query: string, params?: QueryParams, options?: QueryStreamOptions) {
|
|
393
|
+
return makeQueryStream(this, query, params, options);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
query(query: string, params?: QueryParams | Callback, callback?: any, options: InternalQueryOptions = {}): this {
|
|
352
397
|
if (params instanceof Function) {
|
|
353
398
|
options = callback || {};
|
|
354
399
|
callback = params;
|
|
@@ -366,7 +411,7 @@ class Database extends Events.EventEmitter {
|
|
|
366
411
|
return self;
|
|
367
412
|
}
|
|
368
413
|
|
|
369
|
-
drop(callback?:
|
|
414
|
+
drop(callback?: SimpleCallback): void {
|
|
370
415
|
return this.connection.dropDatabase(callback);
|
|
371
416
|
}
|
|
372
417
|
|
|
@@ -377,7 +422,7 @@ class Database extends Events.EventEmitter {
|
|
|
377
422
|
* GDSCode.CANCELLED. `kind` defaults to fb_cancel_raise; cancellation is
|
|
378
423
|
* per-attachment, not per-statement.
|
|
379
424
|
*/
|
|
380
|
-
cancel(kind?: number |
|
|
425
|
+
cancel(kind?: number | SimpleCallback, callback?: SimpleCallback): this {
|
|
381
426
|
if (typeof kind === 'function') {
|
|
382
427
|
callback = kind;
|
|
383
428
|
kind = undefined;
|
|
@@ -386,7 +431,7 @@ class Database extends Events.EventEmitter {
|
|
|
386
431
|
return this;
|
|
387
432
|
}
|
|
388
433
|
|
|
389
|
-
attachEvent(callback:
|
|
434
|
+
attachEvent(callback: Callback<FbEventManager>): this {
|
|
390
435
|
var self = this;
|
|
391
436
|
const eventid = self.eventid++;
|
|
392
437
|
if (process.env.FIREBIRD_DEBUG) {
|
|
@@ -450,7 +495,7 @@ class Database extends Events.EventEmitter {
|
|
|
450
495
|
* @param {function} [callback] - Asynchronous completion callback.
|
|
451
496
|
* @returns {Database}
|
|
452
497
|
*/
|
|
453
|
-
createTablespace(name: string, filePath: string, callback?:
|
|
498
|
+
createTablespace(name: string, filePath: string, callback?: Callback): this {
|
|
454
499
|
const sql = `CREATE TABLESPACE ${name} FILE '${filePath}'`;
|
|
455
500
|
return this.execute(sql, [], callback);
|
|
456
501
|
}
|
|
@@ -464,7 +509,7 @@ class Database extends Events.EventEmitter {
|
|
|
464
509
|
* @param {function} [callback] - Asynchronous completion callback.
|
|
465
510
|
* @returns {Database}
|
|
466
511
|
*/
|
|
467
|
-
alterTablespace(name: string, filePath: string, callback?:
|
|
512
|
+
alterTablespace(name: string, filePath: string, callback?: Callback): this {
|
|
468
513
|
const sql = `ALTER TABLESPACE ${name} SET FILE TO '${filePath}'`;
|
|
469
514
|
return this.execute(sql, [], callback);
|
|
470
515
|
}
|
|
@@ -477,7 +522,7 @@ class Database extends Events.EventEmitter {
|
|
|
477
522
|
* @param {function} [callback] - Asynchronous completion callback.
|
|
478
523
|
* @returns {Database}
|
|
479
524
|
*/
|
|
480
|
-
dropTablespace(name: string, callback?:
|
|
525
|
+
dropTablespace(name: string, callback?: Callback): this {
|
|
481
526
|
const sql = `DROP TABLESPACE ${name}`;
|
|
482
527
|
return this.execute(sql, [], callback);
|
|
483
528
|
}
|
|
@@ -492,7 +537,7 @@ class Database extends Events.EventEmitter {
|
|
|
492
537
|
* @param {function} [callback] - Asynchronous completion callback.
|
|
493
538
|
* @returns {Database}
|
|
494
539
|
*/
|
|
495
|
-
createSchema(schemaName: string, tablespaceName?: string |
|
|
540
|
+
createSchema(schemaName: string, tablespaceName?: string | Callback, callback?: Callback): this {
|
|
496
541
|
if (typeof tablespaceName === 'function') {
|
|
497
542
|
callback = tablespaceName;
|
|
498
543
|
tablespaceName = undefined;
|
|
@@ -511,22 +556,24 @@ class Database extends Events.EventEmitter {
|
|
|
511
556
|
* callback API — the promises resolve with the rows alone.
|
|
512
557
|
*/
|
|
513
558
|
|
|
514
|
-
queryAsync(query: string, params?:
|
|
559
|
+
queryAsync(query: string, params?: QueryParams, options?: InternalQueryOptions): Promise<any[]> {
|
|
515
560
|
var self = this;
|
|
516
561
|
return fromCallback(function(cb) { self.query(query, params, cb, options); });
|
|
517
562
|
}
|
|
518
563
|
|
|
519
|
-
executeAsync(query: string, params?:
|
|
564
|
+
executeAsync(query: string, params?: QueryParams, options?: InternalQueryOptions): Promise<any[]> {
|
|
520
565
|
var self = this;
|
|
521
566
|
return fromCallback(function(cb) { self.execute(query, params, cb, options); });
|
|
522
567
|
}
|
|
523
568
|
|
|
524
|
-
executeBatchAsync(query: string, rows:
|
|
569
|
+
executeBatchAsync(query: string, rows: QueryParams[], options?: BatchOptions): Promise<BatchResult> {
|
|
525
570
|
var self = this;
|
|
526
571
|
return fromCallback(function(cb) { self.executeBatch(query, rows, cb, options); });
|
|
527
572
|
}
|
|
528
573
|
|
|
529
|
-
|
|
574
|
+
/** `on` may hold the options when the params argument is the row callback
|
|
575
|
+
* (public overload: sequentiallyAsync(query, rowCallback, options)). */
|
|
576
|
+
sequentiallyAsync(query: string, params?: any, on?: any, options?: InternalQueryOptions | boolean): Promise<void> {
|
|
530
577
|
if (params instanceof Function) {
|
|
531
578
|
options = on;
|
|
532
579
|
on = params;
|
|
@@ -536,16 +583,16 @@ class Database extends Events.EventEmitter {
|
|
|
536
583
|
return fromCallback(function(cb) { self.sequentially(query, params, on, cb, options); });
|
|
537
584
|
}
|
|
538
585
|
|
|
539
|
-
transactionAsync(options?:
|
|
586
|
+
transactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction> {
|
|
540
587
|
var self = this;
|
|
541
588
|
return fromCallback(function(cb) { self.startTransaction(options, cb); });
|
|
542
589
|
}
|
|
543
590
|
|
|
544
|
-
startTransactionAsync(options?:
|
|
591
|
+
startTransactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction> {
|
|
545
592
|
return this.transactionAsync(options);
|
|
546
593
|
}
|
|
547
594
|
|
|
548
|
-
newStatementAsync(query: string): Promise<
|
|
595
|
+
newStatementAsync(query: string): Promise<Statement> {
|
|
549
596
|
var self = this;
|
|
550
597
|
return fromCallback(function(cb) { self.newStatement(query, cb); });
|
|
551
598
|
}
|
|
@@ -560,7 +607,7 @@ class Database extends Events.EventEmitter {
|
|
|
560
607
|
return fromCallback(function(cb) { self.drop(cb); });
|
|
561
608
|
}
|
|
562
609
|
|
|
563
|
-
attachEventAsync(): Promise<
|
|
610
|
+
attachEventAsync(): Promise<FbEventManager> {
|
|
564
611
|
var self = this;
|
|
565
612
|
return fromCallback(function(cb) { self.attachEvent(cb); });
|
|
566
613
|
}
|
|
@@ -575,7 +622,7 @@ class Database extends Events.EventEmitter {
|
|
|
575
622
|
* resolves, rolls back when it rejects (the original error is rethrown,
|
|
576
623
|
* even if the rollback itself fails).
|
|
577
624
|
*/
|
|
578
|
-
async withTransaction<T>(work: (transaction:
|
|
625
|
+
async withTransaction<T>(work: (transaction: Transaction) => Promise<T> | T, options?: TransactionOptions | Isolation): Promise<T> {
|
|
579
626
|
const transaction = await this.transactionAsync(options);
|
|
580
627
|
try {
|
|
581
628
|
const result = await work(transaction);
|
|
@@ -22,8 +22,8 @@ class EventConnection {
|
|
|
22
22
|
this._isOpened = false;
|
|
23
23
|
this._socket = net.createConnection(port, host);
|
|
24
24
|
this._bind_events(host, port, callback);
|
|
25
|
-
this.error;
|
|
26
|
-
this.eventcallback;
|
|
25
|
+
this.error = null;
|
|
26
|
+
this.eventcallback = null;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
_bind_events(host: string, port: number, callback?: () => void): void {
|
|
@@ -60,9 +60,10 @@ class EventConnection {
|
|
|
60
60
|
xdr.buffer = buf;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
var op_pos = xdr.pos;
|
|
64
|
+
|
|
63
65
|
try {
|
|
64
66
|
|
|
65
|
-
var op_pos = xdr.pos;
|
|
66
67
|
var tmp_event: Record<string, number>;
|
|
67
68
|
while (xdr.pos < xdr.buffer.length) {
|
|
68
69
|
do {
|
|
@@ -72,10 +73,12 @@ class EventConnection {
|
|
|
72
73
|
switch (r) {
|
|
73
74
|
case Const.op_event:
|
|
74
75
|
xdr.readInt(); // db handle
|
|
75
|
-
|
|
76
|
+
// op_event always carries a payload; readArray only
|
|
77
|
+
// returns undefined for zero-length arrays
|
|
78
|
+
buf = xdr.readArray()!;
|
|
76
79
|
// first byte is always set to 1
|
|
77
80
|
tmp_event = {};
|
|
78
|
-
var lst_event = [];
|
|
81
|
+
var lst_event: { name: string; count: number }[] = [];
|
|
79
82
|
var eventname = '';
|
|
80
83
|
var eventcount = 0;
|
|
81
84
|
var pos = 1;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/***************************************
|
|
2
|
+
*
|
|
3
|
+
* queryStream — object-mode Readable over sequentially()
|
|
4
|
+
*
|
|
5
|
+
***************************************/
|
|
6
|
+
|
|
7
|
+
import { Readable } from 'stream';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Build an object-mode Readable that emits one row per chunk, implemented
|
|
11
|
+
* on top of `target.sequentially()`'s next()-based backpressure: fetching
|
|
12
|
+
* pauses whenever the stream's internal buffer is full and resumes when
|
|
13
|
+
* the consumer drains it. Shared by Database.queryStream and
|
|
14
|
+
* Transaction.queryStream.
|
|
15
|
+
*
|
|
16
|
+
* Destroying the stream early (including a pipeline() teardown) aborts the
|
|
17
|
+
* row loop, which releases the statement server-side.
|
|
18
|
+
*/
|
|
19
|
+
function makeQueryStream(target: any, query: string, params?: any, options?: any): Readable {
|
|
20
|
+
options = options || {};
|
|
21
|
+
|
|
22
|
+
const streamOptions: any = { objectMode: true };
|
|
23
|
+
if (options.highWaterMark !== undefined) {
|
|
24
|
+
streamOptions.highWaterMark = options.highWaterMark;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// forwarded to sequentially(); these keys would break its plumbing
|
|
28
|
+
const queryOptions = { ...options };
|
|
29
|
+
delete queryOptions.on;
|
|
30
|
+
delete queryOptions.asStream;
|
|
31
|
+
delete queryOptions.highWaterMark;
|
|
32
|
+
|
|
33
|
+
// sentinel used to stop the row loop on early destroy; recognized by
|
|
34
|
+
// identity in the completion callback and never surfaced to the user
|
|
35
|
+
const abortError = new Error('queryStream destroyed');
|
|
36
|
+
|
|
37
|
+
let pendingNext: ((err?: any) => void) | null = null;
|
|
38
|
+
const resume = (err?: any) => {
|
|
39
|
+
if (pendingNext) {
|
|
40
|
+
const next = pendingNext;
|
|
41
|
+
pendingNext = null;
|
|
42
|
+
next(err);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const stream = new Readable({
|
|
47
|
+
...streamOptions,
|
|
48
|
+
read() {
|
|
49
|
+
resume();
|
|
50
|
+
},
|
|
51
|
+
destroy(err: any, cb: (err?: any) => void) {
|
|
52
|
+
// if the row loop is paused waiting for us, abort it so the
|
|
53
|
+
// statement is released instead of leaking mid-fetch
|
|
54
|
+
resume(abortError);
|
|
55
|
+
cb(err);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
target.sequentially(query, params, function (row: any, _index: number, next: (err?: any) => void) {
|
|
60
|
+
if (stream.destroyed) {
|
|
61
|
+
next(abortError);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (stream.push(row)) {
|
|
65
|
+
next();
|
|
66
|
+
} else {
|
|
67
|
+
pendingNext = next;
|
|
68
|
+
}
|
|
69
|
+
}, function (err: any) {
|
|
70
|
+
if (err && err !== abortError) {
|
|
71
|
+
stream.destroy(err);
|
|
72
|
+
} else if (!stream.destroyed) {
|
|
73
|
+
stream.push(null);
|
|
74
|
+
}
|
|
75
|
+
}, queryOptions);
|
|
76
|
+
|
|
77
|
+
return stream;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export = makeQueryStream;
|
package/src/wire/serialize.ts
CHANGED
|
@@ -421,6 +421,30 @@ export class XdrReader {
|
|
|
421
421
|
buffer: Buffer;
|
|
422
422
|
pos: number;
|
|
423
423
|
|
|
424
|
+
// Row-decode scratch state used by decodeResponse (connection.ts) while
|
|
425
|
+
// decoding op_fetch_response / op_sql_response. Only meaningful within a
|
|
426
|
+
// single decode call: incomplete packets are re-decoded from scratch on
|
|
427
|
+
// a fresh XdrReader, and decodeResponse clears these at branch entry so
|
|
428
|
+
// nothing leaks between packets sharing a data event (issue #341).
|
|
429
|
+
/** opcode carried over for a resumed decode (vestigial, see connection.ts) */
|
|
430
|
+
r?: number | null;
|
|
431
|
+
/** partial fetch-op flag (vestigial) */
|
|
432
|
+
fop?: boolean;
|
|
433
|
+
/** fetch status of the current row batch (100 = end of cursor) */
|
|
434
|
+
fstatus?: number;
|
|
435
|
+
/** rows remaining in the current packet */
|
|
436
|
+
fcount?: number;
|
|
437
|
+
/** column index the row decode stopped at */
|
|
438
|
+
fcolumn?: number;
|
|
439
|
+
/** row currently being decoded (object or array) */
|
|
440
|
+
frow?: any;
|
|
441
|
+
/** rows decoded so far in this call */
|
|
442
|
+
frows?: any[];
|
|
443
|
+
/** cached object-row keys (column aliases, qualified when nestTables is set) */
|
|
444
|
+
fcols?: string[];
|
|
445
|
+
/** cached per-column table keys when nestTables === true */
|
|
446
|
+
ftables?: string[];
|
|
447
|
+
|
|
424
448
|
constructor(buffer: Buffer) {
|
|
425
449
|
this.buffer = buffer;
|
|
426
450
|
this.pos = 0;
|
|
@@ -506,6 +530,13 @@ export class XdrReader {
|
|
|
506
530
|
var len = this.readInt();
|
|
507
531
|
if (!len)
|
|
508
532
|
return;
|
|
533
|
+
// Firebird 2.5 sign-extends XDR opaque lengths above 32767: a
|
|
534
|
+
// 32768-byte array arrives as length 0xFFFF8000. A negative length
|
|
535
|
+
// is never valid, so recover the real length from the low 16 bits
|
|
536
|
+
// instead of corrupting the read position (issue #312 — hang when
|
|
537
|
+
// preparing a statement with very many parameters on FB 2.5).
|
|
538
|
+
if (len < 0)
|
|
539
|
+
len &= 0xFFFF;
|
|
509
540
|
var r = this.buffer.slice(this.pos, this.pos + len);
|
|
510
541
|
this.pos += align(len);
|
|
511
542
|
return r;
|