node-firebird 2.8.1 → 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 +268 -7
- package/lib/index.d.ts +17 -9
- package/lib/index.js +42 -3
- package/lib/named-params.d.ts +42 -0
- package/lib/named-params.js +133 -0
- package/lib/pool.js +1 -1
- package/lib/srp.d.ts +3 -3
- package/lib/types.d.ts +185 -25
- package/lib/uri.d.ts +57 -0
- package/lib/uri.js +193 -0
- package/lib/wire/connection.d.ts +92 -59
- package/lib/wire/connection.js +286 -55
- 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 +40 -20
- package/lib/wire/statement.js +26 -6
- package/lib/wire/transaction.d.ts +32 -18
- package/lib/wire/transaction.js +50 -8
- 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 +54 -15
- package/src/messages.ts +1 -1
- package/src/named-params.ts +145 -0
- package/src/pool.ts +1 -1
- package/src/srp.ts +6 -6
- package/src/types.ts +183 -25
- package/src/unix-crypt.ts +9 -9
- package/src/uri.ts +204 -0
- package/src/wire/connection.ts +481 -234
- 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 +68 -31
- package/src/wire/transaction.ts +85 -33
- 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,39 +200,81 @@ 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;
|
|
90
209
|
this._isDetach = false;
|
|
91
210
|
this._isUsed = false;
|
|
92
211
|
this._pooled = options.isPool||false;
|
|
93
|
-
|
|
94
|
-
|
|
212
|
+
// Credentials may be absent (e.g. a traditional host:database
|
|
213
|
+
// connection string) — apply the driver defaults once here, so every
|
|
214
|
+
// auth path (op_connect CNCT block, SRP proof, legacy cont_auth) sees
|
|
215
|
+
// the same values.
|
|
216
|
+
if (options && !options.user) options.user = Const.DEFAULT_USER;
|
|
217
|
+
if (options && !options.password) options.password = Const.DEFAULT_PASSWORD;
|
|
218
|
+
if (options && options.blobChunkSize && options.blobChunkSize > 65535) options.blobChunkSize = 65535;
|
|
219
|
+
if (options && options.blobReadChunkSize && options.blobReadChunkSize > 65535) options.blobReadChunkSize = 65535;
|
|
95
220
|
this.options = options;
|
|
96
221
|
this._bind_events(host, port, callback);
|
|
97
222
|
this.error;
|
|
98
223
|
this._retry_connection_id;
|
|
99
224
|
this._retry_connection_interval = options.retryConnectionInterval || 1000;
|
|
100
|
-
this.
|
|
101
|
-
this.
|
|
225
|
+
this._statementCacheSize = statementCacheLimit(options);
|
|
226
|
+
this._statementCache = this._statementCacheSize > 0 ? new Map() : null;
|
|
102
227
|
this._messageFile = options.messageFile || path.join(__dirname, 'firebird.msg');
|
|
103
228
|
}
|
|
104
229
|
|
|
105
230
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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;
|
|
111
241
|
}
|
|
112
|
-
|
|
113
|
-
|
|
242
|
+
const statement = cache.get(query);
|
|
243
|
+
if (!statement) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
cache.delete(query);
|
|
247
|
+
return statement;
|
|
114
248
|
}
|
|
115
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
|
+
}
|
|
116
269
|
|
|
117
|
-
|
|
118
|
-
|
|
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);
|
|
119
278
|
}
|
|
120
279
|
|
|
121
280
|
|
|
@@ -125,7 +284,7 @@ class Connection {
|
|
|
125
284
|
// be transparently resumed on a reconnect: a fresh attach() hands out new
|
|
126
285
|
// transaction/statement handles, so nothing the server sends back could
|
|
127
286
|
// ever match a callback queued against the old connection.
|
|
128
|
-
_rejectPending(err) {
|
|
287
|
+
_rejectPending(err: any) {
|
|
129
288
|
var queue = this._queue;
|
|
130
289
|
this._queue = [];
|
|
131
290
|
this._pending = [];
|
|
@@ -136,7 +295,7 @@ class Connection {
|
|
|
136
295
|
}
|
|
137
296
|
|
|
138
297
|
|
|
139
|
-
_bind_events(host, port, callback) {
|
|
298
|
+
_bind_events(host: string, port: number, callback: SimpleCallback | undefined) {
|
|
140
299
|
|
|
141
300
|
var self = this;
|
|
142
301
|
|
|
@@ -162,17 +321,19 @@ class Connection {
|
|
|
162
321
|
|
|
163
322
|
self._retry_connection_id = setTimeout(function() {
|
|
164
323
|
self._socket.removeAllListeners();
|
|
165
|
-
|
|
324
|
+
// transiently null while the replacement Connection is built
|
|
325
|
+
// (restored by the Object.assign(self, ctx) below)
|
|
326
|
+
self._socket = null!;
|
|
166
327
|
|
|
167
|
-
var ctx = new Connection(host, port, function(err) {
|
|
168
|
-
ctx.connect(self.options, function(err) {
|
|
328
|
+
var ctx = new Connection(host, port, function(err: any) {
|
|
329
|
+
ctx.connect(self.options, function(err: any) {
|
|
169
330
|
|
|
170
331
|
if (err) {
|
|
171
332
|
self.db.emit('error', err);
|
|
172
333
|
return;
|
|
173
334
|
}
|
|
174
335
|
|
|
175
|
-
ctx.attach(self.options, function(err) {
|
|
336
|
+
ctx.attach(self.options, function(err: any) {
|
|
176
337
|
|
|
177
338
|
if (err) {
|
|
178
339
|
self.db.emit('error', err);
|
|
@@ -191,7 +352,7 @@ class Connection {
|
|
|
191
352
|
|
|
192
353
|
});
|
|
193
354
|
|
|
194
|
-
self._socket.on('error', function(e) {
|
|
355
|
+
self._socket.on('error', function(e: any) {
|
|
195
356
|
|
|
196
357
|
self.error = e;
|
|
197
358
|
|
|
@@ -210,8 +371,8 @@ class Connection {
|
|
|
210
371
|
callback();
|
|
211
372
|
});
|
|
212
373
|
|
|
213
|
-
self._socket.on('data', function (data) {
|
|
214
|
-
var xdr;
|
|
374
|
+
self._socket.on('data', function (data: any) {
|
|
375
|
+
var xdr: any;
|
|
215
376
|
var hadSavedBuffer = Boolean(self._xdr);
|
|
216
377
|
|
|
217
378
|
if (!self._xdr) {
|
|
@@ -331,7 +492,7 @@ class Connection {
|
|
|
331
492
|
|
|
332
493
|
|
|
333
494
|
|
|
334
|
-
sendOpContAuth(authData, authDataEnc, pluginName) {
|
|
495
|
+
sendOpContAuth(authData: string, authDataEnc: BufferEncoding, pluginName: string) {
|
|
335
496
|
var msg = this._msg;
|
|
336
497
|
msg.pos = 0;
|
|
337
498
|
|
|
@@ -346,7 +507,7 @@ class Connection {
|
|
|
346
507
|
}
|
|
347
508
|
|
|
348
509
|
|
|
349
|
-
sendOpCrypt(encryptPlugin) {
|
|
510
|
+
sendOpCrypt(encryptPlugin: string) {
|
|
350
511
|
var msg = this._msg;
|
|
351
512
|
msg.pos = 0;
|
|
352
513
|
|
|
@@ -358,7 +519,7 @@ class Connection {
|
|
|
358
519
|
}
|
|
359
520
|
|
|
360
521
|
|
|
361
|
-
sendOpCryptKeyCallback(pluginData) {
|
|
522
|
+
sendOpCryptKeyCallback(pluginData: BlrWriter) {
|
|
362
523
|
var msg = this._msg;
|
|
363
524
|
msg.pos = 0;
|
|
364
525
|
|
|
@@ -375,7 +536,7 @@ class Connection {
|
|
|
375
536
|
* makes that operation fail with isc_cancelled (GDSCode.CANCELLED); the
|
|
376
537
|
* op_cancel packet itself has no response, so nothing is queued here.
|
|
377
538
|
*/
|
|
378
|
-
cancelOperation(kind, callback) {
|
|
539
|
+
cancelOperation(kind?: number | SimpleCallback, callback?: SimpleCallback) {
|
|
379
540
|
if (typeof kind === 'function') {
|
|
380
541
|
callback = kind;
|
|
381
542
|
kind = undefined;
|
|
@@ -402,7 +563,7 @@ class Connection {
|
|
|
402
563
|
|
|
403
564
|
|
|
404
565
|
/** Write a prebuilt packet and queue its response callback. */
|
|
405
|
-
_queueEventBuffer(buffer, callback) {
|
|
566
|
+
_queueEventBuffer(buffer: Buffer, callback: QueueCallback | undefined) {
|
|
406
567
|
if (this._isClosed) {
|
|
407
568
|
if (callback)
|
|
408
569
|
callback(new Error('Connection is closed.'));
|
|
@@ -414,7 +575,7 @@ class Connection {
|
|
|
414
575
|
}
|
|
415
576
|
|
|
416
577
|
|
|
417
|
-
_queueEvent(callback, defer = false) {
|
|
578
|
+
_queueEvent(callback: QueueCallback | undefined, defer = false) {
|
|
418
579
|
var self = this;
|
|
419
580
|
|
|
420
581
|
if (self._isClosed) {
|
|
@@ -426,15 +587,24 @@ class Connection {
|
|
|
426
587
|
const canDefer = defer && this.accept.protocolVersion >= Const.PROTOCOL_VERSION11;
|
|
427
588
|
|
|
428
589
|
self._socket.write(self._msg.getData(), canDefer);
|
|
429
|
-
if (canDefer
|
|
430
|
-
|
|
590
|
+
if (canDefer) {
|
|
591
|
+
// A deferred packet sits in the socket buffer until the next
|
|
592
|
+
// non-deferred write flushes it, but the server still answers it
|
|
593
|
+
// with its own op_response (delivered along with that next
|
|
594
|
+
// exchange). Queue a placeholder to consume that response —
|
|
595
|
+
// otherwise the queue pairs it with the NEXT request and every
|
|
596
|
+
// later response is off by one. The op itself is fire-and-forget,
|
|
597
|
+
// so complete the caller right away.
|
|
598
|
+
self._queue.push(undefined);
|
|
599
|
+
if (callback)
|
|
600
|
+
callback();
|
|
431
601
|
} else {
|
|
432
602
|
self._queue.push(callback);
|
|
433
603
|
}
|
|
434
604
|
}
|
|
435
605
|
|
|
436
606
|
|
|
437
|
-
connect(options, callback) {
|
|
607
|
+
connect(options: InternalOptions, callback: Callback<AcceptPacket> | undefined) {
|
|
438
608
|
var pluginName = options.pluginName || Const.AUTH_PLUGIN_LIST[0];
|
|
439
609
|
var msg = this._msg;
|
|
440
610
|
var blr = this._blr;
|
|
@@ -445,7 +615,7 @@ class Connection {
|
|
|
445
615
|
msg.pos = 0;
|
|
446
616
|
blr.pos = 0;
|
|
447
617
|
|
|
448
|
-
blr.addString(Const.CNCT_login, options.user
|
|
618
|
+
blr.addString(Const.CNCT_login, options.user!, Const.DEFAULT_ENCODING);
|
|
449
619
|
blr.addString(Const.CNCT_plugin_name, pluginName, Const.DEFAULT_ENCODING);
|
|
450
620
|
blr.addString(Const.CNCT_plugin_list, Const.AUTH_PLUGIN_LIST.join(','), Const.DEFAULT_ENCODING);
|
|
451
621
|
|
|
@@ -459,7 +629,7 @@ class Connection {
|
|
|
459
629
|
specificData = this.clientKeys.public.toString(16);
|
|
460
630
|
blr.addMultiblockPart(Const.CNCT_specific_data, specificData, Const.DEFAULT_ENCODING);
|
|
461
631
|
} else if (pluginName === Const.AUTH_PLUGIN_LEGACY) {
|
|
462
|
-
specificData = crypt.crypt(options.password
|
|
632
|
+
specificData = crypt.crypt(options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
463
633
|
blr.addMultiblockPart(Const.CNCT_specific_data, specificData, Const.DEFAULT_ENCODING);
|
|
464
634
|
} else {
|
|
465
635
|
doError(new Error('Invalide auth plugin \'' + pluginName + '\''), callback);
|
|
@@ -475,10 +645,17 @@ class Connection {
|
|
|
475
645
|
msg.addInt(Const.CONNECT_VERSION3);
|
|
476
646
|
msg.addInt(Const.ARCHITECTURE_GENERIC);
|
|
477
647
|
msg.addString(options.database || options.filename, Const.DEFAULT_ENCODING);
|
|
478
|
-
|
|
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;
|
|
479
653
|
var protocolsToSend = Const.SUPPORTED_PROTOCOL;
|
|
480
654
|
if (protocolsToSend.length > maxProtocols) {
|
|
481
|
-
|
|
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);
|
|
482
659
|
}
|
|
483
660
|
|
|
484
661
|
msg.addInt(protocolsToSend.length); // Count of Protocol version understood count.
|
|
@@ -497,7 +674,7 @@ class Connection {
|
|
|
497
674
|
}
|
|
498
675
|
|
|
499
676
|
var self = this;
|
|
500
|
-
function cb(err, ret) {
|
|
677
|
+
function cb(err: any, ret: any) {
|
|
501
678
|
if (err) {
|
|
502
679
|
doError(err, callback);
|
|
503
680
|
return;
|
|
@@ -519,11 +696,11 @@ class Connection {
|
|
|
519
696
|
|
|
520
697
|
var selectedPlugin = 'Arc4';
|
|
521
698
|
if (ret.keys) {
|
|
522
|
-
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(); });
|
|
523
700
|
var preferred = ['chacha64', 'chacha', 'arc4'];
|
|
524
701
|
for (var i = 0; i < preferred.length; i++) {
|
|
525
702
|
if (serverPlugins.indexOf(preferred[i]) !== -1) {
|
|
526
|
-
var mapping = {
|
|
703
|
+
var mapping: Record<string, string> = {
|
|
527
704
|
chacha64: 'ChaCha64',
|
|
528
705
|
chacha: 'ChaCha',
|
|
529
706
|
arc4: 'Arc4'
|
|
@@ -544,7 +721,7 @@ class Connection {
|
|
|
544
721
|
}
|
|
545
722
|
|
|
546
723
|
self._pending.push('crypt');
|
|
547
|
-
self._queue.push(function(cryptErr, response) {
|
|
724
|
+
self._queue.push(function(cryptErr: any, response: any) {
|
|
548
725
|
if (cryptErr) {
|
|
549
726
|
doError(cryptErr, callback);
|
|
550
727
|
return;
|
|
@@ -578,7 +755,7 @@ class Connection {
|
|
|
578
755
|
}
|
|
579
756
|
|
|
580
757
|
|
|
581
|
-
attach(options:
|
|
758
|
+
attach(options: InternalOptions, callback?: Callback<Database>, db?: Database) {
|
|
582
759
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
583
760
|
|
|
584
761
|
var database = options.database || options.filename;
|
|
@@ -642,31 +819,19 @@ class Connection {
|
|
|
642
819
|
}
|
|
643
820
|
|
|
644
821
|
// Firebird 6.0 SQL Schema parameters (Protocol 20+).
|
|
645
|
-
// These DPB tags configure the session's current schema and the
|
|
646
|
-
// schema search path for unqualified object name resolution.
|
|
647
822
|
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
// SET SCHEMA <name> immediately after connecting.
|
|
651
|
-
blr.addString(Const.isc_dpb_default_schema, options.defaultSchema, Const.DEFAULT_ENCODING);
|
|
652
|
-
}
|
|
653
|
-
if (options.searchPath) {
|
|
654
|
-
// Comma-separated ordered schema name list, like PostgreSQL's
|
|
655
|
-
// search_path. Unqualified object references are resolved by
|
|
656
|
-
// scanning schemas in this order.
|
|
657
|
-
const sp = Array.isArray(options.searchPath)
|
|
658
|
-
? options.searchPath.join(',')
|
|
659
|
-
: String(options.searchPath);
|
|
823
|
+
const sp = buildSchemaSearchPath(options);
|
|
824
|
+
if (sp) {
|
|
660
825
|
blr.addString(Const.isc_dpb_search_path, sp, Const.DEFAULT_ENCODING);
|
|
661
826
|
}
|
|
662
827
|
}
|
|
663
|
-
|
|
828
|
+
|
|
664
829
|
msg.addInt(Const.op_attach);
|
|
665
830
|
msg.addInt(0); // Database Object ID
|
|
666
831
|
msg.addString(database, Const.DEFAULT_ENCODING);
|
|
667
832
|
msg.addBlr(this._blr);
|
|
668
833
|
|
|
669
|
-
function cb(err, ret) {
|
|
834
|
+
function cb(err: any, ret: any) {
|
|
670
835
|
if (err) {
|
|
671
836
|
doError(err, callback);
|
|
672
837
|
return;
|
|
@@ -693,7 +858,7 @@ class Connection {
|
|
|
693
858
|
}
|
|
694
859
|
|
|
695
860
|
|
|
696
|
-
detach(callback) {
|
|
861
|
+
detach(callback: Callback | undefined) {
|
|
697
862
|
|
|
698
863
|
var self = this;
|
|
699
864
|
|
|
@@ -709,7 +874,7 @@ class Connection {
|
|
|
709
874
|
msg.addInt(Const.op_detach);
|
|
710
875
|
msg.addInt(0); // Database Object ID
|
|
711
876
|
|
|
712
|
-
self._queueEvent(function(err, ret) {
|
|
877
|
+
self._queueEvent(function(err: any, ret: any) {
|
|
713
878
|
clearTimeout(self._retry_connection_id);
|
|
714
879
|
delete(self.dbhandle);
|
|
715
880
|
if (callback)
|
|
@@ -718,7 +883,7 @@ class Connection {
|
|
|
718
883
|
}
|
|
719
884
|
|
|
720
885
|
|
|
721
|
-
createDatabase(options, callback) {
|
|
886
|
+
createDatabase(options: InternalOptions, callback: Callback<Database> | undefined) {
|
|
722
887
|
// Mirror attach(): honour the lowercase_keys option so that db.query()
|
|
723
888
|
// called on a freshly-created database returns the expected column case.
|
|
724
889
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
@@ -781,16 +946,18 @@ class Connection {
|
|
|
781
946
|
|
|
782
947
|
// Firebird 6.0 SQL Schema parameters (Protocol 20+).
|
|
783
948
|
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
if (options.searchPath) {
|
|
788
|
-
const sp = Array.isArray(options.searchPath)
|
|
789
|
-
? options.searchPath.join(',')
|
|
790
|
-
: String(options.searchPath);
|
|
949
|
+
const sp = buildSchemaSearchPath(options);
|
|
950
|
+
if (sp) {
|
|
791
951
|
blr.addString(Const.isc_dpb_search_path, sp, Const.DEFAULT_ENCODING);
|
|
792
952
|
}
|
|
793
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
|
+
}
|
|
794
961
|
|
|
795
962
|
blr.addNumeric(Const.isc_dpb_sql_dialect, 3);
|
|
796
963
|
blr.addNumeric(Const.isc_dpb_force_write, 1);
|
|
@@ -806,7 +973,7 @@ class Connection {
|
|
|
806
973
|
|
|
807
974
|
var self = this;
|
|
808
975
|
|
|
809
|
-
function cb(err, ret) {
|
|
976
|
+
function cb(err: any, ret: any) {
|
|
810
977
|
|
|
811
978
|
if (ret)
|
|
812
979
|
self.dbhandle = ret.handle;
|
|
@@ -823,15 +990,15 @@ class Connection {
|
|
|
823
990
|
}
|
|
824
991
|
|
|
825
992
|
|
|
826
|
-
dropDatabase(callback) {
|
|
993
|
+
dropDatabase(callback: SimpleCallback | undefined) {
|
|
827
994
|
var msg = this._msg;
|
|
828
995
|
msg.pos = 0;
|
|
829
996
|
|
|
830
997
|
msg.addInt(Const.op_drop_database);
|
|
831
|
-
msg.addInt(this.dbhandle);
|
|
998
|
+
msg.addInt(this.dbhandle!);
|
|
832
999
|
|
|
833
1000
|
var self = this;
|
|
834
|
-
this._queueEvent(function(err) {
|
|
1001
|
+
this._queueEvent(function(err: any) {
|
|
835
1002
|
self.detach(function() {
|
|
836
1003
|
self.disconnect();
|
|
837
1004
|
|
|
@@ -842,7 +1009,7 @@ class Connection {
|
|
|
842
1009
|
}
|
|
843
1010
|
|
|
844
1011
|
|
|
845
|
-
throwClosed(callback) {
|
|
1012
|
+
throwClosed(callback: ((err: Error, ...args: any[]) => void) | undefined) {
|
|
846
1013
|
var err = new Error('Connection is closed.');
|
|
847
1014
|
this.db.emit('error', err);
|
|
848
1015
|
if (callback)
|
|
@@ -851,7 +1018,9 @@ class Connection {
|
|
|
851
1018
|
}
|
|
852
1019
|
|
|
853
1020
|
|
|
854
|
-
|
|
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) {
|
|
855
1024
|
|
|
856
1025
|
if (typeof(options) === 'function') {
|
|
857
1026
|
var tmp = options;
|
|
@@ -924,7 +1093,7 @@ class Connection {
|
|
|
924
1093
|
}*/
|
|
925
1094
|
|
|
926
1095
|
msg.addInt(Const.op_transaction);
|
|
927
|
-
msg.addInt(this.dbhandle);
|
|
1096
|
+
msg.addInt(this.dbhandle!);
|
|
928
1097
|
msg.addBlr(blr);
|
|
929
1098
|
callback.response = new Transaction(this);
|
|
930
1099
|
|
|
@@ -933,7 +1102,7 @@ class Connection {
|
|
|
933
1102
|
}
|
|
934
1103
|
|
|
935
1104
|
|
|
936
|
-
commit(transaction, callback) {
|
|
1105
|
+
commit(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
937
1106
|
|
|
938
1107
|
if (this._isClosed)
|
|
939
1108
|
return this.throwClosed(callback);
|
|
@@ -950,7 +1119,7 @@ class Connection {
|
|
|
950
1119
|
}
|
|
951
1120
|
|
|
952
1121
|
|
|
953
|
-
rollback(transaction, callback) {
|
|
1122
|
+
rollback(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
954
1123
|
|
|
955
1124
|
if (this._isClosed)
|
|
956
1125
|
return this.throwClosed(callback);
|
|
@@ -967,7 +1136,7 @@ class Connection {
|
|
|
967
1136
|
}
|
|
968
1137
|
|
|
969
1138
|
|
|
970
|
-
commitRetaining(transaction, callback) {
|
|
1139
|
+
commitRetaining(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
971
1140
|
|
|
972
1141
|
if (this._isClosed)
|
|
973
1142
|
return this.throwClosed(callback);
|
|
@@ -983,7 +1152,7 @@ class Connection {
|
|
|
983
1152
|
}
|
|
984
1153
|
|
|
985
1154
|
|
|
986
|
-
rollbackRetaining(transaction, callback) {
|
|
1155
|
+
rollbackRetaining(transaction: Transaction, callback: QueueCallback | undefined) {
|
|
987
1156
|
|
|
988
1157
|
if (this._isClosed)
|
|
989
1158
|
return this.throwClosed(callback);
|
|
@@ -999,7 +1168,7 @@ class Connection {
|
|
|
999
1168
|
}
|
|
1000
1169
|
|
|
1001
1170
|
|
|
1002
|
-
allocateStatement(callback) {
|
|
1171
|
+
allocateStatement(callback: QueueCallback) {
|
|
1003
1172
|
|
|
1004
1173
|
if (this._isClosed)
|
|
1005
1174
|
return this.throwClosed(callback);
|
|
@@ -1010,13 +1179,13 @@ class Connection {
|
|
|
1010
1179
|
var msg = this._msg;
|
|
1011
1180
|
msg.pos = 0;
|
|
1012
1181
|
msg.addInt(Const.op_allocate_statement);
|
|
1013
|
-
msg.addInt(this.dbhandle);
|
|
1182
|
+
msg.addInt(this.dbhandle!);
|
|
1014
1183
|
callback.response = new Statement(this);
|
|
1015
1184
|
this._queueEvent(callback);
|
|
1016
1185
|
}
|
|
1017
1186
|
|
|
1018
1187
|
|
|
1019
|
-
dropStatement(statement, callback) {
|
|
1188
|
+
dropStatement(statement: Statement, callback: QueueCallback | undefined) {
|
|
1020
1189
|
|
|
1021
1190
|
if (this._isClosed)
|
|
1022
1191
|
return this.throwClosed(callback);
|
|
@@ -1034,7 +1203,7 @@ class Connection {
|
|
|
1034
1203
|
}
|
|
1035
1204
|
|
|
1036
1205
|
|
|
1037
|
-
closeStatement(statement, callback) {
|
|
1206
|
+
closeStatement(statement: Statement, callback: QueueCallback | undefined) {
|
|
1038
1207
|
|
|
1039
1208
|
if (this._isClosed)
|
|
1040
1209
|
return this.throwClosed(callback);
|
|
@@ -1052,16 +1221,15 @@ class Connection {
|
|
|
1052
1221
|
}
|
|
1053
1222
|
|
|
1054
1223
|
|
|
1055
|
-
allocateAndPrepareStatement(transaction, query, plan, callback) {
|
|
1224
|
+
allocateAndPrepareStatement(transaction: Transaction, query: string, plan: boolean, callback: Callback<Statement>) {
|
|
1056
1225
|
var self = this;
|
|
1057
|
-
var mainCallback:
|
|
1226
|
+
var mainCallback: QueueCallback = function(err: any, ret: any) {
|
|
1058
1227
|
if (!err) {
|
|
1059
1228
|
mainCallback.response.handle = ret.handle;
|
|
1060
1229
|
describe(ret.buffer, mainCallback.response);
|
|
1061
1230
|
mainCallback.response.query = query;
|
|
1062
1231
|
self.db.emit('query', query);
|
|
1063
1232
|
ret = mainCallback.response;
|
|
1064
|
-
self._setcachedquery(query, ret);
|
|
1065
1233
|
}
|
|
1066
1234
|
|
|
1067
1235
|
if (callback)
|
|
@@ -1078,7 +1246,7 @@ class Connection {
|
|
|
1078
1246
|
blr.pos = 0;
|
|
1079
1247
|
|
|
1080
1248
|
msg.addInt(Const.op_allocate_statement);
|
|
1081
|
-
msg.addInt(this.dbhandle);
|
|
1249
|
+
msg.addInt(this.dbhandle!);
|
|
1082
1250
|
mainCallback.lazy_count = 1;
|
|
1083
1251
|
|
|
1084
1252
|
const describeBytes = this.accept.protocolVersion >= Const.PROTOCOL_VERSION20 ? Const.DESCRIBE_WITH_SCHEMA : Const.DESCRIBE;
|
|
@@ -1096,6 +1264,12 @@ class Connection {
|
|
|
1096
1264
|
msg.addString(query, Const.DEFAULT_ENCODING);
|
|
1097
1265
|
msg.addBlr(blr);
|
|
1098
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
|
+
}
|
|
1099
1273
|
mainCallback.lazy_count += 1;
|
|
1100
1274
|
|
|
1101
1275
|
mainCallback.response = new Statement(this);
|
|
@@ -1103,13 +1277,13 @@ class Connection {
|
|
|
1103
1277
|
}
|
|
1104
1278
|
|
|
1105
1279
|
|
|
1106
|
-
prepare(transaction, query, plan, callback) {
|
|
1280
|
+
prepare(transaction: Transaction, query: string, plan: boolean, callback: Callback<Statement>) {
|
|
1107
1281
|
var self = this;
|
|
1108
1282
|
|
|
1109
1283
|
if (this.accept.protocolMinimumType === Const.ptype_lazy_send) { // V11 Statement or higher
|
|
1110
1284
|
self.allocateAndPrepareStatement(transaction, query, plan, callback);
|
|
1111
1285
|
} else { // V10 Statement
|
|
1112
|
-
self.allocateStatement(function (err, statement) {
|
|
1286
|
+
self.allocateStatement(function (err: any, statement: Statement) {
|
|
1113
1287
|
if (err) {
|
|
1114
1288
|
doError(err, callback);
|
|
1115
1289
|
return;
|
|
@@ -1122,7 +1296,8 @@ class Connection {
|
|
|
1122
1296
|
|
|
1123
1297
|
|
|
1124
1298
|
|
|
1125
|
-
|
|
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>) {
|
|
1126
1301
|
|
|
1127
1302
|
if (this._isClosed)
|
|
1128
1303
|
return this.throwClosed(callback);
|
|
@@ -1151,16 +1326,18 @@ class Connection {
|
|
|
1151
1326
|
msg.addString(query, Const.DEFAULT_ENCODING);
|
|
1152
1327
|
msg.addBlr(blr);
|
|
1153
1328
|
msg.addInt(65535); // buffer_length
|
|
1329
|
+
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION20) {
|
|
1330
|
+
msg.addInt(0); // p_sqlst_flags (see allocateAndPrepareStatement)
|
|
1331
|
+
}
|
|
1154
1332
|
|
|
1155
1333
|
var self = this;
|
|
1156
|
-
this._queueEvent(function(err, ret) {
|
|
1334
|
+
this._queueEvent(function(err: any, ret: any) {
|
|
1157
1335
|
|
|
1158
1336
|
if (!err) {
|
|
1159
1337
|
describe(ret.buffer, statement);
|
|
1160
1338
|
statement.query = query;
|
|
1161
1339
|
self.db.emit('query', query);
|
|
1162
1340
|
ret = statement;
|
|
1163
|
-
self._setcachedquery(query, ret);
|
|
1164
1341
|
}
|
|
1165
1342
|
|
|
1166
1343
|
if (callback)
|
|
@@ -1183,7 +1360,7 @@ class Connection {
|
|
|
1183
1360
|
* { recordCount, updateCounts, errors: [{recordNumber, error}],
|
|
1184
1361
|
* errorRecordNumbers, success }.
|
|
1185
1362
|
*/
|
|
1186
|
-
executeBatch(transaction, statement, rows, callback, options) {
|
|
1363
|
+
executeBatch(transaction: Transaction, statement: Statement, rows: QueryParams[], callback: BatchCb | undefined, options?: BatchOptions) {
|
|
1187
1364
|
options = options || {};
|
|
1188
1365
|
|
|
1189
1366
|
if (this._isClosed)
|
|
@@ -1229,7 +1406,7 @@ class Connection {
|
|
|
1229
1406
|
|
|
1230
1407
|
var self = this;
|
|
1231
1408
|
var encoders = built.encoders;
|
|
1232
|
-
var chunkSize = options.chunkSize > 0 ? options.chunkSize : 500;
|
|
1409
|
+
var chunkSize = options.chunkSize && options.chunkSize > 0 ? options.chunkSize : 500;
|
|
1233
1410
|
var chunkCount = Math.ceil(rows.length / chunkSize);
|
|
1234
1411
|
|
|
1235
1412
|
var failure: any = null;
|
|
@@ -1249,7 +1426,7 @@ class Connection {
|
|
|
1249
1426
|
}
|
|
1250
1427
|
|
|
1251
1428
|
var detailed = completion ? completion.detailedErrors : [];
|
|
1252
|
-
var errorRecordNumbers = detailed.map(function(e) { return e.recordNumber; })
|
|
1429
|
+
var errorRecordNumbers = detailed.map(function(e: any) { return e.recordNumber; })
|
|
1253
1430
|
.concat(completion ? completion.errorRecordNumbers : []);
|
|
1254
1431
|
|
|
1255
1432
|
if (callback) callback(undefined, {
|
|
@@ -1297,7 +1474,8 @@ class Connection {
|
|
|
1297
1474
|
msg.addInt(end - start);
|
|
1298
1475
|
|
|
1299
1476
|
for (var i = start; i < end; i++) {
|
|
1300
|
-
|
|
1477
|
+
// validated as an array of input.length values above
|
|
1478
|
+
var row = rows[i] as any[];
|
|
1301
1479
|
|
|
1302
1480
|
var nullBits = new BitSet();
|
|
1303
1481
|
for (var j = 0; j < input.length; j++) {
|
|
@@ -1356,7 +1534,7 @@ class Connection {
|
|
|
1356
1534
|
for (var p = 0; p < packets.length; p++) {
|
|
1357
1535
|
this._pending.push('executeBatch');
|
|
1358
1536
|
if (p === execIndex) {
|
|
1359
|
-
this._queueEventBuffer(packets[p], function(err, ret) {
|
|
1537
|
+
this._queueEventBuffer(packets[p], function(err: any, ret: any) {
|
|
1360
1538
|
if (!err && ret && ret.batchCompletion) {
|
|
1361
1539
|
completion = ret.batchCompletion;
|
|
1362
1540
|
settle();
|
|
@@ -1367,13 +1545,14 @@ class Connection {
|
|
|
1367
1545
|
} else if (p === packets.length - 1) {
|
|
1368
1546
|
this._queueEventBuffer(packets[p], function() {});
|
|
1369
1547
|
} else {
|
|
1370
|
-
this._queueEventBuffer(packets[p], function(err) { settle(err); });
|
|
1548
|
+
this._queueEventBuffer(packets[p], function(err: any) { settle(err); });
|
|
1371
1549
|
}
|
|
1372
1550
|
}
|
|
1373
1551
|
}
|
|
1374
1552
|
|
|
1375
1553
|
|
|
1376
|
-
|
|
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) {
|
|
1377
1556
|
|
|
1378
1557
|
if (this._isClosed)
|
|
1379
1558
|
return this.throwClosed(callback);
|
|
@@ -1397,14 +1576,14 @@ class Connection {
|
|
|
1397
1576
|
op = Const.op_execute2;
|
|
1398
1577
|
}
|
|
1399
1578
|
|
|
1400
|
-
function PrepareParams(params, input, callback) {
|
|
1579
|
+
function PrepareParams(params: any[], input: Xsql.SQLVarBase[], callback: (prms: any[]) => void) {
|
|
1401
1580
|
|
|
1402
1581
|
var value, meta;
|
|
1403
1582
|
var ret = new Array(params.length);
|
|
1404
1583
|
|
|
1405
|
-
function putBlobData(index, value, callback) {
|
|
1584
|
+
function putBlobData(index: any, value: any, callback: any) {
|
|
1406
1585
|
|
|
1407
|
-
self.createBlob2(transaction, function(err, blob) {
|
|
1586
|
+
self.createBlob2(transaction, function(err: any, blob: any) {
|
|
1408
1587
|
|
|
1409
1588
|
var b;
|
|
1410
1589
|
var isStream = value.readable;
|
|
@@ -1432,7 +1611,7 @@ class Connection {
|
|
|
1432
1611
|
var isReading = false;
|
|
1433
1612
|
var isEnd = false;
|
|
1434
1613
|
|
|
1435
|
-
value.on('data', function(chunk) {
|
|
1614
|
+
value.on('data', function(chunk: any) {
|
|
1436
1615
|
// Optimization: If chunk is smaller than transfer size, send directly
|
|
1437
1616
|
if (chunk.length <= chunkSize) {
|
|
1438
1617
|
self.batchSegments(blob, chunk, function () {
|
|
@@ -1473,7 +1652,7 @@ class Connection {
|
|
|
1473
1652
|
});
|
|
1474
1653
|
}
|
|
1475
1654
|
|
|
1476
|
-
function step(i) {
|
|
1655
|
+
function step(i: any) {
|
|
1477
1656
|
if (i === params.length) {
|
|
1478
1657
|
callback(ret);
|
|
1479
1658
|
return;
|
|
@@ -1590,12 +1769,12 @@ class Connection {
|
|
|
1590
1769
|
|
|
1591
1770
|
if (!(params instanceof Array)) {
|
|
1592
1771
|
if (params !== undefined && typeof params === 'object' && params !== null) {
|
|
1593
|
-
var mappedParams = [];
|
|
1772
|
+
var mappedParams: any[] = [];
|
|
1594
1773
|
for (var i = 0; i < input.length; i++) {
|
|
1595
1774
|
mappedParams.push(undefined);
|
|
1596
1775
|
}
|
|
1597
1776
|
var matchedCount = 0;
|
|
1598
|
-
var nameMap = {};
|
|
1777
|
+
var nameMap: Record<string, number> = {};
|
|
1599
1778
|
for (var i = 0; i < input.length; i++) {
|
|
1600
1779
|
var name = input[i].alias || input[i].field;
|
|
1601
1780
|
if (name) {
|
|
@@ -1626,11 +1805,11 @@ class Connection {
|
|
|
1626
1805
|
|
|
1627
1806
|
if (params.length !== input.length) {
|
|
1628
1807
|
self._pending.pop();
|
|
1629
|
-
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));
|
|
1630
1809
|
return;
|
|
1631
1810
|
}
|
|
1632
1811
|
|
|
1633
|
-
PrepareParams(params, input, function(prms) {
|
|
1812
|
+
PrepareParams(params, input, function(prms: any) {
|
|
1634
1813
|
self.sendExecute(op, statement, transaction, callback, prms);
|
|
1635
1814
|
});
|
|
1636
1815
|
|
|
@@ -1641,7 +1820,7 @@ class Connection {
|
|
|
1641
1820
|
}
|
|
1642
1821
|
|
|
1643
1822
|
|
|
1644
|
-
sendExecute(op: number, statement:
|
|
1823
|
+
sendExecute(op: number, statement: Statement, transaction: Transaction, callback: QueueCallback | undefined, parameters?: any[]) {
|
|
1645
1824
|
var msg = this._msg;
|
|
1646
1825
|
var blr = this._blr;
|
|
1647
1826
|
msg.pos = 0;
|
|
@@ -1721,14 +1900,15 @@ class Connection {
|
|
|
1721
1900
|
msg.addInt(statement.options?.maxInlineBlobSize !== undefined ? statement.options.maxInlineBlobSize : (this.options?.maxInlineBlobSize || 0)); // p_sqldata_inline_blob_size
|
|
1722
1901
|
}
|
|
1723
1902
|
|
|
1724
|
-
callback
|
|
1903
|
+
callback!.statement = statement;
|
|
1725
1904
|
this._queueEvent(callback);
|
|
1726
1905
|
}
|
|
1727
1906
|
|
|
1728
1907
|
|
|
1729
1908
|
|
|
1730
1909
|
|
|
1731
|
-
|
|
1910
|
+
/** `count` may be the callback itself when no fetch size is given. */
|
|
1911
|
+
fetch(statement: Statement, transaction: Transaction, count: any, callback?: QueueCallback) {
|
|
1732
1912
|
|
|
1733
1913
|
var msg = this._msg;
|
|
1734
1914
|
var blr = this._blr;
|
|
@@ -1748,12 +1928,12 @@ class Connection {
|
|
|
1748
1928
|
msg.addInt(0); // message number
|
|
1749
1929
|
msg.addInt(count || Const.DEFAULT_FETCHSIZE); // fetch count
|
|
1750
1930
|
|
|
1751
|
-
callback
|
|
1931
|
+
callback!.statement = statement;
|
|
1752
1932
|
this._queueEvent(callback);
|
|
1753
1933
|
}
|
|
1754
1934
|
|
|
1755
1935
|
|
|
1756
|
-
fetchScroll(statement, transaction, direction, offset, count, callback) {
|
|
1936
|
+
fetchScroll(statement: Statement, transaction: Transaction, direction: string | number, offset: any, count: any, callback?: QueueCallback) {
|
|
1757
1937
|
if (typeof count === 'function') {
|
|
1758
1938
|
callback = count;
|
|
1759
1939
|
count = undefined;
|
|
@@ -1799,18 +1979,18 @@ class Connection {
|
|
|
1799
1979
|
msg.addInt(dirInt); // fetch operation
|
|
1800
1980
|
msg.addInt(offsetVal); // fetch position (offset)
|
|
1801
1981
|
|
|
1802
|
-
callback
|
|
1982
|
+
callback!.statement = statement;
|
|
1803
1983
|
this._queueEvent(callback);
|
|
1804
1984
|
}
|
|
1805
1985
|
|
|
1806
1986
|
|
|
1807
|
-
fetchAll(statement, transaction, callback) {
|
|
1987
|
+
fetchAll(statement: Statement, transaction: Transaction, callback: Callback<any[]>) {
|
|
1808
1988
|
const self = this;
|
|
1809
1989
|
const custom = statement.options || {};
|
|
1810
1990
|
const asStream = custom.asStream && custom.on;
|
|
1811
|
-
const data = asStream ? null : [];
|
|
1991
|
+
const data: any[] | null = asStream ? null : [];
|
|
1812
1992
|
let streamIndex = 0;
|
|
1813
|
-
const loop = (err, ret) => {
|
|
1993
|
+
const loop = (err: any, ret: any) => {
|
|
1814
1994
|
if (err) {
|
|
1815
1995
|
callback(err);
|
|
1816
1996
|
return;
|
|
@@ -1822,24 +2002,26 @@ class Connection {
|
|
|
1822
2002
|
// which causes a server-side deadlock when many rows contain
|
|
1823
2003
|
// BLOBs and blobAsText is true. See issue #387.
|
|
1824
2004
|
const arrBlobFns = ret.arrBlob || [];
|
|
1825
|
-
const readBlobsSequentially = (index, results) => {
|
|
2005
|
+
const readBlobsSequentially = (index: any, results: any) => {
|
|
1826
2006
|
if (index >= arrBlobFns.length) {
|
|
1827
2007
|
return Promise.resolve(results);
|
|
1828
2008
|
}
|
|
1829
|
-
return arrBlobFns[index](transaction).then((v) => {
|
|
2009
|
+
return arrBlobFns[index](transaction).then((v: any) => {
|
|
1830
2010
|
results.push(v);
|
|
1831
2011
|
return readBlobsSequentially(index + 1, results);
|
|
1832
2012
|
});
|
|
1833
2013
|
};
|
|
1834
2014
|
|
|
1835
|
-
readBlobsSequentially(0, []).then((arrBlob) => {
|
|
2015
|
+
readBlobsSequentially(0, []).then((arrBlob: any) => {
|
|
1836
2016
|
for (let i = 0; i < arrBlob.length; i++) {
|
|
1837
2017
|
const blob = arrBlob[i];
|
|
1838
|
-
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));
|
|
1839
2021
|
}
|
|
1840
2022
|
|
|
1841
2023
|
doSynchronousLoop(ret.data, (row, _i, next) => {
|
|
1842
|
-
const pos = asStream ? streamIndex++ : (data
|
|
2024
|
+
const pos = asStream ? streamIndex++ : (data!.push(row) - 1);
|
|
1843
2025
|
if (asStream) {
|
|
1844
2026
|
executeStreamRow(custom, row, pos, statement.output, next);
|
|
1845
2027
|
} else {
|
|
@@ -1873,7 +2055,7 @@ class Connection {
|
|
|
1873
2055
|
|
|
1874
2056
|
|
|
1875
2057
|
|
|
1876
|
-
openBlob(blob, transaction, callback) {
|
|
2058
|
+
openBlob(blob: Quad, transaction: Transaction, callback: QueueCallback) {
|
|
1877
2059
|
var msg = this._msg;
|
|
1878
2060
|
msg.pos = 0;
|
|
1879
2061
|
msg.addInt(Const.op_open_blob);
|
|
@@ -1883,7 +2065,7 @@ class Connection {
|
|
|
1883
2065
|
}
|
|
1884
2066
|
|
|
1885
2067
|
|
|
1886
|
-
closeBlob(blob, callback, defer = true) {
|
|
2068
|
+
closeBlob(blob: any, callback?: QueueCallback, defer = true) {
|
|
1887
2069
|
var msg = this._msg;
|
|
1888
2070
|
msg.pos = 0;
|
|
1889
2071
|
msg.addInt(Const.op_close_blob);
|
|
@@ -1892,7 +2074,7 @@ class Connection {
|
|
|
1892
2074
|
}
|
|
1893
2075
|
|
|
1894
2076
|
|
|
1895
|
-
getSegment(blob, callback) {
|
|
2077
|
+
getSegment(blob: any, callback: QueueCallback) {
|
|
1896
2078
|
var msg = this._msg;
|
|
1897
2079
|
msg.pos = 0;
|
|
1898
2080
|
msg.addInt(Const.op_get_segment);
|
|
@@ -1903,7 +2085,7 @@ class Connection {
|
|
|
1903
2085
|
}
|
|
1904
2086
|
|
|
1905
2087
|
|
|
1906
|
-
createBlob2(transaction, callback) {
|
|
2088
|
+
createBlob2(transaction: Transaction, callback: QueueCallback) {
|
|
1907
2089
|
var msg = this._msg;
|
|
1908
2090
|
msg.pos = 0;
|
|
1909
2091
|
msg.addInt(Const.op_create_blob2);
|
|
@@ -1915,7 +2097,7 @@ class Connection {
|
|
|
1915
2097
|
}
|
|
1916
2098
|
|
|
1917
2099
|
|
|
1918
|
-
batchSegments(blob, buffer, callback) {
|
|
2100
|
+
batchSegments(blob: any, buffer: Buffer, callback: QueueCallback) {
|
|
1919
2101
|
var msg = this._msg;
|
|
1920
2102
|
var blr = this._blr;
|
|
1921
2103
|
msg.pos = 0;
|
|
@@ -1929,7 +2111,7 @@ class Connection {
|
|
|
1929
2111
|
}
|
|
1930
2112
|
|
|
1931
2113
|
|
|
1932
|
-
svcattach(options:
|
|
2114
|
+
svcattach(options: InternalOptions, callback?: Callback<ServiceManager>, svc?: ServiceManager) {
|
|
1933
2115
|
this._lowercase_keys = options.lowercase_keys || Const.DEFAULT_LOWERCASE_KEYS;
|
|
1934
2116
|
var database = options.database || options.filename;
|
|
1935
2117
|
var user = options.user || Const.DEFAULT_USER;
|
|
@@ -1964,7 +2146,7 @@ class Connection {
|
|
|
1964
2146
|
|
|
1965
2147
|
var self = this;
|
|
1966
2148
|
|
|
1967
|
-
function cb(err, ret) {
|
|
2149
|
+
function cb(err: any, ret: any) {
|
|
1968
2150
|
|
|
1969
2151
|
if (err) {
|
|
1970
2152
|
doError(err, callback);
|
|
@@ -1990,19 +2172,19 @@ class Connection {
|
|
|
1990
2172
|
}
|
|
1991
2173
|
|
|
1992
2174
|
|
|
1993
|
-
svcstart(spbaction, callback) {
|
|
2175
|
+
svcstart(spbaction: BlrWriter, callback: QueueCallback | undefined) {
|
|
1994
2176
|
var msg = this._msg;
|
|
1995
2177
|
var blr = this._blr;
|
|
1996
2178
|
msg.pos = 0;
|
|
1997
2179
|
msg.addInt(Const.op_service_start);
|
|
1998
|
-
msg.addInt(this.svchandle);
|
|
2180
|
+
msg.addInt(this.svchandle!);
|
|
1999
2181
|
msg.addInt(0)
|
|
2000
2182
|
msg.addBlr(spbaction);
|
|
2001
2183
|
this._queueEvent(callback);
|
|
2002
2184
|
}
|
|
2003
2185
|
|
|
2004
2186
|
|
|
2005
|
-
svcquery(spbquery, resultbuffersize, timeout,callback) {
|
|
2187
|
+
svcquery(spbquery: number[], resultbuffersize: number, timeout: number | undefined, callback: QueueCallback | undefined) {
|
|
2006
2188
|
if (resultbuffersize > Const.MAX_BUFFER_SIZE) {
|
|
2007
2189
|
doError(new Error('Buffer is too big'), callback);
|
|
2008
2190
|
return;
|
|
@@ -2015,7 +2197,7 @@ class Connection {
|
|
|
2015
2197
|
blr.addByte(Const.isc_spb_current_version);
|
|
2016
2198
|
//blr.addByteInt32(Const.isc_info_svc_timeout, timeout);
|
|
2017
2199
|
msg.addInt(Const.op_service_info);
|
|
2018
|
-
msg.addInt(this.svchandle);
|
|
2200
|
+
msg.addInt(this.svchandle!);
|
|
2019
2201
|
msg.addInt(0);
|
|
2020
2202
|
msg.addBlr(blr);
|
|
2021
2203
|
blr.pos = 0
|
|
@@ -2026,7 +2208,7 @@ class Connection {
|
|
|
2026
2208
|
}
|
|
2027
2209
|
|
|
2028
2210
|
|
|
2029
|
-
svcdetach(callback) {
|
|
2211
|
+
svcdetach(callback: Callback | undefined) {
|
|
2030
2212
|
var self = this;
|
|
2031
2213
|
|
|
2032
2214
|
if (self._isClosed) {
|
|
@@ -2041,9 +2223,9 @@ class Connection {
|
|
|
2041
2223
|
|
|
2042
2224
|
msg.pos = 0;
|
|
2043
2225
|
msg.addInt(Const.op_service_detach);
|
|
2044
|
-
msg.addInt(this.svchandle); // Database Object ID
|
|
2226
|
+
msg.addInt(this.svchandle!); // Database Object ID
|
|
2045
2227
|
|
|
2046
|
-
self._queueEvent(function (err, ret) {
|
|
2228
|
+
self._queueEvent(function (err: any, ret: any) {
|
|
2047
2229
|
delete (self.svchandle);
|
|
2048
2230
|
if (callback)
|
|
2049
2231
|
callback(err, ret);
|
|
@@ -2052,7 +2234,7 @@ class Connection {
|
|
|
2052
2234
|
|
|
2053
2235
|
|
|
2054
2236
|
|
|
2055
|
-
auxConnection(eventid, callback) {
|
|
2237
|
+
auxConnection(eventid: number | Callback, callback?: Callback) {
|
|
2056
2238
|
if (typeof eventid === 'function') {
|
|
2057
2239
|
// Preserve the older auxConnection(callback) call shape; plain
|
|
2058
2240
|
// auxiliary connections historically used event id 0.
|
|
@@ -2066,13 +2248,13 @@ class Connection {
|
|
|
2066
2248
|
msg.pos = 0;
|
|
2067
2249
|
msg.addInt(Const.op_connect_request);
|
|
2068
2250
|
msg.addInt(1); // async
|
|
2069
|
-
msg.addInt(self.dbhandle);
|
|
2251
|
+
msg.addInt(self.dbhandle!);
|
|
2070
2252
|
msg.addInt(eventid);
|
|
2071
2253
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2072
2254
|
console.log('[fb-debug] auxConnection: sending op_connect_request(53) dbhandle=%d eventid=%d queue_before=%d xdr_saved=%s',
|
|
2073
2255
|
self.dbhandle, eventid, self._queue.length, Boolean(self._xdr));
|
|
2074
2256
|
}
|
|
2075
|
-
function cb(err, ret) {
|
|
2257
|
+
function cb(err: any, ret: any) {
|
|
2076
2258
|
|
|
2077
2259
|
if (err) {
|
|
2078
2260
|
if (process.env.FIREBIRD_DEBUG) {
|
|
@@ -2093,13 +2275,13 @@ class Connection {
|
|
|
2093
2275
|
socket_info.family, socket_info.port, socket_info.host, self._queue.length);
|
|
2094
2276
|
}
|
|
2095
2277
|
|
|
2096
|
-
callback(undefined, socket_info);
|
|
2278
|
+
callback!(undefined, socket_info);
|
|
2097
2279
|
}
|
|
2098
2280
|
this._queueEvent(cb);
|
|
2099
2281
|
}
|
|
2100
2282
|
|
|
2101
2283
|
|
|
2102
|
-
queEvents(events, eventid, callback) {
|
|
2284
|
+
queEvents(events: Record<string, number>, eventid: number, callback: Callback) {
|
|
2103
2285
|
var self = this;
|
|
2104
2286
|
if (this._isClosed)
|
|
2105
2287
|
return this.throwClosed(callback);
|
|
@@ -2108,7 +2290,7 @@ class Connection {
|
|
|
2108
2290
|
blr.pos = 0;
|
|
2109
2291
|
msg.pos = 0;
|
|
2110
2292
|
msg.addInt(Const.op_que_events);
|
|
2111
|
-
msg.addInt(this.dbhandle);
|
|
2293
|
+
msg.addInt(this.dbhandle!);
|
|
2112
2294
|
// prepare EPB
|
|
2113
2295
|
blr.addByte(1) // epb_version
|
|
2114
2296
|
for (var event in events) {
|
|
@@ -2122,7 +2304,7 @@ class Connection {
|
|
|
2122
2304
|
msg.addInt(0); // args
|
|
2123
2305
|
msg.addInt(eventid);
|
|
2124
2306
|
|
|
2125
|
-
function cb(err, ret) {
|
|
2307
|
+
function cb(err: any, ret: any) {
|
|
2126
2308
|
if (err) {
|
|
2127
2309
|
doError(err, callback);
|
|
2128
2310
|
return;
|
|
@@ -2135,17 +2317,17 @@ class Connection {
|
|
|
2135
2317
|
}
|
|
2136
2318
|
|
|
2137
2319
|
|
|
2138
|
-
closeEvents(eventid, callback) {
|
|
2320
|
+
closeEvents(eventid: number, callback: Callback) {
|
|
2139
2321
|
var self = this;
|
|
2140
2322
|
if (this._isClosed)
|
|
2141
2323
|
return this.throwClosed(callback);
|
|
2142
2324
|
var msg = self._msg;
|
|
2143
2325
|
msg.pos = 0;
|
|
2144
2326
|
msg.addInt(Const.op_cancel_events);
|
|
2145
|
-
msg.addInt(self.dbhandle);
|
|
2327
|
+
msg.addInt(self.dbhandle!);
|
|
2146
2328
|
msg.addInt(eventid);
|
|
2147
2329
|
|
|
2148
|
-
function cb(err, ret) {
|
|
2330
|
+
function cb(err: any, ret: any) {
|
|
2149
2331
|
if (err) {
|
|
2150
2332
|
doError(err, callback);
|
|
2151
2333
|
return;
|
|
@@ -2164,7 +2346,7 @@ const opcodeNames = Object.fromEntries(
|
|
|
2164
2346
|
Object.entries(Const).filter(([k]) => k.startsWith('op_')).map(([k, v]) => [v, k])
|
|
2165
2347
|
);
|
|
2166
2348
|
|
|
2167
|
-
function decodeResponse(data:
|
|
2349
|
+
function decodeResponse(data: XdrReader, callback: QueueCallback | undefined, cnx: Connection, lowercase_keys: boolean | undefined, cb: (err?: any, obj?: any) => void) {
|
|
2168
2350
|
try {
|
|
2169
2351
|
do {
|
|
2170
2352
|
var r = data.r || data.readInt();
|
|
@@ -2185,7 +2367,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2185
2367
|
cnx._inlineBlobs = new Map();
|
|
2186
2368
|
}
|
|
2187
2369
|
const cacheKey = `${blob_id.high}:${blob_id.low}`;
|
|
2188
|
-
cnx._inlineBlobs.set(cacheKey, blob_data);
|
|
2370
|
+
cnx._inlineBlobs.set(cacheKey, blob_data!);
|
|
2189
2371
|
r = Const.op_dummy; // Continue loop to read next opcode
|
|
2190
2372
|
}
|
|
2191
2373
|
} while (r === Const.op_dummy);
|
|
@@ -2195,7 +2377,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2195
2377
|
r, opcodeNames[r] || 'unknown', data.pos, data.buffer.length);
|
|
2196
2378
|
}
|
|
2197
2379
|
|
|
2198
|
-
var item, op, response;
|
|
2380
|
+
var item, op, response: any;
|
|
2199
2381
|
|
|
2200
2382
|
switch (r) {
|
|
2201
2383
|
case Const.op_response:
|
|
@@ -2206,7 +2388,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2206
2388
|
response = {};
|
|
2207
2389
|
}
|
|
2208
2390
|
|
|
2209
|
-
let loop = function (err) {
|
|
2391
|
+
let loop = function (err: any) {
|
|
2210
2392
|
if (err) {
|
|
2211
2393
|
return cb(err);
|
|
2212
2394
|
} else {
|
|
@@ -2267,13 +2449,27 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2267
2449
|
}
|
|
2268
2450
|
case Const.op_fetch_response:
|
|
2269
2451
|
case Const.op_sql_response:
|
|
2270
|
-
|
|
2452
|
+
// fetch/sql_response entries always carry their statement
|
|
2453
|
+
var statement = callback!.statement!;
|
|
2271
2454
|
var output = statement.output;
|
|
2272
2455
|
var custom = statement.options || {};
|
|
2273
2456
|
var isOpFetch = r === Const.op_fetch_response;
|
|
2274
2457
|
var _xdrpos;
|
|
2275
2458
|
statement.nbrowsfetched = statement.nbrowsfetched || 0;
|
|
2276
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
|
+
|
|
2277
2473
|
if (isOpFetch && data.fop) { // could be set when a packet is not complete
|
|
2278
2474
|
data.readBuffer(68); // ??
|
|
2279
2475
|
op = data.readInt(); // ??
|
|
@@ -2295,55 +2491,67 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2295
2491
|
|
|
2296
2492
|
if (custom.asObject && !data.fcols) {
|
|
2297
2493
|
if (lowercase_keys) {
|
|
2298
|
-
data.fcols = output.map((column) => column.alias.toLowerCase());
|
|
2494
|
+
data.fcols = output.map((column: any) => column.alias.toLowerCase());
|
|
2299
2495
|
} else {
|
|
2300
|
-
data.fcols = output.map((column) => column.alias);
|
|
2496
|
+
data.fcols = output.map((column: any) => column.alias);
|
|
2301
2497
|
}
|
|
2302
2498
|
}
|
|
2303
2499
|
|
|
2304
|
-
const arrBlob = [];
|
|
2500
|
+
const arrBlob: any[] = [];
|
|
2305
2501
|
const lowerV13 = statement.connection.accept.protocolVersion < Const.PROTOCOL_VERSION13;
|
|
2306
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
|
+
|
|
2307
2511
|
while (data.fcount && (data.fstatus !== 100)) {
|
|
2308
2512
|
let nullBitSet;
|
|
2309
2513
|
if (!lowerV13) {
|
|
2310
2514
|
const nullBitsLen = Math.floor((output.length + 7) / 8);
|
|
2311
|
-
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false));
|
|
2515
|
+
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false)!);
|
|
2312
2516
|
data.readBuffer((4 - nullBitsLen) & 3, false); // Skip padding
|
|
2313
2517
|
}
|
|
2314
2518
|
|
|
2315
2519
|
for (let length = output.length; data.fcolumn < length; data.fcolumn++) {
|
|
2316
2520
|
item = output[data.fcolumn];
|
|
2317
2521
|
|
|
2318
|
-
if (!lowerV13 && nullBitSet
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
} else {
|
|
2322
|
-
data.frow[data.fcolumn] = null;
|
|
2323
|
-
}
|
|
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);
|
|
2324
2525
|
|
|
2325
2526
|
continue;
|
|
2326
2527
|
}
|
|
2327
2528
|
|
|
2328
2529
|
try {
|
|
2329
2530
|
_xdrpos = data.pos;
|
|
2330
|
-
const key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
2531
|
+
const key = custom.asObject ? data.fcols![data.fcolumn!] : data.fcolumn;
|
|
2331
2532
|
const row = data.frows.length;
|
|
2332
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;
|
|
2333
2538
|
|
|
2334
2539
|
if (item.type === Const.SQL_BLOB && value !== null) {
|
|
2335
2540
|
if (item.subType === Const.isc_blob_text && cnx.options.blobAsText) {
|
|
2336
|
-
value = fetch_blob_async_transaction(statement, value, key, row);
|
|
2541
|
+
value = fetch_blob_async_transaction(statement, value, key, row, item);
|
|
2337
2542
|
arrBlob.push(value);
|
|
2543
|
+
pendingTextBlob = true;
|
|
2338
2544
|
} else {
|
|
2339
2545
|
value = fetch_blob_async(statement, value, key, row);
|
|
2340
2546
|
}
|
|
2341
2547
|
}
|
|
2342
2548
|
|
|
2343
|
-
data.frow[key] =
|
|
2549
|
+
data.frow[key] = pendingTextBlob
|
|
2550
|
+
? value
|
|
2551
|
+
: applyTypeCast(cnx.options, item, parseValueIfJson(value, cnx.options));
|
|
2344
2552
|
} catch (e) {
|
|
2345
2553
|
// uncomplete packet read
|
|
2346
|
-
data.pos = _xdrpos
|
|
2554
|
+
data.pos = _xdrpos!;
|
|
2347
2555
|
data.r = r;
|
|
2348
2556
|
return cb(new Error('Packet is not complete'));
|
|
2349
2557
|
}
|
|
@@ -2388,6 +2596,17 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2388
2596
|
statement.nbrowsfetched++;
|
|
2389
2597
|
}
|
|
2390
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
|
+
|
|
2391
2610
|
// ToDo: emit "result" with blob subtype string decoded
|
|
2392
2611
|
statement.connection.db.emit('result', data.frows, arrBlob);
|
|
2393
2612
|
return cb(null, {data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob});
|
|
@@ -2412,7 +2631,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2412
2631
|
}
|
|
2413
2632
|
|
|
2414
2633
|
if (r === Const.op_cond_accept || r === Const.op_accept_data) {
|
|
2415
|
-
var d = new BlrReader(data.readArray());
|
|
2634
|
+
var d = new BlrReader(data.readArray()!);
|
|
2416
2635
|
accept.pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
2417
2636
|
var is_authenticated = data.readInt();
|
|
2418
2637
|
var keys = data.readString(Const.DEFAULT_ENCODING); // keys
|
|
@@ -2432,7 +2651,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2432
2651
|
}
|
|
2433
2652
|
|
|
2434
2653
|
if (Const.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
2435
|
-
var crypto = {
|
|
2654
|
+
var crypto: Record<string, string> = {
|
|
2436
2655
|
Srp: 'sha1',
|
|
2437
2656
|
Srp256: 'sha256',
|
|
2438
2657
|
Srp384: 'sha384',
|
|
@@ -2443,7 +2662,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2443
2662
|
if (!d.buffer) {
|
|
2444
2663
|
cnx._pendingAccept = accept;
|
|
2445
2664
|
cnx.sendOpContAuth(
|
|
2446
|
-
cnx.clientKeys
|
|
2665
|
+
cnx.clientKeys!.public.toString(16),
|
|
2447
2666
|
Const.DEFAULT_ENCODING,
|
|
2448
2667
|
accept.pluginName
|
|
2449
2668
|
);
|
|
@@ -2474,20 +2693,20 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2474
2693
|
|
|
2475
2694
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2476
2695
|
console.log('--- DEBUG SRP Handshake ---');
|
|
2477
|
-
console.log('salt:', cnx.serverKeys
|
|
2478
|
-
console.log('server public key:', cnx.serverKeys
|
|
2479
|
-
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));
|
|
2480
2699
|
console.log('hashAlgo:', accept.srpAlgo);
|
|
2481
2700
|
}
|
|
2482
2701
|
|
|
2483
2702
|
const _t1 = Date.now();
|
|
2484
2703
|
var proof = srp.clientProof(
|
|
2485
|
-
cnx.options.user
|
|
2486
|
-
cnx.options.password
|
|
2487
|
-
cnx.serverKeys
|
|
2488
|
-
cnx.clientKeys
|
|
2489
|
-
cnx.serverKeys
|
|
2490
|
-
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,
|
|
2491
2710
|
accept.srpAlgo
|
|
2492
2711
|
);
|
|
2493
2712
|
|
|
@@ -2504,7 +2723,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2504
2723
|
accept.authData = proof.authData.toString(16);
|
|
2505
2724
|
accept.sessionKey = proof.clientSessionKey;
|
|
2506
2725
|
} else if (accept.pluginName === Const.AUTH_PLUGIN_LEGACY) {
|
|
2507
|
-
accept.authData = crypt.crypt(cnx.options.password
|
|
2726
|
+
accept.authData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2508
2727
|
} else {
|
|
2509
2728
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
2510
2729
|
}
|
|
@@ -2542,7 +2761,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2542
2761
|
|
|
2543
2762
|
return cb(undefined, accept);
|
|
2544
2763
|
case Const.op_cont_auth:
|
|
2545
|
-
var d = new BlrReader(data.readArray());
|
|
2764
|
+
var d = new BlrReader(data.readArray()!);
|
|
2546
2765
|
var pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
2547
2766
|
data.readString(Const.DEFAULT_ENCODING); // plist
|
|
2548
2767
|
data.readString(Const.DEFAULT_ENCODING); // pkey
|
|
@@ -2569,7 +2788,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2569
2788
|
// the proof with the new plugin's hash algorithm - rather than
|
|
2570
2789
|
// as the server's M2 proof, otherwise the client silently waits
|
|
2571
2790
|
// forever for an op_accept the server will never send (#254).
|
|
2572
|
-
if (!cnx.serverKeys || cnx.serverKeys
|
|
2791
|
+
if (!cnx.serverKeys || cnx.serverKeys!.pluginName !== pluginName) {
|
|
2573
2792
|
// Check buffer contains salt
|
|
2574
2793
|
var saltLen = d.buffer.readUInt16LE(0);
|
|
2575
2794
|
if (saltLen > 32 * 2) {
|
|
@@ -2592,7 +2811,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2592
2811
|
pluginName: pluginName
|
|
2593
2812
|
};
|
|
2594
2813
|
|
|
2595
|
-
var crypto = {
|
|
2814
|
+
var crypto: Record<string, string> = {
|
|
2596
2815
|
Srp: 'sha1',
|
|
2597
2816
|
Srp256: 'sha256',
|
|
2598
2817
|
Srp384: 'sha384',
|
|
@@ -2602,20 +2821,20 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2602
2821
|
|
|
2603
2822
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2604
2823
|
console.log('--- DEBUG SRP Handshake ---');
|
|
2605
|
-
console.log('salt:', cnx.serverKeys
|
|
2606
|
-
console.log('server public key:', cnx.serverKeys
|
|
2607
|
-
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));
|
|
2608
2827
|
console.log('hashAlgo:', srpAlgo);
|
|
2609
2828
|
}
|
|
2610
2829
|
|
|
2611
2830
|
const _t1 = Date.now();
|
|
2612
2831
|
var proof = srp.clientProof(
|
|
2613
|
-
cnx.options.user
|
|
2614
|
-
cnx.options.password
|
|
2615
|
-
cnx.serverKeys
|
|
2616
|
-
cnx.clientKeys
|
|
2617
|
-
cnx.serverKeys
|
|
2618
|
-
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,
|
|
2619
2838
|
srpAlgo
|
|
2620
2839
|
);
|
|
2621
2840
|
|
|
@@ -2652,7 +2871,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2652
2871
|
cnx._pendingAccept.protocolVersion,
|
|
2653
2872
|
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
2654
2873
|
}
|
|
2655
|
-
var legacyAuthData = crypt.crypt(cnx.options.password
|
|
2874
|
+
var legacyAuthData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2656
2875
|
cnx.sendOpContAuth(legacyAuthData, Const.DEFAULT_ENCODING, pluginName);
|
|
2657
2876
|
return; // wait for op_accept
|
|
2658
2877
|
}
|
|
@@ -2665,7 +2884,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2665
2884
|
|
|
2666
2885
|
if (pluginName === Const.AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
2667
2886
|
cnx.accept.pluginName = pluginName;
|
|
2668
|
-
cnx.accept.authData = crypt.crypt(cnx.options.password
|
|
2887
|
+
cnx.accept.authData = crypt.crypt(cnx.options.password!, Const.LEGACY_AUTH_SALT).substring(2);
|
|
2669
2888
|
|
|
2670
2889
|
cnx.sendOpContAuth(
|
|
2671
2890
|
cnx.accept.authData,
|
|
@@ -2758,7 +2977,7 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2758
2977
|
}
|
|
2759
2978
|
return cb(new Error('Unexpected:' + r));
|
|
2760
2979
|
}
|
|
2761
|
-
} catch (err) {
|
|
2980
|
+
} catch (err: any) {
|
|
2762
2981
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2763
2982
|
console.warn('[fb-debug] decodeResponse exception: %s (RangeError=%s) pos=%d buflen=%d',
|
|
2764
2983
|
err.message, err instanceof RangeError, data.pos, data.buffer.length);
|
|
@@ -2774,8 +2993,8 @@ function decodeResponse(data: any, callback: any, cnx: any, lowercase_keys: any,
|
|
|
2774
2993
|
* Read one XDR status vector (as in op_response / op_batch_cs error
|
|
2775
2994
|
* vectors): a stream of isc_arg_* items terminated by isc_arg_end.
|
|
2776
2995
|
*/
|
|
2777
|
-
function readStatusVector(data:
|
|
2778
|
-
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: [] };
|
|
2779
2998
|
var item: any = {};
|
|
2780
2999
|
|
|
2781
3000
|
while (true) {
|
|
@@ -2805,13 +3024,24 @@ function readStatusVector(data: any): { status: any[]; sqlcode?: number } {
|
|
|
2805
3024
|
result.sqlcode = n;
|
|
2806
3025
|
}
|
|
2807
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;
|
|
2808
3038
|
default:
|
|
2809
3039
|
throw new Error('Unexpected status vector item: ' + op);
|
|
2810
3040
|
}
|
|
2811
3041
|
}
|
|
2812
3042
|
}
|
|
2813
3043
|
|
|
2814
|
-
function parseOpResponse(data:
|
|
3044
|
+
function parseOpResponse(data: XdrReader, response: WireResponse, cb?: (err?: any, response?: any) => void) {
|
|
2815
3045
|
var handle = data.readInt();
|
|
2816
3046
|
|
|
2817
3047
|
if (!response.handle) {
|
|
@@ -2874,18 +3104,31 @@ function parseOpResponse(data: any, response: any, cb?: (err?: any, response?: a
|
|
|
2874
3104
|
response.sqlcode = num;
|
|
2875
3105
|
}
|
|
2876
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
|
+
}
|
|
2877
3118
|
break;
|
|
2878
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).
|
|
2879
3123
|
if (cb) {
|
|
2880
|
-
cb(new Error('Unexpected: ' + op))
|
|
2881
|
-
} else {
|
|
2882
|
-
throw new Error('Unexpected: ' + op);
|
|
3124
|
+
return cb(new Error('Unexpected: ' + op));
|
|
2883
3125
|
}
|
|
3126
|
+
throw new Error('Unexpected: ' + op);
|
|
2884
3127
|
}
|
|
2885
3128
|
}
|
|
2886
3129
|
}
|
|
2887
3130
|
|
|
2888
|
-
function describe(buff: Buffer, statement:
|
|
3131
|
+
function describe(buff: Buffer, statement: Statement) {
|
|
2889
3132
|
var br = new BlrReader(buff);
|
|
2890
3133
|
var parameters: any = null;
|
|
2891
3134
|
var type: any, param: any;
|
|
@@ -2893,7 +3136,7 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2893
3136
|
while (br.pos < br.buffer.length) {
|
|
2894
3137
|
switch (br.readByteCode()) {
|
|
2895
3138
|
case Const.isc_info_sql_stmt_type:
|
|
2896
|
-
statement.type = br.readInt()
|
|
3139
|
+
statement.type = br.readInt()!;
|
|
2897
3140
|
break;
|
|
2898
3141
|
case Const.isc_info_sql_get_plan:
|
|
2899
3142
|
statement.plan = br.readString(Const.DEFAULT_ENCODING);
|
|
@@ -2917,7 +3160,9 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2917
3160
|
case Const.isc_info_sql_describe_end:
|
|
2918
3161
|
break;
|
|
2919
3162
|
case Const.isc_info_sql_sqlda_seq:
|
|
2920
|
-
|
|
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()!;
|
|
2921
3166
|
break;
|
|
2922
3167
|
case Const.isc_info_sql_type:
|
|
2923
3168
|
type = br.readInt();
|
|
@@ -2948,7 +3193,9 @@ function describe(buff: Buffer, statement: any) {
|
|
|
2948
3193
|
default:
|
|
2949
3194
|
throw new Error('Unexpected');
|
|
2950
3195
|
}
|
|
2951
|
-
|
|
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;
|
|
2952
3199
|
param.type = type;
|
|
2953
3200
|
param.nullable = Boolean(param.type & 1);
|
|
2954
3201
|
param.type &= ~1;
|
|
@@ -3228,10 +3475,10 @@ function CalcBlr(blr: BlrWriter, xsqlda: any[]) {
|
|
|
3228
3475
|
blr.addByte(Const.blr_eoc);
|
|
3229
3476
|
}
|
|
3230
3477
|
|
|
3231
|
-
function fetch_blob_async_transaction(statement:
|
|
3232
|
-
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 };
|
|
3233
3480
|
|
|
3234
|
-
return (transactionArg) => {
|
|
3481
|
+
return (transactionArg: any) => {
|
|
3235
3482
|
const cacheKey = `${id.high}:${id.low}`;
|
|
3236
3483
|
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
3237
3484
|
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
@@ -3241,10 +3488,10 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3241
3488
|
|
|
3242
3489
|
const singleTransaction = transactionArg === undefined;
|
|
3243
3490
|
|
|
3244
|
-
let promiseTransaction
|
|
3491
|
+
let promiseTransaction: Promise<Transaction>;
|
|
3245
3492
|
if (singleTransaction) {
|
|
3246
3493
|
promiseTransaction = new Promise((resolve, reject) => {
|
|
3247
|
-
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
3494
|
+
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err: any, transaction: Transaction) => {
|
|
3248
3495
|
if (err) {
|
|
3249
3496
|
return reject(err);
|
|
3250
3497
|
}
|
|
@@ -3258,7 +3505,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3258
3505
|
return promiseTransaction.then((transaction) => {
|
|
3259
3506
|
return new Promise((resolve, reject) => {
|
|
3260
3507
|
statement.connection._pending.push('openBlob');
|
|
3261
|
-
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
3508
|
+
statement.connection.openBlob(id, transaction, (err: any, blob: any) => {
|
|
3262
3509
|
|
|
3263
3510
|
if (err) {
|
|
3264
3511
|
reject(err);
|
|
@@ -3266,7 +3513,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3266
3513
|
}
|
|
3267
3514
|
|
|
3268
3515
|
const read = () => {
|
|
3269
|
-
statement.connection.getSegment(blob, (err, ret) => {
|
|
3516
|
+
statement.connection.getSegment(blob, (err: any, ret: any) => {
|
|
3270
3517
|
|
|
3271
3518
|
if (err) {
|
|
3272
3519
|
if (singleTransaction) {
|
|
@@ -3290,7 +3537,7 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3290
3537
|
|
|
3291
3538
|
statement.connection.closeBlob(blob);
|
|
3292
3539
|
if (singleTransaction) {
|
|
3293
|
-
transaction.commit((err) => {
|
|
3540
|
+
transaction.commit((err: any) => {
|
|
3294
3541
|
if (err) {
|
|
3295
3542
|
reject(err);
|
|
3296
3543
|
} else {
|
|
@@ -3310,14 +3557,14 @@ function fetch_blob_async_transaction(statement: any, id: any, column: any, row:
|
|
|
3310
3557
|
};
|
|
3311
3558
|
}
|
|
3312
3559
|
|
|
3313
|
-
function fetch_blob_async(statement:
|
|
3314
|
-
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) => {
|
|
3315
3562
|
statement.connection._pending.push('openBlob');
|
|
3316
|
-
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
3563
|
+
statement.connection.openBlob(id, transaction, (err: any, blob: any) => {
|
|
3317
3564
|
let e: any = new Events.EventEmitter();
|
|
3318
3565
|
|
|
3319
|
-
e.pipe = (stream) => {
|
|
3320
|
-
e.on('data', (chunk) => {
|
|
3566
|
+
e.pipe = (stream: any) => {
|
|
3567
|
+
e.on('data', (chunk: any) => {
|
|
3321
3568
|
stream.write(chunk);
|
|
3322
3569
|
});
|
|
3323
3570
|
e.on('end', () => {
|
|
@@ -3330,7 +3577,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3330
3577
|
}
|
|
3331
3578
|
|
|
3332
3579
|
const read = () => {
|
|
3333
|
-
statement.connection.getSegment(blob, (err, ret) => {
|
|
3580
|
+
statement.connection.getSegment(blob, (err: any, ret: any) => {
|
|
3334
3581
|
|
|
3335
3582
|
if (err) {
|
|
3336
3583
|
transaction.rollback(() => {
|
|
@@ -3353,7 +3600,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3353
3600
|
|
|
3354
3601
|
statement.connection.closeBlob(blob);
|
|
3355
3602
|
if (close) {
|
|
3356
|
-
transaction.commit((err) => {
|
|
3603
|
+
transaction.commit((err: any) => {
|
|
3357
3604
|
if (err) {
|
|
3358
3605
|
e.emit('error', err);
|
|
3359
3606
|
} else {
|
|
@@ -3373,7 +3620,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3373
3620
|
});
|
|
3374
3621
|
};
|
|
3375
3622
|
|
|
3376
|
-
return (transaction, callback) => {
|
|
3623
|
+
return (transaction: Transaction, callback: any) => {
|
|
3377
3624
|
// callback(error, nameField, eventEmitter, row)
|
|
3378
3625
|
const singleTransaction = callback === undefined;
|
|
3379
3626
|
const actualCallback = singleTransaction ? transaction : callback;
|
|
@@ -3382,8 +3629,8 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3382
3629
|
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
3383
3630
|
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
3384
3631
|
let e: any = new Events.EventEmitter();
|
|
3385
|
-
e.pipe = (stream) => {
|
|
3386
|
-
e.on('data', (chunk) => {
|
|
3632
|
+
e.pipe = (stream: any) => {
|
|
3633
|
+
e.on('data', (chunk: any) => {
|
|
3387
3634
|
stream.write(chunk);
|
|
3388
3635
|
});
|
|
3389
3636
|
e.on('end', () => {
|
|
@@ -3404,7 +3651,7 @@ function fetch_blob_async(statement: any, id: any, name: any, row: any) {
|
|
|
3404
3651
|
|
|
3405
3652
|
if (singleTransaction) {
|
|
3406
3653
|
callback = transaction;
|
|
3407
|
-
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
3654
|
+
statement.connection.startTransaction(Const.ISOLATION_READ_UNCOMMITTED, (err: any, transaction: Transaction) => {
|
|
3408
3655
|
if (err) {
|
|
3409
3656
|
callback(err);
|
|
3410
3657
|
return;
|
|
@@ -3423,7 +3670,7 @@ function doSynchronousLoop(data: any[], processData: (row: any, index: number, n
|
|
|
3423
3670
|
return;
|
|
3424
3671
|
}
|
|
3425
3672
|
|
|
3426
|
-
const loop = (index) => {
|
|
3673
|
+
const loop = (index: any) => {
|
|
3427
3674
|
processData(data[index], index, (err) => {
|
|
3428
3675
|
if (err) {
|
|
3429
3676
|
done(err);
|