node-firebird 2.9.0 → 2.10.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 +166 -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 +143 -5
- package/lib/uri.js +2 -2
- package/lib/wire/connection.d.ts +92 -59
- package/lib/wire/connection.js +267 -53
- package/lib/wire/const.d.ts +9 -1
- package/lib/wire/const.js +21 -9
- package/lib/wire/database.d.ts +51 -26
- package/lib/wire/database.js +26 -8
- 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 +18 -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 +18 -18
- 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 +140 -5
- package/src/unix-crypt.ts +9 -9
- package/src/uri.ts +2 -2
- package/src/wire/connection.ts +464 -232
- package/src/wire/const.ts +21 -9
- package/src/wire/database.ts +75 -43
- package/src/wire/eventConnection.ts +8 -5
- package/src/wire/query-stream.ts +80 -0
- package/src/wire/serialize.ts +29 -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 +9 -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,26 @@ 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
|
-
ret.data[blob.row][blob.column] =
|
|
2018
|
+
ret.data[blob.row][blob.column] = applyTypeCast(
|
|
2019
|
+
statement.connection.options, blob.meta || {},
|
|
2020
|
+
parseValueIfJson(blob.value, statement.connection.options));
|
|
1854
2021
|
}
|
|
1855
2022
|
|
|
1856
2023
|
doSynchronousLoop(ret.data, (row, _i, next) => {
|
|
1857
|
-
const pos = asStream ? streamIndex++ : (data
|
|
2024
|
+
const pos = asStream ? streamIndex++ : (data!.push(row) - 1);
|
|
1858
2025
|
if (asStream) {
|
|
1859
2026
|
executeStreamRow(custom, row, pos, statement.output, next);
|
|
1860
2027
|
} else {
|
|
@@ -1888,7 +2055,7 @@ class Connection {
|
|
|
1888
2055
|
|
|
1889
2056
|
|
|
1890
2057
|
|
|
1891
|
-
openBlob(blob, transaction, callback) {
|
|
2058
|
+
openBlob(blob: Quad, transaction: Transaction, callback: QueueCallback) {
|
|
1892
2059
|
var msg = this._msg;
|
|
1893
2060
|
msg.pos = 0;
|
|
1894
2061
|
msg.addInt(Const.op_open_blob);
|
|
@@ -1898,7 +2065,7 @@ class Connection {
|
|
|
1898
2065
|
}
|
|
1899
2066
|
|
|
1900
2067
|
|
|
1901
|
-
closeBlob(blob, callback, defer = true) {
|
|
2068
|
+
closeBlob(blob: any, callback?: QueueCallback, defer = true) {
|
|
1902
2069
|
var msg = this._msg;
|
|
1903
2070
|
msg.pos = 0;
|
|
1904
2071
|
msg.addInt(Const.op_close_blob);
|
|
@@ -1907,7 +2074,7 @@ class Connection {
|
|
|
1907
2074
|
}
|
|
1908
2075
|
|
|
1909
2076
|
|
|
1910
|
-
getSegment(blob, callback) {
|
|
2077
|
+
getSegment(blob: any, callback: QueueCallback) {
|
|
1911
2078
|
var msg = this._msg;
|
|
1912
2079
|
msg.pos = 0;
|
|
1913
2080
|
msg.addInt(Const.op_get_segment);
|
|
@@ -1918,7 +2085,7 @@ class Connection {
|
|
|
1918
2085
|
}
|
|
1919
2086
|
|
|
1920
2087
|
|
|
1921
|
-
createBlob2(transaction, callback) {
|
|
2088
|
+
createBlob2(transaction: Transaction, callback: QueueCallback) {
|
|
1922
2089
|
var msg = this._msg;
|
|
1923
2090
|
msg.pos = 0;
|
|
1924
2091
|
msg.addInt(Const.op_create_blob2);
|
|
@@ -1930,7 +2097,7 @@ class Connection {
|
|
|
1930
2097
|
}
|
|
1931
2098
|
|
|
1932
2099
|
|
|
1933
|
-
batchSegments(blob, buffer, callback) {
|
|
2100
|
+
batchSegments(blob: any, buffer: Buffer, callback: QueueCallback) {
|
|
1934
2101
|
var msg = this._msg;
|
|
1935
2102
|
var blr = this._blr;
|
|
1936
2103
|
msg.pos = 0;
|
|
@@ -1944,7 +2111,7 @@ class Connection {
|
|
|
1944
2111
|
}
|
|
1945
2112
|
|
|
1946
2113
|
|
|
1947
|
-
svcattach(options:
|
|
2114
|
+
svcattach(options: InternalOptions, callback?: Callback<ServiceManager>, svc?: ServiceManager) {
|
|
1948
2115
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
1949
2116
|
var database = options.database || options.filename;
|
|
1950
2117
|
var user = options.user || Const.DEFAULT_USER;
|
|
@@ -1979,7 +2146,7 @@ class Connection {
|
|
|
1979
2146
|
|
|
1980
2147
|
var self = this;
|
|
1981
2148
|
|
|
1982
|
-
function cb(err, ret) {
|
|
2149
|
+
function cb(err: any, ret: any) {
|
|
1983
2150
|
|
|
1984
2151
|
if (err) {
|
|
1985
2152
|
doError(err, callback);
|
|
@@ -2005,19 +2172,19 @@ class Connection {
|
|
|
2005
2172
|
}
|
|
2006
2173
|
|
|
2007
2174
|
|
|
2008
|
-
svcstart(spbaction, callback) {
|
|
2175
|
+
svcstart(spbaction: BlrWriter, callback: QueueCallback | undefined) {
|
|
2009
2176
|
var msg = this._msg;
|
|
2010
2177
|
var blr = this._blr;
|
|
2011
2178
|
msg.pos = 0;
|
|
2012
2179
|
msg.addInt(Const.op_service_start);
|
|
2013
|
-
msg.addInt(this.svchandle);
|
|
2180
|
+
msg.addInt(this.svchandle!);
|
|
2014
2181
|
msg.addInt(0)
|
|
2015
2182
|
msg.addBlr(spbaction);
|
|
2016
2183
|
this._queueEvent(callback);
|
|
2017
2184
|
}
|
|
2018
2185
|
|
|
2019
2186
|
|
|
2020
|
-
svcquery(spbquery, resultbuffersize, timeout,callback) {
|
|
2187
|
+
svcquery(spbquery: number[], resultbuffersize: number, timeout: number | undefined, callback: QueueCallback | undefined) {
|
|
2021
2188
|
if (resultbuffersize > Const.MAX_BUFFER_SIZE) {
|
|
2022
2189
|
doError(new Error('Buffer is too big'), callback);
|
|
2023
2190
|
return;
|
|
@@ -2030,7 +2197,7 @@ class Connection {
|
|
|
2030
2197
|
blr.addByte(Const.isc_spb_current_version);
|
|
2031
2198
|
//blr.addByteInt32(Const.isc_info_svc_timeout, timeout);
|
|
2032
2199
|
msg.addInt(Const.op_service_info);
|
|
2033
|
-
msg.addInt(this.svchandle);
|
|
2200
|
+
msg.addInt(this.svchandle!);
|
|
2034
2201
|
msg.addInt(0);
|
|
2035
2202
|
msg.addBlr(blr);
|
|
2036
2203
|
blr.pos = 0
|
|
@@ -2041,7 +2208,7 @@ class Connection {
|
|
|
2041
2208
|
}
|
|
2042
2209
|
|
|
2043
2210
|
|
|
2044
|
-
svcdetach(callback) {
|
|
2211
|
+
svcdetach(callback: Callback | undefined) {
|
|
2045
2212
|
var self = this;
|
|
2046
2213
|
|
|
2047
2214
|
if (self._isClosed) {
|
|
@@ -2056,9 +2223,9 @@ class Connection {
|
|
|
2056
2223
|
|
|
2057
2224
|
msg.pos = 0;
|
|
2058
2225
|
msg.addInt(Const.op_service_detach);
|
|
2059
|
-
msg.addInt(this.svchandle); // Database Object ID
|
|
2226
|
+
msg.addInt(this.svchandle!); // Database Object ID
|
|
2060
2227
|
|
|
2061
|
-
self._queueEvent(function (err, ret) {
|
|
2228
|
+
self._queueEvent(function (err: any, ret: any) {
|
|
2062
2229
|
delete (self.svchandle);
|
|
2063
2230
|
if (callback)
|
|
2064
2231
|
callback(err, ret);
|
|
@@ -2067,7 +2234,7 @@ class Connection {
|
|
|
2067
2234
|
|
|
2068
2235
|
|
|
2069
2236
|
|
|
2070
|
-
auxConnection(eventid, callback) {
|
|
2237
|
+
auxConnection(eventid: number | Callback, callback?: Callback) {
|
|
2071
2238
|
if (typeof eventid === 'function') {
|
|
2072
2239
|
// Preserve the older auxConnection(callback) call shape; plain
|
|
2073
2240
|
// auxiliary connections historically used event id 0.
|
|
@@ -2081,13 +2248,13 @@ class Connection {
|
|
|
2081
2248
|
msg.pos = 0;
|
|
2082
2249
|
msg.addInt(Const.op_connect_request);
|
|
2083
2250
|
msg.addInt(1); // async
|
|
2084
|
-
msg.addInt(self.dbhandle);
|
|
2251
|
+
msg.addInt(self.dbhandle!);
|
|
2085
2252
|
msg.addInt(eventid);
|
|
2086
2253
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2087
2254
|
console.log('[fb-debug] auxConnection: sending op_connect_request(53) dbhandle=%d eventid=%d queue_before=%d xdr_saved=%s',
|
|
2088
2255
|
self.dbhandle, eventid, self._queue.length, Boolean(self._xdr));
|
|
2089
2256
|
}
|
|
2090
|
-
function cb(err, ret) {
|
|
2257
|
+
function cb(err: any, ret: any) {
|
|
2091
2258
|
|
|
2092
2259
|
if (err) {
|
|
2093
2260
|
if (process.env.FIREBIRD_DEBUG) {
|
|
@@ -2108,13 +2275,13 @@ class Connection {
|
|
|
2108
2275
|
socket_info.family, socket_info.port, socket_info.host, self._queue.length);
|
|
2109
2276
|
}
|
|
2110
2277
|
|
|
2111
|
-
callback(undefined, socket_info);
|
|
2278
|
+
callback!(undefined, socket_info);
|
|
2112
2279
|
}
|
|
2113
2280
|
this._queueEvent(cb);
|
|
2114
2281
|
}
|
|
2115
2282
|
|
|
2116
2283
|
|
|
2117
|
-
queEvents(events, eventid, callback) {
|
|
2284
|
+
queEvents(events: Record<string, number>, eventid: number, callback: Callback) {
|
|
2118
2285
|
var self = this;
|
|
2119
2286
|
if (this._isClosed)
|
|
2120
2287
|
return this.throwClosed(callback);
|
|
@@ -2123,7 +2290,7 @@ class Connection {
|
|
|
2123
2290
|
blr.pos = 0;
|
|
2124
2291
|
msg.pos = 0;
|
|
2125
2292
|
msg.addInt(Const.op_que_events);
|
|
2126
|
-
msg.addInt(this.dbhandle);
|
|
2293
|
+
msg.addInt(this.dbhandle!);
|
|
2127
2294
|
// prepare EPB
|
|
2128
2295
|
blr.addByte(1) // epb_version
|
|
2129
2296
|
for (var event in events) {
|
|
@@ -2137,7 +2304,7 @@ class Connection {
|
|
|
2137
2304
|
msg.addInt(0); // args
|
|
2138
2305
|
msg.addInt(eventid);
|
|
2139
2306
|
|
|
2140
|
-
function cb(err, ret) {
|
|
2307
|
+
function cb(err: any, ret: any) {
|
|
2141
2308
|
if (err) {
|
|
2142
2309
|
doError(err, callback);
|
|
2143
2310
|
return;
|
|
@@ -2150,17 +2317,17 @@ class Connection {
|
|
|
2150
2317
|
}
|
|
2151
2318
|
|
|
2152
2319
|
|
|
2153
|
-
closeEvents(eventid, callback) {
|
|
2320
|
+
closeEvents(eventid: number, callback: Callback) {
|
|
2154
2321
|
var self = this;
|
|
2155
2322
|
if (this._isClosed)
|
|
2156
2323
|
return this.throwClosed(callback);
|
|
2157
2324
|
var msg = self._msg;
|
|
2158
2325
|
msg.pos = 0;
|
|
2159
2326
|
msg.addInt(Const.op_cancel_events);
|
|
2160
|
-
msg.addInt(self.dbhandle);
|
|
2327
|
+
msg.addInt(self.dbhandle!);
|
|
2161
2328
|
msg.addInt(eventid);
|
|
2162
2329
|
|
|
2163
|
-
function cb(err, ret) {
|
|
2330
|
+
function cb(err: any, ret: any) {
|
|
2164
2331
|
if (err) {
|
|
2165
2332
|
doError(err, callback);
|
|
2166
2333
|
return;
|
|
@@ -2179,7 +2346,7 @@ const opcodeNames = Object.fromEntries(
|
|
|
2179
2346
|
Object.entries(Const).filter(([k]) => k.startsWith('op_')).map(([k, v]) => [v, k])
|
|
2180
2347
|
);
|
|
2181
2348
|
|
|
2182
|
-
function decodeResponse(data:
|
|
2349
|
+
function decodeResponse(data: XdrReader, callback: QueueCallback | undefined, cnx: Connection, lowercase_keys: boolean | undefined, cb: (err?: any, obj?: any) => void) {
|
|
2183
2350
|
try {
|
|
2184
2351
|
do {
|
|
2185
2352
|
var r = data.r || data.readInt();
|
|
@@ -2200,7 +2367,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2200
2367
|
cnx._inlineBlobs = new Map();
|
|
2201
2368
|
}
|
|
2202
2369
|
const cacheKey = `${blob_id.high}:${blob_id.low}`;
|
|
2203
|
-
cnx._inlineBlobs.set(cacheKey, blob_data);
|
|
2370
|
+
cnx._inlineBlobs.set(cacheKey, blob_data!);
|
|
2204
2371
|
r = Const.op_dummy; // Continue loop to read next opcode
|
|
2205
2372
|
}
|
|
2206
2373
|
} while (r === Const.op_dummy);
|
|
@@ -2210,7 +2377,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2210
2377
|
r, opcodeNames[r] || 'unknown', data.pos, data.buffer.length);
|
|
2211
2378
|
}
|
|
2212
2379
|
|
|
2213
|
-
var item, op, response;
|
|
2380
|
+
var item, op, response: any;
|
|
2214
2381
|
|
|
2215
2382
|
switch (r) {
|
|
2216
2383
|
case Const.op_response:
|
|
@@ -2221,7 +2388,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2221
2388
|
response = {};
|
|
2222
2389
|
}
|
|
2223
2390
|
|
|
2224
|
-
let loop = function (err) {
|
|
2391
|
+
let loop = function (err: any) {
|
|
2225
2392
|
if (err) {
|
|
2226
2393
|
return cb(err);
|
|
2227
2394
|
} else {
|
|
@@ -2282,13 +2449,27 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2282
2449
|
}
|
|
2283
2450
|
case Const.op_fetch_response:
|
|
2284
2451
|
case Const.op_sql_response:
|
|
2285
|
-
|
|
2452
|
+
// fetch/sql_response entries always carry their statement
|
|
2453
|
+
var statement = callback!.statement!;
|
|
2286
2454
|
var output = statement.output;
|
|
2287
2455
|
var custom = statement.options || {};
|
|
2288
2456
|
var isOpFetch = r === Const.op_fetch_response;
|
|
2289
2457
|
var _xdrpos;
|
|
2290
2458
|
statement.nbrowsfetched = statement.nbrowsfetched || 0;
|
|
2291
2459
|
|
|
2460
|
+
// The f* decode state is only meaningful within a single
|
|
2461
|
+
// decode call: incomplete packets are re-decoded from scratch
|
|
2462
|
+
// on a fresh XdrReader (see the 'data' handler). State left by
|
|
2463
|
+
// an earlier packet in the same data event (e.g. fstatus=100 /
|
|
2464
|
+
// fcount=0 from a completed fetch) would make this decode
|
|
2465
|
+
// consume just the opcode and desync every later response.
|
|
2466
|
+
delete data.fstatus;
|
|
2467
|
+
delete data.fcount;
|
|
2468
|
+
delete data.fcolumn;
|
|
2469
|
+
delete data.frow;
|
|
2470
|
+
delete data.frows;
|
|
2471
|
+
delete data.fcols;
|
|
2472
|
+
|
|
2292
2473
|
if (isOpFetch && data.fop) { // could be set when a packet is not complete
|
|
2293
2474
|
data.readBuffer(68); // ??
|
|
2294
2475
|
op = data.readInt(); // ??
|
|
@@ -2310,55 +2491,67 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2310
2491
|
|
|
2311
2492
|
if (custom.asObject && !data.fcols) {
|
|
2312
2493
|
if (lowercase_keys) {
|
|
2313
|
-
data.fcols = output.map((column) => column.alias.toLowerCase());
|
|
2494
|
+
data.fcols = output.map((column: any) => column.alias.toLowerCase());
|
|
2314
2495
|
} else {
|
|
2315
|
-
data.fcols = output.map((column) => column.alias);
|
|
2496
|
+
data.fcols = output.map((column: any) => column.alias);
|
|
2316
2497
|
}
|
|
2317
2498
|
}
|
|
2318
2499
|
|
|
2319
|
-
const arrBlob = [];
|
|
2500
|
+
const arrBlob: any[] = [];
|
|
2320
2501
|
const lowerV13 = statement.connection.accept.protocolVersion < Const.PROTOCOL_VERSION13;
|
|
2321
2502
|
|
|
2503
|
+
// op_sql_response (op_execute2) is always followed by an
|
|
2504
|
+
// op_response carrying the execute status vector. The row loop
|
|
2505
|
+
// below consumes it after the last row, but with zero rows
|
|
2506
|
+
// (e.g. INSERT ... RETURNING failing on a constraint) it stays
|
|
2507
|
+
// in the buffer, shifting every later response to the wrong
|
|
2508
|
+
// callback and poisoning the connection (issue #341).
|
|
2509
|
+
var sqlResponseTrailerPending = !isOpFetch && !data.fcount;
|
|
2510
|
+
|
|
2322
2511
|
while (data.fcount && (data.fstatus !== 100)) {
|
|
2323
2512
|
let nullBitSet;
|
|
2324
2513
|
if (!lowerV13) {
|
|
2325
2514
|
const nullBitsLen = Math.floor((output.length + 7) / 8);
|
|
2326
|
-
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false));
|
|
2515
|
+
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false)!);
|
|
2327
2516
|
data.readBuffer((4 - nullBitsLen) & 3, false); // Skip padding
|
|
2328
2517
|
}
|
|
2329
2518
|
|
|
2330
2519
|
for (let length = output.length; data.fcolumn < length; data.fcolumn++) {
|
|
2331
2520
|
item = output[data.fcolumn];
|
|
2332
2521
|
|
|
2333
|
-
if (!lowerV13 && nullBitSet
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
} else {
|
|
2337
|
-
data.frow[data.fcolumn] = null;
|
|
2338
|
-
}
|
|
2522
|
+
if (!lowerV13 && nullBitSet!.get(data.fcolumn)) {
|
|
2523
|
+
const nullKey = custom.asObject ? data.fcols![data.fcolumn!] : data.fcolumn;
|
|
2524
|
+
data.frow[nullKey] = applyTypeCast(cnx.options, item, null);
|
|
2339
2525
|
|
|
2340
2526
|
continue;
|
|
2341
2527
|
}
|
|
2342
2528
|
|
|
2343
2529
|
try {
|
|
2344
2530
|
_xdrpos = data.pos;
|
|
2345
|
-
const key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
2531
|
+
const key = custom.asObject ? data.fcols![data.fcolumn!] : data.fcolumn;
|
|
2346
2532
|
const row = data.frows.length;
|
|
2347
2533
|
let value = item.decode(data, lowerV13, cnx.options);
|
|
2534
|
+
// text blobs resolved by blobAsText run through the
|
|
2535
|
+
// typeCast hook once the text arrives (see fetchAll),
|
|
2536
|
+
// not here where the value is still a pending fetch
|
|
2537
|
+
let pendingTextBlob = false;
|
|
2348
2538
|
|
|
2349
2539
|
if (item.type === Const.SQL_BLOB && value !== null) {
|
|
2350
2540
|
if (item.subType === Const.isc_blob_text && cnx.options.blobAsText) {
|
|
2351
|
-
value = fetch_blob_async_transaction(statement, value, key, row);
|
|
2541
|
+
value = fetch_blob_async_transaction(statement, value, key, row, item);
|
|
2352
2542
|
arrBlob.push(value);
|
|
2543
|
+
pendingTextBlob = true;
|
|
2353
2544
|
} else {
|
|
2354
2545
|
value = fetch_blob_async(statement, value, key, row);
|
|
2355
2546
|
}
|
|
2356
2547
|
}
|
|
2357
2548
|
|
|
2358
|
-
data.frow[key] =
|
|
2549
|
+
data.frow[key] = pendingTextBlob
|
|
2550
|
+
? value
|
|
2551
|
+
: applyTypeCast(cnx.options, item, parseValueIfJson(value, cnx.options));
|
|
2359
2552
|
} catch (e) {
|
|
2360
2553
|
// uncomplete packet read
|
|
2361
|
-
data.pos = _xdrpos
|
|
2554
|
+
data.pos = _xdrpos!;
|
|
2362
2555
|
data.r = r;
|
|
2363
2556
|
return cb(new Error('Packet is not complete'));
|
|
2364
2557
|
}
|
|
@@ -2403,6 +2596,17 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2403
2596
|
statement.nbrowsfetched++;
|
|
2404
2597
|
}
|
|
2405
2598
|
|
|
2599
|
+
if (sqlResponseTrailerPending) {
|
|
2600
|
+
op = data.readInt();
|
|
2601
|
+
if (op === Const.op_response) {
|
|
2602
|
+
response = {};
|
|
2603
|
+
parseOpResponse(data, response);
|
|
2604
|
+
if (response.status) {
|
|
2605
|
+
return cb(null, response);
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2406
2610
|
// ToDo: emit "result" with blob subtype string decoded
|
|
2407
2611
|
statement.connection.db.emit('result', data.frows, arrBlob);
|
|
2408
2612
|
return cb(null, {data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob});
|
|
@@ -2427,7 +2631,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2427
2631
|
}
|
|
2428
2632
|
|
|
2429
2633
|
if (r === Const.op_cond_accept || r === Const.op_accept_data) {
|
|
2430
|
-
var d = new BlrReader(data.readArray());
|
|
2634
|
+
var d = new BlrReader(data.readArray()!);
|
|
2431
2635
|
accept.pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
2432
2636
|
var is_authenticated = data.readInt();
|
|
2433
2637
|
var keys = data.readString(Const.DEFAULT_ENCODING); // keys
|
|
@@ -2447,7 +2651,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2447
2651
|
}
|
|
2448
2652
|
|
|
2449
2653
|
if (Const.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
2450
|
-
var crypto = {
|
|
2654
|
+
var crypto: Record<string, string> = {
|
|
2451
2655
|
Srp: 'sha1',
|
|
2452
2656
|
Srp256: 'sha256',
|
|
2453
2657
|
Srp384: 'sha384',
|
|
@@ -2458,7 +2662,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2458
2662
|
if (!d.buffer) {
|
|
2459
2663
|
cnx._pendingAccept = accept;
|
|
2460
2664
|
cnx.sendOpContAuth(
|
|
2461
|
-
cnx.clientKeys
|
|
2665
|
+
cnx.clientKeys!.public.toString(16),
|
|
2462
2666
|
Const.DEFAULT_ENCODING,
|
|
2463
2667
|
accept.pluginName
|
|
2464
2668
|
);
|
|
@@ -2489,20 +2693,20 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2489
2693
|
|
|
2490
2694
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2491
2695
|
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
|
|
2696
|
+
console.log('salt:', cnx.serverKeys!.salt);
|
|
2697
|
+
console.log('server public key:', cnx.serverKeys!.public.toString(16));
|
|
2698
|
+
console.log('client public key:', cnx.clientKeys!.public.toString(16));
|
|
2495
2699
|
console.log('hashAlgo:', accept.srpAlgo);
|
|
2496
2700
|
}
|
|
2497
2701
|
|
|
2498
2702
|
const _t1 = Date.now();
|
|
2499
2703
|
var proof = srp.clientProof(
|
|
2500
|
-
cnx.options.user
|
|
2501
|
-
cnx.options.password
|
|
2502
|
-
cnx.serverKeys
|
|
2503
|
-
cnx.clientKeys
|
|
2504
|
-
cnx.serverKeys
|
|
2505
|
-
cnx.clientKeys
|
|
2704
|
+
cnx.options.user!.toUpperCase(),
|
|
2705
|
+
cnx.options.password!,
|
|
2706
|
+
cnx.serverKeys!.salt,
|
|
2707
|
+
cnx.clientKeys!.public,
|
|
2708
|
+
cnx.serverKeys!.public,
|
|
2709
|
+
cnx.clientKeys!.private,
|
|
2506
2710
|
accept.srpAlgo
|
|
2507
2711
|
);
|
|
2508
2712
|
|
|
@@ -2519,7 +2723,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2519
2723
|
accept.authData = proof.authData.toString(16);
|
|
2520
2724
|
accept.sessionKey = proof.clientSessionKey;
|
|
2521
2725
|
} else if (accept.pluginName === Const.AUTH_PLUGIN_LEGACY) {
|
|
2522
|
-
accept.authData = crypt.crypt(cnx.options.password
|
|
2726
|
+
accept.authData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2523
2727
|
} else {
|
|
2524
2728
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
2525
2729
|
}
|
|
@@ -2557,7 +2761,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2557
2761
|
|
|
2558
2762
|
return cb(undefined, accept);
|
|
2559
2763
|
case Const.op_cont_auth:
|
|
2560
|
-
var d = new BlrReader(data.readArray());
|
|
2764
|
+
var d = new BlrReader(data.readArray()!);
|
|
2561
2765
|
var pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
2562
2766
|
data.readString(Const.DEFAULT_ENCODING); // plist
|
|
2563
2767
|
data.readString(Const.DEFAULT_ENCODING); // pkey
|
|
@@ -2584,7 +2788,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2584
2788
|
// the proof with the new plugin's hash algorithm - rather than
|
|
2585
2789
|
// as the server's M2 proof, otherwise the client silently waits
|
|
2586
2790
|
// forever for an op_accept the server will never send (#254).
|
|
2587
|
-
if (!cnx.serverKeys || cnx.serverKeys
|
|
2791
|
+
if (!cnx.serverKeys || cnx.serverKeys!.pluginName !== pluginName) {
|
|
2588
2792
|
// Check buffer contains salt
|
|
2589
2793
|
var saltLen = d.buffer.readUInt16LE(0);
|
|
2590
2794
|
if (saltLen > 32 * 2) {
|
|
@@ -2607,7 +2811,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2607
2811
|
pluginName: pluginName
|
|
2608
2812
|
};
|
|
2609
2813
|
|
|
2610
|
-
var crypto = {
|
|
2814
|
+
var crypto: Record<string, string> = {
|
|
2611
2815
|
Srp: 'sha1',
|
|
2612
2816
|
Srp256: 'sha256',
|
|
2613
2817
|
Srp384: 'sha384',
|
|
@@ -2617,20 +2821,20 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2617
2821
|
|
|
2618
2822
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2619
2823
|
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
|
|
2824
|
+
console.log('salt:', cnx.serverKeys!.salt);
|
|
2825
|
+
console.log('server public key:', cnx.serverKeys!.public.toString(16));
|
|
2826
|
+
console.log('client public key:', cnx.clientKeys!.public.toString(16));
|
|
2623
2827
|
console.log('hashAlgo:', srpAlgo);
|
|
2624
2828
|
}
|
|
2625
2829
|
|
|
2626
2830
|
const _t1 = Date.now();
|
|
2627
2831
|
var proof = srp.clientProof(
|
|
2628
|
-
cnx.options.user
|
|
2629
|
-
cnx.options.password
|
|
2630
|
-
cnx.serverKeys
|
|
2631
|
-
cnx.clientKeys
|
|
2632
|
-
cnx.serverKeys
|
|
2633
|
-
cnx.clientKeys
|
|
2832
|
+
cnx.options.user!.toUpperCase(),
|
|
2833
|
+
cnx.options.password!,
|
|
2834
|
+
cnx.serverKeys!.salt,
|
|
2835
|
+
cnx.clientKeys!.public,
|
|
2836
|
+
cnx.serverKeys!.public,
|
|
2837
|
+
cnx.clientKeys!.private,
|
|
2634
2838
|
srpAlgo
|
|
2635
2839
|
);
|
|
2636
2840
|
|
|
@@ -2667,7 +2871,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2667
2871
|
cnx._pendingAccept.protocolVersion,
|
|
2668
2872
|
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
2669
2873
|
}
|
|
2670
|
-
var legacyAuthData = crypt.crypt(cnx.options.password
|
|
2874
|
+
var legacyAuthData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2671
2875
|
cnx.sendOpContAuth(legacyAuthData, Const.DEFAULT_ENCODING, pluginName);
|
|
2672
2876
|
return; // wait for op_accept
|
|
2673
2877
|
}
|
|
@@ -2680,7 +2884,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2680
2884
|
|
|
2681
2885
|
if (pluginName === Const.AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
2682
2886
|
cnx.accept.pluginName = pluginName;
|
|
2683
|
-
cnx.accept.authData = crypt.crypt(cnx.options.password
|
|
2887
|
+
cnx.accept.authData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2684
2888
|
|
|
2685
2889
|
cnx.sendOpContAuth(
|
|
2686
2890
|
cnx.accept.authData,
|
|
@@ -2773,7 +2977,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2773
2977
|
}
|
|
2774
2978
|
return cb(new Error('Unexpected:' + r));
|
|
2775
2979
|
}
|
|
2776
|
-
} catch (err) {
|
|
2980
|
+
} catch (err: any) {
|
|
2777
2981
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2778
2982
|
console.warn('[fb-debug] decodeResponse exception: %s (RangeError=%s) pos=%d buflen=%d',
|
|
2779
2983
|
err.message, err instanceof RangeError, data.pos, data.buffer.length);
|
|
@@ -2789,8 +2993,8 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2789
2993
|
* Read one XDR status vector (as in op_response / op_batch_cs error
|
|
2790
2994
|
* vectors): a stream of isc_arg_* items terminated by isc_arg_end.
|
|
2791
2995
|
*/
|
|
2792
|
-
function readStatusVector(data:
|
|
2793
|
-
var result: { status: any[]; sqlcode?: number } = { status: [] };
|
|
2996
|
+
function readStatusVector(data: XdrReader): { status: any[]; warnings?: any[]; sqlcode?: number } {
|
|
2997
|
+
var result: { status: any[]; warnings?: any[]; sqlcode?: number } = { status: [] };
|
|
2794
2998
|
var item: any = {};
|
|
2795
2999
|
|
|
2796
3000
|
while (true) {
|
|
@@ -2820,13 +3024,24 @@ function readStatusVector(data: any): { status: any[]; sqlcode?: number } {
|
|
|
2820
3024
|
result.sqlcode = n;
|
|
2821
3025
|
}
|
|
2822
3026
|
break;
|
|
3027
|
+
case Const.isc_arg_warning:
|
|
3028
|
+
// A warning attached to a SUCCESS vector (e.g. "parallel
|
|
3029
|
+
// workers value capped"). Keep it out of `status` so the
|
|
3030
|
+
// operation is not mistaken for a failure; later string/
|
|
3031
|
+
// number items attach to the warning entry.
|
|
3032
|
+
var wnum = data.readInt();
|
|
3033
|
+
item = { gdscode: wnum };
|
|
3034
|
+
if (wnum) {
|
|
3035
|
+
(result.warnings = result.warnings || []).push(item);
|
|
3036
|
+
}
|
|
3037
|
+
break;
|
|
2823
3038
|
default:
|
|
2824
3039
|
throw new Error('Unexpected status vector item: ' + op);
|
|
2825
3040
|
}
|
|
2826
3041
|
}
|
|
2827
3042
|
}
|
|
2828
3043
|
|
|
2829
|
-
function parseOpResponse(data:
|
|
3044
|
+
function parseOpResponse(data: XdrReader, response: WireResponse, cb?: (err?: any, response?: any) => void) {
|
|
2830
3045
|
var handle = data.readInt();
|
|
2831
3046
|
|
|
2832
3047
|
if (!response.handle) {
|
|
@@ -2889,18 +3104,31 @@ function parseOpResponse(data: any, response: any, cb?: (err?: any, response?: a
|
|
|
2889
3104
|
response.sqlcode = num;
|
|
2890
3105
|
}
|
|
2891
3106
|
|
|
3107
|
+
break;
|
|
3108
|
+
case Const.isc_arg_warning:
|
|
3109
|
+
// A warning attached to a SUCCESS response (e.g. Firebird's
|
|
3110
|
+
// "parallel workers value capped" on attach). Keep it out of
|
|
3111
|
+
// `status` so the response is not mistaken for an error;
|
|
3112
|
+
// later string/number items attach to the warning entry.
|
|
3113
|
+
num = data.readInt();
|
|
3114
|
+
item = { gdscode: num };
|
|
3115
|
+
if (num) {
|
|
3116
|
+
(response.warnings = response.warnings || []).push(item);
|
|
3117
|
+
}
|
|
2892
3118
|
break;
|
|
2893
3119
|
default:
|
|
3120
|
+
// Stop parsing: continuing the loop after an unknown item
|
|
3121
|
+
// re-read the same bytes forever (the caller resets the
|
|
3122
|
+
// reader position when the error is delivered).
|
|
2894
3123
|
if (cb) {
|
|
2895
|
-
cb(new Error('Unexpected: ' + op))
|
|
2896
|
-
} else {
|
|
2897
|
-
throw new Error('Unexpected: ' + op);
|
|
3124
|
+
return cb(new Error('Unexpected: ' + op));
|
|
2898
3125
|
}
|
|
3126
|
+
throw new Error('Unexpected: ' + op);
|
|
2899
3127
|
}
|
|
2900
3128
|
}
|
|
2901
3129
|
}
|
|
2902
3130
|
|
|
2903
|
-
function describe(buff: Buffer, statement:
|
|
3131
|
+
function describe(buff: Buffer, statement: Statement) {
|
|
2904
3132
|
var br = new BlrReader(buff);
|
|
2905
3133
|
var parameters: any = null;
|
|
2906
3134
|
var type: any, param: any;
|
|
@@ -2908,7 +3136,7 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2908
3136
|
while (br.pos < br.buffer.length) {
|
|
2909
3137
|
switch (br.readByteCode()) {
|
|
2910
3138
|
case Const.isc_info_sql_stmt_type:
|
|
2911
|
-
statement.type = br.readInt()
|
|
3139
|
+
statement.type = br.readInt()!;
|
|
2912
3140
|
break;
|
|
2913
3141
|
case Const.isc_info_sql_get_plan:
|
|
2914
3142
|
statement.plan = br.readString(Const.DEFAULT_ENCODING);
|
|
@@ -2932,7 +3160,9 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2932
3160
|
case Const.isc_info_sql_describe_end:
|
|
2933
3161
|
break;
|
|
2934
3162
|
case Const.isc_info_sql_sqlda_seq:
|
|
2935
|
-
|
|
3163
|
+
// describe output always encodes the sequence as a
|
|
3164
|
+
// 1/2/4-byte int, so readInt cannot return undefined
|
|
3165
|
+
var num = br.readInt()!;
|
|
2936
3166
|
break;
|
|
2937
3167
|
case Const.isc_info_sql_type:
|
|
2938
3168
|
type = br.readInt();
|
|
@@ -2963,7 +3193,9 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2963
3193
|
default:
|
|
2964
3194
|
throw new Error('Unexpected');
|
|
2965
3195
|
}
|
|
2966
|
-
|
|
3196
|
+
// isc_info_sql_sqlda_seq always precedes the type
|
|
3197
|
+
// item in the describe stream, so num is set here
|
|
3198
|
+
parameters[num!-1] = param;
|
|
2967
3199
|
param.type = type;
|
|
2968
3200
|
param.nullable = Boolean(param.type & 1);
|
|
2969
3201
|
param.type &= ~1;
|
|
@@ -3243,10 +3475,10 @@ function CalcBlr(blr: BlrWriter, xsqlda: any[]) {
|
|
|
3243
3475
|
blr.addByte(Const.blr_eoc);
|
|
3244
3476
|
}
|
|
3245
3477
|
|
|
3246
|
-
function fetch_blob_async_transaction(statement:
|
|
3247
|
-
const infoValue = { row, column, value: '' };
|
|
3478
|
+
function fetch_blob_async_transaction(statement: Statement, id: Quad, column: string | number, row: number, meta?: Xsql.SQLVarBase) {
|
|
3479
|
+
const infoValue = { row, column, value: '', meta };
|
|
3248
3480
|
|
|
3249
|
-
return (transactionArg) => {
|
|
3481
|
+
return (transactionArg: any) => {
|
|
3250
3482
|
const cacheKey = `${id.high}:${id.low}`;
|
|
3251
3483
|
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
3252
3484
|
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
@@ -3256,10 +3488,10 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3256
3488
|
|
|
3257
3489
|
const singleTransaction = transactionArg === undefined;
|
|
3258
3490
|
|
|
3259
|
-
let promiseTransaction
|
|
3491
|
+
let promiseTransaction: Promise<Transaction>;
|
|
3260
3492
|
if (singleTransaction) {
|
|
3261
3493
|
promiseTransaction = new Promise((resolve, reject) => {
|
|
3262
|
-
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
3494
|
+
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err: any, transaction: Transaction) => {
|
|
3263
3495
|
if (err) {
|
|
3264
3496
|
return reject(err);
|
|
3265
3497
|
}
|
|
@@ -3273,7 +3505,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3273
3505
|
return promiseTransaction.then((transaction) => {
|
|
3274
3506
|
return new Promise((resolve, reject) => {
|
|
3275
3507
|
statement.connection._pending.push('openBlob');
|
|
3276
|
-
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
3508
|
+
statement.connection.openBlob(id, transaction, (err: any, blob: any) => {
|
|
3277
3509
|
|
|
3278
3510
|
if (err) {
|
|
3279
3511
|
reject(err);
|
|
@@ -3281,7 +3513,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3281
3513
|
}
|
|
3282
3514
|
|
|
3283
3515
|
const read = () => {
|
|
3284
|
-
statement.connection.getSegment(blob, (err, ret) => {
|
|
3516
|
+
statement.connection.getSegment(blob, (err: any, ret: any) => {
|
|
3285
3517
|
|
|
3286
3518
|
if (err) {
|
|
3287
3519
|
if (singleTransaction) {
|
|
@@ -3305,7 +3537,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3305
3537
|
|
|
3306
3538
|
statement.connection.closeBlob(blob);
|
|
3307
3539
|
if (singleTransaction) {
|
|
3308
|
-
transaction.commit((err) => {
|
|
3540
|
+
transaction.commit((err: any) => {
|
|
3309
3541
|
if (err) {
|
|
3310
3542
|
reject(err);
|
|
3311
3543
|
} else {
|
|
@@ -3325,14 +3557,14 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3325
3557
|
};
|
|
3326
3558
|
}
|
|
3327
3559
|
|
|
3328
|
-
function fetch_blob_async(statement:
|
|
3329
|
-
const cbTransaction = (transaction, close, callback) => {
|
|
3560
|
+
function fetch_blob_async(statement: Statement, id: Quad, name: string | number, row: number) {
|
|
3561
|
+
const cbTransaction = (transaction: Transaction, close: any, callback: any) => {
|
|
3330
3562
|
statement.connection._pending.push('openBlob');
|
|
3331
|
-
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
3563
|
+
statement.connection.openBlob(id, transaction, (err: any, blob: any) => {
|
|
3332
3564
|
let e: any = new Events.EventEmitter();
|
|
3333
3565
|
|
|
3334
|
-
e.pipe = (stream) => {
|
|
3335
|
-
e.on('data', (chunk) => {
|
|
3566
|
+
e.pipe = (stream: any) => {
|
|
3567
|
+
e.on('data', (chunk: any) => {
|
|
3336
3568
|
stream.write(chunk);
|
|
3337
3569
|
});
|
|
3338
3570
|
e.on('end', () => {
|
|
@@ -3345,7 +3577,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3345
3577
|
}
|
|
3346
3578
|
|
|
3347
3579
|
const read = () => {
|
|
3348
|
-
statement.connection.getSegment(blob, (err, ret) => {
|
|
3580
|
+
statement.connection.getSegment(blob, (err: any, ret: any) => {
|
|
3349
3581
|
|
|
3350
3582
|
if (err) {
|
|
3351
3583
|
transaction.rollback(() => {
|
|
@@ -3368,7 +3600,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3368
3600
|
|
|
3369
3601
|
statement.connection.closeBlob(blob);
|
|
3370
3602
|
if (close) {
|
|
3371
|
-
transaction.commit((err) => {
|
|
3603
|
+
transaction.commit((err: any) => {
|
|
3372
3604
|
if (err) {
|
|
3373
3605
|
e.emit('error', err);
|
|
3374
3606
|
} else {
|
|
@@ -3388,7 +3620,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3388
3620
|
});
|
|
3389
3621
|
};
|
|
3390
3622
|
|
|
3391
|
-
return (transaction, callback) => {
|
|
3623
|
+
return (transaction: Transaction, callback: any) => {
|
|
3392
3624
|
// callback(error, nameField, eventEmitter, row)
|
|
3393
3625
|
const singleTransaction = callback === undefined;
|
|
3394
3626
|
const actualCallback = singleTransaction ? transaction : callback;
|
|
@@ -3397,8 +3629,8 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3397
3629
|
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
3398
3630
|
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
3399
3631
|
let e: any = new Events.EventEmitter();
|
|
3400
|
-
e.pipe = (stream) => {
|
|
3401
|
-
e.on('data', (chunk) => {
|
|
3632
|
+
e.pipe = (stream: any) => {
|
|
3633
|
+
e.on('data', (chunk: any) => {
|
|
3402
3634
|
stream.write(chunk);
|
|
3403
3635
|
});
|
|
3404
3636
|
e.on('end', () => {
|
|
@@ -3419,7 +3651,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3419
3651
|
|
|
3420
3652
|
if (singleTransaction) {
|
|
3421
3653
|
callback = transaction;
|
|
3422
|
-
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
3654
|
+
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err: any, transaction: Transaction) => {
|
|
3423
3655
|
if (err) {
|
|
3424
3656
|
callback(err);
|
|
3425
3657
|
return;
|
|
@@ -3438,7 +3670,7 @@ function doSynchronousLoop(data: any[], processData: (row: any, index: number, n
|
|
|
3438
3670
|
return;
|
|
3439
3671
|
}
|
|
3440
3672
|
|
|
3441
|
-
const loop = (index) => {
|
|
3673
|
+
const loop = (index: any) => {
|
|
3442
3674
|
processData(data[index], index, (err) => {
|
|
3443
3675
|
if (err) {
|
|
3444
3676
|
done(err);
|