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/connection.ts
CHANGED
|
@@ -3,7 +3,7 @@ import os from 'os';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
5
|
import { XdrWriter, BlrWriter, XdrReader, BitSet, BlrReader } from './serialize';
|
|
6
|
-
import { doCallback, doError } from '../callback';
|
|
6
|
+
import { doCallback, doError, type Callback, type SimpleCallback } from '../callback';
|
|
7
7
|
import * as srp from '../srp';
|
|
8
8
|
import * as crypt from '../unix-crypt';
|
|
9
9
|
import Const from './const';
|
|
@@ -14,6 +14,8 @@ import Statement from './statement';
|
|
|
14
14
|
import Transaction from './transaction';
|
|
15
15
|
import { lookupMessages, noop, parseDate } from '../utils';
|
|
16
16
|
import Socket from './socket';
|
|
17
|
+
import type { QueueCallback, QueueEntry, WireResponse, InternalOptions, InternalQueryOptions, BatchCb, Quad, AcceptPacket } from './wire-types';
|
|
18
|
+
import type { BatchOptions, BatchResult, QueryParams } from '../types';
|
|
17
19
|
|
|
18
20
|
function parseValueIfJson(value: any, options: any) {
|
|
19
21
|
if (options && options.jsonAsObject && typeof value === 'string' && (value.startsWith('{') || value.startsWith('['))) {
|
|
@@ -26,6 +28,115 @@ function parseValueIfJson(value: any, options: any) {
|
|
|
26
28
|
return value;
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the prepared-statement cache limit from the connection options:
|
|
33
|
+
* `statementCacheSize` (new), or the legacy `cacheQuery`/`maxCachedQuery`
|
|
34
|
+
* pair (which had no eviction; it now gets a bounded LRU). 0 = disabled.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Build the isc_dpb_search_path value from the defaultSchema / searchPath
|
|
38
|
+
* options (Firebird 6.0 / protocol 20+). There is no "default schema" DPB
|
|
39
|
+
* tag in Firebird: CURRENT_SCHEMA is simply the first existing schema of
|
|
40
|
+
* the search path, so defaultSchema is implemented by putting it at the
|
|
41
|
+
* front of the list. When only defaultSchema is given, PUBLIC is kept as a
|
|
42
|
+
* fallback so unqualified names outside the new schema still resolve (the
|
|
43
|
+
* server always appends SYSTEM itself). Returns null when neither option
|
|
44
|
+
* is set.
|
|
45
|
+
*/
|
|
46
|
+
function buildSchemaSearchPath(options: InternalOptions): string | null {
|
|
47
|
+
var list: string[] = [];
|
|
48
|
+
if (options.searchPath) {
|
|
49
|
+
list = Array.isArray(options.searchPath)
|
|
50
|
+
? options.searchPath.slice()
|
|
51
|
+
: String(options.searchPath).split(',').map(function(s: string) { return s.trim(); }).filter(Boolean);
|
|
52
|
+
}
|
|
53
|
+
var def = options.defaultSchema;
|
|
54
|
+
if (def) {
|
|
55
|
+
if (list.length === 0) {
|
|
56
|
+
// defaultSchema alone: keep PUBLIC as a fallback after it
|
|
57
|
+
list = def === 'PUBLIC' ? ['PUBLIC'] : [def, 'PUBLIC'];
|
|
58
|
+
} else {
|
|
59
|
+
// explicit searchPath: respect it, just move defaultSchema first
|
|
60
|
+
list = [def].concat(list.filter(function(s) { return s !== def; }));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return list.length ? list.join(',') : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function statementCacheLimit(options: InternalOptions): number {
|
|
67
|
+
const size = options && options.statementCacheSize;
|
|
68
|
+
if (size && size > 0) {
|
|
69
|
+
return Math.floor(size);
|
|
70
|
+
}
|
|
71
|
+
if (options && options.cacheQuery) {
|
|
72
|
+
const legacy = options.maxCachedQuery;
|
|
73
|
+
return legacy && legacy > 0 ? Math.floor(legacy) : 100;
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const SQL_TYPE_NAMES: Record<number, string> = {
|
|
79
|
+
[Const.SQL_TEXT]: 'TEXT',
|
|
80
|
+
[Const.SQL_VARYING]: 'VARYING',
|
|
81
|
+
[Const.SQL_SHORT]: 'SHORT',
|
|
82
|
+
[Const.SQL_LONG]: 'LONG',
|
|
83
|
+
[Const.SQL_FLOAT]: 'FLOAT',
|
|
84
|
+
[Const.SQL_DOUBLE]: 'DOUBLE',
|
|
85
|
+
[Const.SQL_D_FLOAT]: 'D_FLOAT',
|
|
86
|
+
[Const.SQL_TIMESTAMP]: 'TIMESTAMP',
|
|
87
|
+
[Const.SQL_BLOB]: 'BLOB',
|
|
88
|
+
[Const.SQL_ARRAY]: 'ARRAY',
|
|
89
|
+
[Const.SQL_QUAD]: 'QUAD',
|
|
90
|
+
[Const.SQL_TYPE_TIME]: 'TIME',
|
|
91
|
+
[Const.SQL_TYPE_DATE]: 'DATE',
|
|
92
|
+
[Const.SQL_INT64]: 'INT64',
|
|
93
|
+
[Const.SQL_INT128]: 'INT128',
|
|
94
|
+
[Const.SQL_TIMESTAMP_TZ]: 'TIMESTAMP_TZ',
|
|
95
|
+
[Const.SQL_TIMESTAMP_TZ_EX]: 'TIMESTAMP_TZ_EX',
|
|
96
|
+
[Const.SQL_TIME_TZ]: 'TIME_TZ',
|
|
97
|
+
[Const.SQL_TIME_TZ_EX]: 'TIME_TZ_EX',
|
|
98
|
+
[Const.SQL_DEC16]: 'DEC16',
|
|
99
|
+
[Const.SQL_DEC34]: 'DEC34',
|
|
100
|
+
[Const.SQL_BOOLEAN]: 'BOOLEAN',
|
|
101
|
+
[Const.SQL_NULL]: 'NULL',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Run the user's typeCast hook (options.typeCast) for one column value.
|
|
106
|
+
* The hook receives the column metadata and a next() returning the value
|
|
107
|
+
* the driver would produce by default (after blobAsText/jsonAsObject);
|
|
108
|
+
* whatever it returns becomes the value in the row. Rows may be decoded
|
|
109
|
+
* more than once when a response spans TCP packets, so the hook must be
|
|
110
|
+
* a pure function of its inputs.
|
|
111
|
+
*/
|
|
112
|
+
function applyTypeCast(options: InternalOptions, meta: Partial<Xsql.SQLVarBase>, defaultValue: any) {
|
|
113
|
+
const typeCast = options && options.typeCast;
|
|
114
|
+
if (typeof typeCast !== 'function') {
|
|
115
|
+
return defaultValue;
|
|
116
|
+
}
|
|
117
|
+
const column = {
|
|
118
|
+
type: meta.type!,
|
|
119
|
+
typeName: SQL_TYPE_NAMES[meta.type!] || 'UNKNOWN',
|
|
120
|
+
subType: meta.subType,
|
|
121
|
+
scale: meta.scale,
|
|
122
|
+
length: meta.length,
|
|
123
|
+
field: meta.field,
|
|
124
|
+
relation: meta.relation,
|
|
125
|
+
alias: meta.alias,
|
|
126
|
+
};
|
|
127
|
+
// A hook exception must never escape into the row-decode loop: there it
|
|
128
|
+
// would be mistaken for an incomplete packet and desync the response
|
|
129
|
+
// queue (the same failure mode as issue #341). Fall back to the default
|
|
130
|
+
// value instead and tell the user.
|
|
131
|
+
try {
|
|
132
|
+
return typeCast(column, function () { return defaultValue; });
|
|
133
|
+
} catch (err: any) {
|
|
134
|
+
console.warn('[node-firebird] typeCast hook threw for column "%s" (%s): %s — using default value',
|
|
135
|
+
column.alias || column.field, column.typeName, err && err.message);
|
|
136
|
+
return defaultValue;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
29
140
|
/***************************************
|
|
30
141
|
*
|
|
31
142
|
* Connection
|
|
@@ -39,10 +150,12 @@ class Connection {
|
|
|
39
150
|
static parseValueIfJson: typeof parseValueIfJson;
|
|
40
151
|
static describe: typeof describe;
|
|
41
152
|
|
|
42
|
-
db:
|
|
43
|
-
svc:
|
|
44
|
-
options:
|
|
45
|
-
|
|
153
|
+
db: Database;
|
|
154
|
+
svc: ServiceManager | undefined;
|
|
155
|
+
options: InternalOptions;
|
|
156
|
+
/** protocol negotiation result (op_accept / op_cond_accept / op_accept_data);
|
|
157
|
+
* populated during the connect/attach handshake */
|
|
158
|
+
accept!: AcceptPacket;
|
|
46
159
|
error: any;
|
|
47
160
|
dbhandle: number | undefined;
|
|
48
161
|
svchandle: number | undefined;
|
|
@@ -51,10 +164,12 @@ class Connection {
|
|
|
51
164
|
|
|
52
165
|
_msg: XdrWriter;
|
|
53
166
|
_blr: BlrWriter;
|
|
54
|
-
|
|
167
|
+
/** response queue: one entry per expected server response (see wire-types) */
|
|
168
|
+
_queue: QueueEntry[];
|
|
55
169
|
_pending: string[];
|
|
56
|
-
_socket:
|
|
57
|
-
|
|
170
|
+
_socket: Socket;
|
|
171
|
+
/** partially received packet buffered between 'data' events */
|
|
172
|
+
_xdr: XdrReader | undefined;
|
|
58
173
|
_isOpened: boolean;
|
|
59
174
|
_isClosed: boolean;
|
|
60
175
|
_isDetach: boolean;
|
|
@@ -66,16 +181,18 @@ class Connection {
|
|
|
66
181
|
_detachAuto: any;
|
|
67
182
|
_retry_connection_id: any;
|
|
68
183
|
_retry_connection_interval: number;
|
|
69
|
-
|
|
70
|
-
|
|
184
|
+
_statementCacheSize: number;
|
|
185
|
+
_statementCache: Map<string, Statement> | null;
|
|
71
186
|
_messageFile: string;
|
|
72
187
|
_authStartTime: number | undefined;
|
|
73
188
|
_pendingAccept: any;
|
|
74
189
|
_inlineBlobs: Map<string, Buffer> | undefined;
|
|
75
190
|
|
|
76
|
-
constructor(host: string, port: number, callback:
|
|
191
|
+
constructor(host: string, port: number, callback: SimpleCallback | undefined, options: InternalOptions, db?: Database, svc?: ServiceManager) {
|
|
77
192
|
var self = this;
|
|
78
|
-
|
|
193
|
+
// db is absent for service-manager connections; the wire core only
|
|
194
|
+
// touches it on database attachments, where it is always set
|
|
195
|
+
this.db = db!;
|
|
79
196
|
this.svc = svc
|
|
80
197
|
this._msg = new XdrWriter(32);
|
|
81
198
|
this._blr = new BlrWriter(32);
|
|
@@ -83,7 +200,9 @@ class Connection {
|
|
|
83
200
|
this._detachTimeout;
|
|
84
201
|
this._detachCallback;
|
|
85
202
|
this._detachAuto;
|
|
86
|
-
this._socket = new Socket(port, host
|
|
203
|
+
this._socket = new Socket(port, host,
|
|
204
|
+
options.enableKeepAlive !== false,
|
|
205
|
+
options.keepAliveInitialDelay);
|
|
87
206
|
this._pending = [];
|
|
88
207
|
this._isOpened = false;
|
|
89
208
|
this._isClosed = false;
|
|
@@ -96,32 +215,66 @@ class Connection {
|
|
|
96
215
|
// the same values.
|
|
97
216
|
if (options && !options.user) options.user = Const.DEFAULT_USER;
|
|
98
217
|
if (options && !options.password) options.password = Const.DEFAULT_PASSWORD;
|
|
99
|
-
if (options && options.blobChunkSize > 65535) options.blobChunkSize = 65535;
|
|
100
|
-
if (options && options.blobReadChunkSize > 65535) options.blobReadChunkSize = 65535;
|
|
218
|
+
if (options && options.blobChunkSize && options.blobChunkSize > 65535) options.blobChunkSize = 65535;
|
|
219
|
+
if (options && options.blobReadChunkSize && options.blobReadChunkSize > 65535) options.blobReadChunkSize = 65535;
|
|
101
220
|
this.options = options;
|
|
102
221
|
this._bind_events(host, port, callback);
|
|
103
222
|
this.error;
|
|
104
223
|
this._retry_connection_id;
|
|
105
224
|
this._retry_connection_interval = options.retryConnectionInterval || 1000;
|
|
106
|
-
this.
|
|
107
|
-
this.
|
|
225
|
+
this._statementCacheSize = statementCacheLimit(options);
|
|
226
|
+
this._statementCache = this._statementCacheSize > 0 ? new Map() : null;
|
|
108
227
|
this._messageFile = options.messageFile || path.join(__dirname, 'firebird.msg');
|
|
109
228
|
}
|
|
110
229
|
|
|
111
230
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
231
|
+
/**
|
|
232
|
+
* Take an idle prepared statement for `query` out of the cache, or null.
|
|
233
|
+
* The statement leaves the cache while in use, so concurrent callers of
|
|
234
|
+
* the same query never share a server-side cursor — they simply prepare
|
|
235
|
+
* a fresh statement and the spare is dropped when released.
|
|
236
|
+
*/
|
|
237
|
+
takeCachedStatement(query: string) {
|
|
238
|
+
const cache = this._statementCache;
|
|
239
|
+
if (!cache) {
|
|
240
|
+
return null;
|
|
117
241
|
}
|
|
118
|
-
|
|
119
|
-
|
|
242
|
+
const statement = cache.get(query);
|
|
243
|
+
if (!statement) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
cache.delete(query);
|
|
247
|
+
return statement;
|
|
120
248
|
}
|
|
121
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Return a statement after use. With the statement cache enabled the
|
|
252
|
+
* statement goes back into the cache as most-recently-used (closing its
|
|
253
|
+
* cursor but keeping the prepared handle), evicting the least-recently
|
|
254
|
+
* used statement over the limit. Failed statements, DDL and spares for
|
|
255
|
+
* an already-cached query are dropped instead.
|
|
256
|
+
*/
|
|
257
|
+
releaseStatement(statement: Statement, callback?: QueueCallback) {
|
|
258
|
+
const cache = this._statementCache;
|
|
259
|
+
const cacheable = cache &&
|
|
260
|
+
statement.query &&
|
|
261
|
+
!statement._failed &&
|
|
262
|
+
statement.type !== Const.isc_info_sql_stmt_ddl &&
|
|
263
|
+
!cache.has(statement.query);
|
|
264
|
+
|
|
265
|
+
if (!cacheable) {
|
|
266
|
+
this.dropStatement(statement, callback);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
122
269
|
|
|
123
|
-
|
|
124
|
-
|
|
270
|
+
cache!.set(statement.query, statement);
|
|
271
|
+
while (cache!.size > this._statementCacheSize) {
|
|
272
|
+
const oldestKey = cache!.keys().next().value!;
|
|
273
|
+
const oldest = cache!.get(oldestKey)!;
|
|
274
|
+
cache!.delete(oldestKey);
|
|
275
|
+
this.dropStatement(oldest, undefined);
|
|
276
|
+
}
|
|
277
|
+
this.closeStatement(statement, callback);
|
|
125
278
|
}
|
|
126
279
|
|
|
127
280
|
|
|
@@ -131,7 +284,7 @@ class Connection {
|
|
|
131
284
|
// be transparently resumed on a reconnect: a fresh attach() hands out new
|
|
132
285
|
// transaction/statement handles, so nothing the server sends back could
|
|
133
286
|
// ever match a callback queued against the old connection.
|
|
134
|
-
_rejectPending(err) {
|
|
287
|
+
_rejectPending(err: any) {
|
|
135
288
|
var queue = this._queue;
|
|
136
289
|
this._queue = [];
|
|
137
290
|
this._pending = [];
|
|
@@ -142,7 +295,7 @@ class Connection {
|
|
|
142
295
|
}
|
|
143
296
|
|
|
144
297
|
|
|
145
|
-
_bind_events(host, port, callback) {
|
|
298
|
+
_bind_events(host: string, port: number, callback: SimpleCallback | undefined) {
|
|
146
299
|
|
|
147
300
|
var self = this;
|
|
148
301
|
|
|
@@ -168,17 +321,19 @@ class Connection {
|
|
|
168
321
|
|
|
169
322
|
self._retry_connection_id = setTimeout(function() {
|
|
170
323
|
self._socket.removeAllListeners();
|
|
171
|
-
|
|
324
|
+
// transiently null while the replacement Connection is built
|
|
325
|
+
// (restored by the Object.assign(self, ctx) below)
|
|
326
|
+
self._socket = null!;
|
|
172
327
|
|
|
173
|
-
var ctx = new Connection(host, port, function(err) {
|
|
174
|
-
ctx.connect(self.options, function(err) {
|
|
328
|
+
var ctx = new Connection(host, port, function(err: any) {
|
|
329
|
+
ctx.connect(self.options, function(err: any) {
|
|
175
330
|
|
|
176
331
|
if (err) {
|
|
177
332
|
self.db.emit('error', err);
|
|
178
333
|
return;
|
|
179
334
|
}
|
|
180
335
|
|
|
181
|
-
ctx.attach(self.options, function(err) {
|
|
336
|
+
ctx.attach(self.options, function(err: any) {
|
|
182
337
|
|
|
183
338
|
if (err) {
|
|
184
339
|
self.db.emit('error', err);
|
|
@@ -197,7 +352,7 @@ class Connection {
|
|
|
197
352
|
|
|
198
353
|
});
|
|
199
354
|
|
|
200
|
-
self._socket.on('error', function(e) {
|
|
355
|
+
self._socket.on('error', function(e: any) {
|
|
201
356
|
|
|
202
357
|
self.error = e;
|
|
203
358
|
|
|
@@ -216,8 +371,8 @@ class Connection {
|
|
|
216
371
|
callback();
|
|
217
372
|
});
|
|
218
373
|
|
|
219
|
-
self._socket.on('data', function (data) {
|
|
220
|
-
var xdr;
|
|
374
|
+
self._socket.on('data', function (data: any) {
|
|
375
|
+
var xdr: any;
|
|
221
376
|
var hadSavedBuffer = Boolean(self._xdr);
|
|
222
377
|
|
|
223
378
|
if (!self._xdr) {
|
|
@@ -337,7 +492,7 @@ class Connection {
|
|
|
337
492
|
|
|
338
493
|
|
|
339
494
|
|
|
340
|
-
sendOpContAuth(authData, authDataEnc, pluginName) {
|
|
495
|
+
sendOpContAuth(authData: string, authDataEnc: BufferEncoding, pluginName: string) {
|
|
341
496
|
var msg = this._msg;
|
|
342
497
|
msg.pos = 0;
|
|
343
498
|
|
|
@@ -352,7 +507,7 @@ class Connection {
|
|
|
352
507
|
}
|
|
353
508
|
|
|
354
509
|
|
|
355
|
-
sendOpCrypt(encryptPlugin) {
|
|
510
|
+
sendOpCrypt(encryptPlugin: string) {
|
|
356
511
|
var msg = this._msg;
|
|
357
512
|
msg.pos = 0;
|
|
358
513
|
|
|
@@ -364,7 +519,7 @@ class Connection {
|
|
|
364
519
|
}
|
|
365
520
|
|
|
366
521
|
|
|
367
|
-
sendOpCryptKeyCallback(pluginData) {
|
|
522
|
+
sendOpCryptKeyCallback(pluginData: BlrWriter) {
|
|
368
523
|
var msg = this._msg;
|
|
369
524
|
msg.pos = 0;
|
|
370
525
|
|
|
@@ -381,7 +536,7 @@ class Connection {
|
|
|
381
536
|
* makes that operation fail with isc_cancelled (GDSCode.CANCELLED); the
|
|
382
537
|
* op_cancel packet itself has no response, so nothing is queued here.
|
|
383
538
|
*/
|
|
384
|
-
cancelOperation(kind, callback) {
|
|
539
|
+
cancelOperation(kind?: number | SimpleCallback, callback?: SimpleCallback) {
|
|
385
540
|
if (typeof kind === 'function') {
|
|
386
541
|
callback = kind;
|
|
387
542
|
kind = undefined;
|
|
@@ -408,7 +563,7 @@ class Connection {
|
|
|
408
563
|
|
|
409
564
|
|
|
410
565
|
/** Write a prebuilt packet and queue its response callback. */
|
|
411
|
-
_queueEventBuffer(buffer, callback) {
|
|
566
|
+
_queueEventBuffer(buffer: Buffer, callback: QueueCallback | undefined) {
|
|
412
567
|
if (this._isClosed) {
|
|
413
568
|
if (callback)
|
|
414
569
|
callback(new Error('Connection is closed.'));
|
|
@@ -420,7 +575,7 @@ class Connection {
|
|
|
420
575
|
}
|
|
421
576
|
|
|
422
577
|
|
|
423
|
-
_queueEvent(callback, defer = false) {
|
|
578
|
+
_queueEvent(callback: QueueCallback | undefined, defer = false) {
|
|
424
579
|
var self = this;
|
|
425
580
|
|
|
426
581
|
if (self._isClosed) {
|
|
@@ -449,7 +604,7 @@ class Connection {
|
|
|
449
604
|
}
|
|
450
605
|
|
|
451
606
|
|
|
452
|
-
connect(options, callback) {
|
|
607
|
+
connect(options: InternalOptions, callback: Callback<AcceptPacket> | undefined) {
|
|
453
608
|
var pluginName = options.pluginName || Const.AUTH_PLUGIN_LIST[0];
|
|
454
609
|
var msg = this._msg;
|
|
455
610
|
var blr = this._blr;
|
|
@@ -460,7 +615,7 @@ class Connection {
|
|
|
460
615
|
msg.pos = 0;
|
|
461
616
|
blr.pos = 0;
|
|
462
617
|
|
|
463
|
-
blr.addString(Const.CNCT_login, options.user
|
|
618
|
+
blr.addString(Const.CNCT_login, options.user!, Const.DEFAULT_ENCODING);
|
|
464
619
|
blr.addString(Const.CNCT_plugin_name, pluginName, Const.DEFAULT_ENCODING);
|
|
465
620
|
blr.addString(Const.CNCT_plugin_list, Const.AUTH_PLUGIN_LIST.join(','), Const.DEFAULT_ENCODING);
|
|
466
621
|
|
|
@@ -474,7 +629,7 @@ class Connection {
|
|
|
474
629
|
specificData = this.clientKeys.public.toString(16);
|
|
475
630
|
blr.addMultiblockPart(Const.CNCT_specific_data, specificData, Const.DEFAULT_ENCODING);
|
|
476
631
|
} else if (pluginName === Const.AUTH_PLUGIN_LEGACY) {
|
|
477
|
-
specificData = crypt.crypt(options.password
|
|
632
|
+
specificData = crypt.crypt(options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
478
633
|
blr.addMultiblockPart(Const.CNCT_specific_data, specificData, Const.DEFAULT_ENCODING);
|
|
479
634
|
} else {
|
|
480
635
|
doError(new Error('Invalide auth plugin \'' + pluginName + '\''), callback);
|
|
@@ -490,10 +645,17 @@ class Connection {
|
|
|
490
645
|
msg.addInt(Const.CONNECT_VERSION3);
|
|
491
646
|
msg.addInt(Const.ARCHITECTURE_GENERIC);
|
|
492
647
|
msg.addString(options.database || options.filename, Const.DEFAULT_ENCODING);
|
|
493
|
-
|
|
648
|
+
// Send the full list by default. Servers parse every entry and ignore
|
|
649
|
+
// versions they do not know (verified back to Firebird 2.5), so the
|
|
650
|
+
// list length itself is harmless; the option remains as an escape
|
|
651
|
+
// hatch to cap negotiation at an older protocol.
|
|
652
|
+
var maxProtocols = options.maxNegotiatedProtocols !== undefined ? options.maxNegotiatedProtocols : Const.SUPPORTED_PROTOCOL.length;
|
|
494
653
|
var protocolsToSend = Const.SUPPORTED_PROTOCOL;
|
|
495
654
|
if (protocolsToSend.length > maxProtocols) {
|
|
496
|
-
|
|
655
|
+
// keep the FIRST N entries: the list is ordered oldest→newest, so
|
|
656
|
+
// capping the count caps the newest protocol offered (e.g. 10 =
|
|
657
|
+
// stop at protocol 19, the documented pre-Firebird-6 behavior)
|
|
658
|
+
protocolsToSend = protocolsToSend.slice(0, maxProtocols);
|
|
497
659
|
}
|
|
498
660
|
|
|
499
661
|
msg.addInt(protocolsToSend.length); // Count of Protocol version understood count.
|
|
@@ -512,7 +674,7 @@ class Connection {
|
|
|
512
674
|
}
|
|
513
675
|
|
|
514
676
|
var self = this;
|
|
515
|
-
function cb(err, ret) {
|
|
677
|
+
function cb(err: any, ret: any) {
|
|
516
678
|
if (err) {
|
|
517
679
|
doError(err, callback);
|
|
518
680
|
return;
|
|
@@ -534,11 +696,11 @@ class Connection {
|
|
|
534
696
|
|
|
535
697
|
var selectedPlugin = 'Arc4';
|
|
536
698
|
if (ret.keys) {
|
|
537
|
-
var serverPlugins = ret.keys.split(',').map(function(s) { return s.trim().toLowerCase(); });
|
|
699
|
+
var serverPlugins = ret.keys.split(',').map(function(s: any) { return s.trim().toLowerCase(); });
|
|
538
700
|
var preferred = ['chacha64', 'chacha', 'arc4'];
|
|
539
701
|
for (var i = 0; i < preferred.length; i++) {
|
|
540
702
|
if (serverPlugins.indexOf(preferred[i]) !== -1) {
|
|
541
|
-
var mapping = {
|
|
703
|
+
var mapping: Record<string, string> = {
|
|
542
704
|
chacha64: 'ChaCha64',
|
|
543
705
|
chacha: 'ChaCha',
|
|
544
706
|
arc4: 'Arc4'
|
|
@@ -559,7 +721,7 @@ class Connection {
|
|
|
559
721
|
}
|
|
560
722
|
|
|
561
723
|
self._pending.push('crypt');
|
|
562
|
-
self._queue.push(function(cryptErr, response) {
|
|
724
|
+
self._queue.push(function(cryptErr: any, response: any) {
|
|
563
725
|
if (cryptErr) {
|
|
564
726
|
doError(cryptErr, callback);
|
|
565
727
|
return;
|
|
@@ -593,7 +755,7 @@ class Connection {
|
|
|
593
755
|
}
|
|
594
756
|
|
|
595
757
|
|
|
596
|
-
attach(options:
|
|
758
|
+
attach(options: InternalOptions, callback?: Callback<Database>, db?: Database) {
|
|
597
759
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
598
760
|
|
|
599
761
|
var database = options.database || options.filename;
|
|
@@ -657,31 +819,19 @@ class Connection {
|
|
|
657
819
|
}
|
|
658
820
|
|
|
659
821
|
// Firebird 6.0 SQL Schema parameters (Protocol 20+).
|
|
660
|
-
// These DPB tags configure the session's current schema and the
|
|
661
|
-
// schema search path for unqualified object name resolution.
|
|
662
822
|
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
// SET SCHEMA <name> immediately after connecting.
|
|
666
|
-
blr.addString(Const.isc_dpb_default_schema, options.defaultSchema, Const.DEFAULT_ENCODING);
|
|
667
|
-
}
|
|
668
|
-
if (options.searchPath) {
|
|
669
|
-
// Comma-separated ordered schema name list, like PostgreSQL's
|
|
670
|
-
// search_path. Unqualified object references are resolved by
|
|
671
|
-
// scanning schemas in this order.
|
|
672
|
-
const sp = Array.isArray(options.searchPath)
|
|
673
|
-
? options.searchPath.join(',')
|
|
674
|
-
: String(options.searchPath);
|
|
823
|
+
const sp = buildSchemaSearchPath(options);
|
|
824
|
+
if (sp) {
|
|
675
825
|
blr.addString(Const.isc_dpb_search_path, sp, Const.DEFAULT_ENCODING);
|
|
676
826
|
}
|
|
677
827
|
}
|
|
678
|
-
|
|
828
|
+
|
|
679
829
|
msg.addInt(Const.op_attach);
|
|
680
830
|
msg.addInt(0); // Database Object ID
|
|
681
831
|
msg.addString(database, Const.DEFAULT_ENCODING);
|
|
682
832
|
msg.addBlr(this._blr);
|
|
683
833
|
|
|
684
|
-
function cb(err, ret) {
|
|
834
|
+
function cb(err: any, ret: any) {
|
|
685
835
|
if (err) {
|
|
686
836
|
doError(err, callback);
|
|
687
837
|
return;
|
|
@@ -708,7 +858,7 @@ class Connection {
|
|
|
708
858
|
}
|
|
709
859
|
|
|
710
860
|
|
|
711
|
-
detach(callback) {
|
|
861
|
+
detach(callback: Callback | undefined) {
|
|
712
862
|
|
|
713
863
|
var self = this;
|
|
714
864
|
|
|
@@ -724,7 +874,7 @@ class Connection {
|
|
|
724
874
|
msg.addInt(Const.op_detach);
|
|
725
875
|
msg.addInt(0); // Database Object ID
|
|
726
876
|
|
|
727
|
-
self._queueEvent(function(err, ret) {
|
|
877
|
+
self._queueEvent(function(err: any, ret: any) {
|
|
728
878
|
clearTimeout(self._retry_connection_id);
|
|
729
879
|
delete(self.dbhandle);
|
|
730
880
|
if (callback)
|
|
@@ -733,7 +883,7 @@ class Connection {
|
|
|
733
883
|
}
|
|
734
884
|
|
|
735
885
|
|
|
736
|
-
createDatabase(options, callback) {
|
|
886
|
+
createDatabase(options: InternalOptions, callback: Callback<Database> | undefined) {
|
|
737
887
|
// Mirror attach(): honour the lowercase_keys option so that db.query()
|
|
738
888
|
// called on a freshly-created database returns the expected column case.
|
|
739
889
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
@@ -796,16 +946,18 @@ class Connection {
|
|
|
796
946
|
|
|
797
947
|
// Firebird 6.0 SQL Schema parameters (Protocol 20+).
|
|
798
948
|
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
}
|
|
802
|
-
if (options.searchPath) {
|
|
803
|
-
const sp = Array.isArray(options.searchPath)
|
|
804
|
-
? options.searchPath.join(',')
|
|
805
|
-
: String(options.searchPath);
|
|
949
|
+
const sp = buildSchemaSearchPath(options);
|
|
950
|
+
if (sp) {
|
|
806
951
|
blr.addString(Const.isc_dpb_search_path, sp, Const.DEFAULT_ENCODING);
|
|
807
952
|
}
|
|
808
953
|
}
|
|
954
|
+
|
|
955
|
+
if (options.owner) {
|
|
956
|
+
// Firebird 6.0+ (issue #7718): create the database owned by a
|
|
957
|
+
// different user (requires superuser rights). Older servers
|
|
958
|
+
// ignore unknown DPB tags, so this is safe to always send.
|
|
959
|
+
blr.addString(Const.isc_dpb_owner, options.owner, Const.DEFAULT_ENCODING);
|
|
960
|
+
}
|
|
809
961
|
|
|
810
962
|
blr.addNumeric(Const.isc_dpb_sql_dialect, 3);
|
|
811
963
|
blr.addNumeric(Const.isc_dpb_force_write, 1);
|
|
@@ -821,7 +973,7 @@ class Connection {
|
|
|
821
973
|
|
|
822
974
|
var self = this;
|
|
823
975
|
|
|
824
|
-
function cb(err, ret) {
|
|
976
|
+
function cb(err: any, ret: any) {
|
|
825
977
|
|
|
826
978
|
if (ret)
|
|
827
979
|
self.dbhandle = ret.handle;
|
|
@@ -838,15 +990,15 @@ class Connection {
|
|
|
838
990
|
}
|
|
839
991
|
|
|
840
992
|
|
|
841
|
-
dropDatabase(callback) {
|
|
993
|
+
dropDatabase(callback: SimpleCallback | undefined) {
|
|
842
994
|
var msg = this._msg;
|
|
843
995
|
msg.pos = 0;
|
|
844
996
|
|
|
845
997
|
msg.addInt(Const.op_drop_database);
|
|
846
|
-
msg.addInt(this.dbhandle);
|
|
998
|
+
msg.addInt(this.dbhandle!);
|
|
847
999
|
|
|
848
1000
|
var self = this;
|
|
849
|
-
this._queueEvent(function(err) {
|
|
1001
|
+
this._queueEvent(function(err: any) {
|
|
850
1002
|
self.detach(function() {
|
|
851
1003
|
self.disconnect();
|
|
852
1004
|
|
|
@@ -857,7 +1009,7 @@ class Connection {
|
|
|
857
1009
|
}
|
|
858
1010
|
|
|
859
1011
|
|
|
860
|
-
throwClosed(callback) {
|
|
1012
|
+
throwClosed(callback: ((err: Error, ...args: any[]) => void) | undefined) {
|
|
861
1013
|
var err = new Error('Connection is closed.');
|
|
862
1014
|
this.db.emit('error', err);
|
|
863
1015
|
if (callback)
|
|
@@ -866,7 +1018,9 @@ class Connection {
|
|
|
866
1018
|
}
|
|
867
1019
|
|
|
868
1020
|
|
|
869
|
-
|
|
1021
|
+
/** `options` is a resolved options object, a bare isolation array, or
|
|
1022
|
+
* the callback itself when no options are given. */
|
|
1023
|
+
startTransaction(options: any, callback?: any) {
|
|
870
1024
|
|
|
871
1025
|
if (typeof(options) === 'function') {
|
|
872
1026
|
var tmp = options;
|
|
@@ -939,7 +1093,7 @@ class Connection {
|
|
|
939
1093
|
}*/
|
|
940
1094
|
|
|
941
1095
|
msg.addInt(Const.op_transaction);
|
|
942
|
-
msg.addInt(this.dbhandle);
|
|
1096
|
+
msg.addInt(this.dbhandle!);
|
|
943
1097
|
msg.addBlr(blr);
|
|
944
1098
|
callback.response = new Transaction(this);
|
|
945
1099
|
|
|
@@ -948,7 +1102,7 @@ class Connection {
|
|
|
948
1102
|
}
|
|
949
1103
|
|
|
950
1104
|
|
|
951
|
-
commit(transaction, callback) {
|
|
1105
|
+
commit(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
952
1106
|
|
|
953
1107
|
if (this._isClosed)
|
|
954
1108
|
return this.throwClosed(callback);
|
|
@@ -965,7 +1119,7 @@ class Connection {
|
|
|
965
1119
|
}
|
|
966
1120
|
|
|
967
1121
|
|
|
968
|
-
rollback(transaction, callback) {
|
|
1122
|
+
rollback(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
969
1123
|
|
|
970
1124
|
if (this._isClosed)
|
|
971
1125
|
return this.throwClosed(callback);
|
|
@@ -982,7 +1136,7 @@ class Connection {
|
|
|
982
1136
|
}
|
|
983
1137
|
|
|
984
1138
|
|
|
985
|
-
commitRetaining(transaction, callback) {
|
|
1139
|
+
commitRetaining(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
986
1140
|
|
|
987
1141
|
if (this._isClosed)
|
|
988
1142
|
return this.throwClosed(callback);
|
|
@@ -998,7 +1152,7 @@ class Connection {
|
|
|
998
1152
|
}
|
|
999
1153
|
|
|
1000
1154
|
|
|
1001
|
-
rollbackRetaining(transaction, callback) {
|
|
1155
|
+
rollbackRetaining(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
1002
1156
|
|
|
1003
1157
|
if (this._isClosed)
|
|
1004
1158
|
return this.throwClosed(callback);
|
|
@@ -1014,7 +1168,7 @@ class Connection {
|
|
|
1014
1168
|
}
|
|
1015
1169
|
|
|
1016
1170
|
|
|
1017
|
-
allocateStatement(callback) {
|
|
1171
|
+
allocateStatement(callback: QueueCallback) {
|
|
1018
1172
|
|
|
1019
1173
|
if (this._isClosed)
|
|
1020
1174
|
return this.throwClosed(callback);
|
|
@@ -1025,13 +1179,13 @@ class Connection {
|
|
|
1025
1179
|
var msg = this._msg;
|
|
1026
1180
|
msg.pos = 0;
|
|
1027
1181
|
msg.addInt(Const.op_allocate_statement);
|
|
1028
|
-
msg.addInt(this.dbhandle);
|
|
1182
|
+
msg.addInt(this.dbhandle!);
|
|
1029
1183
|
callback.response = new Statement(this);
|
|
1030
1184
|
this._queueEvent(callback);
|
|
1031
1185
|
}
|
|
1032
1186
|
|
|
1033
1187
|
|
|
1034
|
-
dropStatement(statement, callback) {
|
|
1188
|
+
dropStatement(statement: Statement, callback: QueueCallback | undefined) {
|
|
1035
1189
|
|
|
1036
1190
|
if (this._isClosed)
|
|
1037
1191
|
return this.throwClosed(callback);
|
|
@@ -1049,7 +1203,7 @@ class Connection {
|
|
|
1049
1203
|
}
|
|
1050
1204
|
|
|
1051
1205
|
|
|
1052
|
-
closeStatement(statement, callback) {
|
|
1206
|
+
closeStatement(statement: Statement, callback: QueueCallback | undefined) {
|
|
1053
1207
|
|
|
1054
1208
|
if (this._isClosed)
|
|
1055
1209
|
return this.throwClosed(callback);
|
|
@@ -1067,16 +1221,15 @@ class Connection {
|
|
|
1067
1221
|
}
|
|
1068
1222
|
|
|
1069
1223
|
|
|
1070
|
-
allocateAndPrepareStatement(transaction, query, plan, callback) {
|
|
1224
|
+
allocateAndPrepareStatement(transaction: Transaction, query: string, plan: boolean, callback: Callback<Statement>) {
|
|
1071
1225
|
var self = this;
|
|
1072
|
-
var mainCallback:
|
|
1226
|
+
var mainCallback: QueueCallback = function(err: any, ret: any) {
|
|
1073
1227
|
if (!err) {
|
|
1074
1228
|
mainCallback.response.handle = ret.handle;
|
|
1075
1229
|
describe(ret.buffer, mainCallback.response);
|
|
1076
1230
|
mainCallback.response.query = query;
|
|
1077
1231
|
self.db.emit('query', query);
|
|
1078
1232
|
ret = mainCallback.response;
|
|
1079
|
-
self._setcachedquery(query, ret);
|
|
1080
1233
|
}
|
|
1081
1234
|
|
|
1082
1235
|
if (callback)
|
|
@@ -1093,7 +1246,7 @@ class Connection {
|
|
|
1093
1246
|
blr.pos = 0;
|
|
1094
1247
|
|
|
1095
1248
|
msg.addInt(Const.op_allocate_statement);
|
|
1096
|
-
msg.addInt(this.dbhandle);
|
|
1249
|
+
msg.addInt(this.dbhandle!);
|
|
1097
1250
|
mainCallback.lazy_count = 1;
|
|
1098
1251
|
|
|
1099
1252
|
const describeBytes = this.accept.protocolVersion >= Const.PROTOCOL_VERSION20 ? Const.DESCRIBE_WITH_SCHEMA : Const.DESCRIBE;
|
|
@@ -1111,6 +1264,12 @@ class Connection {
|
|
|
1111
1264
|
msg.addString(query, Const.DEFAULT_ENCODING);
|
|
1112
1265
|
msg.addBlr(blr);
|
|
1113
1266
|
msg.addInt(65535); // buffer_length
|
|
1267
|
+
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
1268
|
+
// p_sqlst_flags (IStatement::PREPARE_* bits, none needed) — the
|
|
1269
|
+
// server blocks reading this field if it is missing, which was
|
|
1270
|
+
// the protocol-20 "prepare hang"
|
|
1271
|
+
msg.addInt(0);
|
|
1272
|
+
}
|
|
1114
1273
|
mainCallback.lazy_count += 1;
|
|
1115
1274
|
|
|
1116
1275
|
mainCallback.response = new Statement(this);
|
|
@@ -1118,13 +1277,13 @@ class Connection {
|
|
|
1118
1277
|
}
|
|
1119
1278
|
|
|
1120
1279
|
|
|
1121
|
-
prepare(transaction, query, plan, callback) {
|
|
1280
|
+
prepare(transaction: Transaction, query: string, plan: boolean, callback: Callback<Statement>) {
|
|
1122
1281
|
var self = this;
|
|
1123
1282
|
|
|
1124
1283
|
if (this.accept.protocolMinimumType === Const.ptype_lazy_send) { // V11 Statement or higher
|
|
1125
1284
|
self.allocateAndPrepareStatement(transaction, query, plan, callback);
|
|
1126
1285
|
} else { // V10 Statement
|
|
1127
|
-
self.allocateStatement(function (err, statement) {
|
|
1286
|
+
self.allocateStatement(function (err: any, statement: Statement) {
|
|
1128
1287
|
if (err) {
|
|
1129
1288
|
doError(err, callback);
|
|
1130
1289
|
return;
|
|
@@ -1137,7 +1296,8 @@ class Connection {
|
|
|
1137
1296
|
|
|
1138
1297
|
|
|
1139
1298
|
|
|
1140
|
-
|
|
1299
|
+
/** `plan` may be the callback itself when no plan flag is given. */
|
|
1300
|
+
prepareStatement(transaction: Transaction, statement: Statement, query: string, plan: boolean | Callback<Statement>, callback?: Callback<Statement>) {
|
|
1141
1301
|
|
|
1142
1302
|
if (this._isClosed)
|
|
1143
1303
|
return this.throwClosed(callback);
|
|
@@ -1166,16 +1326,18 @@ class Connection {
|
|
|
1166
1326
|
msg.addString(query, Const.DEFAULT_ENCODING);
|
|
1167
1327
|
msg.addBlr(blr);
|
|
1168
1328
|
msg.addInt(65535); // buffer_length
|
|
1329
|
+
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
1330
|
+
msg.addInt(0); // p_sqlst_flags (see allocateAndPrepareStatement)
|
|
1331
|
+
}
|
|
1169
1332
|
|
|
1170
1333
|
var self = this;
|
|
1171
|
-
this._queueEvent(function(err, ret) {
|
|
1334
|
+
this._queueEvent(function(err: any, ret: any) {
|
|
1172
1335
|
|
|
1173
1336
|
if (!err) {
|
|
1174
1337
|
describe(ret.buffer, statement);
|
|
1175
1338
|
statement.query = query;
|
|
1176
1339
|
self.db.emit('query', query);
|
|
1177
1340
|
ret = statement;
|
|
1178
|
-
self._setcachedquery(query, ret);
|
|
1179
1341
|
}
|
|
1180
1342
|
|
|
1181
1343
|
if (callback)
|
|
@@ -1198,7 +1360,7 @@ class Connection {
|
|
|
1198
1360
|
* { recordCount, updateCounts, errors: [{recordNumber, error}],
|
|
1199
1361
|
* errorRecordNumbers, success }.
|
|
1200
1362
|
*/
|
|
1201
|
-
executeBatch(transaction, statement, rows, callback, options) {
|
|
1363
|
+
executeBatch(transaction: Transaction, statement: Statement, rows: QueryParams[], callback: BatchCb | undefined, options?: BatchOptions) {
|
|
1202
1364
|
options = options || {};
|
|
1203
1365
|
|
|
1204
1366
|
if (this._isClosed)
|
|
@@ -1244,7 +1406,7 @@ class Connection {
|
|
|
1244
1406
|
|
|
1245
1407
|
var self = this;
|
|
1246
1408
|
var encoders = built.encoders;
|
|
1247
|
-
var chunkSize = options.chunkSize > 0 ? options.chunkSize : 500;
|
|
1409
|
+
var chunkSize = options.chunkSize && options.chunkSize > 0 ? options.chunkSize : 500;
|
|
1248
1410
|
var chunkCount = Math.ceil(rows.length / chunkSize);
|
|
1249
1411
|
|
|
1250
1412
|
var failure: any = null;
|
|
@@ -1264,7 +1426,7 @@ class Connection {
|
|
|
1264
1426
|
}
|
|
1265
1427
|
|
|
1266
1428
|
var detailed = completion ? completion.detailedErrors : [];
|
|
1267
|
-
var errorRecordNumbers = detailed.map(function(e) { return e.recordNumber; })
|
|
1429
|
+
var errorRecordNumbers = detailed.map(function(e: any) { return e.recordNumber; })
|
|
1268
1430
|
.concat(completion ? completion.errorRecordNumbers : []);
|
|
1269
1431
|
|
|
1270
1432
|
if (callback) callback(undefined, {
|
|
@@ -1312,7 +1474,8 @@ class Connection {
|
|
|
1312
1474
|
msg.addInt(end - start);
|
|
1313
1475
|
|
|
1314
1476
|
for (var i = start; i < end; i++) {
|
|
1315
|
-
|
|
1477
|
+
// validated as an array of input.length values above
|
|
1478
|
+
var row = rows[i] as any[];
|
|
1316
1479
|
|
|
1317
1480
|
var nullBits = new BitSet();
|
|
1318
1481
|
for (var j = 0; j < input.length; j++) {
|
|
@@ -1371,7 +1534,7 @@ class Connection {
|
|
|
1371
1534
|
for (var p = 0; p < packets.length; p++) {
|
|
1372
1535
|
this._pending.push('executeBatch');
|
|
1373
1536
|
if (p === execIndex) {
|
|
1374
|
-
this._queueEventBuffer(packets[p], function(err, ret) {
|
|
1537
|
+
this._queueEventBuffer(packets[p], function(err: any, ret: any) {
|
|
1375
1538
|
if (!err && ret && ret.batchCompletion) {
|
|
1376
1539
|
completion = ret.batchCompletion;
|
|
1377
1540
|
settle();
|
|
@@ -1382,13 +1545,14 @@ class Connection {
|
|
|
1382
1545
|
} else if (p === packets.length - 1) {
|
|
1383
1546
|
this._queueEventBuffer(packets[p], function() {});
|
|
1384
1547
|
} else {
|
|
1385
|
-
this._queueEventBuffer(packets[p], function(err) { settle(err); });
|
|
1548
|
+
this._queueEventBuffer(packets[p], function(err: any) { settle(err); });
|
|
1386
1549
|
}
|
|
1387
1550
|
}
|
|
1388
1551
|
}
|
|
1389
1552
|
|
|
1390
1553
|
|
|
1391
|
-
|
|
1554
|
+
/** `params` may be the callback itself when the statement has no parameters. */
|
|
1555
|
+
executeStatement(transaction: Transaction, statement: Statement, params: any, callback?: QueueCallback, custom?: InternalQueryOptions) {
|
|
1392
1556
|
|
|
1393
1557
|
if (this._isClosed)
|
|
1394
1558
|
return this.throwClosed(callback);
|
|
@@ -1412,14 +1576,14 @@ class Connection {
|
|
|
1412
1576
|
op = Const.op_execute2;
|
|
1413
1577
|
}
|
|
1414
1578
|
|
|
1415
|
-
function PrepareParams(params, input, callback) {
|
|
1579
|
+
function PrepareParams(params: any[], input: Xsql.SQLVarBase[], callback: (prms: any[]) => void) {
|
|
1416
1580
|
|
|
1417
1581
|
var value, meta;
|
|
1418
1582
|
var ret = new Array(params.length);
|
|
1419
1583
|
|
|
1420
|
-
function putBlobData(index, value, callback) {
|
|
1584
|
+
function putBlobData(index: any, value: any, callback: any) {
|
|
1421
1585
|
|
|
1422
|
-
self.createBlob2(transaction, function(err, blob) {
|
|
1586
|
+
self.createBlob2(transaction, function(err: any, blob: any) {
|
|
1423
1587
|
|
|
1424
1588
|
var b;
|
|
1425
1589
|
var isStream = value.readable;
|
|
@@ -1447,7 +1611,7 @@ class Connection {
|
|
|
1447
1611
|
var isReading = false;
|
|
1448
1612
|
var isEnd = false;
|
|
1449
1613
|
|
|
1450
|
-
value.on('data', function(chunk) {
|
|
1614
|
+
value.on('data', function(chunk: any) {
|
|
1451
1615
|
// Optimization: If chunk is smaller than transfer size, send directly
|
|
1452
1616
|
if (chunk.length <= chunkSize) {
|
|
1453
1617
|
self.batchSegments(blob, chunk, function () {
|
|
@@ -1488,7 +1652,7 @@ class Connection {
|
|
|
1488
1652
|
});
|
|
1489
1653
|
}
|
|
1490
1654
|
|
|
1491
|
-
function step(i) {
|
|
1655
|
+
function step(i: any) {
|
|
1492
1656
|
if (i === params.length) {
|
|
1493
1657
|
callback(ret);
|
|
1494
1658
|
return;
|
|
@@ -1605,12 +1769,12 @@ class Connection {
|
|
|
1605
1769
|
|
|
1606
1770
|
if (!(params instanceof Array)) {
|
|
1607
1771
|
if (params !== undefined && typeof params === 'object' && params !== null) {
|
|
1608
|
-
var mappedParams = [];
|
|
1772
|
+
var mappedParams: any[] = [];
|
|
1609
1773
|
for (var i = 0; i < input.length; i++) {
|
|
1610
1774
|
mappedParams.push(undefined);
|
|
1611
1775
|
}
|
|
1612
1776
|
var matchedCount = 0;
|
|
1613
|
-
var nameMap = {};
|
|
1777
|
+
var nameMap: Record<string, number> = {};
|
|
1614
1778
|
for (var i = 0; i < input.length; i++) {
|
|
1615
1779
|
var name = input[i].alias || input[i].field;
|
|
1616
1780
|
if (name) {
|
|
@@ -1641,11 +1805,11 @@ class Connection {
|
|
|
1641
1805
|
|
|
1642
1806
|
if (params.length !== input.length) {
|
|
1643
1807
|
self._pending.pop();
|
|
1644
|
-
callback(new Error('Expected parameters: (params=' + params.length + ' vs. expected=' + input.length + ') - ' + statement.query));
|
|
1808
|
+
callback!(new Error('Expected parameters: (params=' + params.length + ' vs. expected=' + input.length + ') - ' + statement.query));
|
|
1645
1809
|
return;
|
|
1646
1810
|
}
|
|
1647
1811
|
|
|
1648
|
-
PrepareParams(params, input, function(prms) {
|
|
1812
|
+
PrepareParams(params, input, function(prms: any) {
|
|
1649
1813
|
self.sendExecute(op, statement, transaction, callback, prms);
|
|
1650
1814
|
});
|
|
1651
1815
|
|
|
@@ -1656,7 +1820,7 @@ class Connection {
|
|
|
1656
1820
|
}
|
|
1657
1821
|
|
|
1658
1822
|
|
|
1659
|
-
sendExecute(op: number, statement:
|
|
1823
|
+
sendExecute(op: number, statement: Statement, transaction: Transaction, callback: QueueCallback | undefined, parameters?: any[]) {
|
|
1660
1824
|
var msg = this._msg;
|
|
1661
1825
|
var blr = this._blr;
|
|
1662
1826
|
msg.pos = 0;
|
|
@@ -1736,14 +1900,15 @@ class Connection {
|
|
|
1736
1900
|
msg.addInt(statement.options?.maxInlineBlobSize !== undefined ? statement.options.maxInlineBlobSize : (this.options?.maxInlineBlobSize || 0)); // p_sqldata_inline_blob_size
|
|
1737
1901
|
}
|
|
1738
1902
|
|
|
1739
|
-
callback
|
|
1903
|
+
callback!.statement = statement;
|
|
1740
1904
|
this._queueEvent(callback);
|
|
1741
1905
|
}
|
|
1742
1906
|
|
|
1743
1907
|
|
|
1744
1908
|
|
|
1745
1909
|
|
|
1746
|
-
|
|
1910
|
+
/** `count` may be the callback itself when no fetch size is given. */
|
|
1911
|
+
fetch(statement: Statement, transaction: Transaction, count: any, callback?: QueueCallback) {
|
|
1747
1912
|
|
|
1748
1913
|
var msg = this._msg;
|
|
1749
1914
|
var blr = this._blr;
|
|
@@ -1763,12 +1928,12 @@ class Connection {
|
|
|
1763
1928
|
msg.addInt(0); // message number
|
|
1764
1929
|
msg.addInt(count || Const.DEFAULT_FETCHSIZE); // fetch count
|
|
1765
1930
|
|
|
1766
|
-
callback
|
|
1931
|
+
callback!.statement = statement;
|
|
1767
1932
|
this._queueEvent(callback);
|
|
1768
1933
|
}
|
|
1769
1934
|
|
|
1770
1935
|
|
|
1771
|
-
fetchScroll(statement, transaction, direction, offset, count, callback) {
|
|
1936
|
+
fetchScroll(statement: Statement, transaction: Transaction, direction: string | number, offset: any, count: any, callback?: QueueCallback) {
|
|
1772
1937
|
if (typeof count === 'function') {
|
|
1773
1938
|
callback = count;
|
|
1774
1939
|
count = undefined;
|
|
@@ -1814,18 +1979,18 @@ class Connection {
|
|
|
1814
1979
|
msg.addInt(dirInt); // fetch operation
|
|
1815
1980
|
msg.addInt(offsetVal); // fetch position (offset)
|
|
1816
1981
|
|
|
1817
|
-
callback
|
|
1982
|
+
callback!.statement = statement;
|
|
1818
1983
|
this._queueEvent(callback);
|
|
1819
1984
|
}
|
|
1820
1985
|
|
|
1821
1986
|
|
|
1822
|
-
fetchAll(statement, transaction, callback) {
|
|
1987
|
+
fetchAll(statement: Statement, transaction: Transaction, callback: Callback<any[]>) {
|
|
1823
1988
|
const self = this;
|
|
1824
1989
|
const custom = statement.options || {};
|
|
1825
1990
|
const asStream = custom.asStream && custom.on;
|
|
1826
|
-
const data = asStream ? null : [];
|
|
1991
|
+
const data: any[] | null = asStream ? null : [];
|
|
1827
1992
|
let streamIndex = 0;
|
|
1828
|
-
const loop = (err, ret) => {
|
|
1993
|
+
const loop = (err: any, ret: any) => {
|
|
1829
1994
|
if (err) {
|
|
1830
1995
|
callback(err);
|
|
1831
1996
|
return;
|
|
@@ -1837,24 +2002,28 @@ class Connection {
|
|
|
1837
2002
|
// which causes a server-side deadlock when many rows contain
|
|
1838
2003
|
// BLOBs and blobAsText is true. See issue #387.
|
|
1839
2004
|
const arrBlobFns = ret.arrBlob || [];
|
|
1840
|
-
const readBlobsSequentially = (index, results) => {
|
|
2005
|
+
const readBlobsSequentially = (index: any, results: any) => {
|
|
1841
2006
|
if (index >= arrBlobFns.length) {
|
|
1842
2007
|
return Promise.resolve(results);
|
|
1843
2008
|
}
|
|
1844
|
-
return arrBlobFns[index](transaction).then((v) => {
|
|
2009
|
+
return arrBlobFns[index](transaction).then((v: any) => {
|
|
1845
2010
|
results.push(v);
|
|
1846
2011
|
return readBlobsSequentially(index + 1, results);
|
|
1847
2012
|
});
|
|
1848
2013
|
};
|
|
1849
2014
|
|
|
1850
|
-
readBlobsSequentially(0, []).then((arrBlob) => {
|
|
2015
|
+
readBlobsSequentially(0, []).then((arrBlob: any) => {
|
|
1851
2016
|
for (let i = 0; i < arrBlob.length; i++) {
|
|
1852
2017
|
const blob = arrBlob[i];
|
|
1853
|
-
|
|
2018
|
+
// nestTables === true rows: the value lives in the
|
|
2019
|
+
// per-table sub-object, not on the row itself
|
|
2020
|
+
Xsql.nestCell(ret.data[blob.row], blob.table)[blob.column] = applyTypeCast(
|
|
2021
|
+
statement.connection.options, blob.meta || {},
|
|
2022
|
+
parseValueIfJson(blob.value, statement.connection.options));
|
|
1854
2023
|
}
|
|
1855
2024
|
|
|
1856
2025
|
doSynchronousLoop(ret.data, (row, _i, next) => {
|
|
1857
|
-
const pos = asStream ? streamIndex++ : (data
|
|
2026
|
+
const pos = asStream ? streamIndex++ : (data!.push(row) - 1);
|
|
1858
2027
|
if (asStream) {
|
|
1859
2028
|
executeStreamRow(custom, row, pos, statement.output, next);
|
|
1860
2029
|
} else {
|
|
@@ -1888,7 +2057,7 @@ class Connection {
|
|
|
1888
2057
|
|
|
1889
2058
|
|
|
1890
2059
|
|
|
1891
|
-
openBlob(blob, transaction, callback) {
|
|
2060
|
+
openBlob(blob: Quad, transaction: Transaction, callback: QueueCallback) {
|
|
1892
2061
|
var msg = this._msg;
|
|
1893
2062
|
msg.pos = 0;
|
|
1894
2063
|
msg.addInt(Const.op_open_blob);
|
|
@@ -1898,7 +2067,7 @@ class Connection {
|
|
|
1898
2067
|
}
|
|
1899
2068
|
|
|
1900
2069
|
|
|
1901
|
-
closeBlob(blob, callback, defer = true) {
|
|
2070
|
+
closeBlob(blob: any, callback?: QueueCallback, defer = true) {
|
|
1902
2071
|
var msg = this._msg;
|
|
1903
2072
|
msg.pos = 0;
|
|
1904
2073
|
msg.addInt(Const.op_close_blob);
|
|
@@ -1907,7 +2076,7 @@ class Connection {
|
|
|
1907
2076
|
}
|
|
1908
2077
|
|
|
1909
2078
|
|
|
1910
|
-
getSegment(blob, callback) {
|
|
2079
|
+
getSegment(blob: any, callback: QueueCallback) {
|
|
1911
2080
|
var msg = this._msg;
|
|
1912
2081
|
msg.pos = 0;
|
|
1913
2082
|
msg.addInt(Const.op_get_segment);
|
|
@@ -1918,7 +2087,7 @@ class Connection {
|
|
|
1918
2087
|
}
|
|
1919
2088
|
|
|
1920
2089
|
|
|
1921
|
-
createBlob2(transaction, callback) {
|
|
2090
|
+
createBlob2(transaction: Transaction, callback: QueueCallback) {
|
|
1922
2091
|
var msg = this._msg;
|
|
1923
2092
|
msg.pos = 0;
|
|
1924
2093
|
msg.addInt(Const.op_create_blob2);
|
|
@@ -1930,7 +2099,7 @@ class Connection {
|
|
|
1930
2099
|
}
|
|
1931
2100
|
|
|
1932
2101
|
|
|
1933
|
-
batchSegments(blob, buffer, callback) {
|
|
2102
|
+
batchSegments(blob: any, buffer: Buffer, callback: QueueCallback) {
|
|
1934
2103
|
var msg = this._msg;
|
|
1935
2104
|
var blr = this._blr;
|
|
1936
2105
|
msg.pos = 0;
|
|
@@ -1944,7 +2113,7 @@ class Connection {
|
|
|
1944
2113
|
}
|
|
1945
2114
|
|
|
1946
2115
|
|
|
1947
|
-
svcattach(options:
|
|
2116
|
+
svcattach(options: InternalOptions, callback?: Callback<ServiceManager>, svc?: ServiceManager) {
|
|
1948
2117
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
1949
2118
|
var database = options.database || options.filename;
|
|
1950
2119
|
var user = options.user || Const.DEFAULT_USER;
|
|
@@ -1979,7 +2148,7 @@ class Connection {
|
|
|
1979
2148
|
|
|
1980
2149
|
var self = this;
|
|
1981
2150
|
|
|
1982
|
-
function cb(err, ret) {
|
|
2151
|
+
function cb(err: any, ret: any) {
|
|
1983
2152
|
|
|
1984
2153
|
if (err) {
|
|
1985
2154
|
doError(err, callback);
|
|
@@ -2005,19 +2174,19 @@ class Connection {
|
|
|
2005
2174
|
}
|
|
2006
2175
|
|
|
2007
2176
|
|
|
2008
|
-
svcstart(spbaction, callback) {
|
|
2177
|
+
svcstart(spbaction: BlrWriter, callback: QueueCallback | undefined) {
|
|
2009
2178
|
var msg = this._msg;
|
|
2010
2179
|
var blr = this._blr;
|
|
2011
2180
|
msg.pos = 0;
|
|
2012
2181
|
msg.addInt(Const.op_service_start);
|
|
2013
|
-
msg.addInt(this.svchandle);
|
|
2182
|
+
msg.addInt(this.svchandle!);
|
|
2014
2183
|
msg.addInt(0)
|
|
2015
2184
|
msg.addBlr(spbaction);
|
|
2016
2185
|
this._queueEvent(callback);
|
|
2017
2186
|
}
|
|
2018
2187
|
|
|
2019
2188
|
|
|
2020
|
-
svcquery(spbquery, resultbuffersize, timeout,callback) {
|
|
2189
|
+
svcquery(spbquery: number[], resultbuffersize: number, timeout: number | undefined, callback: QueueCallback | undefined) {
|
|
2021
2190
|
if (resultbuffersize > Const.MAX_BUFFER_SIZE) {
|
|
2022
2191
|
doError(new Error('Buffer is too big'), callback);
|
|
2023
2192
|
return;
|
|
@@ -2030,7 +2199,7 @@ class Connection {
|
|
|
2030
2199
|
blr.addByte(Const.isc_spb_current_version);
|
|
2031
2200
|
//blr.addByteInt32(Const.isc_info_svc_timeout, timeout);
|
|
2032
2201
|
msg.addInt(Const.op_service_info);
|
|
2033
|
-
msg.addInt(this.svchandle);
|
|
2202
|
+
msg.addInt(this.svchandle!);
|
|
2034
2203
|
msg.addInt(0);
|
|
2035
2204
|
msg.addBlr(blr);
|
|
2036
2205
|
blr.pos = 0
|
|
@@ -2041,7 +2210,7 @@ class Connection {
|
|
|
2041
2210
|
}
|
|
2042
2211
|
|
|
2043
2212
|
|
|
2044
|
-
svcdetach(callback) {
|
|
2213
|
+
svcdetach(callback: Callback | undefined) {
|
|
2045
2214
|
var self = this;
|
|
2046
2215
|
|
|
2047
2216
|
if (self._isClosed) {
|
|
@@ -2056,9 +2225,9 @@ class Connection {
|
|
|
2056
2225
|
|
|
2057
2226
|
msg.pos = 0;
|
|
2058
2227
|
msg.addInt(Const.op_service_detach);
|
|
2059
|
-
msg.addInt(this.svchandle); // Database Object ID
|
|
2228
|
+
msg.addInt(this.svchandle!); // Database Object ID
|
|
2060
2229
|
|
|
2061
|
-
self._queueEvent(function (err, ret) {
|
|
2230
|
+
self._queueEvent(function (err: any, ret: any) {
|
|
2062
2231
|
delete (self.svchandle);
|
|
2063
2232
|
if (callback)
|
|
2064
2233
|
callback(err, ret);
|
|
@@ -2067,7 +2236,7 @@ class Connection {
|
|
|
2067
2236
|
|
|
2068
2237
|
|
|
2069
2238
|
|
|
2070
|
-
auxConnection(eventid, callback) {
|
|
2239
|
+
auxConnection(eventid: number | Callback, callback?: Callback) {
|
|
2071
2240
|
if (typeof eventid === 'function') {
|
|
2072
2241
|
// Preserve the older auxConnection(callback) call shape; plain
|
|
2073
2242
|
// auxiliary connections historically used event id 0.
|
|
@@ -2081,13 +2250,13 @@ class Connection {
|
|
|
2081
2250
|
msg.pos = 0;
|
|
2082
2251
|
msg.addInt(Const.op_connect_request);
|
|
2083
2252
|
msg.addInt(1); // async
|
|
2084
|
-
msg.addInt(self.dbhandle);
|
|
2253
|
+
msg.addInt(self.dbhandle!);
|
|
2085
2254
|
msg.addInt(eventid);
|
|
2086
2255
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2087
2256
|
console.log('[fb-debug] auxConnection: sending op_connect_request(53) dbhandle=%d eventid=%d queue_before=%d xdr_saved=%s',
|
|
2088
2257
|
self.dbhandle, eventid, self._queue.length, Boolean(self._xdr));
|
|
2089
2258
|
}
|
|
2090
|
-
function cb(err, ret) {
|
|
2259
|
+
function cb(err: any, ret: any) {
|
|
2091
2260
|
|
|
2092
2261
|
if (err) {
|
|
2093
2262
|
if (process.env.FIREBIRD_DEBUG) {
|
|
@@ -2108,13 +2277,13 @@ class Connection {
|
|
|
2108
2277
|
socket_info.family, socket_info.port, socket_info.host, self._queue.length);
|
|
2109
2278
|
}
|
|
2110
2279
|
|
|
2111
|
-
callback(undefined, socket_info);
|
|
2280
|
+
callback!(undefined, socket_info);
|
|
2112
2281
|
}
|
|
2113
2282
|
this._queueEvent(cb);
|
|
2114
2283
|
}
|
|
2115
2284
|
|
|
2116
2285
|
|
|
2117
|
-
queEvents(events, eventid, callback) {
|
|
2286
|
+
queEvents(events: Record<string, number>, eventid: number, callback: Callback) {
|
|
2118
2287
|
var self = this;
|
|
2119
2288
|
if (this._isClosed)
|
|
2120
2289
|
return this.throwClosed(callback);
|
|
@@ -2123,7 +2292,7 @@ class Connection {
|
|
|
2123
2292
|
blr.pos = 0;
|
|
2124
2293
|
msg.pos = 0;
|
|
2125
2294
|
msg.addInt(Const.op_que_events);
|
|
2126
|
-
msg.addInt(this.dbhandle);
|
|
2295
|
+
msg.addInt(this.dbhandle!);
|
|
2127
2296
|
// prepare EPB
|
|
2128
2297
|
blr.addByte(1) // epb_version
|
|
2129
2298
|
for (var event in events) {
|
|
@@ -2137,7 +2306,7 @@ class Connection {
|
|
|
2137
2306
|
msg.addInt(0); // args
|
|
2138
2307
|
msg.addInt(eventid);
|
|
2139
2308
|
|
|
2140
|
-
function cb(err, ret) {
|
|
2309
|
+
function cb(err: any, ret: any) {
|
|
2141
2310
|
if (err) {
|
|
2142
2311
|
doError(err, callback);
|
|
2143
2312
|
return;
|
|
@@ -2150,17 +2319,17 @@ class Connection {
|
|
|
2150
2319
|
}
|
|
2151
2320
|
|
|
2152
2321
|
|
|
2153
|
-
closeEvents(eventid, callback) {
|
|
2322
|
+
closeEvents(eventid: number, callback: Callback) {
|
|
2154
2323
|
var self = this;
|
|
2155
2324
|
if (this._isClosed)
|
|
2156
2325
|
return this.throwClosed(callback);
|
|
2157
2326
|
var msg = self._msg;
|
|
2158
2327
|
msg.pos = 0;
|
|
2159
2328
|
msg.addInt(Const.op_cancel_events);
|
|
2160
|
-
msg.addInt(self.dbhandle);
|
|
2329
|
+
msg.addInt(self.dbhandle!);
|
|
2161
2330
|
msg.addInt(eventid);
|
|
2162
2331
|
|
|
2163
|
-
function cb(err, ret) {
|
|
2332
|
+
function cb(err: any, ret: any) {
|
|
2164
2333
|
if (err) {
|
|
2165
2334
|
doError(err, callback);
|
|
2166
2335
|
return;
|
|
@@ -2179,7 +2348,7 @@ const opcodeNames = Object.fromEntries(
|
|
|
2179
2348
|
Object.entries(Const).filter(([k]) => k.startsWith('op_')).map(([k, v]) => [v, k])
|
|
2180
2349
|
);
|
|
2181
2350
|
|
|
2182
|
-
function decodeResponse(data:
|
|
2351
|
+
function decodeResponse(data: XdrReader, callback: QueueCallback | undefined, cnx: Connection, lowercase_keys: boolean | undefined, cb: (err?: any, obj?: any) => void) {
|
|
2183
2352
|
try {
|
|
2184
2353
|
do {
|
|
2185
2354
|
var r = data.r || data.readInt();
|
|
@@ -2200,7 +2369,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2200
2369
|
cnx._inlineBlobs = new Map();
|
|
2201
2370
|
}
|
|
2202
2371
|
const cacheKey = `${blob_id.high}:${blob_id.low}`;
|
|
2203
|
-
cnx._inlineBlobs.set(cacheKey, blob_data);
|
|
2372
|
+
cnx._inlineBlobs.set(cacheKey, blob_data!);
|
|
2204
2373
|
r = Const.op_dummy; // Continue loop to read next opcode
|
|
2205
2374
|
}
|
|
2206
2375
|
} while (r === Const.op_dummy);
|
|
@@ -2210,7 +2379,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2210
2379
|
r, opcodeNames[r] || 'unknown', data.pos, data.buffer.length);
|
|
2211
2380
|
}
|
|
2212
2381
|
|
|
2213
|
-
var item, op, response;
|
|
2382
|
+
var item, op, response: any;
|
|
2214
2383
|
|
|
2215
2384
|
switch (r) {
|
|
2216
2385
|
case Const.op_response:
|
|
@@ -2221,7 +2390,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2221
2390
|
response = {};
|
|
2222
2391
|
}
|
|
2223
2392
|
|
|
2224
|
-
let loop = function (err) {
|
|
2393
|
+
let loop = function (err: any) {
|
|
2225
2394
|
if (err) {
|
|
2226
2395
|
return cb(err);
|
|
2227
2396
|
} else {
|
|
@@ -2282,13 +2451,28 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2282
2451
|
}
|
|
2283
2452
|
case Const.op_fetch_response:
|
|
2284
2453
|
case Const.op_sql_response:
|
|
2285
|
-
|
|
2454
|
+
// fetch/sql_response entries always carry their statement
|
|
2455
|
+
var statement = callback!.statement!;
|
|
2286
2456
|
var output = statement.output;
|
|
2287
2457
|
var custom = statement.options || {};
|
|
2288
2458
|
var isOpFetch = r === Const.op_fetch_response;
|
|
2289
2459
|
var _xdrpos;
|
|
2290
2460
|
statement.nbrowsfetched = statement.nbrowsfetched || 0;
|
|
2291
2461
|
|
|
2462
|
+
// The f* decode state is only meaningful within a single
|
|
2463
|
+
// decode call: incomplete packets are re-decoded from scratch
|
|
2464
|
+
// on a fresh XdrReader (see the 'data' handler). State left by
|
|
2465
|
+
// an earlier packet in the same data event (e.g. fstatus=100 /
|
|
2466
|
+
// fcount=0 from a completed fetch) would make this decode
|
|
2467
|
+
// consume just the opcode and desync every later response.
|
|
2468
|
+
delete data.fstatus;
|
|
2469
|
+
delete data.fcount;
|
|
2470
|
+
delete data.fcolumn;
|
|
2471
|
+
delete data.frow;
|
|
2472
|
+
delete data.frows;
|
|
2473
|
+
delete data.fcols;
|
|
2474
|
+
delete data.ftables;
|
|
2475
|
+
|
|
2292
2476
|
if (isOpFetch && data.fop) { // could be set when a packet is not complete
|
|
2293
2477
|
data.readBuffer(68); // ??
|
|
2294
2478
|
op = data.readInt(); // ??
|
|
@@ -2309,56 +2493,74 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2309
2493
|
data.frows = data.frows || [];
|
|
2310
2494
|
|
|
2311
2495
|
if (custom.asObject && !data.fcols) {
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2496
|
+
const nest = Xsql.resolveNestTables(custom, cnx.options);
|
|
2497
|
+
const columnKeys = Xsql.computeColumnKeys(output, nest, lowercase_keys);
|
|
2498
|
+
data.fcols = columnKeys.map((k) => k.key);
|
|
2499
|
+
if (nest === true) {
|
|
2500
|
+
// computeColumnKeys always sets table when nesting
|
|
2501
|
+
data.ftables = columnKeys.map((k) => k.table!);
|
|
2316
2502
|
}
|
|
2317
2503
|
}
|
|
2318
2504
|
|
|
2319
|
-
const arrBlob = [];
|
|
2505
|
+
const arrBlob: any[] = [];
|
|
2320
2506
|
const lowerV13 = statement.connection.accept.protocolVersion < Const.PROTOCOL_VERSION13;
|
|
2321
2507
|
|
|
2508
|
+
// op_sql_response (op_execute2) is always followed by an
|
|
2509
|
+
// op_response carrying the execute status vector. The row loop
|
|
2510
|
+
// below consumes it after the last row, but with zero rows
|
|
2511
|
+
// (e.g. INSERT ... RETURNING failing on a constraint) it stays
|
|
2512
|
+
// in the buffer, shifting every later response to the wrong
|
|
2513
|
+
// callback and poisoning the connection (issue #341).
|
|
2514
|
+
var sqlResponseTrailerPending = !isOpFetch && !data.fcount;
|
|
2515
|
+
|
|
2322
2516
|
while (data.fcount && (data.fstatus !== 100)) {
|
|
2323
2517
|
let nullBitSet;
|
|
2324
2518
|
if (!lowerV13) {
|
|
2325
2519
|
const nullBitsLen = Math.floor((output.length + 7) / 8);
|
|
2326
|
-
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false));
|
|
2520
|
+
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false)!);
|
|
2327
2521
|
data.readBuffer((4 - nullBitsLen) & 3, false); // Skip padding
|
|
2328
2522
|
}
|
|
2329
2523
|
|
|
2330
2524
|
for (let length = output.length; data.fcolumn < length; data.fcolumn++) {
|
|
2331
2525
|
item = output[data.fcolumn];
|
|
2332
2526
|
|
|
2333
|
-
if (!lowerV13 && nullBitSet
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2527
|
+
if (!lowerV13 && nullBitSet!.get(data.fcolumn)) {
|
|
2528
|
+
const nullKey = custom.asObject ? data.fcols![data.fcolumn!] : data.fcolumn;
|
|
2529
|
+
// ftables is only set when nestTables === true, so
|
|
2530
|
+
// the default path writes straight into the row
|
|
2531
|
+
(data.ftables ? Xsql.nestCell(data.frow, data.ftables[data.fcolumn!]) : data.frow)[nullKey] =
|
|
2532
|
+
applyTypeCast(cnx.options, item, null);
|
|
2339
2533
|
|
|
2340
2534
|
continue;
|
|
2341
2535
|
}
|
|
2342
2536
|
|
|
2343
2537
|
try {
|
|
2344
2538
|
_xdrpos = data.pos;
|
|
2345
|
-
const key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
2539
|
+
const key = custom.asObject ? data.fcols![data.fcolumn!] : data.fcolumn;
|
|
2346
2540
|
const row = data.frows.length;
|
|
2347
2541
|
let value = item.decode(data, lowerV13, cnx.options);
|
|
2542
|
+
// text blobs resolved by blobAsText run through the
|
|
2543
|
+
// typeCast hook once the text arrives (see fetchAll),
|
|
2544
|
+
// not here where the value is still a pending fetch
|
|
2545
|
+
let pendingTextBlob = false;
|
|
2348
2546
|
|
|
2349
2547
|
if (item.type === Const.SQL_BLOB && value !== null) {
|
|
2350
2548
|
if (item.subType === Const.isc_blob_text && cnx.options.blobAsText) {
|
|
2351
|
-
value = fetch_blob_async_transaction(statement, value, key, row
|
|
2549
|
+
value = fetch_blob_async_transaction(statement, value, key, row, item,
|
|
2550
|
+
data.ftables && data.ftables[data.fcolumn!]);
|
|
2352
2551
|
arrBlob.push(value);
|
|
2552
|
+
pendingTextBlob = true;
|
|
2353
2553
|
} else {
|
|
2354
2554
|
value = fetch_blob_async(statement, value, key, row);
|
|
2355
2555
|
}
|
|
2356
2556
|
}
|
|
2357
2557
|
|
|
2358
|
-
data.frow[key] =
|
|
2558
|
+
(data.ftables ? Xsql.nestCell(data.frow, data.ftables[data.fcolumn!]) : data.frow)[key] = pendingTextBlob
|
|
2559
|
+
? value
|
|
2560
|
+
: applyTypeCast(cnx.options, item, parseValueIfJson(value, cnx.options));
|
|
2359
2561
|
} catch (e) {
|
|
2360
2562
|
// uncomplete packet read
|
|
2361
|
-
data.pos = _xdrpos
|
|
2563
|
+
data.pos = _xdrpos!;
|
|
2362
2564
|
data.r = r;
|
|
2363
2565
|
return cb(new Error('Packet is not complete'));
|
|
2364
2566
|
}
|
|
@@ -2403,6 +2605,17 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2403
2605
|
statement.nbrowsfetched++;
|
|
2404
2606
|
}
|
|
2405
2607
|
|
|
2608
|
+
if (sqlResponseTrailerPending) {
|
|
2609
|
+
op = data.readInt();
|
|
2610
|
+
if (op === Const.op_response) {
|
|
2611
|
+
response = {};
|
|
2612
|
+
parseOpResponse(data, response);
|
|
2613
|
+
if (response.status) {
|
|
2614
|
+
return cb(null, response);
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2406
2619
|
// ToDo: emit "result" with blob subtype string decoded
|
|
2407
2620
|
statement.connection.db.emit('result', data.frows, arrBlob);
|
|
2408
2621
|
return cb(null, {data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob});
|
|
@@ -2427,7 +2640,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2427
2640
|
}
|
|
2428
2641
|
|
|
2429
2642
|
if (r === Const.op_cond_accept || r === Const.op_accept_data) {
|
|
2430
|
-
var d = new BlrReader(data.readArray());
|
|
2643
|
+
var d = new BlrReader(data.readArray()!);
|
|
2431
2644
|
accept.pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
2432
2645
|
var is_authenticated = data.readInt();
|
|
2433
2646
|
var keys = data.readString(Const.DEFAULT_ENCODING); // keys
|
|
@@ -2447,7 +2660,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2447
2660
|
}
|
|
2448
2661
|
|
|
2449
2662
|
if (Const.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
2450
|
-
var crypto = {
|
|
2663
|
+
var crypto: Record<string, string> = {
|
|
2451
2664
|
Srp: 'sha1',
|
|
2452
2665
|
Srp256: 'sha256',
|
|
2453
2666
|
Srp384: 'sha384',
|
|
@@ -2458,7 +2671,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2458
2671
|
if (!d.buffer) {
|
|
2459
2672
|
cnx._pendingAccept = accept;
|
|
2460
2673
|
cnx.sendOpContAuth(
|
|
2461
|
-
cnx.clientKeys
|
|
2674
|
+
cnx.clientKeys!.public.toString(16),
|
|
2462
2675
|
Const.DEFAULT_ENCODING,
|
|
2463
2676
|
accept.pluginName
|
|
2464
2677
|
);
|
|
@@ -2489,20 +2702,20 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2489
2702
|
|
|
2490
2703
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2491
2704
|
console.log('--- DEBUG SRP Handshake ---');
|
|
2492
|
-
console.log('salt:', cnx.serverKeys
|
|
2493
|
-
console.log('server public key:', cnx.serverKeys
|
|
2494
|
-
console.log('client public key:', cnx.clientKeys
|
|
2705
|
+
console.log('salt:', cnx.serverKeys!.salt);
|
|
2706
|
+
console.log('server public key:', cnx.serverKeys!.public.toString(16));
|
|
2707
|
+
console.log('client public key:', cnx.clientKeys!.public.toString(16));
|
|
2495
2708
|
console.log('hashAlgo:', accept.srpAlgo);
|
|
2496
2709
|
}
|
|
2497
2710
|
|
|
2498
2711
|
const _t1 = Date.now();
|
|
2499
2712
|
var proof = srp.clientProof(
|
|
2500
|
-
cnx.options.user
|
|
2501
|
-
cnx.options.password
|
|
2502
|
-
cnx.serverKeys
|
|
2503
|
-
cnx.clientKeys
|
|
2504
|
-
cnx.serverKeys
|
|
2505
|
-
cnx.clientKeys
|
|
2713
|
+
cnx.options.user!.toUpperCase(),
|
|
2714
|
+
cnx.options.password!,
|
|
2715
|
+
cnx.serverKeys!.salt,
|
|
2716
|
+
cnx.clientKeys!.public,
|
|
2717
|
+
cnx.serverKeys!.public,
|
|
2718
|
+
cnx.clientKeys!.private,
|
|
2506
2719
|
accept.srpAlgo
|
|
2507
2720
|
);
|
|
2508
2721
|
|
|
@@ -2519,7 +2732,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2519
2732
|
accept.authData = proof.authData.toString(16);
|
|
2520
2733
|
accept.sessionKey = proof.clientSessionKey;
|
|
2521
2734
|
} else if (accept.pluginName === Const.AUTH_PLUGIN_LEGACY) {
|
|
2522
|
-
accept.authData = crypt.crypt(cnx.options.password
|
|
2735
|
+
accept.authData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2523
2736
|
} else {
|
|
2524
2737
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
2525
2738
|
}
|
|
@@ -2557,7 +2770,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2557
2770
|
|
|
2558
2771
|
return cb(undefined, accept);
|
|
2559
2772
|
case Const.op_cont_auth:
|
|
2560
|
-
var d = new BlrReader(data.readArray());
|
|
2773
|
+
var d = new BlrReader(data.readArray()!);
|
|
2561
2774
|
var pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
2562
2775
|
data.readString(Const.DEFAULT_ENCODING); // plist
|
|
2563
2776
|
data.readString(Const.DEFAULT_ENCODING); // pkey
|
|
@@ -2584,7 +2797,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2584
2797
|
// the proof with the new plugin's hash algorithm - rather than
|
|
2585
2798
|
// as the server's M2 proof, otherwise the client silently waits
|
|
2586
2799
|
// forever for an op_accept the server will never send (#254).
|
|
2587
|
-
if (!cnx.serverKeys || cnx.serverKeys
|
|
2800
|
+
if (!cnx.serverKeys || cnx.serverKeys!.pluginName !== pluginName) {
|
|
2588
2801
|
// Check buffer contains salt
|
|
2589
2802
|
var saltLen = d.buffer.readUInt16LE(0);
|
|
2590
2803
|
if (saltLen > 32 * 2) {
|
|
@@ -2607,7 +2820,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2607
2820
|
pluginName: pluginName
|
|
2608
2821
|
};
|
|
2609
2822
|
|
|
2610
|
-
var crypto = {
|
|
2823
|
+
var crypto: Record<string, string> = {
|
|
2611
2824
|
Srp: 'sha1',
|
|
2612
2825
|
Srp256: 'sha256',
|
|
2613
2826
|
Srp384: 'sha384',
|
|
@@ -2617,20 +2830,20 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2617
2830
|
|
|
2618
2831
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2619
2832
|
console.log('--- DEBUG SRP Handshake ---');
|
|
2620
|
-
console.log('salt:', cnx.serverKeys
|
|
2621
|
-
console.log('server public key:', cnx.serverKeys
|
|
2622
|
-
console.log('client public key:', cnx.clientKeys
|
|
2833
|
+
console.log('salt:', cnx.serverKeys!.salt);
|
|
2834
|
+
console.log('server public key:', cnx.serverKeys!.public.toString(16));
|
|
2835
|
+
console.log('client public key:', cnx.clientKeys!.public.toString(16));
|
|
2623
2836
|
console.log('hashAlgo:', srpAlgo);
|
|
2624
2837
|
}
|
|
2625
2838
|
|
|
2626
2839
|
const _t1 = Date.now();
|
|
2627
2840
|
var proof = srp.clientProof(
|
|
2628
|
-
cnx.options.user
|
|
2629
|
-
cnx.options.password
|
|
2630
|
-
cnx.serverKeys
|
|
2631
|
-
cnx.clientKeys
|
|
2632
|
-
cnx.serverKeys
|
|
2633
|
-
cnx.clientKeys
|
|
2841
|
+
cnx.options.user!.toUpperCase(),
|
|
2842
|
+
cnx.options.password!,
|
|
2843
|
+
cnx.serverKeys!.salt,
|
|
2844
|
+
cnx.clientKeys!.public,
|
|
2845
|
+
cnx.serverKeys!.public,
|
|
2846
|
+
cnx.clientKeys!.private,
|
|
2634
2847
|
srpAlgo
|
|
2635
2848
|
);
|
|
2636
2849
|
|
|
@@ -2667,7 +2880,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2667
2880
|
cnx._pendingAccept.protocolVersion,
|
|
2668
2881
|
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
2669
2882
|
}
|
|
2670
|
-
var legacyAuthData = crypt.crypt(cnx.options.password
|
|
2883
|
+
var legacyAuthData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2671
2884
|
cnx.sendOpContAuth(legacyAuthData, Const.DEFAULT_ENCODING, pluginName);
|
|
2672
2885
|
return; // wait for op_accept
|
|
2673
2886
|
}
|
|
@@ -2680,7 +2893,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2680
2893
|
|
|
2681
2894
|
if (pluginName === Const.AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
2682
2895
|
cnx.accept.pluginName = pluginName;
|
|
2683
|
-
cnx.accept.authData = crypt.crypt(cnx.options.password
|
|
2896
|
+
cnx.accept.authData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2684
2897
|
|
|
2685
2898
|
cnx.sendOpContAuth(
|
|
2686
2899
|
cnx.accept.authData,
|
|
@@ -2773,7 +2986,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2773
2986
|
}
|
|
2774
2987
|
return cb(new Error('Unexpected:' + r));
|
|
2775
2988
|
}
|
|
2776
|
-
} catch (err) {
|
|
2989
|
+
} catch (err: any) {
|
|
2777
2990
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2778
2991
|
console.warn('[fb-debug] decodeResponse exception: %s (RangeError=%s) pos=%d buflen=%d',
|
|
2779
2992
|
err.message, err instanceof RangeError, data.pos, data.buffer.length);
|
|
@@ -2789,8 +3002,8 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2789
3002
|
* Read one XDR status vector (as in op_response / op_batch_cs error
|
|
2790
3003
|
* vectors): a stream of isc_arg_* items terminated by isc_arg_end.
|
|
2791
3004
|
*/
|
|
2792
|
-
function readStatusVector(data:
|
|
2793
|
-
var result: { status: any[]; sqlcode?: number } = { status: [] };
|
|
3005
|
+
function readStatusVector(data: XdrReader): { status: any[]; warnings?: any[]; sqlcode?: number } {
|
|
3006
|
+
var result: { status: any[]; warnings?: any[]; sqlcode?: number } = { status: [] };
|
|
2794
3007
|
var item: any = {};
|
|
2795
3008
|
|
|
2796
3009
|
while (true) {
|
|
@@ -2820,13 +3033,24 @@ function readStatusVector(data: any): { status: any[]; sqlcode?: number } {
|
|
|
2820
3033
|
result.sqlcode = n;
|
|
2821
3034
|
}
|
|
2822
3035
|
break;
|
|
3036
|
+
case Const.isc_arg_warning:
|
|
3037
|
+
// A warning attached to a SUCCESS vector (e.g. "parallel
|
|
3038
|
+
// workers value capped"). Keep it out of `status` so the
|
|
3039
|
+
// operation is not mistaken for a failure; later string/
|
|
3040
|
+
// number items attach to the warning entry.
|
|
3041
|
+
var wnum = data.readInt();
|
|
3042
|
+
item = { gdscode: wnum };
|
|
3043
|
+
if (wnum) {
|
|
3044
|
+
(result.warnings = result.warnings || []).push(item);
|
|
3045
|
+
}
|
|
3046
|
+
break;
|
|
2823
3047
|
default:
|
|
2824
3048
|
throw new Error('Unexpected status vector item: ' + op);
|
|
2825
3049
|
}
|
|
2826
3050
|
}
|
|
2827
3051
|
}
|
|
2828
3052
|
|
|
2829
|
-
function parseOpResponse(data:
|
|
3053
|
+
function parseOpResponse(data: XdrReader, response: WireResponse, cb?: (err?: any, response?: any) => void) {
|
|
2830
3054
|
var handle = data.readInt();
|
|
2831
3055
|
|
|
2832
3056
|
if (!response.handle) {
|
|
@@ -2889,18 +3113,31 @@ function parseOpResponse(data: any, response: any, cb?: (err?: any, response?: a
|
|
|
2889
3113
|
response.sqlcode = num;
|
|
2890
3114
|
}
|
|
2891
3115
|
|
|
3116
|
+
break;
|
|
3117
|
+
case Const.isc_arg_warning:
|
|
3118
|
+
// A warning attached to a SUCCESS response (e.g. Firebird's
|
|
3119
|
+
// "parallel workers value capped" on attach). Keep it out of
|
|
3120
|
+
// `status` so the response is not mistaken for an error;
|
|
3121
|
+
// later string/number items attach to the warning entry.
|
|
3122
|
+
num = data.readInt();
|
|
3123
|
+
item = { gdscode: num };
|
|
3124
|
+
if (num) {
|
|
3125
|
+
(response.warnings = response.warnings || []).push(item);
|
|
3126
|
+
}
|
|
2892
3127
|
break;
|
|
2893
3128
|
default:
|
|
3129
|
+
// Stop parsing: continuing the loop after an unknown item
|
|
3130
|
+
// re-read the same bytes forever (the caller resets the
|
|
3131
|
+
// reader position when the error is delivered).
|
|
2894
3132
|
if (cb) {
|
|
2895
|
-
cb(new Error('Unexpected: ' + op))
|
|
2896
|
-
} else {
|
|
2897
|
-
throw new Error('Unexpected: ' + op);
|
|
3133
|
+
return cb(new Error('Unexpected: ' + op));
|
|
2898
3134
|
}
|
|
3135
|
+
throw new Error('Unexpected: ' + op);
|
|
2899
3136
|
}
|
|
2900
3137
|
}
|
|
2901
3138
|
}
|
|
2902
3139
|
|
|
2903
|
-
function describe(buff: Buffer, statement:
|
|
3140
|
+
function describe(buff: Buffer, statement: Statement) {
|
|
2904
3141
|
var br = new BlrReader(buff);
|
|
2905
3142
|
var parameters: any = null;
|
|
2906
3143
|
var type: any, param: any;
|
|
@@ -2908,7 +3145,7 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2908
3145
|
while (br.pos < br.buffer.length) {
|
|
2909
3146
|
switch (br.readByteCode()) {
|
|
2910
3147
|
case Const.isc_info_sql_stmt_type:
|
|
2911
|
-
statement.type = br.readInt()
|
|
3148
|
+
statement.type = br.readInt()!;
|
|
2912
3149
|
break;
|
|
2913
3150
|
case Const.isc_info_sql_get_plan:
|
|
2914
3151
|
statement.plan = br.readString(Const.DEFAULT_ENCODING);
|
|
@@ -2932,7 +3169,9 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2932
3169
|
case Const.isc_info_sql_describe_end:
|
|
2933
3170
|
break;
|
|
2934
3171
|
case Const.isc_info_sql_sqlda_seq:
|
|
2935
|
-
|
|
3172
|
+
// describe output always encodes the sequence as a
|
|
3173
|
+
// 1/2/4-byte int, so readInt cannot return undefined
|
|
3174
|
+
var num = br.readInt()!;
|
|
2936
3175
|
break;
|
|
2937
3176
|
case Const.isc_info_sql_type:
|
|
2938
3177
|
type = br.readInt();
|
|
@@ -2963,7 +3202,9 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2963
3202
|
default:
|
|
2964
3203
|
throw new Error('Unexpected');
|
|
2965
3204
|
}
|
|
2966
|
-
|
|
3205
|
+
// isc_info_sql_sqlda_seq always precedes the type
|
|
3206
|
+
// item in the describe stream, so num is set here
|
|
3207
|
+
parameters[num!-1] = param;
|
|
2967
3208
|
param.type = type;
|
|
2968
3209
|
param.nullable = Boolean(param.type & 1);
|
|
2969
3210
|
param.type &= ~1;
|
|
@@ -3243,10 +3484,10 @@ function CalcBlr(blr: BlrWriter, xsqlda: any[]) {
|
|
|
3243
3484
|
blr.addByte(Const.blr_eoc);
|
|
3244
3485
|
}
|
|
3245
3486
|
|
|
3246
|
-
function fetch_blob_async_transaction(statement:
|
|
3247
|
-
const infoValue = { row, column, value: '' };
|
|
3487
|
+
function fetch_blob_async_transaction(statement: Statement, id: Quad, column: string | number, row: number, meta?: Xsql.SQLVarBase, table?: string) {
|
|
3488
|
+
const infoValue = { row, column, value: '', meta, table };
|
|
3248
3489
|
|
|
3249
|
-
return (transactionArg) => {
|
|
3490
|
+
return (transactionArg: any) => {
|
|
3250
3491
|
const cacheKey = `${id.high}:${id.low}`;
|
|
3251
3492
|
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
3252
3493
|
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
@@ -3256,10 +3497,10 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3256
3497
|
|
|
3257
3498
|
const singleTransaction = transactionArg === undefined;
|
|
3258
3499
|
|
|
3259
|
-
let promiseTransaction
|
|
3500
|
+
let promiseTransaction: Promise<Transaction>;
|
|
3260
3501
|
if (singleTransaction) {
|
|
3261
3502
|
promiseTransaction = new Promise((resolve, reject) => {
|
|
3262
|
-
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
3503
|
+
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err: any, transaction: Transaction) => {
|
|
3263
3504
|
if (err) {
|
|
3264
3505
|
return reject(err);
|
|
3265
3506
|
}
|
|
@@ -3273,7 +3514,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3273
3514
|
return promiseTransaction.then((transaction) => {
|
|
3274
3515
|
return new Promise((resolve, reject) => {
|
|
3275
3516
|
statement.connection._pending.push('openBlob');
|
|
3276
|
-
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
3517
|
+
statement.connection.openBlob(id, transaction, (err: any, blob: any) => {
|
|
3277
3518
|
|
|
3278
3519
|
if (err) {
|
|
3279
3520
|
reject(err);
|
|
@@ -3281,7 +3522,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3281
3522
|
}
|
|
3282
3523
|
|
|
3283
3524
|
const read = () => {
|
|
3284
|
-
statement.connection.getSegment(blob, (err, ret) => {
|
|
3525
|
+
statement.connection.getSegment(blob, (err: any, ret: any) => {
|
|
3285
3526
|
|
|
3286
3527
|
if (err) {
|
|
3287
3528
|
if (singleTransaction) {
|
|
@@ -3305,7 +3546,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3305
3546
|
|
|
3306
3547
|
statement.connection.closeBlob(blob);
|
|
3307
3548
|
if (singleTransaction) {
|
|
3308
|
-
transaction.commit((err) => {
|
|
3549
|
+
transaction.commit((err: any) => {
|
|
3309
3550
|
if (err) {
|
|
3310
3551
|
reject(err);
|
|
3311
3552
|
} else {
|
|
@@ -3325,14 +3566,14 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3325
3566
|
};
|
|
3326
3567
|
}
|
|
3327
3568
|
|
|
3328
|
-
function fetch_blob_async(statement:
|
|
3329
|
-
const cbTransaction = (transaction, close, callback) => {
|
|
3569
|
+
function fetch_blob_async(statement: Statement, id: Quad, name: string | number, row: number) {
|
|
3570
|
+
const cbTransaction = (transaction: Transaction, close: any, callback: any) => {
|
|
3330
3571
|
statement.connection._pending.push('openBlob');
|
|
3331
|
-
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
3572
|
+
statement.connection.openBlob(id, transaction, (err: any, blob: any) => {
|
|
3332
3573
|
let e: any = new Events.EventEmitter();
|
|
3333
3574
|
|
|
3334
|
-
e.pipe = (stream) => {
|
|
3335
|
-
e.on('data', (chunk) => {
|
|
3575
|
+
e.pipe = (stream: any) => {
|
|
3576
|
+
e.on('data', (chunk: any) => {
|
|
3336
3577
|
stream.write(chunk);
|
|
3337
3578
|
});
|
|
3338
3579
|
e.on('end', () => {
|
|
@@ -3345,7 +3586,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3345
3586
|
}
|
|
3346
3587
|
|
|
3347
3588
|
const read = () => {
|
|
3348
|
-
statement.connection.getSegment(blob, (err, ret) => {
|
|
3589
|
+
statement.connection.getSegment(blob, (err: any, ret: any) => {
|
|
3349
3590
|
|
|
3350
3591
|
if (err) {
|
|
3351
3592
|
transaction.rollback(() => {
|
|
@@ -3368,7 +3609,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3368
3609
|
|
|
3369
3610
|
statement.connection.closeBlob(blob);
|
|
3370
3611
|
if (close) {
|
|
3371
|
-
transaction.commit((err) => {
|
|
3612
|
+
transaction.commit((err: any) => {
|
|
3372
3613
|
if (err) {
|
|
3373
3614
|
e.emit('error', err);
|
|
3374
3615
|
} else {
|
|
@@ -3388,7 +3629,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3388
3629
|
});
|
|
3389
3630
|
};
|
|
3390
3631
|
|
|
3391
|
-
return (transaction, callback) => {
|
|
3632
|
+
return (transaction: Transaction, callback: any) => {
|
|
3392
3633
|
// callback(error, nameField, eventEmitter, row)
|
|
3393
3634
|
const singleTransaction = callback === undefined;
|
|
3394
3635
|
const actualCallback = singleTransaction ? transaction : callback;
|
|
@@ -3397,8 +3638,8 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3397
3638
|
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
3398
3639
|
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
3399
3640
|
let e: any = new Events.EventEmitter();
|
|
3400
|
-
e.pipe = (stream) => {
|
|
3401
|
-
e.on('data', (chunk) => {
|
|
3641
|
+
e.pipe = (stream: any) => {
|
|
3642
|
+
e.on('data', (chunk: any) => {
|
|
3402
3643
|
stream.write(chunk);
|
|
3403
3644
|
});
|
|
3404
3645
|
e.on('end', () => {
|
|
@@ -3419,7 +3660,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3419
3660
|
|
|
3420
3661
|
if (singleTransaction) {
|
|
3421
3662
|
callback = transaction;
|
|
3422
|
-
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
3663
|
+
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err: any, transaction: Transaction) => {
|
|
3423
3664
|
if (err) {
|
|
3424
3665
|
callback(err);
|
|
3425
3666
|
return;
|
|
@@ -3438,7 +3679,7 @@ function doSynchronousLoop(data: any[], processData: (row: any, index: number, n
|
|
|
3438
3679
|
return;
|
|
3439
3680
|
}
|
|
3440
3681
|
|
|
3441
|
-
const loop = (index) => {
|
|
3682
|
+
const loop = (index: any) => {
|
|
3442
3683
|
processData(data[index], index, (err) => {
|
|
3443
3684
|
if (err) {
|
|
3444
3685
|
done(err);
|