node-firebird 2.3.4 → 2.4.1
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 +574 -20
- package/lib/callback.d.ts +20 -0
- package/lib/callback.js +6 -16
- package/lib/firebird.msg.json +1370 -1370
- package/lib/gdscodes.d.ts +1519 -1520
- package/lib/gdscodes.js +5 -5
- package/lib/ieee754-decimal.d.ts +38 -0
- package/lib/ieee754-decimal.js +71 -118
- package/lib/index.d.ts +37 -338
- package/lib/index.js +97 -86
- package/lib/messages.d.ts +6 -0
- package/lib/messages.js +135 -162
- package/lib/pool.d.ts +23 -0
- package/lib/pool.js +34 -47
- package/lib/srp.d.ts +51 -0
- package/lib/srp.js +62 -72
- package/lib/types.d.ts +375 -0
- package/lib/types.js +22 -0
- package/lib/unix-crypt.d.ts +1 -0
- package/lib/unix-crypt.js +126 -152
- package/lib/utils.d.ts +16 -0
- package/lib/utils.js +24 -48
- package/lib/wire/connection.d.ts +100 -0
- package/lib/wire/connection.js +1029 -1009
- package/lib/wire/const.d.ts +567 -0
- package/lib/wire/const.js +620 -599
- package/lib/wire/database.d.ts +57 -0
- package/lib/wire/database.js +111 -108
- package/lib/wire/eventConnection.d.ts +16 -0
- package/lib/wire/eventConnection.js +29 -31
- package/lib/wire/fbEventManager.d.ts +45 -0
- package/lib/wire/fbEventManager.js +38 -57
- package/lib/wire/serialize.d.ts +97 -0
- package/lib/wire/serialize.js +42 -141
- package/lib/wire/service.d.ts +66 -0
- package/lib/wire/service.js +374 -401
- package/lib/wire/socket.d.ts +59 -0
- package/lib/wire/socket.js +79 -40
- package/lib/wire/statement.d.ts +25 -0
- package/lib/wire/statement.js +13 -9
- package/lib/wire/transaction.d.ts +21 -0
- package/lib/wire/transaction.js +33 -61
- package/lib/wire/xsqlvar.d.ts +175 -0
- package/lib/wire/xsqlvar.js +169 -269
- package/package.json +12 -4
- package/src/callback.ts +55 -0
- package/{poc/node_modules/node-firebird/lib/gdscodes.js → src/gdscodes.ts} +3 -3
- package/{poc/node_modules/node-firebird/lib/ieee754-decimal.js → src/ieee754-decimal.ts} +7 -14
- package/src/index.ts +157 -0
- package/{poc/node_modules/node-firebird/lib/messages.js → src/messages.ts} +163 -162
- package/src/pool.ts +209 -0
- package/{poc/node_modules/node-firebird/lib/srp.js → src/srp.ts} +74 -33
- package/src/types.ts +419 -0
- package/{poc/node_modules/node-firebird/lib/unix-crypt.js → src/unix-crypt.ts} +6 -12
- package/{poc/node_modules/node-firebird/lib/utils.js → src/utils.ts} +11 -20
- package/{poc/node_modules/node-firebird/lib/wire/connection.js → src/wire/connection.ts} +611 -129
- package/{poc/node_modules/node-firebird/lib/wire/const.js → src/wire/const.ts} +96 -9
- package/{poc/node_modules/node-firebird/lib/wire/database.js → src/wire/database.ts} +110 -44
- package/{poc/node_modules/node-firebird/lib/wire/eventConnection.js → src/wire/eventConnection.ts} +29 -14
- package/{poc/node_modules/node-firebird/lib/wire/fbEventManager.js → src/wire/fbEventManager.ts} +39 -30
- package/{poc/node_modules/node-firebird/lib/wire/serialize.js → src/wire/serialize.ts} +78 -59
- package/{poc/node_modules/node-firebird/lib/wire/service.js → src/wire/service.ts} +90 -88
- package/src/wire/socket.ts +262 -0
- package/src/wire/statement.ts +71 -0
- package/{poc/node_modules/node-firebird/lib/wire/transaction.js → src/wire/transaction.ts} +25 -19
- package/{poc/node_modules/node-firebird/lib/wire/xsqlvar.js → src/wire/xsqlvar.ts} +244 -143
- package/.eslintrc.json +0 -12
- package/.github/workflows/codeql.yml +0 -76
- package/.github/workflows/node.js.yml +0 -95
- package/BIGINT_MIGRATION.md +0 -374
- package/CI_DEBUGGING_GUIDE.md +0 -148
- package/ENCRYPTION_CALLBACK.md +0 -152
- package/FIREBIRD_LOG_FEATURE.md +0 -145
- package/MINIMAL_CHANGES_SUMMARY.md +0 -136
- package/PR_SUMMARY.md +0 -96
- package/ROADMAP.md +0 -223
- package/SRP_PROTOCOL.md +0 -482
- package/poc/README.md +0 -160
- package/poc/helpers.js +0 -59
- package/poc/node_modules/.package-lock.json +0 -14
- package/poc/node_modules/node-firebird/.eslintrc.json +0 -12
- package/poc/node_modules/node-firebird/.github/workflows/codeql.yml +0 -76
- package/poc/node_modules/node-firebird/.github/workflows/node.js.yml +0 -95
- package/poc/node_modules/node-firebird/BIGINT_MIGRATION.md +0 -374
- package/poc/node_modules/node-firebird/CI_DEBUGGING_GUIDE.md +0 -148
- package/poc/node_modules/node-firebird/ENCRYPTION_CALLBACK.md +0 -152
- package/poc/node_modules/node-firebird/FIREBIRD_LOG_FEATURE.md +0 -145
- package/poc/node_modules/node-firebird/LICENSE +0 -373
- package/poc/node_modules/node-firebird/MINIMAL_CHANGES_SUMMARY.md +0 -136
- package/poc/node_modules/node-firebird/PR_SUMMARY.md +0 -96
- package/poc/node_modules/node-firebird/README.md +0 -794
- package/poc/node_modules/node-firebird/ROADMAP.md +0 -223
- package/poc/node_modules/node-firebird/SRP_PROTOCOL.md +0 -482
- package/poc/node_modules/node-firebird/lib/callback.js +0 -38
- package/poc/node_modules/node-firebird/lib/gdscodes.d.ts +0 -1524
- package/poc/node_modules/node-firebird/lib/index.d.ts +0 -316
- package/poc/node_modules/node-firebird/lib/index.js +0 -128
- package/poc/node_modules/node-firebird/lib/pool.js +0 -108
- package/poc/node_modules/node-firebird/lib/wire/socket.js +0 -175
- package/poc/node_modules/node-firebird/lib/wire/statement.js +0 -48
- package/poc/node_modules/node-firebird/package.json +0 -38
- package/poc/node_modules/node-firebird/vitest.config.js +0 -24
- package/poc/package-lock.json +0 -21
- package/poc/package.json +0 -12
- package/poc/reproduce-fixed.js +0 -150
- package/poc/reproduce.js +0 -133
- package/vitest.config.js +0 -27
- /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg +0 -0
- /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg.json +0 -0
package/lib/wire/connection.js
CHANGED
|
@@ -1,165 +1,193 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
const events_1 = __importDefault(require("events"));
|
|
39
|
+
const os_1 = __importDefault(require("os"));
|
|
40
|
+
const path_1 = __importDefault(require("path"));
|
|
41
|
+
const serialize_1 = require("./serialize");
|
|
42
|
+
const callback_1 = require("../callback");
|
|
43
|
+
const srp = __importStar(require("../srp"));
|
|
44
|
+
const crypt = __importStar(require("../unix-crypt"));
|
|
45
|
+
const const_1 = __importDefault(require("./const"));
|
|
46
|
+
const Xsql = __importStar(require("./xsqlvar"));
|
|
47
|
+
const service_1 = __importDefault(require("./service"));
|
|
48
|
+
const database_1 = __importDefault(require("./database"));
|
|
49
|
+
const statement_1 = __importDefault(require("./statement"));
|
|
50
|
+
const transaction_1 = __importDefault(require("./transaction"));
|
|
51
|
+
const utils_1 = require("../utils");
|
|
52
|
+
const socket_1 = __importDefault(require("./socket"));
|
|
53
|
+
function parseValueIfJson(value, options) {
|
|
54
|
+
if (options && options.jsonAsObject && typeof value === 'string' && (value.startsWith('{') || value.startsWith('['))) {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(value);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
// Ignore parse error and keep as string
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
18
64
|
/***************************************
|
|
19
65
|
*
|
|
20
66
|
* Connection
|
|
21
67
|
*
|
|
22
68
|
***************************************/
|
|
23
|
-
|
|
24
69
|
class Connection {
|
|
25
70
|
constructor(host, port, callback, options, db, svc) {
|
|
26
71
|
var self = this;
|
|
27
72
|
this.db = db;
|
|
28
|
-
this.svc = svc
|
|
29
|
-
this._msg = new XdrWriter(32);
|
|
30
|
-
this._blr = new BlrWriter(32);
|
|
73
|
+
this.svc = svc;
|
|
74
|
+
this._msg = new serialize_1.XdrWriter(32);
|
|
75
|
+
this._blr = new serialize_1.BlrWriter(32);
|
|
31
76
|
this._queue = [];
|
|
32
77
|
this._detachTimeout;
|
|
33
78
|
this._detachCallback;
|
|
34
79
|
this._detachAuto;
|
|
35
|
-
this._socket = new
|
|
80
|
+
this._socket = new socket_1.default(port, host);
|
|
36
81
|
this._pending = [];
|
|
37
82
|
this._isOpened = false;
|
|
38
83
|
this._isClosed = false;
|
|
39
84
|
this._isDetach = false;
|
|
40
85
|
this._isUsed = false;
|
|
41
|
-
this._pooled = options.isPool||false;
|
|
42
|
-
if (options && options.blobChunkSize > 65535)
|
|
43
|
-
|
|
86
|
+
this._pooled = options.isPool || false;
|
|
87
|
+
if (options && options.blobChunkSize > 65535)
|
|
88
|
+
options.blobChunkSize = 65535;
|
|
89
|
+
if (options && options.blobReadChunkSize > 65535)
|
|
90
|
+
options.blobReadChunkSize = 65535;
|
|
44
91
|
this.options = options;
|
|
45
92
|
this._bind_events(host, port, callback);
|
|
46
93
|
this.error;
|
|
47
94
|
this._retry_connection_id;
|
|
48
95
|
this._retry_connection_interval = options.retryConnectionInterval || 1000;
|
|
49
96
|
this._max_cached_query = options.maxCachedQuery || -1;
|
|
50
|
-
this._cache_query = options.cacheQuery?{}:null;
|
|
51
|
-
this._messageFile = options.messageFile ||
|
|
97
|
+
this._cache_query = options.cacheQuery ? {} : null;
|
|
98
|
+
this._messageFile = options.messageFile || path_1.default.join(__dirname, 'firebird.msg');
|
|
52
99
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
100
|
_setcachedquery(query, statement) {
|
|
56
|
-
if (this._cache_query){
|
|
57
|
-
if (this._max_cached_query === -1 || this._max_cached_query > Object.keys(this._cache_query).length){
|
|
101
|
+
if (this._cache_query) {
|
|
102
|
+
if (this._max_cached_query === -1 || this._max_cached_query > Object.keys(this._cache_query).length) {
|
|
58
103
|
this._cache_query[query] = statement;
|
|
59
104
|
}
|
|
60
105
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
106
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
107
|
getCachedQuery(query) {
|
|
67
108
|
return this._cache_query ? this._cache_query[query] : null;
|
|
68
109
|
}
|
|
69
|
-
|
|
70
|
-
|
|
110
|
+
// Reject every request that is still awaiting a server response (e.g. a
|
|
111
|
+
// transaction.commit() sent right before the server went away) instead of
|
|
112
|
+
// leaving its callback to hang forever. Requests already in flight cannot
|
|
113
|
+
// be transparently resumed on a reconnect: a fresh attach() hands out new
|
|
114
|
+
// transaction/statement handles, so nothing the server sends back could
|
|
115
|
+
// ever match a callback queued against the old connection.
|
|
116
|
+
_rejectPending(err) {
|
|
117
|
+
var queue = this._queue;
|
|
118
|
+
this._queue = [];
|
|
119
|
+
this._pending = [];
|
|
120
|
+
for (var i = 0; i < queue.length; i++) {
|
|
121
|
+
(0, callback_1.doError)(err, queue[i]);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
71
124
|
_bind_events(host, port, callback) {
|
|
72
|
-
|
|
73
125
|
var self = this;
|
|
74
|
-
|
|
75
|
-
self._socket.on('close', function() {
|
|
76
|
-
|
|
126
|
+
self._socket.on('close', function () {
|
|
77
127
|
if (!self._isOpened || self._isDetach) {
|
|
78
128
|
return;
|
|
79
129
|
}
|
|
80
|
-
|
|
81
130
|
self._isOpened = false;
|
|
82
|
-
|
|
131
|
+
self._isClosed = true;
|
|
132
|
+
var lostError = self.error || new Error('Connection to Firebird server was lost.');
|
|
83
133
|
if (!self.db) {
|
|
134
|
+
self._rejectPending(lostError);
|
|
84
135
|
if (callback)
|
|
85
136
|
callback(self.error);
|
|
86
137
|
return;
|
|
87
138
|
}
|
|
88
|
-
|
|
89
|
-
self._retry_connection_id = setTimeout(function() {
|
|
139
|
+
self._rejectPending(lostError);
|
|
140
|
+
self._retry_connection_id = setTimeout(function () {
|
|
90
141
|
self._socket.removeAllListeners();
|
|
91
142
|
self._socket = null;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
ctx.connect(self.options, function(err) {
|
|
95
|
-
|
|
143
|
+
var ctx = new Connection(host, port, function (err) {
|
|
144
|
+
ctx.connect(self.options, function (err) {
|
|
96
145
|
if (err) {
|
|
97
146
|
self.db.emit('error', err);
|
|
98
147
|
return;
|
|
99
148
|
}
|
|
100
|
-
|
|
101
|
-
ctx.attach(self.options, function(err) {
|
|
102
|
-
|
|
149
|
+
ctx.attach(self.options, function (err) {
|
|
103
150
|
if (err) {
|
|
104
151
|
self.db.emit('error', err);
|
|
105
152
|
return;
|
|
106
153
|
}
|
|
107
|
-
|
|
108
|
-
ctx._queue = ctx._queue.concat(self._queue);
|
|
109
|
-
ctx._pending = ctx._pending.concat(self._pending);
|
|
110
154
|
self.db.emit('reconnect');
|
|
111
|
-
|
|
112
155
|
}, self.db);
|
|
113
156
|
});
|
|
114
|
-
|
|
115
157
|
Object.assign(self, ctx);
|
|
116
|
-
|
|
117
158
|
}, self.options, self.db);
|
|
118
159
|
}, self._retry_connection_interval);
|
|
119
|
-
|
|
120
160
|
});
|
|
121
|
-
|
|
122
|
-
self._socket.on('error', function(e) {
|
|
123
|
-
|
|
161
|
+
self._socket.on('error', function (e) {
|
|
124
162
|
self.error = e;
|
|
125
|
-
|
|
126
163
|
if (self.db)
|
|
127
|
-
self.db.emit('error', e)
|
|
128
|
-
|
|
164
|
+
self.db.emit('error', e);
|
|
129
165
|
if (callback)
|
|
130
166
|
callback(e);
|
|
131
|
-
|
|
132
167
|
});
|
|
133
|
-
|
|
134
|
-
self._socket.on('connect', function() {
|
|
168
|
+
self._socket.on('connect', function () {
|
|
135
169
|
self._isClosed = false;
|
|
136
170
|
self._isOpened = true;
|
|
137
171
|
if (callback)
|
|
138
172
|
callback();
|
|
139
173
|
});
|
|
140
|
-
|
|
141
174
|
self._socket.on('data', function (data) {
|
|
142
175
|
var xdr;
|
|
143
176
|
var hadSavedBuffer = Boolean(self._xdr);
|
|
144
|
-
|
|
145
177
|
if (!self._xdr) {
|
|
146
|
-
xdr = new XdrReader(data);
|
|
147
|
-
}
|
|
148
|
-
|
|
178
|
+
xdr = new serialize_1.XdrReader(data);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
xdr = new serialize_1.XdrReader(Buffer.concat([self._xdr.buffer, data], self._xdr.buffer.length + data.length));
|
|
149
182
|
delete (self._xdr);
|
|
150
183
|
}
|
|
151
|
-
|
|
152
184
|
if (process.env.FIREBIRD_DEBUG) {
|
|
153
|
-
console.log('[fb-debug] data event: bytes=%d queue=%d pending=%d xdr.pos=%d savedBuf=%s',
|
|
154
|
-
xdr.buffer.length, self._queue.length, self._pending.length, xdr.pos, hadSavedBuffer);
|
|
185
|
+
console.log('[fb-debug] data event: bytes=%d queue=%d pending=%d xdr.pos=%d savedBuf=%s', xdr.buffer.length, self._queue.length, self._pending.length, xdr.pos, hadSavedBuffer);
|
|
155
186
|
}
|
|
156
|
-
|
|
157
187
|
while (xdr.pos < xdr.buffer.length) {
|
|
158
188
|
var cb = self._queue[0], pos = xdr.pos;
|
|
159
189
|
var lazySnapshot = cb ? cb.lazy_count : undefined;
|
|
160
|
-
|
|
161
190
|
decodeResponse(xdr, cb, self, self._lowercase_keys, function (err, obj) {
|
|
162
|
-
|
|
163
191
|
if (err) {
|
|
164
192
|
if (err instanceof RangeError) {
|
|
165
193
|
// Genuinely incomplete packet – buffer the remaining bytes
|
|
@@ -167,12 +195,9 @@ class Connection {
|
|
|
167
195
|
xdr.buffer = xdr.buffer.slice(pos);
|
|
168
196
|
xdr.pos = 0;
|
|
169
197
|
self._xdr = xdr;
|
|
170
|
-
|
|
171
198
|
if (process.env.FIREBIRD_DEBUG) {
|
|
172
|
-
console.log('[fb-debug] incomplete packet: saved %d bytes at pos=%d queue=%d',
|
|
173
|
-
xdr.buffer.length, pos, self._queue.length);
|
|
199
|
+
console.log('[fb-debug] incomplete packet: saved %d bytes at pos=%d queue=%d', xdr.buffer.length, pos, self._queue.length);
|
|
174
200
|
}
|
|
175
|
-
|
|
176
201
|
// Restore lazy_count to its value before this (failed)
|
|
177
202
|
// decode attempt. Forcing lazy_count = 2 here made the
|
|
178
203
|
// decoder expect a second op_response that never arrives
|
|
@@ -181,11 +206,13 @@ class Connection {
|
|
|
181
206
|
if (cb) {
|
|
182
207
|
if (lazySnapshot === undefined) {
|
|
183
208
|
delete cb.lazy_count;
|
|
184
|
-
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
185
211
|
cb.lazy_count = lazySnapshot;
|
|
186
212
|
}
|
|
187
213
|
}
|
|
188
|
-
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
189
216
|
// Any other error (truly unknown opcode not handled above).
|
|
190
217
|
// Save the buffer so it can be retried, but log a warning.
|
|
191
218
|
if (process.env.FIREBIRD_DEBUG) {
|
|
@@ -197,437 +224,429 @@ class Connection {
|
|
|
197
224
|
}
|
|
198
225
|
return;
|
|
199
226
|
}
|
|
200
|
-
|
|
201
227
|
// remove the op flag, needed for partial packet
|
|
202
228
|
if (xdr.r) {
|
|
203
229
|
delete (xdr.r);
|
|
204
230
|
}
|
|
205
|
-
|
|
206
231
|
// op_event / op_response_piggyback received on the main connection:
|
|
207
232
|
// data has been consumed by decodeResponse but it does not belong to
|
|
208
233
|
// any queued request – do NOT shift the queue or invoke any pending
|
|
209
234
|
// callback.
|
|
210
235
|
if (obj && obj._isOpEvent) {
|
|
211
236
|
if (process.env.FIREBIRD_DEBUG) {
|
|
212
|
-
console.log('[fb-debug] async opcode consumed (ignored): queue=%d xdr.pos=%d remaining=%d',
|
|
213
|
-
self._queue.length, xdr.pos, xdr.buffer.length - xdr.pos);
|
|
237
|
+
console.log('[fb-debug] async opcode consumed (ignored): queue=%d xdr.pos=%d remaining=%d', self._queue.length, xdr.pos, xdr.buffer.length - xdr.pos);
|
|
214
238
|
}
|
|
215
239
|
return;
|
|
216
240
|
}
|
|
217
|
-
|
|
218
241
|
self._queue.shift();
|
|
219
242
|
self._pending.shift();
|
|
220
|
-
|
|
221
243
|
if (process.env.FIREBIRD_DEBUG) {
|
|
222
|
-
console.log('[fb-debug] response dispatched: queue remaining=%d pending remaining=%d xdr.pos=%d',
|
|
223
|
-
self._queue.length, self._pending.length, xdr.pos);
|
|
244
|
+
console.log('[fb-debug] response dispatched: queue remaining=%d pending remaining=%d xdr.pos=%d', self._queue.length, self._pending.length, xdr.pos);
|
|
224
245
|
}
|
|
225
|
-
|
|
226
246
|
if (obj && obj.status) {
|
|
227
|
-
obj.message = lookupMessages(obj.status);
|
|
228
|
-
doCallback(obj, cb);
|
|
229
|
-
}
|
|
230
|
-
|
|
247
|
+
obj.message = (0, utils_1.lookupMessages)(obj.status);
|
|
248
|
+
(0, callback_1.doCallback)(obj, cb);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
(0, callback_1.doCallback)(obj, cb);
|
|
231
252
|
}
|
|
232
|
-
|
|
233
253
|
});
|
|
234
|
-
|
|
235
254
|
if (xdr.pos === 0) {
|
|
236
255
|
break;
|
|
237
256
|
}
|
|
238
257
|
}
|
|
239
|
-
|
|
240
258
|
if (!self._detachAuto || self._pending.length !== 0) {
|
|
241
259
|
return;
|
|
242
260
|
}
|
|
243
|
-
|
|
244
261
|
clearTimeout(self._detachTimeout);
|
|
245
262
|
self._detachTimeout = setTimeout(function () {
|
|
246
263
|
self.db.detach(self._detachCallback);
|
|
247
264
|
self._detachAuto = false;
|
|
248
265
|
}, 100);
|
|
249
|
-
|
|
250
266
|
});
|
|
251
267
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
268
|
disconnect() {
|
|
255
269
|
this._socket.end();
|
|
256
270
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
271
|
sendOpContAuth(authData, authDataEnc, pluginName) {
|
|
263
272
|
var msg = this._msg;
|
|
264
273
|
msg.pos = 0;
|
|
265
|
-
|
|
266
|
-
msg.addInt(Const.op_cont_auth);
|
|
274
|
+
msg.addInt(const_1.default.op_cont_auth);
|
|
267
275
|
msg.addString(authData, authDataEnc);
|
|
268
|
-
msg.addString(pluginName,
|
|
269
|
-
msg.addString(
|
|
276
|
+
msg.addString(pluginName, const_1.default.DEFAULT_ENCODING);
|
|
277
|
+
msg.addString(const_1.default.AUTH_PLUGIN_LIST.join(','), const_1.default.DEFAULT_ENCODING);
|
|
270
278
|
// msg.addInt(0); // p_list
|
|
271
279
|
msg.addInt(0); // keys
|
|
272
|
-
|
|
273
280
|
this._socket.write(msg.getData());
|
|
274
281
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
282
|
sendOpCrypt(encryptPlugin) {
|
|
278
283
|
var msg = this._msg;
|
|
279
284
|
msg.pos = 0;
|
|
280
|
-
|
|
281
|
-
msg.
|
|
282
|
-
msg.addString(
|
|
283
|
-
msg.addString('Symmetric', Const.DEFAULT_ENCODING);
|
|
284
|
-
|
|
285
|
+
msg.addInt(const_1.default.op_crypt);
|
|
286
|
+
msg.addString(encryptPlugin || 'Arc4', const_1.default.DEFAULT_ENCODING);
|
|
287
|
+
msg.addString('Symmetric', const_1.default.DEFAULT_ENCODING);
|
|
285
288
|
this._socket.write(msg.getData());
|
|
286
289
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
290
|
sendOpCryptKeyCallback(pluginData) {
|
|
290
291
|
var msg = this._msg;
|
|
291
292
|
msg.pos = 0;
|
|
292
|
-
|
|
293
|
-
msg.addInt(Const.op_crypt_key_callback);
|
|
293
|
+
msg.addInt(const_1.default.op_crypt_key_callback);
|
|
294
294
|
msg.addBlr(pluginData); // Send the callback response data as a buffer
|
|
295
|
-
|
|
296
295
|
this._socket.write(msg.getData());
|
|
297
296
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
297
|
_queueEvent(callback, defer = false) {
|
|
301
298
|
var self = this;
|
|
302
|
-
|
|
303
299
|
if (self._isClosed) {
|
|
304
300
|
if (callback)
|
|
305
301
|
callback(new Error('Connection is closed.'));
|
|
306
302
|
return;
|
|
307
303
|
}
|
|
308
|
-
|
|
309
|
-
const canDefer = defer && this.accept.protocolVersion >= Const.PROTOCOL_VERSION11;
|
|
310
|
-
|
|
304
|
+
const canDefer = defer && this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION11;
|
|
311
305
|
self._socket.write(self._msg.getData(), canDefer);
|
|
312
306
|
if (canDefer && callback) {
|
|
313
307
|
callback();
|
|
314
|
-
}
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
315
310
|
self._queue.push(callback);
|
|
316
311
|
}
|
|
317
312
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
313
|
connect(options, callback) {
|
|
321
|
-
var pluginName = options.
|
|
314
|
+
var pluginName = options.pluginName || const_1.default.AUTH_PLUGIN_LIST[0];
|
|
322
315
|
var msg = this._msg;
|
|
323
316
|
var blr = this._blr;
|
|
324
|
-
|
|
325
317
|
this._pending.push('connect');
|
|
326
318
|
this._authStartTime = Date.now();
|
|
327
|
-
|
|
328
319
|
msg.pos = 0;
|
|
329
320
|
blr.pos = 0;
|
|
330
|
-
|
|
331
|
-
blr.addString(
|
|
332
|
-
blr.addString(
|
|
333
|
-
blr.addString(Const.CNCT_plugin_list, Const.AUTH_PLUGIN_LIST.join(','), Const.DEFAULT_ENCODING);
|
|
334
|
-
|
|
321
|
+
blr.addString(const_1.default.CNCT_login, options.user, const_1.default.DEFAULT_ENCODING);
|
|
322
|
+
blr.addString(const_1.default.CNCT_plugin_name, pluginName, const_1.default.DEFAULT_ENCODING);
|
|
323
|
+
blr.addString(const_1.default.CNCT_plugin_list, const_1.default.AUTH_PLUGIN_LIST.join(','), const_1.default.DEFAULT_ENCODING);
|
|
335
324
|
var specificData = '';
|
|
336
|
-
if (
|
|
325
|
+
if (const_1.default.AUTH_PLUGIN_SRP_LIST.indexOf(pluginName) > -1) {
|
|
337
326
|
const _t0 = Date.now();
|
|
338
327
|
this.clientKeys = srp.clientSeed();
|
|
339
328
|
if (process.env.FIREBIRD_DEBUG) {
|
|
340
329
|
console.log('[fb-debug] srp.clientSeed: %dms', Date.now() - _t0);
|
|
341
330
|
}
|
|
342
331
|
specificData = this.clientKeys.public.toString(16);
|
|
343
|
-
blr.addMultiblockPart(
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
332
|
+
blr.addMultiblockPart(const_1.default.CNCT_specific_data, specificData, const_1.default.DEFAULT_ENCODING);
|
|
333
|
+
}
|
|
334
|
+
else if (pluginName === const_1.default.AUTH_PLUGIN_LEGACY) {
|
|
335
|
+
specificData = crypt.crypt(options.password, const_1.default.LEGACY_AUTH_SALT).substring(2);
|
|
336
|
+
blr.addMultiblockPart(const_1.default.CNCT_specific_data, specificData, const_1.default.DEFAULT_ENCODING);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
(0, callback_1.doError)(new Error('Invalide auth plugin \'' + pluginName + '\''), callback);
|
|
349
340
|
return;
|
|
350
341
|
}
|
|
351
|
-
blr.addBytes([
|
|
352
|
-
blr.addString(
|
|
353
|
-
blr.addString(
|
|
354
|
-
blr.addBytes([
|
|
355
|
-
|
|
356
|
-
msg.addInt(
|
|
357
|
-
msg.addInt(
|
|
358
|
-
msg.addInt(
|
|
359
|
-
msg.
|
|
360
|
-
|
|
361
|
-
|
|
342
|
+
blr.addBytes([const_1.default.CNCT_client_crypt, 4, options.wireCrypt !== undefined ? options.wireCrypt : const_1.default.WIRE_CRYPT_ENABLE, 0, 0, 0]);
|
|
343
|
+
blr.addString(const_1.default.CNCT_user, os_1.default.userInfo().username || 'Unknown', const_1.default.DEFAULT_ENCODING);
|
|
344
|
+
blr.addString(const_1.default.CNCT_host, os_1.default.hostname(), const_1.default.DEFAULT_ENCODING);
|
|
345
|
+
blr.addBytes([const_1.default.CNCT_user_verification, 0]);
|
|
346
|
+
msg.addInt(const_1.default.op_connect);
|
|
347
|
+
msg.addInt(const_1.default.op_attach);
|
|
348
|
+
msg.addInt(const_1.default.CONNECT_VERSION3);
|
|
349
|
+
msg.addInt(const_1.default.ARCHITECTURE_GENERIC);
|
|
350
|
+
msg.addString(options.database || options.filename, const_1.default.DEFAULT_ENCODING);
|
|
351
|
+
var maxProtocols = options.maxNegotiatedProtocols !== undefined ? options.maxNegotiatedProtocols : 10;
|
|
352
|
+
var protocolsToSend = const_1.default.SUPPORTED_PROTOCOL;
|
|
353
|
+
if (protocolsToSend.length > maxProtocols) {
|
|
354
|
+
protocolsToSend = protocolsToSend.slice(-maxProtocols);
|
|
355
|
+
}
|
|
356
|
+
msg.addInt(protocolsToSend.length); // Count of Protocol version understood count.
|
|
362
357
|
msg.addBlr(this._blr);
|
|
363
|
-
|
|
364
|
-
for (var protocol of Const.SUPPORTED_PROTOCOL) {
|
|
358
|
+
for (var protocol of protocolsToSend) {
|
|
365
359
|
msg.addInt(protocol[0]); // Version
|
|
366
360
|
msg.addInt(protocol[1]); // Architecture
|
|
367
361
|
msg.addInt(protocol[2]); // Min type
|
|
368
|
-
if (protocol[0] >=
|
|
369
|
-
msg.addInt(protocol[3] |
|
|
370
|
-
}
|
|
362
|
+
if (protocol[0] >= const_1.default.PROTOCOL_VERSION13 && options.wireCompression) {
|
|
363
|
+
msg.addInt(protocol[3] | const_1.default.pflag_compress); // Max type with compress flag
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
371
366
|
msg.addInt(protocol[3]); // Max type
|
|
372
367
|
}
|
|
373
368
|
msg.addInt(protocol[4]); // Preference weight
|
|
374
369
|
}
|
|
375
|
-
|
|
376
370
|
var self = this;
|
|
377
371
|
function cb(err, ret) {
|
|
378
372
|
if (err) {
|
|
379
|
-
doError(err, callback);
|
|
373
|
+
(0, callback_1.doError)(err, callback);
|
|
380
374
|
return;
|
|
381
375
|
}
|
|
382
|
-
|
|
383
376
|
// Check for pending accept from op_cond_accept flow
|
|
384
377
|
if (self._pendingAccept) {
|
|
385
378
|
ret = self._pendingAccept;
|
|
386
379
|
delete self._pendingAccept;
|
|
387
380
|
}
|
|
388
|
-
|
|
389
381
|
self.accept = ret;
|
|
390
|
-
|
|
391
382
|
// Wire encryption: send op_crypt if SRP session key is available
|
|
392
|
-
if (ret.sessionKey && ret.protocolVersion >=
|
|
393
|
-
options.wireCrypt !==
|
|
394
|
-
var
|
|
395
|
-
|
|
396
|
-
|
|
383
|
+
if (ret.sessionKey && ret.protocolVersion >= const_1.default.PROTOCOL_VERSION13 &&
|
|
384
|
+
options.wireCrypt !== const_1.default.WIRE_CRYPT_DISABLE) {
|
|
385
|
+
var padLen = 40;
|
|
386
|
+
var keyBuf = Buffer.from(ret.sessionKey.toString(16).padStart(padLen, '0'), 'hex');
|
|
387
|
+
var selectedPlugin = 'Arc4';
|
|
388
|
+
if (ret.keys) {
|
|
389
|
+
var serverPlugins = ret.keys.split(',').map(function (s) { return s.trim().toLowerCase(); });
|
|
390
|
+
var preferred = ['chacha64', 'chacha', 'arc4'];
|
|
391
|
+
for (var i = 0; i < preferred.length; i++) {
|
|
392
|
+
if (serverPlugins.indexOf(preferred[i]) !== -1) {
|
|
393
|
+
var mapping = {
|
|
394
|
+
chacha64: 'ChaCha64',
|
|
395
|
+
chacha: 'ChaCha',
|
|
396
|
+
arc4: 'Arc4'
|
|
397
|
+
};
|
|
398
|
+
selectedPlugin = mapping[preferred[i]];
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Send op_crypt BEFORE enabling encryption (op_crypt is sent plaintext)
|
|
404
|
+
// The server then enables encryption from its side.
|
|
405
|
+
// After the op_response to op_crypt, both sides are encrypted.
|
|
406
|
+
self.sendOpCrypt(selectedPlugin);
|
|
407
|
+
if (selectedPlugin === 'Arc4') {
|
|
408
|
+
self._socket.enableEncryption(keyBuf, 'Arc4');
|
|
409
|
+
}
|
|
397
410
|
self._pending.push('crypt');
|
|
398
|
-
self._queue.push(function(cryptErr) {
|
|
411
|
+
self._queue.push(function (cryptErr, response) {
|
|
399
412
|
if (cryptErr) {
|
|
400
|
-
doError(cryptErr, callback);
|
|
413
|
+
(0, callback_1.doError)(cryptErr, callback);
|
|
401
414
|
return;
|
|
402
415
|
}
|
|
416
|
+
if (selectedPlugin !== 'Arc4') {
|
|
417
|
+
var iv = response && response.buffer;
|
|
418
|
+
if (!iv || (selectedPlugin === 'ChaCha64' && iv.length < 8) || (selectedPlugin === 'ChaCha' && iv.length < 12)) {
|
|
419
|
+
var errIv = new Error('Invalid or missing IV for ' + selectedPlugin + ' encryption');
|
|
420
|
+
(0, callback_1.doError)(errIv, callback);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
self._socket.enableEncryption(keyBuf, selectedPlugin, iv);
|
|
424
|
+
}
|
|
403
425
|
if (callback)
|
|
404
426
|
callback(undefined, ret);
|
|
405
427
|
});
|
|
406
428
|
return;
|
|
407
429
|
}
|
|
408
|
-
|
|
409
430
|
if (callback)
|
|
410
431
|
callback(undefined, ret);
|
|
411
432
|
}
|
|
412
|
-
|
|
413
433
|
if (process.env.FIREBIRD_DEBUG) {
|
|
414
434
|
console.log('[fb-debug] auth: op_connect sent plugin=%s t=%dms', pluginName, Date.now() - this._authStartTime);
|
|
415
435
|
}
|
|
416
436
|
this._queueEvent(cb);
|
|
417
437
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
438
|
attach(options, callback, db) {
|
|
421
|
-
this._lowercase_keys = options.lowercase_keys ||
|
|
422
|
-
|
|
439
|
+
this._lowercase_keys = options.lowercase_keys || const_1.default.DEFAULT_LOWERCASE_KEYS;
|
|
423
440
|
var database = options.database || options.filename;
|
|
424
441
|
if (database == null || database.length === 0) {
|
|
425
|
-
doError(new Error('No database specified'), callback);
|
|
442
|
+
(0, callback_1.doError)(new Error('No database specified'), callback);
|
|
426
443
|
return;
|
|
427
444
|
}
|
|
428
|
-
|
|
429
|
-
var
|
|
430
|
-
var password = options.password || Const.DEFAULT_PASSWORD;
|
|
445
|
+
var user = options.user || const_1.default.DEFAULT_USER;
|
|
446
|
+
var password = options.password || const_1.default.DEFAULT_PASSWORD;
|
|
431
447
|
var role = options.role;
|
|
432
448
|
var self = this;
|
|
433
449
|
var msg = this._msg;
|
|
434
450
|
var blr = this._blr;
|
|
435
451
|
msg.pos = 0;
|
|
436
452
|
blr.pos = 0;
|
|
437
|
-
|
|
438
|
-
blr.
|
|
439
|
-
blr.addString(Const.isc_dpb_lc_ctype, options.encoding || 'UTF8', Const.DEFAULT_ENCODING);
|
|
440
|
-
|
|
453
|
+
blr.addByte(const_1.default.isc_dpb_version1);
|
|
454
|
+
blr.addString(const_1.default.isc_dpb_lc_ctype, options.encoding || 'UTF8', const_1.default.DEFAULT_ENCODING);
|
|
441
455
|
// For Firebird 3+ (protocol 13+), add UTF-8 filename flag to ensure all DPB strings are handled with UTF-8
|
|
442
|
-
if (this.accept.protocolVersion >=
|
|
443
|
-
blr.addByte(
|
|
456
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION13) {
|
|
457
|
+
blr.addByte(const_1.default.isc_dpb_utf8_filename);
|
|
444
458
|
blr.addByte(0);
|
|
445
459
|
}
|
|
446
|
-
|
|
447
|
-
blr.addString(Const.isc_dpb_user_name, user, Const.DEFAULT_ENCODING);
|
|
460
|
+
blr.addString(const_1.default.isc_dpb_user_name, user, const_1.default.DEFAULT_ENCODING);
|
|
448
461
|
if (options.password && !this.accept.authData) {
|
|
449
|
-
if (this.accept.protocolVersion <
|
|
450
|
-
if (this.accept.protocolVersion ===
|
|
451
|
-
blr.addString(
|
|
452
|
-
}
|
|
453
|
-
|
|
462
|
+
if (this.accept.protocolVersion < const_1.default.PROTOCOL_VERSION13) {
|
|
463
|
+
if (this.accept.protocolVersion === const_1.default.PROTOCOL_VERSION10) {
|
|
464
|
+
blr.addString(const_1.default.isc_dpb_password, password, const_1.default.DEFAULT_ENCODING);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
blr.addString(const_1.default.isc_dpb_password_enc, crypt.crypt(password, const_1.default.LEGACY_AUTH_SALT).substring(2), const_1.default.DEFAULT_ENCODING);
|
|
454
468
|
}
|
|
455
469
|
}
|
|
456
470
|
}
|
|
457
|
-
|
|
458
471
|
if (role)
|
|
459
|
-
blr.addString(
|
|
460
|
-
|
|
461
|
-
blr.addBytes([Const.isc_dpb_process_id, 4]);
|
|
472
|
+
blr.addString(const_1.default.isc_dpb_sql_role_name, role, const_1.default.DEFAULT_ENCODING);
|
|
473
|
+
blr.addBytes([const_1.default.isc_dpb_process_id, 4]);
|
|
462
474
|
blr.addInt32(process.pid);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
blr.addString(Const.isc_dpb_process_name, processName.length > 255 ? processName.substring(processName.length - 255, processName.length) : processName, Const.DEFAULT_ENCODING);
|
|
466
|
-
|
|
475
|
+
let processName = process.title || "";
|
|
476
|
+
blr.addString(const_1.default.isc_dpb_process_name, processName.length > 255 ? processName.substring(processName.length - 255, processName.length) : processName, const_1.default.DEFAULT_ENCODING);
|
|
467
477
|
if (this.accept.authData) {
|
|
468
|
-
blr.addString(
|
|
478
|
+
blr.addString(const_1.default.isc_dpb_specific_auth_data, this.accept.authData, const_1.default.DEFAULT_ENCODING);
|
|
469
479
|
}
|
|
470
|
-
|
|
471
480
|
if (options.sessionTimeZone) {
|
|
472
|
-
blr.addString(
|
|
481
|
+
blr.addString(const_1.default.isc_dpb_session_time_zone, options.sessionTimeZone, const_1.default.DEFAULT_ENCODING);
|
|
473
482
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
483
|
+
if (options.parallelWorkers !== undefined) {
|
|
484
|
+
blr.addNumeric(const_1.default.isc_dpb_parallel_workers, options.parallelWorkers);
|
|
485
|
+
}
|
|
486
|
+
if (options.maxInlineBlobSize !== undefined) {
|
|
487
|
+
blr.addNumeric(const_1.default.isc_dpb_max_inline_blob_size, options.maxInlineBlobSize);
|
|
488
|
+
}
|
|
489
|
+
// Firebird 6.0 SQL Schema parameters (Protocol 20+).
|
|
490
|
+
// These DPB tags configure the session's current schema and the
|
|
491
|
+
// schema search path for unqualified object name resolution.
|
|
492
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION20) {
|
|
493
|
+
if (options.defaultSchema) {
|
|
494
|
+
// Sets CURRENT_SCHEMA for the session. Equivalent to issuing
|
|
495
|
+
// SET SCHEMA <name> immediately after connecting.
|
|
496
|
+
blr.addString(const_1.default.isc_dpb_default_schema, options.defaultSchema, const_1.default.DEFAULT_ENCODING);
|
|
497
|
+
}
|
|
498
|
+
if (options.searchPath) {
|
|
499
|
+
// Comma-separated ordered schema name list, like PostgreSQL's
|
|
500
|
+
// search_path. Unqualified object references are resolved by
|
|
501
|
+
// scanning schemas in this order.
|
|
502
|
+
const sp = Array.isArray(options.searchPath)
|
|
503
|
+
? options.searchPath.join(',')
|
|
504
|
+
: String(options.searchPath);
|
|
505
|
+
blr.addString(const_1.default.isc_dpb_search_path, sp, const_1.default.DEFAULT_ENCODING);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
msg.addInt(const_1.default.op_attach);
|
|
509
|
+
msg.addInt(0); // Database Object ID
|
|
510
|
+
msg.addString(database, const_1.default.DEFAULT_ENCODING);
|
|
478
511
|
msg.addBlr(this._blr);
|
|
479
|
-
|
|
480
512
|
function cb(err, ret) {
|
|
481
513
|
if (err) {
|
|
482
|
-
doError(err, callback);
|
|
514
|
+
(0, callback_1.doError)(err, callback);
|
|
483
515
|
return;
|
|
484
516
|
}
|
|
485
|
-
|
|
486
517
|
self.dbhandle = ret.handle;
|
|
487
518
|
if (callback)
|
|
488
519
|
callback(undefined, ret);
|
|
489
520
|
if (!db)
|
|
490
521
|
ret.emit('attach', ret);
|
|
491
522
|
}
|
|
492
|
-
|
|
493
523
|
// For reconnect
|
|
494
524
|
if (db) {
|
|
495
525
|
db.connection = this;
|
|
496
526
|
cb.response = db;
|
|
497
|
-
}
|
|
498
|
-
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
cb.response = new database_1.default(this);
|
|
499
530
|
cb.response.removeAllListeners('error');
|
|
500
|
-
cb.response.on('error', noop);
|
|
531
|
+
cb.response.on('error', utils_1.noop);
|
|
501
532
|
}
|
|
502
|
-
|
|
503
533
|
this._queueEvent(cb);
|
|
504
534
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
535
|
detach(callback) {
|
|
508
|
-
|
|
509
536
|
var self = this;
|
|
510
|
-
|
|
511
537
|
if (self._isClosed)
|
|
512
|
-
return;
|
|
513
|
-
|
|
538
|
+
return this.throwClosed(callback);
|
|
514
539
|
self._isUsed = false;
|
|
515
540
|
self._isDetach = true;
|
|
516
|
-
|
|
517
541
|
var msg = self._msg;
|
|
518
|
-
|
|
519
542
|
msg.pos = 0;
|
|
520
|
-
msg.addInt(
|
|
543
|
+
msg.addInt(const_1.default.op_detach);
|
|
521
544
|
msg.addInt(0); // Database Object ID
|
|
522
|
-
|
|
523
|
-
self._queueEvent(function(err, ret) {
|
|
545
|
+
self._queueEvent(function (err, ret) {
|
|
524
546
|
clearTimeout(self._retry_connection_id);
|
|
525
|
-
delete(self.dbhandle);
|
|
547
|
+
delete (self.dbhandle);
|
|
526
548
|
if (callback)
|
|
527
549
|
callback(err, ret);
|
|
528
550
|
});
|
|
529
551
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
552
|
createDatabase(options, callback) {
|
|
553
|
+
// Mirror attach(): honour the lowercase_keys option so that db.query()
|
|
554
|
+
// called on a freshly-created database returns the expected column case.
|
|
555
|
+
this._lowercase_keys = options.lowercase_keys || const_1.default.DEFAULT_LOWERCASE_KEYS;
|
|
533
556
|
var database = options.database || options.filename;
|
|
534
557
|
if (database == null || database.length === 0) {
|
|
535
|
-
doError(new Error('No database specified'), callback);
|
|
558
|
+
(0, callback_1.doError)(new Error('No database specified'), callback);
|
|
536
559
|
return;
|
|
537
560
|
}
|
|
538
|
-
|
|
539
|
-
var
|
|
540
|
-
var
|
|
541
|
-
var pageSize = options.pageSize || Const.DEFAULT_PAGE_SIZE;
|
|
561
|
+
var user = options.user || const_1.default.DEFAULT_USER;
|
|
562
|
+
var password = options.password || const_1.default.DEFAULT_PASSWORD;
|
|
563
|
+
var pageSize = options.pageSize || const_1.default.DEFAULT_PAGE_SIZE;
|
|
542
564
|
var role = options.role;
|
|
543
565
|
var blr = this._blr;
|
|
544
|
-
|
|
545
566
|
blr.pos = 0;
|
|
546
|
-
blr.addByte(
|
|
547
|
-
blr.addString(
|
|
548
|
-
blr.addString(
|
|
549
|
-
|
|
567
|
+
blr.addByte(const_1.default.isc_dpb_version1);
|
|
568
|
+
blr.addString(const_1.default.isc_dpb_set_db_charset, 'UTF8', const_1.default.DEFAULT_ENCODING);
|
|
569
|
+
blr.addString(const_1.default.isc_dpb_lc_ctype, 'UTF8', const_1.default.DEFAULT_ENCODING);
|
|
550
570
|
// For Firebird 3+ (protocol 13+), add UTF-8 filename flag to ensure all DPB strings are handled with UTF-8
|
|
551
|
-
if (this.accept.protocolVersion >=
|
|
552
|
-
blr.addByte(
|
|
571
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION13) {
|
|
572
|
+
blr.addByte(const_1.default.isc_dpb_utf8_filename);
|
|
553
573
|
blr.addByte(0);
|
|
554
574
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
blr.addString(
|
|
575
|
+
blr.addString(const_1.default.isc_dpb_user_name, user, const_1.default.DEFAULT_ENCODING);
|
|
576
|
+
if (this.accept.protocolVersion < const_1.default.PROTOCOL_VERSION13) {
|
|
577
|
+
if (this.accept.protocolVersion === const_1.default.PROTOCOL_VERSION10) {
|
|
578
|
+
blr.addString(const_1.default.isc_dpb_password, password, const_1.default.DEFAULT_ENCODING);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
blr.addString(const_1.default.isc_dpb_password_enc, crypt.crypt(password, const_1.default.LEGACY_AUTH_SALT).substring(2), const_1.default.DEFAULT_ENCODING);
|
|
562
582
|
}
|
|
563
583
|
}
|
|
564
584
|
if (role)
|
|
565
|
-
blr.addString(
|
|
566
|
-
|
|
567
|
-
blr.addBytes([Const.isc_dpb_process_id, 4]);
|
|
585
|
+
blr.addString(const_1.default.isc_dpb_sql_role_name, role, const_1.default.DEFAULT_ENCODING);
|
|
586
|
+
blr.addBytes([const_1.default.isc_dpb_process_id, 4]);
|
|
568
587
|
blr.addInt32(process.pid);
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
blr.addString(Const.isc_dpb_process_name, processName.length > 255 ? processName.substring(processName.length - 255, processName.length) : processName, Const.DEFAULT_ENCODING);
|
|
572
|
-
|
|
588
|
+
let processName = process.title || "";
|
|
589
|
+
blr.addString(const_1.default.isc_dpb_process_name, processName.length > 255 ? processName.substring(processName.length - 255, processName.length) : processName, const_1.default.DEFAULT_ENCODING);
|
|
573
590
|
if (this.accept.authData) {
|
|
574
|
-
blr.addString(
|
|
591
|
+
blr.addString(const_1.default.isc_dpb_specific_auth_data, this.accept.authData, const_1.default.DEFAULT_ENCODING);
|
|
575
592
|
}
|
|
576
|
-
|
|
577
593
|
if (options.sessionTimeZone) {
|
|
578
|
-
blr.addString(
|
|
594
|
+
blr.addString(const_1.default.isc_dpb_session_time_zone, options.sessionTimeZone, const_1.default.DEFAULT_ENCODING);
|
|
579
595
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
596
|
+
if (options.parallelWorkers !== undefined) {
|
|
597
|
+
blr.addNumeric(const_1.default.isc_dpb_parallel_workers, options.parallelWorkers);
|
|
598
|
+
}
|
|
599
|
+
if (options.maxInlineBlobSize !== undefined) {
|
|
600
|
+
blr.addNumeric(const_1.default.isc_dpb_max_inline_blob_size, options.maxInlineBlobSize);
|
|
601
|
+
}
|
|
602
|
+
// Firebird 6.0 SQL Schema parameters (Protocol 20+).
|
|
603
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION20) {
|
|
604
|
+
if (options.defaultSchema) {
|
|
605
|
+
blr.addString(const_1.default.isc_dpb_default_schema, options.defaultSchema, const_1.default.DEFAULT_ENCODING);
|
|
606
|
+
}
|
|
607
|
+
if (options.searchPath) {
|
|
608
|
+
const sp = Array.isArray(options.searchPath)
|
|
609
|
+
? options.searchPath.join(',')
|
|
610
|
+
: String(options.searchPath);
|
|
611
|
+
blr.addString(const_1.default.isc_dpb_search_path, sp, const_1.default.DEFAULT_ENCODING);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
blr.addNumeric(const_1.default.isc_dpb_sql_dialect, 3);
|
|
615
|
+
blr.addNumeric(const_1.default.isc_dpb_force_write, 1);
|
|
616
|
+
blr.addNumeric(const_1.default.isc_dpb_overwrite, 1);
|
|
617
|
+
blr.addNumeric(const_1.default.isc_dpb_page_size, pageSize);
|
|
586
618
|
var msg = this._msg;
|
|
587
619
|
msg.pos = 0;
|
|
588
|
-
msg.addInt(
|
|
589
|
-
msg.addInt(0);
|
|
590
|
-
msg.addString(database,
|
|
620
|
+
msg.addInt(const_1.default.op_create); // op_create
|
|
621
|
+
msg.addInt(0); // Database Object ID
|
|
622
|
+
msg.addString(database, const_1.default.DEFAULT_ENCODING);
|
|
591
623
|
msg.addBlr(blr);
|
|
592
|
-
|
|
593
624
|
var self = this;
|
|
594
|
-
|
|
595
625
|
function cb(err, ret) {
|
|
596
|
-
|
|
597
626
|
if (ret)
|
|
598
627
|
self.dbhandle = ret.handle;
|
|
599
|
-
|
|
600
628
|
if (callback)
|
|
601
629
|
callback(err, ret);
|
|
602
|
-
|
|
603
630
|
if (!err && ret)
|
|
604
631
|
ret.emit('attach', ret);
|
|
605
632
|
}
|
|
606
|
-
|
|
607
|
-
cb.response = new Database(this);
|
|
633
|
+
cb.response = new database_1.default(this);
|
|
608
634
|
this._queueEvent(cb);
|
|
609
635
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
636
|
dropDatabase(callback) {
|
|
613
637
|
var msg = this._msg;
|
|
614
638
|
msg.pos = 0;
|
|
615
|
-
|
|
616
|
-
msg.addInt(Const.op_drop_database);
|
|
639
|
+
msg.addInt(const_1.default.op_drop_database);
|
|
617
640
|
msg.addInt(this.dbhandle);
|
|
618
|
-
|
|
619
641
|
var self = this;
|
|
620
|
-
this._queueEvent(function(err) {
|
|
621
|
-
self.detach(function() {
|
|
642
|
+
this._queueEvent(function (err) {
|
|
643
|
+
self.detach(function () {
|
|
622
644
|
self.disconnect();
|
|
623
|
-
|
|
624
645
|
if (callback)
|
|
625
646
|
callback(err);
|
|
626
647
|
});
|
|
627
648
|
});
|
|
628
649
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
650
|
throwClosed(callback) {
|
|
632
651
|
var err = new Error('Connection is closed.');
|
|
633
652
|
this.db.emit('error', err);
|
|
@@ -635,68 +654,58 @@ class Connection {
|
|
|
635
654
|
callback(err);
|
|
636
655
|
return this;
|
|
637
656
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
657
|
startTransaction(options, callback) {
|
|
641
|
-
|
|
642
|
-
if (typeof(options) === 'function') {
|
|
658
|
+
if (typeof (options) === 'function') {
|
|
643
659
|
var tmp = options;
|
|
644
660
|
options = callback;
|
|
645
661
|
callback = tmp;
|
|
646
662
|
}
|
|
647
|
-
|
|
648
663
|
// Compatibility
|
|
649
664
|
if (Array.isArray(options)) {
|
|
650
665
|
options = {
|
|
651
666
|
isolation: options,
|
|
652
|
-
readOnly: (options ===
|
|
667
|
+
readOnly: (options === const_1.default.ISOLATION_READ_COMMITTED_READ_ONLY),
|
|
653
668
|
};
|
|
654
669
|
}
|
|
655
|
-
|
|
656
670
|
// Default options
|
|
657
671
|
options = Object.assign({
|
|
658
672
|
autoCommit: false,
|
|
659
673
|
autoUndo: true,
|
|
660
|
-
isolation:
|
|
674
|
+
isolation: const_1.default.ISOLATION_READ_COMMITTED,
|
|
661
675
|
ignoreLimbo: false,
|
|
662
676
|
//lock: [],
|
|
663
677
|
readOnly: false,
|
|
664
678
|
wait: true,
|
|
665
679
|
waitTimeout: 0,
|
|
666
680
|
}, options);
|
|
667
|
-
|
|
668
681
|
if (this._isClosed)
|
|
669
682
|
return this.throwClosed(callback);
|
|
670
|
-
|
|
671
683
|
// for auto detach
|
|
672
684
|
this._pending.push('startTransaction');
|
|
673
|
-
|
|
674
685
|
var blr = this._blr;
|
|
675
686
|
var msg = this._msg;
|
|
676
|
-
|
|
677
687
|
blr.pos = 0;
|
|
678
688
|
msg.pos = 0;
|
|
679
|
-
|
|
680
|
-
blr.addByte(Const.isc_tpb_version3);
|
|
689
|
+
blr.addByte(const_1.default.isc_tpb_version3);
|
|
681
690
|
blr.addBytes(options.isolation);
|
|
682
|
-
blr.addByte(options.readOnly ?
|
|
691
|
+
blr.addByte(options.readOnly ? const_1.default.isc_tpb_read : const_1.default.isc_tpb_write);
|
|
683
692
|
if (options.wait) {
|
|
684
|
-
blr.addByte(
|
|
685
|
-
|
|
693
|
+
blr.addByte(const_1.default.isc_tpb_wait);
|
|
686
694
|
if (options.waitTimeout) {
|
|
687
|
-
blr.addNumeric(
|
|
695
|
+
blr.addNumeric(const_1.default.isc_tpb_lock_timeout, options.waitTimeout);
|
|
688
696
|
}
|
|
689
|
-
}
|
|
690
|
-
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
blr.addByte(const_1.default.isc_tpb_nowait);
|
|
691
700
|
}
|
|
692
701
|
if (!options.autoUndo) {
|
|
693
|
-
blr.addByte(
|
|
702
|
+
blr.addByte(const_1.default.isc_tpb_no_auto_undo);
|
|
694
703
|
}
|
|
695
704
|
if (options.autoCommit) {
|
|
696
|
-
blr.addByte(
|
|
705
|
+
blr.addByte(const_1.default.isc_tpb_autocommit);
|
|
697
706
|
}
|
|
698
707
|
if (options.ignoreLimbo) {
|
|
699
|
-
blr.addByte(
|
|
708
|
+
blr.addByte(const_1.default.isc_tpb_ignore_limbo);
|
|
700
709
|
}
|
|
701
710
|
// TODO
|
|
702
711
|
/*if (options.lock.length) {
|
|
@@ -708,139 +717,98 @@ class Connection {
|
|
|
708
717
|
blr.addByte(lockType);
|
|
709
718
|
}
|
|
710
719
|
}*/
|
|
711
|
-
|
|
712
|
-
msg.addInt(Const.op_transaction);
|
|
720
|
+
msg.addInt(const_1.default.op_transaction);
|
|
713
721
|
msg.addInt(this.dbhandle);
|
|
714
722
|
msg.addBlr(blr);
|
|
715
|
-
callback.response = new
|
|
716
|
-
|
|
723
|
+
callback.response = new transaction_1.default(this);
|
|
717
724
|
this.db.emit('transaction', options);
|
|
718
725
|
this._queueEvent(callback);
|
|
719
726
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
727
|
commit(transaction, callback) {
|
|
723
|
-
|
|
724
728
|
if (this._isClosed)
|
|
725
729
|
return this.throwClosed(callback);
|
|
726
|
-
|
|
727
730
|
// for auto detach
|
|
728
731
|
this._pending.push('commit');
|
|
729
|
-
|
|
730
732
|
var msg = this._msg;
|
|
731
733
|
msg.pos = 0;
|
|
732
|
-
msg.addInt(
|
|
734
|
+
msg.addInt(const_1.default.op_commit);
|
|
733
735
|
msg.addInt(transaction.handle);
|
|
734
736
|
this.db.emit('commit');
|
|
735
737
|
this._queueEvent(callback);
|
|
736
738
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
739
|
rollback(transaction, callback) {
|
|
740
|
-
|
|
741
740
|
if (this._isClosed)
|
|
742
741
|
return this.throwClosed(callback);
|
|
743
|
-
|
|
744
742
|
// for auto detach
|
|
745
743
|
this._pending.push('rollback');
|
|
746
|
-
|
|
747
744
|
var msg = this._msg;
|
|
748
745
|
msg.pos = 0;
|
|
749
|
-
msg.addInt(
|
|
746
|
+
msg.addInt(const_1.default.op_rollback);
|
|
750
747
|
msg.addInt(transaction.handle);
|
|
751
748
|
this.db.emit('rollback');
|
|
752
749
|
this._queueEvent(callback);
|
|
753
750
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
751
|
commitRetaining(transaction, callback) {
|
|
757
|
-
|
|
758
752
|
if (this._isClosed)
|
|
759
|
-
|
|
760
|
-
|
|
753
|
+
return this.throwClosed(callback);
|
|
761
754
|
// for auto detach
|
|
762
755
|
this._pending.push('commitRetaining');
|
|
763
|
-
|
|
764
756
|
var msg = this._msg;
|
|
765
757
|
msg.pos = 0;
|
|
766
|
-
msg.addInt(
|
|
758
|
+
msg.addInt(const_1.default.op_commit_retaining);
|
|
767
759
|
msg.addInt(transaction.handle);
|
|
768
760
|
this._queueEvent(callback);
|
|
769
761
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
762
|
rollbackRetaining(transaction, callback) {
|
|
773
|
-
|
|
774
763
|
if (this._isClosed)
|
|
775
764
|
return this.throwClosed(callback);
|
|
776
|
-
|
|
777
765
|
// for auto detach
|
|
778
766
|
this._pending.push('rollbackRetaining');
|
|
779
|
-
|
|
780
767
|
var msg = this._msg;
|
|
781
768
|
msg.pos = 0;
|
|
782
|
-
msg.addInt(
|
|
769
|
+
msg.addInt(const_1.default.op_rollback_retaining);
|
|
783
770
|
msg.addInt(transaction.handle);
|
|
784
771
|
this._queueEvent(callback);
|
|
785
772
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
773
|
allocateStatement(callback) {
|
|
789
|
-
|
|
790
774
|
if (this._isClosed)
|
|
791
775
|
return this.throwClosed(callback);
|
|
792
|
-
|
|
793
776
|
// for auto detach
|
|
794
777
|
this._pending.push('allocateStatement');
|
|
795
|
-
|
|
796
778
|
var msg = this._msg;
|
|
797
779
|
msg.pos = 0;
|
|
798
|
-
msg.addInt(
|
|
780
|
+
msg.addInt(const_1.default.op_allocate_statement);
|
|
799
781
|
msg.addInt(this.dbhandle);
|
|
800
|
-
callback.response = new
|
|
782
|
+
callback.response = new statement_1.default(this);
|
|
801
783
|
this._queueEvent(callback);
|
|
802
784
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
785
|
dropStatement(statement, callback) {
|
|
806
|
-
|
|
807
786
|
if (this._isClosed)
|
|
808
787
|
return this.throwClosed(callback);
|
|
809
|
-
|
|
810
788
|
// for auto detach
|
|
811
789
|
this._pending.push('dropStatement');
|
|
812
|
-
|
|
813
790
|
var msg = this._msg;
|
|
814
791
|
msg.pos = 0;
|
|
815
|
-
msg.addInt(
|
|
792
|
+
msg.addInt(const_1.default.op_free_statement);
|
|
816
793
|
msg.addInt(statement.handle);
|
|
817
|
-
msg.addInt(
|
|
818
|
-
|
|
794
|
+
msg.addInt(const_1.default.DSQL_drop);
|
|
819
795
|
this._queueEvent(callback, true);
|
|
820
796
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
797
|
closeStatement(statement, callback) {
|
|
824
|
-
|
|
825
798
|
if (this._isClosed)
|
|
826
799
|
return this.throwClosed(callback);
|
|
827
|
-
|
|
828
800
|
// for auto detach
|
|
829
801
|
this._pending.push('closeStatement');
|
|
830
|
-
|
|
831
802
|
var msg = this._msg;
|
|
832
803
|
msg.pos = 0;
|
|
833
|
-
msg.addInt(
|
|
804
|
+
msg.addInt(const_1.default.op_free_statement);
|
|
834
805
|
msg.addInt(statement.handle);
|
|
835
|
-
msg.addInt(
|
|
836
|
-
|
|
806
|
+
msg.addInt(const_1.default.DSQL_close);
|
|
837
807
|
this._queueEvent(callback, true);
|
|
838
808
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
809
|
allocateAndPrepareStatement(transaction, query, plan, callback) {
|
|
842
810
|
var self = this;
|
|
843
|
-
var mainCallback = function(err, ret) {
|
|
811
|
+
var mainCallback = function (err, ret) {
|
|
844
812
|
if (!err) {
|
|
845
813
|
mainCallback.response.handle = ret.handle;
|
|
846
814
|
describe(ret.buffer, mainCallback.response);
|
|
@@ -849,93 +817,75 @@ class Connection {
|
|
|
849
817
|
ret = mainCallback.response;
|
|
850
818
|
self._setcachedquery(query, ret);
|
|
851
819
|
}
|
|
852
|
-
|
|
853
820
|
if (callback)
|
|
854
821
|
callback(err, ret);
|
|
855
822
|
};
|
|
856
|
-
|
|
857
823
|
// for auto detach
|
|
858
824
|
this._pending.push('allocateAndPrepareStatement');
|
|
859
|
-
|
|
860
825
|
var msg = this._msg;
|
|
861
826
|
var blr = this._blr;
|
|
862
|
-
|
|
863
827
|
msg.pos = 0;
|
|
864
828
|
blr.pos = 0;
|
|
865
|
-
|
|
866
|
-
msg.addInt(Const.op_allocate_statement);
|
|
829
|
+
msg.addInt(const_1.default.op_allocate_statement);
|
|
867
830
|
msg.addInt(this.dbhandle);
|
|
868
831
|
mainCallback.lazy_count = 1;
|
|
869
|
-
|
|
870
|
-
|
|
832
|
+
const describeBytes = this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION20 ? const_1.default.DESCRIBE_WITH_SCHEMA : const_1.default.DESCRIBE;
|
|
833
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
834
|
+
console.log('[fb-debug] describeBytes:', describeBytes);
|
|
835
|
+
}
|
|
836
|
+
blr.addBytes(describeBytes);
|
|
871
837
|
if (plan)
|
|
872
|
-
blr.addByte(
|
|
873
|
-
|
|
874
|
-
msg.addInt(Const.op_prepare_statement);
|
|
838
|
+
blr.addByte(const_1.default.isc_info_sql_get_plan);
|
|
839
|
+
msg.addInt(const_1.default.op_prepare_statement);
|
|
875
840
|
msg.addInt(transaction.handle);
|
|
876
841
|
msg.addInt(0xFFFF);
|
|
877
842
|
msg.addInt(3); // dialect = 3
|
|
878
|
-
msg.addString(query,
|
|
843
|
+
msg.addString(query, const_1.default.DEFAULT_ENCODING);
|
|
879
844
|
msg.addBlr(blr);
|
|
880
845
|
msg.addInt(65535); // buffer_length
|
|
881
846
|
mainCallback.lazy_count += 1;
|
|
882
|
-
|
|
883
|
-
mainCallback.response = new Statement(this);
|
|
847
|
+
mainCallback.response = new statement_1.default(this);
|
|
884
848
|
this._queueEvent(mainCallback);
|
|
885
849
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
850
|
prepare(transaction, query, plan, callback) {
|
|
889
851
|
var self = this;
|
|
890
|
-
|
|
891
|
-
if (this.accept.protocolMinimumType === Const.ptype_lazy_send) { // V11 Statement or higher
|
|
852
|
+
if (this.accept.protocolMinimumType === const_1.default.ptype_lazy_send) { // V11 Statement or higher
|
|
892
853
|
self.allocateAndPrepareStatement(transaction, query, plan, callback);
|
|
893
|
-
}
|
|
854
|
+
}
|
|
855
|
+
else { // V10 Statement
|
|
894
856
|
self.allocateStatement(function (err, statement) {
|
|
895
857
|
if (err) {
|
|
896
|
-
doError(err, callback);
|
|
858
|
+
(0, callback_1.doError)(err, callback);
|
|
897
859
|
return;
|
|
898
860
|
}
|
|
899
|
-
|
|
900
861
|
self.prepareStatement(transaction, statement, query, plan, callback);
|
|
901
862
|
});
|
|
902
863
|
}
|
|
903
864
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
865
|
prepareStatement(transaction, statement, query, plan, callback) {
|
|
908
|
-
|
|
909
866
|
if (this._isClosed)
|
|
910
867
|
return this.throwClosed(callback);
|
|
911
|
-
|
|
912
868
|
var msg = this._msg;
|
|
913
869
|
var blr = this._blr;
|
|
914
|
-
|
|
915
870
|
msg.pos = 0;
|
|
916
871
|
blr.pos = 0;
|
|
917
|
-
|
|
918
872
|
if (plan instanceof Function) {
|
|
919
873
|
callback = plan;
|
|
920
874
|
plan = false;
|
|
921
875
|
}
|
|
922
|
-
|
|
923
|
-
blr.addBytes(
|
|
924
|
-
|
|
876
|
+
const describeBytes = this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION20 ? const_1.default.DESCRIBE_WITH_SCHEMA : const_1.default.DESCRIBE;
|
|
877
|
+
blr.addBytes(describeBytes);
|
|
925
878
|
if (plan)
|
|
926
|
-
blr.addByte(
|
|
927
|
-
|
|
928
|
-
msg.addInt(Const.op_prepare_statement);
|
|
879
|
+
blr.addByte(const_1.default.isc_info_sql_get_plan);
|
|
880
|
+
msg.addInt(const_1.default.op_prepare_statement);
|
|
929
881
|
msg.addInt(transaction.handle);
|
|
930
882
|
msg.addInt(statement.handle);
|
|
931
883
|
msg.addInt(3); // dialect = 3
|
|
932
|
-
msg.addString(query,
|
|
884
|
+
msg.addString(query, const_1.default.DEFAULT_ENCODING);
|
|
933
885
|
msg.addBlr(blr);
|
|
934
886
|
msg.addInt(65535); // buffer_length
|
|
935
|
-
|
|
936
887
|
var self = this;
|
|
937
|
-
this._queueEvent(function(err, ret) {
|
|
938
|
-
|
|
888
|
+
this._queueEvent(function (err, ret) {
|
|
939
889
|
if (!err) {
|
|
940
890
|
describe(ret.buffer, statement);
|
|
941
891
|
statement.query = query;
|
|
@@ -943,75 +893,53 @@ class Connection {
|
|
|
943
893
|
ret = statement;
|
|
944
894
|
self._setcachedquery(query, ret);
|
|
945
895
|
}
|
|
946
|
-
|
|
947
896
|
if (callback)
|
|
948
897
|
callback(err, ret);
|
|
949
898
|
});
|
|
950
|
-
|
|
951
899
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
900
|
executeStatement(transaction, statement, params, callback, custom) {
|
|
956
|
-
|
|
957
901
|
if (this._isClosed)
|
|
958
902
|
return this.throwClosed(callback);
|
|
959
|
-
|
|
960
903
|
// for auto detach
|
|
961
904
|
this._pending.push('executeStatement');
|
|
962
|
-
|
|
963
905
|
if (params instanceof Function) {
|
|
964
906
|
callback = params;
|
|
965
907
|
params = undefined;
|
|
966
908
|
}
|
|
967
|
-
|
|
968
909
|
var self = this;
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
statement.output.length
|
|
975
|
-
) {
|
|
976
|
-
op = Const.op_execute2;
|
|
910
|
+
var op = const_1.default.op_execute;
|
|
911
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION13 &&
|
|
912
|
+
statement.type === const_1.default.isc_info_sql_stmt_exec_procedure &&
|
|
913
|
+
statement.output.length) {
|
|
914
|
+
op = const_1.default.op_execute2;
|
|
977
915
|
}
|
|
978
|
-
|
|
979
916
|
function PrepareParams(params, input, callback) {
|
|
980
|
-
|
|
981
917
|
var value, meta;
|
|
982
918
|
var ret = new Array(params.length);
|
|
983
|
-
|
|
984
919
|
function putBlobData(index, value, callback) {
|
|
985
|
-
|
|
986
|
-
self.createBlob2(transaction, function(err, blob) {
|
|
987
|
-
|
|
920
|
+
self.createBlob2(transaction, function (err, blob) {
|
|
988
921
|
var b;
|
|
989
922
|
var isStream = value.readable;
|
|
990
|
-
|
|
991
923
|
if (Buffer.isBuffer(value))
|
|
992
924
|
b = value;
|
|
993
|
-
else if (typeof(value) === 'string')
|
|
994
|
-
b = Buffer.from(value,
|
|
925
|
+
else if (typeof (value) === 'string')
|
|
926
|
+
b = Buffer.from(value, const_1.default.DEFAULT_ENCODING);
|
|
995
927
|
else if (!isStream)
|
|
996
|
-
b = Buffer.from(JSON.stringify(value),
|
|
997
|
-
|
|
928
|
+
b = Buffer.from(JSON.stringify(value), const_1.default.DEFAULT_ENCODING);
|
|
998
929
|
// Use configured transfer size or default to 1024
|
|
999
930
|
var chunkSize = self.options.blobChunkSize || 1024;
|
|
1000
|
-
|
|
1001
931
|
if (Buffer.isBuffer(b)) {
|
|
1002
932
|
bufferReader(b, chunkSize, function (b, next) {
|
|
1003
933
|
self.batchSegments(blob, b, next);
|
|
1004
|
-
}, function() {
|
|
934
|
+
}, function () {
|
|
1005
935
|
ret[index] = new Xsql.SQLParamQuad(blob.oid);
|
|
1006
936
|
self.closeBlob(blob, callback, false);
|
|
1007
937
|
});
|
|
1008
938
|
return;
|
|
1009
939
|
}
|
|
1010
|
-
|
|
1011
940
|
var isReading = false;
|
|
1012
941
|
var isEnd = false;
|
|
1013
|
-
|
|
1014
|
-
value.on('data', function(chunk) {
|
|
942
|
+
value.on('data', function (chunk) {
|
|
1015
943
|
// Optimization: If chunk is smaller than transfer size, send directly
|
|
1016
944
|
if (chunk.length <= chunkSize) {
|
|
1017
945
|
self.batchSegments(blob, chunk, function () {
|
|
@@ -1022,23 +950,21 @@ class Connection {
|
|
|
1022
950
|
});
|
|
1023
951
|
return;
|
|
1024
952
|
}
|
|
1025
|
-
|
|
1026
953
|
value.pause();
|
|
1027
954
|
isReading = true;
|
|
1028
955
|
bufferReader(chunk, chunkSize, function (b, next) {
|
|
1029
956
|
self.batchSegments(blob, b, next);
|
|
1030
|
-
}, function() {
|
|
957
|
+
}, function () {
|
|
1031
958
|
isReading = false;
|
|
1032
|
-
|
|
1033
959
|
if (isEnd) {
|
|
1034
960
|
ret[index] = new Xsql.SQLParamQuad(blob.oid);
|
|
1035
961
|
self.closeBlob(blob, callback, false);
|
|
1036
|
-
}
|
|
962
|
+
}
|
|
963
|
+
else
|
|
1037
964
|
value.resume();
|
|
1038
965
|
});
|
|
1039
966
|
});
|
|
1040
|
-
|
|
1041
|
-
value.on('end', function() {
|
|
967
|
+
value.on('end', function () {
|
|
1042
968
|
isEnd = true;
|
|
1043
969
|
if (isReading)
|
|
1044
970
|
return;
|
|
@@ -1051,164 +977,186 @@ class Connection {
|
|
|
1051
977
|
});
|
|
1052
978
|
});
|
|
1053
979
|
}
|
|
1054
|
-
|
|
1055
980
|
function step(i) {
|
|
1056
981
|
if (i === params.length) {
|
|
1057
982
|
callback(ret);
|
|
1058
983
|
return;
|
|
1059
984
|
}
|
|
1060
|
-
|
|
1061
985
|
value = params[i];
|
|
1062
986
|
meta = input[i];
|
|
1063
|
-
|
|
987
|
+
if (statement.connection.options && statement.connection.options.jsonAsObject && value !== null && value !== undefined && typeof value === 'object' && !(value instanceof Date) && !(value instanceof Buffer)) {
|
|
988
|
+
if (typeof value.pipe !== 'function') {
|
|
989
|
+
value = JSON.stringify(value);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
1064
992
|
if (value === null || value === undefined) {
|
|
1065
993
|
switch (meta.type) {
|
|
1066
|
-
case
|
|
1067
|
-
case
|
|
1068
|
-
case
|
|
994
|
+
case const_1.default.SQL_VARYING:
|
|
995
|
+
case const_1.default.SQL_NULL:
|
|
996
|
+
case const_1.default.SQL_TEXT:
|
|
1069
997
|
ret[i] = new Xsql.SQLParamString(null);
|
|
1070
998
|
break;
|
|
1071
|
-
case
|
|
1072
|
-
case
|
|
1073
|
-
case
|
|
999
|
+
case const_1.default.SQL_DOUBLE:
|
|
1000
|
+
case const_1.default.SQL_FLOAT:
|
|
1001
|
+
case const_1.default.SQL_D_FLOAT:
|
|
1074
1002
|
ret[i] = new Xsql.SQLParamDouble(null);
|
|
1075
1003
|
break;
|
|
1076
|
-
case
|
|
1077
|
-
case
|
|
1078
|
-
case
|
|
1079
|
-
case
|
|
1080
|
-
case
|
|
1081
|
-
case
|
|
1082
|
-
case
|
|
1004
|
+
case const_1.default.SQL_TYPE_DATE:
|
|
1005
|
+
case const_1.default.SQL_TYPE_TIME:
|
|
1006
|
+
case const_1.default.SQL_TIMESTAMP:
|
|
1007
|
+
case const_1.default.SQL_TIME_TZ:
|
|
1008
|
+
case const_1.default.SQL_TIME_TZ_EX:
|
|
1009
|
+
case const_1.default.SQL_TIMESTAMP_TZ:
|
|
1010
|
+
case const_1.default.SQL_TIMESTAMP_TZ_EX:
|
|
1083
1011
|
ret[i] = new Xsql.SQLParamDate(null);
|
|
1084
1012
|
break;
|
|
1085
|
-
case
|
|
1086
|
-
case
|
|
1087
|
-
case
|
|
1013
|
+
case const_1.default.SQL_BLOB:
|
|
1014
|
+
case const_1.default.SQL_ARRAY:
|
|
1015
|
+
case const_1.default.SQL_QUAD:
|
|
1088
1016
|
ret[i] = new Xsql.SQLParamQuad(null);
|
|
1089
1017
|
break;
|
|
1090
|
-
case
|
|
1091
|
-
case
|
|
1092
|
-
case
|
|
1093
|
-
case
|
|
1018
|
+
case const_1.default.SQL_LONG:
|
|
1019
|
+
case const_1.default.SQL_SHORT:
|
|
1020
|
+
case const_1.default.SQL_INT64:
|
|
1021
|
+
case const_1.default.SQL_BOOLEAN:
|
|
1094
1022
|
ret[i] = new Xsql.SQLParamInt(null);
|
|
1095
1023
|
break;
|
|
1096
1024
|
default:
|
|
1097
1025
|
ret[i] = null;
|
|
1098
1026
|
}
|
|
1099
1027
|
step(i + 1);
|
|
1100
|
-
}
|
|
1028
|
+
}
|
|
1029
|
+
else {
|
|
1101
1030
|
switch (meta.type) {
|
|
1102
|
-
case
|
|
1103
|
-
putBlobData(i, value, function() { step(i + 1); });
|
|
1031
|
+
case const_1.default.SQL_BLOB:
|
|
1032
|
+
putBlobData(i, value, function () { step(i + 1); });
|
|
1104
1033
|
break;
|
|
1105
|
-
|
|
1106
|
-
case
|
|
1107
|
-
case
|
|
1108
|
-
case
|
|
1109
|
-
case
|
|
1110
|
-
case
|
|
1111
|
-
case
|
|
1112
|
-
case Const.SQL_TIMESTAMP_TZ_EX:
|
|
1034
|
+
case const_1.default.SQL_TIMESTAMP:
|
|
1035
|
+
case const_1.default.SQL_TYPE_DATE:
|
|
1036
|
+
case const_1.default.SQL_TYPE_TIME:
|
|
1037
|
+
case const_1.default.SQL_TIME_TZ:
|
|
1038
|
+
case const_1.default.SQL_TIME_TZ_EX:
|
|
1039
|
+
case const_1.default.SQL_TIMESTAMP_TZ:
|
|
1040
|
+
case const_1.default.SQL_TIMESTAMP_TZ_EX:
|
|
1113
1041
|
if (value instanceof Date)
|
|
1114
1042
|
ret[i] = new Xsql.SQLParamDate(value);
|
|
1115
|
-
else if (typeof(value) === 'string')
|
|
1116
|
-
ret[i] = new Xsql.SQLParamDate(parseDate(value));
|
|
1043
|
+
else if (typeof (value) === 'string')
|
|
1044
|
+
ret[i] = new Xsql.SQLParamDate((0, utils_1.parseDate)(value));
|
|
1117
1045
|
else
|
|
1118
1046
|
ret[i] = new Xsql.SQLParamDate(new Date(value));
|
|
1119
|
-
|
|
1120
1047
|
step(i + 1);
|
|
1121
1048
|
break;
|
|
1122
|
-
|
|
1123
1049
|
default:
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1050
|
+
if (Buffer.isBuffer(value)) {
|
|
1051
|
+
ret[i] = new Xsql.SQLParamBuffer(value);
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
switch (typeof value) {
|
|
1055
|
+
case 'bigint':
|
|
1056
|
+
ret[i] = new Xsql.SQLParamInt128(value);
|
|
1057
|
+
break;
|
|
1058
|
+
case 'number':
|
|
1059
|
+
if (value % 1 === 0) {
|
|
1060
|
+
if (value >= const_1.default.MIN_INT && value <= const_1.default.MAX_INT)
|
|
1061
|
+
ret[i] = new Xsql.SQLParamInt(value);
|
|
1062
|
+
else
|
|
1063
|
+
ret[i] = new Xsql.SQLParamInt64(value);
|
|
1064
|
+
}
|
|
1132
1065
|
else
|
|
1133
|
-
ret[i] = new Xsql.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
break;
|
|
1066
|
+
ret[i] = new Xsql.SQLParamDouble(value);
|
|
1067
|
+
break;
|
|
1068
|
+
case 'string':
|
|
1069
|
+
ret[i] = new Xsql.SQLParamString(value);
|
|
1070
|
+
break;
|
|
1071
|
+
case 'boolean':
|
|
1072
|
+
ret[i] = new Xsql.SQLParamBool(value);
|
|
1073
|
+
break;
|
|
1074
|
+
default:
|
|
1075
|
+
//throw new Error('Unexpected parametter: ' + JSON.stringify(params) + ' - ' + JSON.stringify(input));
|
|
1076
|
+
ret[i] = new Xsql.SQLParamString(value.toString());
|
|
1077
|
+
break;
|
|
1078
|
+
}
|
|
1147
1079
|
}
|
|
1148
1080
|
step(i + 1);
|
|
1149
1081
|
}
|
|
1150
1082
|
}
|
|
1151
1083
|
}
|
|
1152
|
-
|
|
1153
1084
|
step(0);
|
|
1154
1085
|
}
|
|
1155
|
-
|
|
1156
1086
|
var input = statement.input;
|
|
1157
|
-
|
|
1158
1087
|
if (input.length) {
|
|
1159
|
-
|
|
1160
1088
|
if (!(params instanceof Array)) {
|
|
1161
|
-
if (params !== undefined)
|
|
1089
|
+
if (params !== undefined && typeof params === 'object' && params !== null) {
|
|
1090
|
+
var mappedParams = [];
|
|
1091
|
+
for (var i = 0; i < input.length; i++) {
|
|
1092
|
+
mappedParams.push(undefined);
|
|
1093
|
+
}
|
|
1094
|
+
var matchedCount = 0;
|
|
1095
|
+
var nameMap = {};
|
|
1096
|
+
for (var i = 0; i < input.length; i++) {
|
|
1097
|
+
var name = input[i].alias || input[i].field;
|
|
1098
|
+
if (name) {
|
|
1099
|
+
nameMap[name.toUpperCase()] = i;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
for (var key in params) {
|
|
1103
|
+
if (Object.prototype.hasOwnProperty.call(params, key)) {
|
|
1104
|
+
var cleanKey = key.startsWith(':') ? key.substring(1) : key;
|
|
1105
|
+
var index = nameMap[cleanKey.toUpperCase()];
|
|
1106
|
+
if (index !== undefined) {
|
|
1107
|
+
mappedParams[index] = params[key];
|
|
1108
|
+
matchedCount++;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
if (matchedCount > 0) {
|
|
1113
|
+
params = mappedParams;
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
params = [params];
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
else if (params !== undefined) {
|
|
1162
1120
|
params = [params];
|
|
1163
|
-
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1164
1123
|
params = [];
|
|
1124
|
+
}
|
|
1165
1125
|
}
|
|
1166
|
-
|
|
1167
1126
|
if (params.length !== input.length) {
|
|
1168
1127
|
self._pending.pop();
|
|
1169
1128
|
callback(new Error('Expected parameters: (params=' + params.length + ' vs. expected=' + input.length + ') - ' + statement.query));
|
|
1170
1129
|
return;
|
|
1171
1130
|
}
|
|
1172
|
-
|
|
1173
|
-
PrepareParams(params, input, function(prms) {
|
|
1131
|
+
PrepareParams(params, input, function (prms) {
|
|
1174
1132
|
self.sendExecute(op, statement, transaction, callback, prms);
|
|
1175
1133
|
});
|
|
1176
|
-
|
|
1177
1134
|
return;
|
|
1178
1135
|
}
|
|
1179
|
-
|
|
1180
1136
|
this.sendExecute(op, statement, transaction, callback);
|
|
1181
1137
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
1138
|
sendExecute(op, statement, transaction, callback, parameters) {
|
|
1185
1139
|
var msg = this._msg;
|
|
1186
1140
|
var blr = this._blr;
|
|
1187
1141
|
msg.pos = 0;
|
|
1188
1142
|
blr.pos = 0;
|
|
1189
|
-
|
|
1190
1143
|
msg.addInt(op);
|
|
1191
1144
|
msg.addInt(statement.handle);
|
|
1192
1145
|
msg.addInt(transaction.handle);
|
|
1193
|
-
|
|
1194
1146
|
if (parameters && parameters.length) {
|
|
1195
1147
|
CalcBlr(blr, parameters);
|
|
1196
|
-
msg.addBlr(blr);
|
|
1148
|
+
msg.addBlr(blr); // params blr
|
|
1197
1149
|
msg.addInt(0); // message number
|
|
1198
1150
|
msg.addInt(1); // param count
|
|
1199
|
-
|
|
1200
|
-
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION13) {
|
|
1151
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION13) {
|
|
1201
1152
|
// start with null indicator bitmap
|
|
1202
|
-
var nullBits = new BitSet();
|
|
1203
|
-
|
|
1153
|
+
var nullBits = new serialize_1.BitSet();
|
|
1204
1154
|
for (var i = 0; i < parameters.length; i++) {
|
|
1205
|
-
nullBits.set(i,
|
|
1155
|
+
nullBits.set(i, parameters[i].value === null ? 1 : 0);
|
|
1206
1156
|
}
|
|
1207
|
-
|
|
1208
1157
|
var nullBuffer = nullBits.toBuffer();
|
|
1209
1158
|
var requireBytes = Math.floor((parameters.length + 7) / 8);
|
|
1210
1159
|
var remainingBytes = requireBytes - nullBuffer.length;
|
|
1211
|
-
|
|
1212
1160
|
if (nullBuffer.length) {
|
|
1213
1161
|
msg.addBuffer(nullBuffer);
|
|
1214
1162
|
}
|
|
@@ -1216,75 +1164,124 @@ class Connection {
|
|
|
1216
1164
|
msg.addBuffer(Buffer.alloc(remainingBytes));
|
|
1217
1165
|
}
|
|
1218
1166
|
msg.addAlignment(requireBytes);
|
|
1219
|
-
|
|
1220
|
-
for(var i = 0; i < parameters.length; i++) {
|
|
1167
|
+
for (var i = 0; i < parameters.length; i++) {
|
|
1221
1168
|
if (parameters[i].value !== null) {
|
|
1222
1169
|
parameters[i].encode(msg);
|
|
1223
1170
|
}
|
|
1224
1171
|
}
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
for (var i = 0; i < parameters.length; i++) {
|
|
1227
1175
|
parameters[i].encode(msg);
|
|
1228
1176
|
if (parameters[i].value !== null) {
|
|
1229
1177
|
msg.addInt(0);
|
|
1230
1178
|
}
|
|
1231
1179
|
}
|
|
1232
1180
|
}
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
msg.addBlr(blr); // empty
|
|
1235
1184
|
msg.addInt(0); // message number
|
|
1236
1185
|
msg.addInt(0); // param count
|
|
1237
1186
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
var outputBlr = new BlrWriter(32);
|
|
1241
|
-
|
|
1187
|
+
if (op === const_1.default.op_execute2) {
|
|
1188
|
+
var outputBlr = new serialize_1.BlrWriter(32);
|
|
1242
1189
|
if (statement.output && statement.output.length) {
|
|
1243
1190
|
CalcBlr(outputBlr, statement.output);
|
|
1244
1191
|
msg.addBlr(outputBlr);
|
|
1245
|
-
}
|
|
1192
|
+
}
|
|
1193
|
+
else {
|
|
1246
1194
|
msg.addBlr(outputBlr); // empty
|
|
1247
1195
|
}
|
|
1248
1196
|
msg.addInt(0); // out_message_number = out_message_type
|
|
1249
1197
|
}
|
|
1250
|
-
|
|
1251
|
-
if (this.accept.protocolVersion >= Const.PROTOCOL_VERSION16) {
|
|
1198
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION16) {
|
|
1252
1199
|
// TODO impl statement timout
|
|
1253
1200
|
msg.addInt(statement.options?.timeout || 0); // p_sqldata_timeout
|
|
1254
1201
|
}
|
|
1255
|
-
|
|
1202
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION18) {
|
|
1203
|
+
msg.addInt(statement.options?.scrollable ? 1 : 0); // p_sqldata_cursor_flags (1 = CURSOR_TYPE_SCROLLABLE)
|
|
1204
|
+
}
|
|
1205
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION19) {
|
|
1206
|
+
msg.addInt(statement.options?.maxInlineBlobSize !== undefined ? statement.options.maxInlineBlobSize : (this.options?.maxInlineBlobSize || 0)); // p_sqldata_inline_blob_size
|
|
1207
|
+
}
|
|
1256
1208
|
callback.statement = statement;
|
|
1257
1209
|
this._queueEvent(callback);
|
|
1258
1210
|
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
1211
|
fetch(statement, transaction, count, callback) {
|
|
1264
|
-
|
|
1265
1212
|
var msg = this._msg;
|
|
1266
1213
|
var blr = this._blr;
|
|
1267
|
-
|
|
1268
1214
|
msg.pos = 0;
|
|
1269
1215
|
blr.pos = 0;
|
|
1270
|
-
|
|
1271
1216
|
if (count instanceof Function) {
|
|
1272
1217
|
callback = count;
|
|
1273
|
-
count =
|
|
1218
|
+
count = const_1.default.DEFAULT_FETCHSIZE;
|
|
1274
1219
|
}
|
|
1275
|
-
|
|
1276
|
-
msg.addInt(Const.op_fetch);
|
|
1220
|
+
msg.addInt(const_1.default.op_fetch);
|
|
1277
1221
|
msg.addInt(statement.handle);
|
|
1278
1222
|
CalcBlr(blr, statement.output);
|
|
1279
1223
|
msg.addBlr(blr);
|
|
1280
1224
|
msg.addInt(0); // message number
|
|
1281
|
-
msg.addInt(count ||
|
|
1282
|
-
|
|
1225
|
+
msg.addInt(count || const_1.default.DEFAULT_FETCHSIZE); // fetch count
|
|
1226
|
+
callback.statement = statement;
|
|
1227
|
+
this._queueEvent(callback);
|
|
1228
|
+
}
|
|
1229
|
+
fetchScroll(statement, transaction, direction, offset, count, callback) {
|
|
1230
|
+
if (typeof count === 'function') {
|
|
1231
|
+
callback = count;
|
|
1232
|
+
count = undefined;
|
|
1233
|
+
}
|
|
1234
|
+
if (typeof offset === 'function') {
|
|
1235
|
+
callback = offset;
|
|
1236
|
+
offset = undefined;
|
|
1237
|
+
count = undefined;
|
|
1238
|
+
}
|
|
1239
|
+
var msg = this._msg;
|
|
1240
|
+
var blr = this._blr;
|
|
1241
|
+
msg.pos = 0;
|
|
1242
|
+
blr.pos = 0;
|
|
1243
|
+
let dirInt = 0;
|
|
1244
|
+
if (typeof direction === 'number') {
|
|
1245
|
+
dirInt = direction;
|
|
1246
|
+
}
|
|
1247
|
+
else if (typeof direction === 'string') {
|
|
1248
|
+
const dirUpper = direction.toUpperCase();
|
|
1249
|
+
switch (dirUpper) {
|
|
1250
|
+
case 'NEXT':
|
|
1251
|
+
dirInt = 0;
|
|
1252
|
+
break;
|
|
1253
|
+
case 'PRIOR':
|
|
1254
|
+
dirInt = 1;
|
|
1255
|
+
break;
|
|
1256
|
+
case 'FIRST':
|
|
1257
|
+
dirInt = 2;
|
|
1258
|
+
break;
|
|
1259
|
+
case 'LAST':
|
|
1260
|
+
dirInt = 3;
|
|
1261
|
+
break;
|
|
1262
|
+
case 'ABSOLUTE':
|
|
1263
|
+
dirInt = 4;
|
|
1264
|
+
break;
|
|
1265
|
+
case 'RELATIVE':
|
|
1266
|
+
dirInt = 5;
|
|
1267
|
+
break;
|
|
1268
|
+
default:
|
|
1269
|
+
throw new Error('Invalid fetch direction: ' + direction);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
const offsetVal = offset || 0;
|
|
1273
|
+
const fetchCount = count || 1;
|
|
1274
|
+
msg.addInt(const_1.default.op_fetch_scroll);
|
|
1275
|
+
msg.addInt(statement.handle);
|
|
1276
|
+
CalcBlr(blr, statement.output);
|
|
1277
|
+
msg.addBlr(blr);
|
|
1278
|
+
msg.addInt(0); // message number
|
|
1279
|
+
msg.addInt(fetchCount); // fetch count
|
|
1280
|
+
msg.addInt(dirInt); // fetch operation
|
|
1281
|
+
msg.addInt(offsetVal); // fetch position (offset)
|
|
1283
1282
|
callback.statement = statement;
|
|
1284
1283
|
this._queueEvent(callback);
|
|
1285
1284
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
1285
|
fetchAll(statement, transaction, callback) {
|
|
1289
1286
|
const self = this;
|
|
1290
1287
|
const custom = statement.options || {};
|
|
@@ -1296,7 +1293,6 @@ class Connection {
|
|
|
1296
1293
|
callback(err);
|
|
1297
1294
|
return;
|
|
1298
1295
|
}
|
|
1299
|
-
|
|
1300
1296
|
if (ret && ret.data && ret.data.length) {
|
|
1301
1297
|
// Read blobs sequentially instead of in parallel to avoid
|
|
1302
1298
|
// exceeding Firebird's per-connection open-blob-handle limit,
|
|
@@ -1312,18 +1308,17 @@ class Connection {
|
|
|
1312
1308
|
return readBlobsSequentially(index + 1, results);
|
|
1313
1309
|
});
|
|
1314
1310
|
};
|
|
1315
|
-
|
|
1316
1311
|
readBlobsSequentially(0, []).then((arrBlob) => {
|
|
1317
1312
|
for (let i = 0; i < arrBlob.length; i++) {
|
|
1318
1313
|
const blob = arrBlob[i];
|
|
1319
|
-
ret.data[blob.row][blob.column] = blob.value;
|
|
1314
|
+
ret.data[blob.row][blob.column] = parseValueIfJson(blob.value, statement.connection.options);
|
|
1320
1315
|
}
|
|
1321
|
-
|
|
1322
1316
|
doSynchronousLoop(ret.data, (row, _i, next) => {
|
|
1323
1317
|
const pos = asStream ? streamIndex++ : (data.push(row) - 1);
|
|
1324
1318
|
if (asStream) {
|
|
1325
1319
|
executeStreamRow(custom, row, pos, statement.output, next);
|
|
1326
|
-
}
|
|
1320
|
+
}
|
|
1321
|
+
else {
|
|
1327
1322
|
next();
|
|
1328
1323
|
}
|
|
1329
1324
|
}, (streamErr) => {
|
|
@@ -1331,247 +1326,209 @@ class Connection {
|
|
|
1331
1326
|
callback(streamErr);
|
|
1332
1327
|
return;
|
|
1333
1328
|
}
|
|
1334
|
-
|
|
1335
1329
|
if (ret.fetched) {
|
|
1336
1330
|
callback(undefined, data || []);
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1331
|
+
}
|
|
1332
|
+
else {
|
|
1333
|
+
self.fetch(statement, transaction, const_1.default.DEFAULT_FETCHSIZE, loop);
|
|
1339
1334
|
}
|
|
1340
1335
|
});
|
|
1341
1336
|
}).catch(callback);
|
|
1342
1337
|
return;
|
|
1343
1338
|
}
|
|
1344
|
-
|
|
1345
1339
|
if (ret && ret.fetched) {
|
|
1346
1340
|
callback(undefined, data || []);
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
self.fetch(statement, transaction, const_1.default.DEFAULT_FETCHSIZE, loop);
|
|
1349
1344
|
}
|
|
1350
1345
|
};
|
|
1351
|
-
|
|
1352
|
-
this.fetch(statement, transaction, Const.DEFAULT_FETCHSIZE, loop);
|
|
1346
|
+
this.fetch(statement, transaction, const_1.default.DEFAULT_FETCHSIZE, loop);
|
|
1353
1347
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
1348
|
openBlob(blob, transaction, callback) {
|
|
1358
1349
|
var msg = this._msg;
|
|
1359
1350
|
msg.pos = 0;
|
|
1360
|
-
msg.addInt(
|
|
1351
|
+
msg.addInt(const_1.default.op_open_blob);
|
|
1361
1352
|
msg.addInt(transaction.handle);
|
|
1362
1353
|
msg.addQuad(blob);
|
|
1363
1354
|
this._queueEvent(callback);
|
|
1364
1355
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
1356
|
closeBlob(blob, callback, defer = true) {
|
|
1368
1357
|
var msg = this._msg;
|
|
1369
1358
|
msg.pos = 0;
|
|
1370
|
-
msg.addInt(
|
|
1359
|
+
msg.addInt(const_1.default.op_close_blob);
|
|
1371
1360
|
msg.addInt(blob.handle);
|
|
1372
1361
|
this._queueEvent(callback, defer);
|
|
1373
1362
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
1363
|
getSegment(blob, callback) {
|
|
1377
1364
|
var msg = this._msg;
|
|
1378
1365
|
msg.pos = 0;
|
|
1379
|
-
msg.addInt(
|
|
1366
|
+
msg.addInt(const_1.default.op_get_segment);
|
|
1380
1367
|
msg.addInt(blob.handle);
|
|
1381
1368
|
msg.addInt(this.options.blobReadChunkSize || 1024); // buffer length (max 65535)
|
|
1382
1369
|
msg.addInt(0); // ???
|
|
1383
1370
|
this._queueEvent(callback);
|
|
1384
1371
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
1372
|
createBlob2(transaction, callback) {
|
|
1388
1373
|
var msg = this._msg;
|
|
1389
1374
|
msg.pos = 0;
|
|
1390
|
-
msg.addInt(
|
|
1375
|
+
msg.addInt(const_1.default.op_create_blob2);
|
|
1391
1376
|
msg.addInt(0);
|
|
1392
1377
|
msg.addInt(transaction.handle);
|
|
1393
1378
|
msg.addInt(0);
|
|
1394
1379
|
msg.addInt(0);
|
|
1395
1380
|
this._queueEvent(callback);
|
|
1396
1381
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
1382
|
batchSegments(blob, buffer, callback) {
|
|
1400
1383
|
var msg = this._msg;
|
|
1401
1384
|
var blr = this._blr;
|
|
1402
1385
|
msg.pos = 0;
|
|
1403
1386
|
blr.pos = 0;
|
|
1404
|
-
msg.addInt(
|
|
1387
|
+
msg.addInt(const_1.default.op_batch_segments);
|
|
1405
1388
|
msg.addInt(blob.handle);
|
|
1406
1389
|
msg.addInt(buffer.length + 2);
|
|
1407
1390
|
blr.addBuffer(buffer);
|
|
1408
1391
|
msg.addBlr(blr);
|
|
1409
1392
|
this._queueEvent(callback);
|
|
1410
1393
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
1394
|
svcattach(options, callback, svc) {
|
|
1414
|
-
this._lowercase_keys = options.lowercase_keys ||
|
|
1395
|
+
this._lowercase_keys = options.lowercase_keys || const_1.default.DEFAULT_LOWERCASE_KEYS;
|
|
1415
1396
|
var database = options.database || options.filename;
|
|
1416
|
-
var user = options.user ||
|
|
1417
|
-
var password = options.password ||
|
|
1397
|
+
var user = options.user || const_1.default.DEFAULT_USER;
|
|
1398
|
+
var password = options.password || const_1.default.DEFAULT_PASSWORD;
|
|
1418
1399
|
var role = options.role;
|
|
1419
1400
|
var msg = this._msg;
|
|
1420
1401
|
var blr = this._blr;
|
|
1421
1402
|
msg.pos = 0;
|
|
1422
1403
|
blr.pos = 0;
|
|
1423
|
-
|
|
1424
|
-
blr.
|
|
1425
|
-
blr.addString(Const.isc_dpb_lc_ctype, 'UTF8', Const.DEFAULT_ENCODING);
|
|
1426
|
-
|
|
1404
|
+
blr.addBytes([const_1.default.isc_dpb_version2, const_1.default.isc_dpb_version2]);
|
|
1405
|
+
blr.addString(const_1.default.isc_dpb_lc_ctype, 'UTF8', const_1.default.DEFAULT_ENCODING);
|
|
1427
1406
|
// For Firebird 3+ (protocol 13+), add UTF-8 filename flag to ensure all DPB strings are handled with UTF-8
|
|
1428
|
-
if (this.accept.protocolVersion >=
|
|
1429
|
-
blr.addByte(
|
|
1407
|
+
if (this.accept.protocolVersion >= const_1.default.PROTOCOL_VERSION13) {
|
|
1408
|
+
blr.addByte(const_1.default.isc_dpb_utf8_filename);
|
|
1430
1409
|
blr.addByte(0);
|
|
1431
1410
|
}
|
|
1432
|
-
|
|
1433
|
-
blr.addString(
|
|
1434
|
-
blr.
|
|
1435
|
-
blr.addByte(Const.isc_dpb_dummy_packet_interval);
|
|
1411
|
+
blr.addString(const_1.default.isc_dpb_user_name, user, const_1.default.DEFAULT_ENCODING);
|
|
1412
|
+
blr.addString(const_1.default.isc_dpb_password, password, const_1.default.DEFAULT_ENCODING);
|
|
1413
|
+
blr.addByte(const_1.default.isc_dpb_dummy_packet_interval);
|
|
1436
1414
|
blr.addByte(4);
|
|
1437
1415
|
blr.addBytes([120, 10, 0, 0]); // FROM DOT NET PROVIDER
|
|
1438
1416
|
if (role)
|
|
1439
|
-
blr.addString(
|
|
1440
|
-
|
|
1441
|
-
msg.addInt(Const.op_service_attach);
|
|
1417
|
+
blr.addString(const_1.default.isc_dpb_sql_role_name, role, const_1.default.DEFAULT_ENCODING);
|
|
1418
|
+
msg.addInt(const_1.default.op_service_attach);
|
|
1442
1419
|
msg.addInt(0);
|
|
1443
|
-
msg.addString(
|
|
1420
|
+
msg.addString(const_1.default.DEFAULT_SVC_NAME, const_1.default.DEFAULT_ENCODING); // only local for moment
|
|
1444
1421
|
msg.addBlr(this._blr);
|
|
1445
|
-
|
|
1446
1422
|
var self = this;
|
|
1447
|
-
|
|
1448
1423
|
function cb(err, ret) {
|
|
1449
|
-
|
|
1450
1424
|
if (err) {
|
|
1451
|
-
doError(err, callback);
|
|
1425
|
+
(0, callback_1.doError)(err, callback);
|
|
1452
1426
|
return;
|
|
1453
1427
|
}
|
|
1454
|
-
|
|
1455
1428
|
self.svchandle = ret.handle;
|
|
1456
1429
|
if (callback)
|
|
1457
1430
|
callback(undefined, ret);
|
|
1458
1431
|
}
|
|
1459
|
-
|
|
1460
1432
|
// For reconnect
|
|
1461
1433
|
if (svc) {
|
|
1462
1434
|
svc.connection = this;
|
|
1463
1435
|
cb.response = svc;
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1436
|
+
}
|
|
1437
|
+
else {
|
|
1438
|
+
cb.response = new service_1.default(this);
|
|
1466
1439
|
cb.response.removeAllListeners('error');
|
|
1467
|
-
cb.response.on('error', noop);
|
|
1440
|
+
cb.response.on('error', utils_1.noop);
|
|
1468
1441
|
}
|
|
1469
|
-
|
|
1470
1442
|
this._queueEvent(cb);
|
|
1471
1443
|
}
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
1444
|
svcstart(spbaction, callback) {
|
|
1475
1445
|
var msg = this._msg;
|
|
1476
1446
|
var blr = this._blr;
|
|
1477
1447
|
msg.pos = 0;
|
|
1478
|
-
msg.addInt(
|
|
1448
|
+
msg.addInt(const_1.default.op_service_start);
|
|
1479
1449
|
msg.addInt(this.svchandle);
|
|
1480
|
-
msg.addInt(0)
|
|
1450
|
+
msg.addInt(0);
|
|
1481
1451
|
msg.addBlr(spbaction);
|
|
1482
1452
|
this._queueEvent(callback);
|
|
1483
1453
|
}
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
if (resultbuffersize > Const.MAX_BUFFER_SIZE) {
|
|
1488
|
-
doError(new Error('Buffer is too big'), callback);
|
|
1454
|
+
svcquery(spbquery, resultbuffersize, timeout, callback) {
|
|
1455
|
+
if (resultbuffersize > const_1.default.MAX_BUFFER_SIZE) {
|
|
1456
|
+
(0, callback_1.doError)(new Error('Buffer is too big'), callback);
|
|
1489
1457
|
return;
|
|
1490
1458
|
}
|
|
1491
|
-
|
|
1492
1459
|
var msg = this._msg;
|
|
1493
1460
|
var blr = this._blr;
|
|
1494
1461
|
msg.pos = 0;
|
|
1495
1462
|
blr.pos = 0;
|
|
1496
|
-
blr.addByte(
|
|
1463
|
+
blr.addByte(const_1.default.isc_spb_current_version);
|
|
1497
1464
|
//blr.addByteInt32(Const.isc_info_svc_timeout, timeout);
|
|
1498
|
-
msg.addInt(
|
|
1465
|
+
msg.addInt(const_1.default.op_service_info);
|
|
1499
1466
|
msg.addInt(this.svchandle);
|
|
1500
1467
|
msg.addInt(0);
|
|
1501
1468
|
msg.addBlr(blr);
|
|
1502
|
-
blr.pos = 0
|
|
1469
|
+
blr.pos = 0;
|
|
1503
1470
|
blr.addBytes(spbquery);
|
|
1504
1471
|
msg.addBlr(blr);
|
|
1505
1472
|
msg.addInt(resultbuffersize);
|
|
1506
1473
|
this._queueEvent(callback);
|
|
1507
1474
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
1475
|
svcdetach(callback) {
|
|
1511
1476
|
var self = this;
|
|
1512
|
-
|
|
1513
|
-
|
|
1477
|
+
if (self._isClosed) {
|
|
1478
|
+
(0, callback_1.doError)(new Error('Connection is closed.'), callback);
|
|
1514
1479
|
return;
|
|
1515
|
-
|
|
1480
|
+
}
|
|
1516
1481
|
self._isUsed = false;
|
|
1517
1482
|
self._isDetach = true;
|
|
1518
|
-
|
|
1519
1483
|
var msg = self._msg;
|
|
1520
|
-
|
|
1521
1484
|
msg.pos = 0;
|
|
1522
|
-
msg.addInt(
|
|
1485
|
+
msg.addInt(const_1.default.op_service_detach);
|
|
1523
1486
|
msg.addInt(this.svchandle); // Database Object ID
|
|
1524
|
-
|
|
1525
1487
|
self._queueEvent(function (err, ret) {
|
|
1526
1488
|
delete (self.svchandle);
|
|
1527
1489
|
if (callback)
|
|
1528
1490
|
callback(err, ret);
|
|
1529
1491
|
});
|
|
1530
1492
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1493
|
+
auxConnection(eventid, callback) {
|
|
1494
|
+
if (typeof eventid === 'function') {
|
|
1495
|
+
// Preserve the older auxConnection(callback) call shape; plain
|
|
1496
|
+
// auxiliary connections historically used event id 0.
|
|
1497
|
+
callback = eventid;
|
|
1498
|
+
eventid = 0;
|
|
1499
|
+
}
|
|
1535
1500
|
var self = this;
|
|
1536
1501
|
if (self._isClosed)
|
|
1537
1502
|
return this.throwClosed(callback);
|
|
1538
1503
|
var msg = self._msg;
|
|
1539
1504
|
msg.pos = 0;
|
|
1540
|
-
msg.addInt(
|
|
1505
|
+
msg.addInt(const_1.default.op_connect_request);
|
|
1541
1506
|
msg.addInt(1); // async
|
|
1542
1507
|
msg.addInt(self.dbhandle);
|
|
1543
|
-
msg.addInt(
|
|
1508
|
+
msg.addInt(eventid);
|
|
1544
1509
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1545
|
-
console.log('[fb-debug] auxConnection: sending op_connect_request(53) dbhandle=%d queue_before=%d xdr_saved=%s',
|
|
1546
|
-
self.dbhandle, self._queue.length, Boolean(self._xdr));
|
|
1510
|
+
console.log('[fb-debug] auxConnection: sending op_connect_request(53) dbhandle=%d eventid=%d queue_before=%d xdr_saved=%s', self.dbhandle, eventid, self._queue.length, Boolean(self._xdr));
|
|
1547
1511
|
}
|
|
1548
1512
|
function cb(err, ret) {
|
|
1549
|
-
|
|
1550
1513
|
if (err) {
|
|
1551
1514
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1552
1515
|
console.log('[fb-debug] auxConnection: op_connect_request error: %s queue=%d', err.message, self._queue.length);
|
|
1553
1516
|
}
|
|
1554
|
-
doError(err, callback);
|
|
1517
|
+
(0, callback_1.doError)(err, callback);
|
|
1555
1518
|
return;
|
|
1556
1519
|
}
|
|
1557
|
-
|
|
1558
1520
|
var socket_info = {
|
|
1559
1521
|
family: ret.buffer.readInt16BE(0),
|
|
1560
1522
|
port: ret.buffer.readUInt16BE(2),
|
|
1561
1523
|
host: ret.buffer.readUInt8(4) + '.' + ret.buffer.readUInt8(5) + '.' + ret.buffer.readUInt8(6) + '.' + ret.buffer.readUInt8(7)
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1524
|
+
};
|
|
1564
1525
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1565
|
-
console.log('[fb-debug] auxConnection: op_response ok → aux family=%d port=%d host=%s queue=%d',
|
|
1566
|
-
socket_info.family, socket_info.port, socket_info.host, self._queue.length);
|
|
1526
|
+
console.log('[fb-debug] auxConnection: op_response ok → aux family=%d port=%d host=%s queue=%d', socket_info.family, socket_info.port, socket_info.host, self._queue.length);
|
|
1567
1527
|
}
|
|
1568
|
-
|
|
1569
1528
|
callback(undefined, socket_info);
|
|
1570
1529
|
}
|
|
1571
1530
|
this._queueEvent(cb);
|
|
1572
1531
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
1532
|
queEvents(events, eventid, callback) {
|
|
1576
1533
|
var self = this;
|
|
1577
1534
|
if (this._isClosed)
|
|
@@ -1580,189 +1537,184 @@ class Connection {
|
|
|
1580
1537
|
var blr = this._blr;
|
|
1581
1538
|
blr.pos = 0;
|
|
1582
1539
|
msg.pos = 0;
|
|
1583
|
-
msg.addInt(
|
|
1540
|
+
msg.addInt(const_1.default.op_que_events);
|
|
1584
1541
|
msg.addInt(this.dbhandle);
|
|
1585
1542
|
// prepare EPB
|
|
1586
|
-
blr.addByte(1) // epb_version
|
|
1543
|
+
blr.addByte(1); // epb_version
|
|
1587
1544
|
for (var event in events) {
|
|
1588
|
-
var event_buffer = Buffer.from(event, '
|
|
1545
|
+
var event_buffer = Buffer.from(event, 'utf8');
|
|
1589
1546
|
blr.addByte(event_buffer.length);
|
|
1590
1547
|
blr.addBytes(event_buffer);
|
|
1591
1548
|
blr.addInt32(events[event]);
|
|
1592
1549
|
}
|
|
1593
|
-
msg.addBlr(blr);
|
|
1594
|
-
msg.addInt(0);
|
|
1595
|
-
msg.addInt(0);
|
|
1550
|
+
msg.addBlr(blr); // epb
|
|
1551
|
+
msg.addInt(0); // ast
|
|
1552
|
+
msg.addInt(0); // args
|
|
1596
1553
|
msg.addInt(eventid);
|
|
1597
|
-
|
|
1598
1554
|
function cb(err, ret) {
|
|
1599
1555
|
if (err) {
|
|
1600
|
-
doError(err, callback);
|
|
1556
|
+
(0, callback_1.doError)(err, callback);
|
|
1601
1557
|
return;
|
|
1602
1558
|
}
|
|
1603
|
-
|
|
1604
1559
|
callback(null, ret);
|
|
1605
1560
|
}
|
|
1606
|
-
|
|
1607
1561
|
this._queueEvent(cb);
|
|
1608
1562
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
1563
|
closeEvents(eventid, callback) {
|
|
1612
1564
|
var self = this;
|
|
1613
1565
|
if (this._isClosed)
|
|
1614
1566
|
return this.throwClosed(callback);
|
|
1615
1567
|
var msg = self._msg;
|
|
1616
1568
|
msg.pos = 0;
|
|
1617
|
-
msg.addInt(
|
|
1569
|
+
msg.addInt(const_1.default.op_cancel_events);
|
|
1618
1570
|
msg.addInt(self.dbhandle);
|
|
1619
1571
|
msg.addInt(eventid);
|
|
1620
|
-
|
|
1621
1572
|
function cb(err, ret) {
|
|
1622
1573
|
if (err) {
|
|
1623
|
-
doError(err, callback);
|
|
1574
|
+
(0, callback_1.doError)(err, callback);
|
|
1624
1575
|
return;
|
|
1625
1576
|
}
|
|
1626
|
-
|
|
1627
1577
|
callback(null);
|
|
1628
1578
|
}
|
|
1629
|
-
|
|
1630
1579
|
this._queueEvent(cb);
|
|
1631
1580
|
}
|
|
1632
|
-
|
|
1633
1581
|
}
|
|
1634
|
-
|
|
1635
1582
|
// Reverse-lookup table: opcode number → name for FIREBIRD_DEBUG trace logging.
|
|
1636
|
-
const opcodeNames = Object.fromEntries(
|
|
1637
|
-
Object.entries(Const).filter(([k]) => k.startsWith('op_')).map(([k, v]) => [v, k])
|
|
1638
|
-
);
|
|
1639
|
-
|
|
1583
|
+
const opcodeNames = Object.fromEntries(Object.entries(const_1.default).filter(([k]) => k.startsWith('op_')).map(([k, v]) => [v, k]));
|
|
1640
1584
|
function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
1641
1585
|
try {
|
|
1642
1586
|
do {
|
|
1643
1587
|
var r = data.r || data.readInt();
|
|
1644
|
-
|
|
1645
|
-
|
|
1588
|
+
if (data.r) {
|
|
1589
|
+
data.r = null;
|
|
1590
|
+
}
|
|
1591
|
+
if (r === const_1.default.op_dummy) {
|
|
1592
|
+
continue;
|
|
1593
|
+
}
|
|
1594
|
+
if (r === const_1.default.op_inline_blob) {
|
|
1595
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
1596
|
+
console.log('[fb-debug] decodeResponse: opcode=op_inline_blob');
|
|
1597
|
+
}
|
|
1598
|
+
var tran_id = data.readInt();
|
|
1599
|
+
var blob_id = data.readQuad();
|
|
1600
|
+
var blob_data = data.readArray();
|
|
1601
|
+
if (!cnx._inlineBlobs) {
|
|
1602
|
+
cnx._inlineBlobs = new Map();
|
|
1603
|
+
}
|
|
1604
|
+
const cacheKey = `${blob_id.high}:${blob_id.low}`;
|
|
1605
|
+
cnx._inlineBlobs.set(cacheKey, blob_data);
|
|
1606
|
+
r = const_1.default.op_dummy; // Continue loop to read next opcode
|
|
1607
|
+
}
|
|
1608
|
+
} while (r === const_1.default.op_dummy);
|
|
1646
1609
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1647
|
-
console.log('[fb-debug] decodeResponse: opcode=%d(%s) pos=%d buflen=%d',
|
|
1648
|
-
r, opcodeNames[r] || 'unknown', data.pos, data.buffer.length);
|
|
1610
|
+
console.log('[fb-debug] decodeResponse: opcode=%d(%s) pos=%d buflen=%d', r, opcodeNames[r] || 'unknown', data.pos, data.buffer.length);
|
|
1649
1611
|
}
|
|
1650
|
-
|
|
1651
1612
|
var item, op, response;
|
|
1652
|
-
|
|
1653
1613
|
switch (r) {
|
|
1654
|
-
case
|
|
1655
|
-
|
|
1614
|
+
case const_1.default.op_response:
|
|
1656
1615
|
if (callback) {
|
|
1657
1616
|
response = callback.response || {};
|
|
1658
|
-
}
|
|
1617
|
+
}
|
|
1618
|
+
else {
|
|
1659
1619
|
response = {};
|
|
1660
1620
|
}
|
|
1661
|
-
|
|
1662
1621
|
let loop = function (err) {
|
|
1663
1622
|
if (err) {
|
|
1664
1623
|
return cb(err);
|
|
1665
|
-
}
|
|
1624
|
+
}
|
|
1625
|
+
else {
|
|
1666
1626
|
if (callback && callback.lazy_count) {
|
|
1667
1627
|
callback.lazy_count--;
|
|
1668
1628
|
if (callback.lazy_count > 0) {
|
|
1669
1629
|
r = data.readInt(); // Read new op
|
|
1670
1630
|
parseOpResponse(data, response, loop);
|
|
1671
|
-
}
|
|
1631
|
+
}
|
|
1632
|
+
else {
|
|
1672
1633
|
cb(null, response);
|
|
1673
1634
|
}
|
|
1674
|
-
}
|
|
1635
|
+
}
|
|
1636
|
+
else {
|
|
1675
1637
|
cb(null, response);
|
|
1676
1638
|
}
|
|
1677
1639
|
}
|
|
1678
1640
|
};
|
|
1679
1641
|
// Parse normal and lazy response
|
|
1680
1642
|
return parseOpResponse(data, response, loop);
|
|
1681
|
-
case
|
|
1682
|
-
case
|
|
1643
|
+
case const_1.default.op_fetch_response:
|
|
1644
|
+
case const_1.default.op_sql_response:
|
|
1683
1645
|
var statement = callback.statement;
|
|
1684
1646
|
var output = statement.output;
|
|
1685
1647
|
var custom = statement.options || {};
|
|
1686
|
-
var isOpFetch = r ===
|
|
1648
|
+
var isOpFetch = r === const_1.default.op_fetch_response;
|
|
1687
1649
|
var _xdrpos;
|
|
1688
1650
|
statement.nbrowsfetched = statement.nbrowsfetched || 0;
|
|
1689
|
-
|
|
1690
1651
|
if (isOpFetch && data.fop) { // could be set when a packet is not complete
|
|
1691
1652
|
data.readBuffer(68); // ??
|
|
1692
1653
|
op = data.readInt(); // ??
|
|
1693
1654
|
data.fop = false;
|
|
1694
|
-
if (op ===
|
|
1655
|
+
if (op === const_1.default.op_response) {
|
|
1695
1656
|
return parseOpResponse(data, {}, cb);
|
|
1696
1657
|
}
|
|
1697
1658
|
}
|
|
1698
|
-
|
|
1699
1659
|
if (!isOpFetch) {
|
|
1700
1660
|
data.fstatus = 0;
|
|
1701
1661
|
}
|
|
1702
|
-
|
|
1703
1662
|
data.fstatus = data.fstatus !== undefined ? data.fstatus : data.readInt();
|
|
1704
1663
|
data.fcount = data.fcount !== undefined ? data.fcount : data.readInt();
|
|
1705
1664
|
data.fcolumn = data.fcolumn || 0;
|
|
1706
1665
|
data.frow = data.frow || (custom.asObject ? {} : new Array(output.length));
|
|
1707
1666
|
data.frows = data.frows || [];
|
|
1708
|
-
|
|
1709
1667
|
if (custom.asObject && !data.fcols) {
|
|
1710
1668
|
if (lowercase_keys) {
|
|
1711
1669
|
data.fcols = output.map((column) => column.alias.toLowerCase());
|
|
1712
|
-
}
|
|
1670
|
+
}
|
|
1671
|
+
else {
|
|
1713
1672
|
data.fcols = output.map((column) => column.alias);
|
|
1714
1673
|
}
|
|
1715
1674
|
}
|
|
1716
|
-
|
|
1717
1675
|
const arrBlob = [];
|
|
1718
|
-
const lowerV13 = statement.connection.accept.protocolVersion <
|
|
1719
|
-
|
|
1676
|
+
const lowerV13 = statement.connection.accept.protocolVersion < const_1.default.PROTOCOL_VERSION13;
|
|
1720
1677
|
while (data.fcount && (data.fstatus !== 100)) {
|
|
1721
1678
|
let nullBitSet;
|
|
1722
1679
|
if (!lowerV13) {
|
|
1723
1680
|
const nullBitsLen = Math.floor((output.length + 7) / 8);
|
|
1724
|
-
nullBitSet = new BitSet(data.readBuffer(nullBitsLen, false));
|
|
1681
|
+
nullBitSet = new serialize_1.BitSet(data.readBuffer(nullBitsLen, false));
|
|
1725
1682
|
data.readBuffer((4 - nullBitsLen) & 3, false); // Skip padding
|
|
1726
1683
|
}
|
|
1727
|
-
|
|
1728
1684
|
for (let length = output.length; data.fcolumn < length; data.fcolumn++) {
|
|
1729
1685
|
item = output[data.fcolumn];
|
|
1730
|
-
|
|
1731
1686
|
if (!lowerV13 && nullBitSet.get(data.fcolumn)) {
|
|
1732
1687
|
if (custom.asObject) {
|
|
1733
1688
|
data.frow[data.fcols[data.fcolumn]] = null;
|
|
1734
|
-
}
|
|
1689
|
+
}
|
|
1690
|
+
else {
|
|
1735
1691
|
data.frow[data.fcolumn] = null;
|
|
1736
1692
|
}
|
|
1737
|
-
|
|
1738
1693
|
continue;
|
|
1739
1694
|
}
|
|
1740
|
-
|
|
1741
1695
|
try {
|
|
1742
1696
|
_xdrpos = data.pos;
|
|
1743
1697
|
const key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
1744
1698
|
const row = data.frows.length;
|
|
1745
1699
|
let value = item.decode(data, lowerV13, cnx.options);
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
if (item.subType === Const.isc_blob_text && cnx.options.blobAsText) {
|
|
1700
|
+
if (item.type === const_1.default.SQL_BLOB && value !== null) {
|
|
1701
|
+
if (item.subType === const_1.default.isc_blob_text && cnx.options.blobAsText) {
|
|
1749
1702
|
value = fetch_blob_async_transaction(statement, value, key, row);
|
|
1750
1703
|
arrBlob.push(value);
|
|
1751
|
-
}
|
|
1704
|
+
}
|
|
1705
|
+
else {
|
|
1752
1706
|
value = fetch_blob_async(statement, value, key, row);
|
|
1753
1707
|
}
|
|
1754
1708
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1709
|
+
data.frow[key] = parseValueIfJson(value, cnx.options);
|
|
1710
|
+
}
|
|
1711
|
+
catch (e) {
|
|
1758
1712
|
// uncomplete packet read
|
|
1759
1713
|
data.pos = _xdrpos;
|
|
1760
1714
|
data.r = r;
|
|
1761
1715
|
return cb(new Error('Packet is not complete'));
|
|
1762
1716
|
}
|
|
1763
|
-
|
|
1764
1717
|
}
|
|
1765
|
-
|
|
1766
1718
|
data.fcolumn = 0;
|
|
1767
1719
|
// ToDo: emit "row" with blob subtype string decoded
|
|
1768
1720
|
// use: data.frow['fieldBlob'](transaction?).then(({ value }) => console.log(value))
|
|
@@ -1770,28 +1722,29 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
1770
1722
|
statement.connection.db.emit('row', data.frow, statement.nbrowsfetched, custom.asObject);
|
|
1771
1723
|
data.frows.push(data.frow);
|
|
1772
1724
|
data.frow = custom.asObject ? {} : new Array(output.length);
|
|
1773
|
-
|
|
1774
1725
|
try {
|
|
1775
1726
|
_xdrpos = data.pos;
|
|
1776
1727
|
if (isOpFetch) {
|
|
1777
1728
|
delete data.fstatus;
|
|
1778
1729
|
delete data.fcount;
|
|
1779
1730
|
op = data.readInt(); // ??
|
|
1780
|
-
if (op ===
|
|
1731
|
+
if (op === const_1.default.op_response) {
|
|
1781
1732
|
return parseOpResponse(data, {}, cb);
|
|
1782
1733
|
}
|
|
1783
1734
|
data.fstatus = data.readInt();
|
|
1784
1735
|
data.fcount = data.readInt();
|
|
1785
|
-
}
|
|
1736
|
+
}
|
|
1737
|
+
else {
|
|
1786
1738
|
data.fcount--;
|
|
1787
|
-
if (r ===
|
|
1739
|
+
if (r === const_1.default.op_sql_response) {
|
|
1788
1740
|
op = data.readInt();
|
|
1789
|
-
if (op ===
|
|
1741
|
+
if (op === const_1.default.op_response) {
|
|
1790
1742
|
parseOpResponse(data, {});
|
|
1791
1743
|
}
|
|
1792
1744
|
}
|
|
1793
1745
|
}
|
|
1794
|
-
}
|
|
1746
|
+
}
|
|
1747
|
+
catch (e) {
|
|
1795
1748
|
if (_xdrpos === data.pos) {
|
|
1796
1749
|
data.fop = true;
|
|
1797
1750
|
}
|
|
@@ -1800,13 +1753,12 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
1800
1753
|
}
|
|
1801
1754
|
statement.nbrowsfetched++;
|
|
1802
1755
|
}
|
|
1803
|
-
|
|
1804
1756
|
// ToDo: emit "result" with blob subtype string decoded
|
|
1805
1757
|
statement.connection.db.emit('result', data.frows, arrBlob);
|
|
1806
|
-
return cb(null, {data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob});
|
|
1807
|
-
case
|
|
1808
|
-
case
|
|
1809
|
-
case
|
|
1758
|
+
return cb(null, { data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob });
|
|
1759
|
+
case const_1.default.op_accept:
|
|
1760
|
+
case const_1.default.op_cond_accept:
|
|
1761
|
+
case const_1.default.op_accept_data:
|
|
1810
1762
|
let accept = {
|
|
1811
1763
|
protocolVersion: data.readInt(),
|
|
1812
1764
|
protocolArchitecture: data.readInt(),
|
|
@@ -1816,214 +1768,224 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
1816
1768
|
authData: '',
|
|
1817
1769
|
sessionKey: ''
|
|
1818
1770
|
};
|
|
1819
|
-
|
|
1820
|
-
accept.
|
|
1821
|
-
accept.protocolMinimumType = accept.protocolMinimumType & Const.ptype_mask;
|
|
1771
|
+
accept.compress = (accept.protocolMinimumType & const_1.default.pflag_compress) !== 0;
|
|
1772
|
+
accept.protocolMinimumType = accept.protocolMinimumType & const_1.default.ptype_mask;
|
|
1822
1773
|
//accept.compress = (accept.acceptType & pflag_compress) !== 0; // TODO Handle zlib compression
|
|
1823
1774
|
if (accept.protocolVersion < 0) {
|
|
1824
|
-
accept.protocolVersion = (accept.protocolVersion &
|
|
1775
|
+
accept.protocolVersion = (accept.protocolVersion & const_1.default.FB_PROTOCOL_MASK) | const_1.default.FB_PROTOCOL_FLAG;
|
|
1825
1776
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
accept.pluginName = data.readString(Const.DEFAULT_ENCODING);
|
|
1777
|
+
if (r === const_1.default.op_cond_accept || r === const_1.default.op_accept_data) {
|
|
1778
|
+
var d = new serialize_1.BlrReader(data.readArray());
|
|
1779
|
+
accept.pluginName = data.readString(const_1.default.DEFAULT_ENCODING);
|
|
1830
1780
|
var is_authenticated = data.readInt();
|
|
1831
|
-
var keys = data.readString(
|
|
1832
|
-
|
|
1781
|
+
var keys = data.readString(const_1.default.DEFAULT_ENCODING); // keys
|
|
1782
|
+
accept.keys = keys;
|
|
1833
1783
|
if (is_authenticated === 0) {
|
|
1834
1784
|
if (cnx.options.pluginName && cnx.options.pluginName !== accept.pluginName) {
|
|
1835
1785
|
var errPlugin = new Error('Server don\'t accept plugin : ' + cnx.options.pluginName + ', but support : ' + accept.pluginName);
|
|
1836
|
-
doError(errPlugin, callback);
|
|
1786
|
+
(0, callback_1.doError)(errPlugin, callback);
|
|
1837
1787
|
return cb(errPlugin);
|
|
1838
1788
|
}
|
|
1839
|
-
|
|
1840
|
-
if (Const.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1 && !cnx.clientKeys) {
|
|
1789
|
+
if (const_1.default.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1 && !cnx.clientKeys) {
|
|
1841
1790
|
var errPlugin = new Error('Server accepted plugin : ' + accept.pluginName + ', but client did not initialize SRP keys');
|
|
1842
|
-
doError(errPlugin, callback);
|
|
1791
|
+
(0, callback_1.doError)(errPlugin, callback);
|
|
1843
1792
|
return cb(errPlugin);
|
|
1844
1793
|
}
|
|
1845
|
-
|
|
1846
|
-
if (Const.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
1794
|
+
if (const_1.default.AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
1847
1795
|
var crypto = {
|
|
1848
1796
|
Srp: 'sha1',
|
|
1849
|
-
Srp256: 'sha256'
|
|
1797
|
+
Srp256: 'sha256',
|
|
1798
|
+
Srp384: 'sha384',
|
|
1799
|
+
Srp512: 'sha512'
|
|
1850
1800
|
};
|
|
1851
1801
|
accept.srpAlgo = crypto[accept.pluginName];
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
DEFAULT_ENCODING,
|
|
1858
|
-
accept.pluginName
|
|
1859
|
-
);
|
|
1860
|
-
|
|
1861
|
-
return cb(new Error('login'));
|
|
1862
|
-
}*/
|
|
1863
|
-
|
|
1802
|
+
if (!d.buffer) {
|
|
1803
|
+
cnx._pendingAccept = accept;
|
|
1804
|
+
cnx.sendOpContAuth(cnx.clientKeys.public.toString(16), const_1.default.DEFAULT_ENCODING, accept.pluginName);
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1864
1807
|
// Check buffer contains salt
|
|
1865
1808
|
var saltLen = d.buffer.readUInt16LE(0);
|
|
1866
1809
|
if (saltLen > 32 * 2) {
|
|
1867
1810
|
console.log('salt to long'); // TODO : Throw error
|
|
1868
1811
|
}
|
|
1869
|
-
|
|
1870
1812
|
// Check buffer contains key
|
|
1871
1813
|
var keyLen = d.buffer.readUInt16LE(saltLen + 2);
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1814
|
+
if (d.buffer.length < saltLen + 4) {
|
|
1815
|
+
var errBuf = new Error('Invalid buffer size for ' + accept.pluginName + ' login');
|
|
1816
|
+
(0, callback_1.doError)(errBuf, callback);
|
|
1817
|
+
return cb(errBuf);
|
|
1875
1818
|
}
|
|
1876
|
-
|
|
1819
|
+
var keyStart = (saltLen + 2 + 3) & ~3;
|
|
1877
1820
|
// Server keys
|
|
1878
1821
|
cnx.serverKeys = {
|
|
1879
1822
|
salt: d.buffer.slice(2, saltLen + 2).toString('utf8'),
|
|
1880
|
-
public: BigInt('0x' + d.buffer.slice(keyStart, d.buffer.length).toString('utf8'))
|
|
1823
|
+
public: BigInt('0x' + d.buffer.slice(keyStart, d.buffer.length).toString('utf8')),
|
|
1824
|
+
pluginName: accept.pluginName
|
|
1881
1825
|
};
|
|
1882
|
-
|
|
1826
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
1827
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
1828
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
1829
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
1830
|
+
console.log('client private key:', cnx.clientKeys.private.toString(16));
|
|
1831
|
+
console.log('hashAlgo:', accept.srpAlgo);
|
|
1883
1832
|
const _t1 = Date.now();
|
|
1884
|
-
var proof = srp.clientProof(
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
cnx.serverKeys.salt,
|
|
1888
|
-
cnx.clientKeys.public,
|
|
1889
|
-
cnx.serverKeys.public,
|
|
1890
|
-
cnx.clientKeys.private,
|
|
1891
|
-
accept.srpAlgo
|
|
1892
|
-
);
|
|
1833
|
+
var proof = srp.clientProof(cnx.options.user.toUpperCase(), cnx.options.password, cnx.serverKeys.salt, cnx.clientKeys.public, cnx.serverKeys.public, cnx.clientKeys.private, accept.srpAlgo);
|
|
1834
|
+
console.log('client proof M1:', proof.authData.toString(16));
|
|
1835
|
+
console.log('client session key K:', proof.clientSessionKey.toString(16));
|
|
1893
1836
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1894
1837
|
console.log('[fb-debug] srp.clientProof(%s): %dms', accept.srpAlgo, Date.now() - _t1);
|
|
1895
1838
|
}
|
|
1896
|
-
|
|
1897
1839
|
accept.authData = proof.authData.toString(16);
|
|
1898
1840
|
accept.sessionKey = proof.clientSessionKey;
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1841
|
+
}
|
|
1842
|
+
else if (accept.pluginName === const_1.default.AUTH_PLUGIN_LEGACY) {
|
|
1843
|
+
accept.authData = crypt.crypt(cnx.options.password, const_1.default.LEGACY_AUTH_SALT).substring(2);
|
|
1844
|
+
}
|
|
1845
|
+
else {
|
|
1902
1846
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
1903
1847
|
}
|
|
1904
|
-
}
|
|
1848
|
+
}
|
|
1849
|
+
else {
|
|
1905
1850
|
accept.authData = '';
|
|
1906
1851
|
accept.sessionKey = '';
|
|
1907
1852
|
}
|
|
1908
1853
|
}
|
|
1909
|
-
|
|
1910
1854
|
if (accept.compress) {
|
|
1911
1855
|
cnx._socket.enableCompression();
|
|
1912
1856
|
}
|
|
1913
|
-
|
|
1914
1857
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1915
|
-
console.log('[fb-debug] auth: %s received plugin=%s proto=%d t=%dms',
|
|
1916
|
-
r === Const.op_cond_accept ? 'op_cond_accept' : r === Const.op_accept_data ? 'op_accept_data' : 'op_accept',
|
|
1917
|
-
accept.pluginName, accept.protocolVersion,
|
|
1918
|
-
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1858
|
+
console.log('[fb-debug] auth: %s received plugin=%s proto=%d t=%dms', r === const_1.default.op_cond_accept ? 'op_cond_accept' : r === const_1.default.op_accept_data ? 'op_accept_data' : 'op_accept', accept.pluginName, accept.protocolVersion, cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1919
1859
|
}
|
|
1920
|
-
|
|
1921
1860
|
// For op_cond_accept: send op_cont_auth and wait for response
|
|
1922
|
-
if (r ===
|
|
1861
|
+
if (r === const_1.default.op_cond_accept && accept.authData) {
|
|
1923
1862
|
cnx._pendingAccept = accept;
|
|
1924
1863
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1925
|
-
console.log('[fb-debug] auth: sending op_cont_auth plugin=%s t=%dms',
|
|
1926
|
-
accept.pluginName, cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1864
|
+
console.log('[fb-debug] auth: sending op_cont_auth plugin=%s t=%dms', accept.pluginName, cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1927
1865
|
}
|
|
1928
|
-
cnx.sendOpContAuth(
|
|
1929
|
-
accept.authData,
|
|
1930
|
-
Const.DEFAULT_ENCODING,
|
|
1931
|
-
accept.pluginName
|
|
1932
|
-
);
|
|
1866
|
+
cnx.sendOpContAuth(accept.authData, const_1.default.DEFAULT_ENCODING, accept.pluginName);
|
|
1933
1867
|
return; // Don't call cb - queue stays for op_response
|
|
1934
1868
|
}
|
|
1935
|
-
|
|
1936
1869
|
return cb(undefined, accept);
|
|
1937
|
-
case
|
|
1938
|
-
var d = new BlrReader(data.readArray());
|
|
1939
|
-
var pluginName = data.readString(
|
|
1940
|
-
data.readString(
|
|
1941
|
-
data.readString(
|
|
1942
|
-
|
|
1870
|
+
case const_1.default.op_cont_auth:
|
|
1871
|
+
var d = new serialize_1.BlrReader(data.readArray());
|
|
1872
|
+
var pluginName = data.readString(const_1.default.DEFAULT_ENCODING);
|
|
1873
|
+
data.readString(const_1.default.DEFAULT_ENCODING); // plist
|
|
1874
|
+
data.readString(const_1.default.DEFAULT_ENCODING); // pkey
|
|
1943
1875
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1944
|
-
console.log('[fb-debug] auth: op_cont_auth received plugin=%s pendingAccept=%s t=%dms',
|
|
1945
|
-
pluginName,
|
|
1946
|
-
cnx._pendingAccept ? cnx._pendingAccept.pluginName : 'none',
|
|
1947
|
-
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1876
|
+
console.log('[fb-debug] auth: op_cont_auth received plugin=%s pendingAccept=%s t=%dms', pluginName, cnx._pendingAccept ? cnx._pendingAccept.pluginName : 'none', cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1948
1877
|
}
|
|
1949
|
-
|
|
1950
1878
|
// During SRP mutual authentication, the server sends op_cont_auth
|
|
1951
1879
|
// with its proof (M2) after receiving the client's proof (M1).
|
|
1952
|
-
// When we have an active auth exchange for this plugin
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1880
|
+
// When we have an active auth exchange for this plugin:
|
|
1881
|
+
if (cnx._pendingAccept && (cnx._pendingAccept.pluginName === pluginName || const_1.default.AUTH_PLUGIN_SRP_LIST.indexOf(pluginName) !== -1)) {
|
|
1882
|
+
if (cnx._pendingAccept.pluginName !== pluginName) {
|
|
1883
|
+
cnx._pendingAccept.pluginName = pluginName;
|
|
1884
|
+
}
|
|
1885
|
+
// The server can switch SRP hash variants mid-handshake: after
|
|
1886
|
+
// the client answers with e.g. Srp256, some accounts make the
|
|
1887
|
+
// server come back with a fresh op_cont_auth naming a different
|
|
1888
|
+
// SRP plugin (e.g. plain Srp/sha1), reusing the same salt/B.
|
|
1889
|
+
// That must be treated as a brand-new challenge - recomputing
|
|
1890
|
+
// the proof with the new plugin's hash algorithm - rather than
|
|
1891
|
+
// as the server's M2 proof, otherwise the client silently waits
|
|
1892
|
+
// forever for an op_accept the server will never send (#254).
|
|
1893
|
+
if (!cnx.serverKeys || cnx.serverKeys.pluginName !== pluginName) {
|
|
1894
|
+
// Check buffer contains salt
|
|
1895
|
+
var saltLen = d.buffer.readUInt16LE(0);
|
|
1896
|
+
if (saltLen > 32 * 2) {
|
|
1897
|
+
console.log('salt to long'); // TODO : Throw error
|
|
1898
|
+
}
|
|
1899
|
+
// Check buffer contains key
|
|
1900
|
+
var keyLen = d.buffer.readUInt16LE(saltLen + 2);
|
|
1901
|
+
if (d.buffer.length < saltLen + 4) {
|
|
1902
|
+
var errBuf = new Error('Invalid buffer size for ' + pluginName + ' login');
|
|
1903
|
+
(0, callback_1.doError)(errBuf, callback);
|
|
1904
|
+
return cb(errBuf);
|
|
1905
|
+
}
|
|
1906
|
+
var keyStart = (saltLen + 2 + 3) & ~3;
|
|
1907
|
+
// Server keys
|
|
1908
|
+
cnx.serverKeys = {
|
|
1909
|
+
salt: d.buffer.slice(2, saltLen + 2).toString('utf8'),
|
|
1910
|
+
public: BigInt('0x' + d.buffer.slice(keyStart, d.buffer.length).toString('utf8')),
|
|
1911
|
+
pluginName: pluginName
|
|
1912
|
+
};
|
|
1913
|
+
var crypto = {
|
|
1914
|
+
Srp: 'sha1',
|
|
1915
|
+
Srp256: 'sha256',
|
|
1916
|
+
Srp384: 'sha384',
|
|
1917
|
+
Srp512: 'sha512'
|
|
1918
|
+
};
|
|
1919
|
+
var srpAlgo = crypto[pluginName];
|
|
1920
|
+
console.log('--- DEBUG SRP Handshake ---');
|
|
1921
|
+
console.log('salt:', cnx.serverKeys.salt);
|
|
1922
|
+
console.log('server public key:', cnx.serverKeys.public.toString(16));
|
|
1923
|
+
console.log('client public key:', cnx.clientKeys.public.toString(16));
|
|
1924
|
+
console.log('client private key:', cnx.clientKeys.private.toString(16));
|
|
1925
|
+
console.log('hashAlgo:', srpAlgo);
|
|
1926
|
+
const _t1 = Date.now();
|
|
1927
|
+
var proof = srp.clientProof(cnx.options.user.toUpperCase(), cnx.options.password, cnx.serverKeys.salt, cnx.clientKeys.public, cnx.serverKeys.public, cnx.clientKeys.private, srpAlgo);
|
|
1928
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
1929
|
+
console.log('[fb-debug] srp.clientProof(%s): %dms', srpAlgo, Date.now() - _t1);
|
|
1930
|
+
}
|
|
1931
|
+
cnx._pendingAccept.authData = proof.authData.toString(16);
|
|
1932
|
+
cnx._pendingAccept.sessionKey = proof.clientSessionKey;
|
|
1933
|
+
cnx.sendOpContAuth(cnx._pendingAccept.authData, const_1.default.DEFAULT_ENCODING, pluginName);
|
|
1934
|
+
return; // wait for server SRP proof (M2) and/or op_accept
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
if (process.env.FIREBIRD_DEBUG) {
|
|
1938
|
+
console.log('[fb-debug] auth: server SRP proof (M2) received, waiting for op_accept t=%dms', cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1939
|
+
}
|
|
1940
|
+
return; // Server SRP proof received - wait for op_accept
|
|
1958
1941
|
}
|
|
1959
|
-
return; // Server SRP proof received - wait for op_accept
|
|
1960
1942
|
}
|
|
1961
|
-
|
|
1962
1943
|
// Firebird 4/5 (protocols 16/17) chained-auth: after the client sends
|
|
1963
1944
|
// the SRP M1 proof, the server sends op_cont_auth with Legacy_Auth.
|
|
1964
1945
|
// SRP has already established the session key; the server additionally
|
|
1965
1946
|
// requires a Legacy_Auth verification step before sending op_accept.
|
|
1966
1947
|
// Respond with Legacy_Auth credentials and wait for op_accept.
|
|
1967
|
-
if (cnx._pendingAccept && pluginName ===
|
|
1948
|
+
if (cnx._pendingAccept && pluginName === const_1.default.AUTH_PLUGIN_LEGACY) {
|
|
1968
1949
|
if (process.env.FIREBIRD_DEBUG) {
|
|
1969
|
-
console.log('[fb-debug] auth: SRP+Legacy_Auth chained-auth (proto %d), sending Legacy_Auth credentials t=%dms',
|
|
1970
|
-
cnx._pendingAccept.protocolVersion,
|
|
1971
|
-
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1950
|
+
console.log('[fb-debug] auth: SRP+Legacy_Auth chained-auth (proto %d), sending Legacy_Auth credentials t=%dms', cnx._pendingAccept.protocolVersion, cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1972
1951
|
}
|
|
1973
|
-
var legacyAuthData = crypt.crypt(cnx.options.password,
|
|
1974
|
-
cnx.sendOpContAuth(legacyAuthData,
|
|
1952
|
+
var legacyAuthData = crypt.crypt(cnx.options.password, const_1.default.LEGACY_AUTH_SALT).substring(2);
|
|
1953
|
+
cnx.sendOpContAuth(legacyAuthData, const_1.default.DEFAULT_ENCODING, pluginName);
|
|
1975
1954
|
return; // wait for op_accept
|
|
1976
1955
|
}
|
|
1977
|
-
|
|
1978
1956
|
if (!cnx.options.pluginName) {
|
|
1979
1957
|
if (cnx.accept && cnx.accept.pluginName === pluginName) {
|
|
1980
1958
|
// Erreur plugin not able to connect
|
|
1981
1959
|
return cb(new Error("Unable to connect with plugin " + cnx.accept.pluginName));
|
|
1982
1960
|
}
|
|
1983
|
-
|
|
1984
|
-
if (pluginName === Const.AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
1961
|
+
if (pluginName === const_1.default.AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
1985
1962
|
cnx.accept.pluginName = pluginName;
|
|
1986
|
-
cnx.accept.authData = crypt.crypt(cnx.options.password,
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
cnx.accept.authData,
|
|
1990
|
-
Const.DEFAULT_ENCODING,
|
|
1991
|
-
pluginName
|
|
1992
|
-
);
|
|
1993
|
-
|
|
1994
|
-
return {error: new Error('login')};
|
|
1963
|
+
cnx.accept.authData = crypt.crypt(cnx.options.password, const_1.default.LEGACY_AUTH_SALT).substring(2);
|
|
1964
|
+
cnx.sendOpContAuth(cnx.accept.authData, const_1.default.DEFAULT_ENCODING, pluginName);
|
|
1965
|
+
return { error: new Error('login') };
|
|
1995
1966
|
}
|
|
1996
1967
|
}
|
|
1997
|
-
|
|
1998
1968
|
// Server sent op_cont_auth but we don't know how to handle it.
|
|
1999
1969
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2000
|
-
console.warn('[fb-debug] auth: op_cont_auth unhandled plugin=%s pendingAccept=%s options.plugin=%s t=%dms',
|
|
2001
|
-
pluginName,
|
|
2002
|
-
cnx._pendingAccept ? cnx._pendingAccept.pluginName : 'none',
|
|
2003
|
-
cnx.options.pluginName || 'none',
|
|
2004
|
-
cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
1970
|
+
console.warn('[fb-debug] auth: op_cont_auth unhandled plugin=%s pendingAccept=%s options.plugin=%s t=%dms', pluginName, cnx._pendingAccept ? cnx._pendingAccept.pluginName : 'none', cnx.options.pluginName || 'none', cnx._authStartTime ? Date.now() - cnx._authStartTime : -1);
|
|
2005
1971
|
}
|
|
2006
1972
|
return cb(new Error('Unhandled server op_cont_auth for plugin: ' + pluginName));
|
|
2007
|
-
case
|
|
1973
|
+
case const_1.default.op_crypt_key_callback:
|
|
2008
1974
|
// Database encryption key callback
|
|
2009
1975
|
// Read server data (plugin data sent by server)
|
|
2010
1976
|
var serverPluginData = data.readArray();
|
|
2011
1977
|
data.readInt(); // p_cc_reply
|
|
2012
|
-
|
|
2013
1978
|
// Get client response from dbCryptConfig option
|
|
2014
1979
|
var clientPluginData = parseDbCryptConfig(cnx.options.dbCryptConfig);
|
|
2015
|
-
|
|
2016
1980
|
// Create a BlrWriter to send the response
|
|
2017
1981
|
// Note: BlrWriter needs initial buffer size allocation
|
|
2018
|
-
var responseBlr = new BlrWriter(clientPluginData.length + 4);
|
|
1982
|
+
var responseBlr = new serialize_1.BlrWriter(clientPluginData.length + 4);
|
|
2019
1983
|
responseBlr.addBytes(clientPluginData);
|
|
2020
|
-
|
|
2021
1984
|
// Send the response back to the server
|
|
2022
1985
|
cnx.sendOpCryptKeyCallback(responseBlr);
|
|
2023
|
-
|
|
2024
1986
|
// Don't call cb - wait for next operation (likely op_response or another op_crypt_key_callback)
|
|
2025
1987
|
return;
|
|
2026
|
-
case
|
|
1988
|
+
case const_1.default.op_event:
|
|
2027
1989
|
// op_event may occasionally arrive on the main connection
|
|
2028
1990
|
// (e.g. Firebird routing an async notification here instead of
|
|
2029
1991
|
// the dedicated aux socket). Consume all its fields so the
|
|
@@ -2036,16 +1998,16 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
2036
1998
|
// p_event_ast : Int64 – AST routine pointer (0 for remote)
|
|
2037
1999
|
// p_event_rid : Int32 – remote event ID
|
|
2038
2000
|
{
|
|
2039
|
-
const evtDb = data.readInt();
|
|
2040
|
-
data.readArray();
|
|
2041
|
-
data.readInt64();
|
|
2042
|
-
const evtRid = data.readInt();
|
|
2001
|
+
const evtDb = data.readInt(); // p_event_database
|
|
2002
|
+
data.readArray(); // p_event_items (EPB buffer)
|
|
2003
|
+
data.readInt64(); // p_event_ast
|
|
2004
|
+
const evtRid = data.readInt(); // p_event_rid
|
|
2043
2005
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2044
2006
|
console.log('[fb-debug] op_event on main connection: db=%d rid=%d (consumed, not queued)', evtDb, evtRid);
|
|
2045
2007
|
}
|
|
2046
2008
|
}
|
|
2047
2009
|
return cb(null, { _isOpEvent: true });
|
|
2048
|
-
case
|
|
2010
|
+
case const_1.default.op_response_piggyback:
|
|
2049
2011
|
// Firebird 5 (Protocol 16/17) sends op_response_piggyback (72)
|
|
2050
2012
|
// as an unsolicited cleanup notification after certain operations
|
|
2051
2013
|
// (e.g. after the EventConnection aux socket is torn down).
|
|
@@ -2059,11 +2021,12 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
2059
2021
|
// object : Quad (2x Int32)
|
|
2060
2022
|
// data : Array
|
|
2061
2023
|
// status : status-vector ending with isc_arg_end
|
|
2062
|
-
parseOpResponse(data, {}, function(err) {
|
|
2024
|
+
parseOpResponse(data, {}, function (err) {
|
|
2063
2025
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2064
2026
|
if (err) {
|
|
2065
2027
|
console.warn('[fb-debug] op_response_piggyback parse error:', err.message);
|
|
2066
|
-
}
|
|
2028
|
+
}
|
|
2029
|
+
else {
|
|
2067
2030
|
console.log('[fb-debug] op_response_piggyback consumed (unsolicited Firebird 5 cleanup)');
|
|
2068
2031
|
}
|
|
2069
2032
|
}
|
|
@@ -2071,15 +2034,14 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
2071
2034
|
return cb(null, { _isOpEvent: true });
|
|
2072
2035
|
default:
|
|
2073
2036
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2074
|
-
console.warn('[fb-debug] unknown opcode=%d at pos=%d buflen=%d queue=%d',
|
|
2075
|
-
r, data.pos, data.buffer.length, cnx && cnx._queue ? cnx._queue.length : 0);
|
|
2037
|
+
console.warn('[fb-debug] unknown opcode=%d at pos=%d buflen=%d queue=%d', r, data.pos, data.buffer.length, cnx && cnx._queue ? cnx._queue.length : 0);
|
|
2076
2038
|
}
|
|
2077
2039
|
return cb(new Error('Unexpected:' + r));
|
|
2078
2040
|
}
|
|
2079
|
-
}
|
|
2041
|
+
}
|
|
2042
|
+
catch (err) {
|
|
2080
2043
|
if (process.env.FIREBIRD_DEBUG) {
|
|
2081
|
-
console.warn('[fb-debug] decodeResponse exception: %s (RangeError=%s) pos=%d buflen=%d',
|
|
2082
|
-
err.message, err instanceof RangeError, data.pos, data.buffer.length);
|
|
2044
|
+
console.warn('[fb-debug] decodeResponse exception: %s (RangeError=%s) pos=%d buflen=%d', err.message, err instanceof RangeError, data.pos, data.buffer.length);
|
|
2083
2045
|
}
|
|
2084
2046
|
if (err instanceof RangeError) {
|
|
2085
2047
|
return cb(err);
|
|
@@ -2087,177 +2049,218 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
2087
2049
|
throw err;
|
|
2088
2050
|
}
|
|
2089
2051
|
}
|
|
2090
|
-
|
|
2091
2052
|
function parseOpResponse(data, response, cb) {
|
|
2092
2053
|
var handle = data.readInt();
|
|
2093
|
-
|
|
2094
2054
|
if (!response.handle) {
|
|
2095
2055
|
response.handle = handle;
|
|
2096
2056
|
}
|
|
2097
|
-
|
|
2098
2057
|
var oid = data.readQuad();
|
|
2099
2058
|
if (oid.low || oid.high) {
|
|
2100
2059
|
response.oid = oid;
|
|
2101
2060
|
}
|
|
2102
|
-
|
|
2103
2061
|
var buf = data.readArray();
|
|
2104
2062
|
if (buf) {
|
|
2105
2063
|
response.buffer = buf;
|
|
2106
2064
|
}
|
|
2107
|
-
|
|
2108
2065
|
var num, op, item = {};
|
|
2109
2066
|
while (true) {
|
|
2110
2067
|
op = data.readInt();
|
|
2111
|
-
|
|
2112
2068
|
switch (op) {
|
|
2113
|
-
case
|
|
2069
|
+
case const_1.default.isc_arg_end:
|
|
2114
2070
|
return cb ? cb(undefined, response) : response;
|
|
2115
|
-
case
|
|
2071
|
+
case const_1.default.isc_arg_gds:
|
|
2116
2072
|
num = data.readInt();
|
|
2117
2073
|
if (!num) {
|
|
2118
2074
|
break;
|
|
2119
2075
|
}
|
|
2120
|
-
|
|
2121
|
-
item = {gdscode: num};
|
|
2122
|
-
|
|
2076
|
+
item = { gdscode: num };
|
|
2123
2077
|
if (response.status) {
|
|
2124
2078
|
response.status.push(item);
|
|
2125
|
-
}
|
|
2079
|
+
}
|
|
2080
|
+
else {
|
|
2126
2081
|
response.status = [item];
|
|
2127
2082
|
}
|
|
2128
|
-
|
|
2129
2083
|
break;
|
|
2130
|
-
case
|
|
2131
|
-
case
|
|
2132
|
-
case
|
|
2084
|
+
case const_1.default.isc_arg_string:
|
|
2085
|
+
case const_1.default.isc_arg_interpreted:
|
|
2086
|
+
case const_1.default.isc_arg_sql_state:
|
|
2133
2087
|
if (item.params) {
|
|
2134
|
-
var str = data.readString(
|
|
2088
|
+
var str = data.readString(const_1.default.DEFAULT_ENCODING);
|
|
2135
2089
|
item.params.push(str);
|
|
2136
|
-
} else {
|
|
2137
|
-
item.params = [data.readString(Const.DEFAULT_ENCODING)];
|
|
2138
2090
|
}
|
|
2139
|
-
|
|
2091
|
+
else {
|
|
2092
|
+
item.params = [data.readString(const_1.default.DEFAULT_ENCODING)];
|
|
2093
|
+
}
|
|
2140
2094
|
break;
|
|
2141
|
-
case
|
|
2095
|
+
case const_1.default.isc_arg_number:
|
|
2142
2096
|
num = data.readInt();
|
|
2143
|
-
|
|
2144
2097
|
if (item.params) {
|
|
2145
2098
|
item.params.push(num);
|
|
2146
|
-
}
|
|
2099
|
+
}
|
|
2100
|
+
else {
|
|
2147
2101
|
item.params = [num];
|
|
2148
2102
|
}
|
|
2149
|
-
|
|
2150
|
-
if (item.gdscode === Const.isc_sqlerr) {
|
|
2103
|
+
if (item.gdscode === const_1.default.isc_sqlerr) {
|
|
2151
2104
|
response.sqlcode = num;
|
|
2152
2105
|
}
|
|
2153
|
-
|
|
2154
2106
|
break;
|
|
2155
2107
|
default:
|
|
2156
2108
|
if (cb) {
|
|
2157
|
-
cb(new Error('Unexpected: ' + op))
|
|
2158
|
-
}
|
|
2109
|
+
cb(new Error('Unexpected: ' + op));
|
|
2110
|
+
}
|
|
2111
|
+
else {
|
|
2159
2112
|
throw new Error('Unexpected: ' + op);
|
|
2160
2113
|
}
|
|
2161
2114
|
}
|
|
2162
2115
|
}
|
|
2163
2116
|
}
|
|
2164
|
-
|
|
2165
2117
|
function describe(buff, statement) {
|
|
2166
|
-
var br = new BlrReader(buff);
|
|
2118
|
+
var br = new serialize_1.BlrReader(buff);
|
|
2167
2119
|
var parameters = null;
|
|
2168
2120
|
var type, param;
|
|
2169
|
-
|
|
2170
2121
|
while (br.pos < br.buffer.length) {
|
|
2171
2122
|
switch (br.readByteCode()) {
|
|
2172
|
-
case
|
|
2123
|
+
case const_1.default.isc_info_sql_stmt_type:
|
|
2173
2124
|
statement.type = br.readInt();
|
|
2174
2125
|
break;
|
|
2175
|
-
case
|
|
2176
|
-
statement.plan = br.readString(
|
|
2126
|
+
case const_1.default.isc_info_sql_get_plan:
|
|
2127
|
+
statement.plan = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2177
2128
|
break;
|
|
2178
|
-
case
|
|
2129
|
+
case const_1.default.isc_info_sql_select:
|
|
2179
2130
|
statement.output = parameters = [];
|
|
2180
2131
|
break;
|
|
2181
|
-
case
|
|
2132
|
+
case const_1.default.isc_info_sql_bind:
|
|
2182
2133
|
statement.input = parameters = [];
|
|
2183
2134
|
break;
|
|
2184
|
-
case
|
|
2135
|
+
case const_1.default.isc_info_sql_num_variables:
|
|
2185
2136
|
br.readInt(); // eat int
|
|
2186
2137
|
break;
|
|
2187
|
-
case
|
|
2188
|
-
if (!parameters) {
|
|
2138
|
+
case const_1.default.isc_info_sql_describe_vars:
|
|
2139
|
+
if (!parameters) {
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2189
2142
|
br.readInt(); // eat int ?
|
|
2190
2143
|
var finishDescribe = false;
|
|
2191
2144
|
param = null;
|
|
2192
|
-
while (!finishDescribe){
|
|
2145
|
+
while (!finishDescribe) {
|
|
2193
2146
|
switch (br.readByteCode()) {
|
|
2194
|
-
case
|
|
2147
|
+
case const_1.default.isc_info_sql_describe_end:
|
|
2195
2148
|
break;
|
|
2196
|
-
case
|
|
2149
|
+
case const_1.default.isc_info_sql_sqlda_seq:
|
|
2197
2150
|
var num = br.readInt();
|
|
2198
2151
|
break;
|
|
2199
|
-
case
|
|
2152
|
+
case const_1.default.isc_info_sql_type:
|
|
2200
2153
|
type = br.readInt();
|
|
2201
|
-
switch (type
|
|
2202
|
-
case
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
case
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
case
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
case
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
case
|
|
2215
|
-
case
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
case
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
case
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
case
|
|
2154
|
+
switch (type & ~1) {
|
|
2155
|
+
case const_1.default.SQL_VARYING:
|
|
2156
|
+
param = new Xsql.SQLVarString();
|
|
2157
|
+
break;
|
|
2158
|
+
case const_1.default.SQL_NULL:
|
|
2159
|
+
param = new Xsql.SQLVarNull();
|
|
2160
|
+
break;
|
|
2161
|
+
case const_1.default.SQL_TEXT:
|
|
2162
|
+
param = new Xsql.SQLVarText();
|
|
2163
|
+
break;
|
|
2164
|
+
case const_1.default.SQL_DOUBLE:
|
|
2165
|
+
param = new Xsql.SQLVarDouble();
|
|
2166
|
+
break;
|
|
2167
|
+
case const_1.default.SQL_FLOAT:
|
|
2168
|
+
case const_1.default.SQL_D_FLOAT:
|
|
2169
|
+
param = new Xsql.SQLVarFloat();
|
|
2170
|
+
break;
|
|
2171
|
+
case const_1.default.SQL_TYPE_DATE:
|
|
2172
|
+
param = new Xsql.SQLVarDate();
|
|
2173
|
+
break;
|
|
2174
|
+
case const_1.default.SQL_TYPE_TIME:
|
|
2175
|
+
param = new Xsql.SQLVarTime();
|
|
2176
|
+
break;
|
|
2177
|
+
case const_1.default.SQL_TIMESTAMP:
|
|
2178
|
+
param = new Xsql.SQLVarTimeStamp();
|
|
2179
|
+
break;
|
|
2180
|
+
case const_1.default.SQL_TIME_TZ:
|
|
2181
|
+
param = new Xsql.SQLVarTimeTz();
|
|
2182
|
+
break;
|
|
2183
|
+
case const_1.default.SQL_TIME_TZ_EX:
|
|
2184
|
+
param = new Xsql.SQLVarTimeTzEx();
|
|
2185
|
+
break;
|
|
2186
|
+
case const_1.default.SQL_TIMESTAMP_TZ:
|
|
2187
|
+
param = new Xsql.SQLVarTimeStampTz();
|
|
2188
|
+
break;
|
|
2189
|
+
case const_1.default.SQL_TIMESTAMP_TZ_EX:
|
|
2190
|
+
param = new Xsql.SQLVarTimeStampTzEx();
|
|
2191
|
+
break;
|
|
2192
|
+
case const_1.default.SQL_BLOB:
|
|
2193
|
+
param = new Xsql.SQLVarBlob();
|
|
2194
|
+
break;
|
|
2195
|
+
case const_1.default.SQL_ARRAY:
|
|
2196
|
+
param = new Xsql.SQLVarArray();
|
|
2197
|
+
break;
|
|
2198
|
+
case const_1.default.SQL_QUAD:
|
|
2199
|
+
param = new Xsql.SQLVarQuad();
|
|
2200
|
+
break;
|
|
2201
|
+
case const_1.default.SQL_LONG:
|
|
2202
|
+
param = new Xsql.SQLVarInt();
|
|
2203
|
+
break;
|
|
2204
|
+
case const_1.default.SQL_SHORT:
|
|
2205
|
+
param = new Xsql.SQLVarShort();
|
|
2206
|
+
break;
|
|
2207
|
+
case const_1.default.SQL_INT64:
|
|
2208
|
+
param = new Xsql.SQLVarInt64();
|
|
2209
|
+
break;
|
|
2210
|
+
case const_1.default.SQL_INT128:
|
|
2211
|
+
param = new Xsql.SQLVarInt128();
|
|
2212
|
+
break;
|
|
2213
|
+
case const_1.default.SQL_DEC16:
|
|
2214
|
+
param = new Xsql.SQLVarDecFloat16();
|
|
2215
|
+
break;
|
|
2216
|
+
case const_1.default.SQL_DEC34:
|
|
2217
|
+
param = new Xsql.SQLVarDecFloat34();
|
|
2218
|
+
break;
|
|
2219
|
+
case const_1.default.SQL_BOOLEAN:
|
|
2220
|
+
param = new Xsql.SQLVarBoolean();
|
|
2221
|
+
break;
|
|
2225
2222
|
default:
|
|
2226
2223
|
throw new Error('Unexpected');
|
|
2227
2224
|
}
|
|
2228
|
-
parameters[num-1] = param;
|
|
2225
|
+
parameters[num - 1] = param;
|
|
2229
2226
|
param.type = type;
|
|
2230
2227
|
param.nullable = Boolean(param.type & 1);
|
|
2231
2228
|
param.type &= ~1;
|
|
2232
2229
|
break;
|
|
2233
|
-
case
|
|
2230
|
+
case const_1.default.isc_info_sql_sub_type:
|
|
2234
2231
|
param.subType = br.readInt();
|
|
2235
2232
|
break;
|
|
2236
|
-
case
|
|
2233
|
+
case const_1.default.isc_info_sql_scale:
|
|
2237
2234
|
param.scale = br.readInt();
|
|
2238
2235
|
break;
|
|
2239
|
-
case
|
|
2236
|
+
case const_1.default.isc_info_sql_length:
|
|
2240
2237
|
param.length = br.readInt();
|
|
2241
2238
|
break;
|
|
2242
|
-
case
|
|
2239
|
+
case const_1.default.isc_info_sql_null_ind:
|
|
2243
2240
|
param.nullable = Boolean(br.readInt());
|
|
2244
2241
|
break;
|
|
2245
|
-
case
|
|
2246
|
-
param.field = br.readString(
|
|
2242
|
+
case const_1.default.isc_info_sql_field:
|
|
2243
|
+
param.field = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2247
2244
|
break;
|
|
2248
|
-
case
|
|
2249
|
-
param.relation = br.readString(
|
|
2245
|
+
case const_1.default.isc_info_sql_relation:
|
|
2246
|
+
param.relation = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2250
2247
|
break;
|
|
2251
|
-
case
|
|
2252
|
-
|
|
2248
|
+
case const_1.default.isc_info_sql_relation_schema:
|
|
2249
|
+
// Firebird 6.0 (Protocol 20+): schema that owns the
|
|
2250
|
+
// source relation. Empty string means the default
|
|
2251
|
+
// (PUBLIC) schema or a non-schema-aware server.
|
|
2252
|
+
param.relationSchema = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2253
2253
|
break;
|
|
2254
|
-
case
|
|
2255
|
-
param.
|
|
2254
|
+
case const_1.default.isc_info_sql_owner:
|
|
2255
|
+
param.owner = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2256
2256
|
break;
|
|
2257
|
-
case
|
|
2258
|
-
param.
|
|
2257
|
+
case const_1.default.isc_info_sql_alias:
|
|
2258
|
+
param.alias = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2259
2259
|
break;
|
|
2260
|
-
case
|
|
2260
|
+
case const_1.default.isc_info_sql_relation_alias:
|
|
2261
|
+
param.relationAlias = br.readString(const_1.default.DEFAULT_ENCODING);
|
|
2262
|
+
break;
|
|
2263
|
+
case const_1.default.isc_info_truncated:
|
|
2261
2264
|
throw new Error('Truncated');
|
|
2262
2265
|
default:
|
|
2263
2266
|
finishDescribe = true;
|
|
@@ -2266,103 +2269,112 @@ function describe(buff, statement) {
|
|
|
2266
2269
|
}
|
|
2267
2270
|
}
|
|
2268
2271
|
}
|
|
2272
|
+
function unpackCharSetCollation(params) {
|
|
2273
|
+
if (!params)
|
|
2274
|
+
return;
|
|
2275
|
+
for (let i = 0; i < params.length; i++) {
|
|
2276
|
+
const p = params[i];
|
|
2277
|
+
if (p && (p.type === const_1.default.SQL_TEXT || p.type === const_1.default.SQL_VARYING)) {
|
|
2278
|
+
if (p.subType !== undefined) {
|
|
2279
|
+
p.charSetId = p.subType & 0xFF;
|
|
2280
|
+
p.collationId = p.subType >> 8;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
unpackCharSetCollation(statement.input);
|
|
2286
|
+
unpackCharSetCollation(statement.output);
|
|
2269
2287
|
}
|
|
2270
|
-
|
|
2271
2288
|
function CalcBlr(blr, xsqlda) {
|
|
2272
|
-
blr.addBytes([
|
|
2289
|
+
blr.addBytes([const_1.default.blr_version5, const_1.default.blr_begin, const_1.default.blr_message, 0]); // + message number
|
|
2273
2290
|
blr.addWord(xsqlda.length * 2);
|
|
2274
|
-
|
|
2275
2291
|
for (var i = 0, length = xsqlda.length; i < length; i++) {
|
|
2276
2292
|
xsqlda[i].calcBlr(blr);
|
|
2277
|
-
blr.addByte(
|
|
2293
|
+
blr.addByte(const_1.default.blr_short);
|
|
2278
2294
|
blr.addByte(0);
|
|
2279
2295
|
}
|
|
2280
|
-
|
|
2281
|
-
blr.addByte(
|
|
2282
|
-
blr.addByte(Const.blr_eoc);
|
|
2296
|
+
blr.addByte(const_1.default.blr_end);
|
|
2297
|
+
blr.addByte(const_1.default.blr_eoc);
|
|
2283
2298
|
}
|
|
2284
|
-
|
|
2285
2299
|
function fetch_blob_async_transaction(statement, id, column, row) {
|
|
2286
2300
|
const infoValue = { row, column, value: '' };
|
|
2287
|
-
|
|
2288
2301
|
return (transactionArg) => {
|
|
2302
|
+
const cacheKey = `${id.high}:${id.low}`;
|
|
2303
|
+
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
2304
|
+
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
2305
|
+
infoValue.value = data ? data.toString(const_1.default.DEFAULT_ENCODING) : '';
|
|
2306
|
+
return Promise.resolve(infoValue);
|
|
2307
|
+
}
|
|
2289
2308
|
const singleTransaction = transactionArg === undefined;
|
|
2290
|
-
|
|
2291
2309
|
let promiseTransaction;
|
|
2292
2310
|
if (singleTransaction) {
|
|
2293
2311
|
promiseTransaction = new Promise((resolve, reject) => {
|
|
2294
|
-
statement.connection.startTransaction(
|
|
2312
|
+
statement.connection.startTransaction(const_1.default.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
2295
2313
|
if (err) {
|
|
2296
2314
|
return reject(err);
|
|
2297
2315
|
}
|
|
2298
2316
|
resolve(transaction);
|
|
2299
2317
|
});
|
|
2300
2318
|
});
|
|
2301
|
-
}
|
|
2319
|
+
}
|
|
2320
|
+
else {
|
|
2302
2321
|
promiseTransaction = Promise.resolve(transactionArg);
|
|
2303
2322
|
}
|
|
2304
|
-
|
|
2305
2323
|
return promiseTransaction.then((transaction) => {
|
|
2306
2324
|
return new Promise((resolve, reject) => {
|
|
2307
2325
|
statement.connection._pending.push('openBlob');
|
|
2308
2326
|
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
2309
|
-
|
|
2310
2327
|
if (err) {
|
|
2311
2328
|
reject(err);
|
|
2312
2329
|
return;
|
|
2313
2330
|
}
|
|
2314
|
-
|
|
2315
2331
|
const read = () => {
|
|
2316
2332
|
statement.connection.getSegment(blob, (err, ret) => {
|
|
2317
|
-
|
|
2318
2333
|
if (err) {
|
|
2319
2334
|
if (singleTransaction) {
|
|
2320
2335
|
transaction.rollback(() => reject(err));
|
|
2321
|
-
}
|
|
2336
|
+
}
|
|
2337
|
+
else {
|
|
2322
2338
|
reject(err);
|
|
2323
2339
|
}
|
|
2324
2340
|
return;
|
|
2325
2341
|
}
|
|
2326
|
-
|
|
2327
2342
|
if (ret.buffer) {
|
|
2328
|
-
const blr = new BlrReader(ret.buffer);
|
|
2343
|
+
const blr = new serialize_1.BlrReader(ret.buffer);
|
|
2329
2344
|
const data = blr.readSegment();
|
|
2330
|
-
infoValue.value += data.toString(
|
|
2345
|
+
infoValue.value += data.toString(const_1.default.DEFAULT_ENCODING);
|
|
2331
2346
|
}
|
|
2332
|
-
|
|
2333
2347
|
if (ret.handle !== 2) {
|
|
2334
2348
|
read();
|
|
2335
2349
|
return;
|
|
2336
2350
|
}
|
|
2337
|
-
|
|
2338
2351
|
statement.connection.closeBlob(blob);
|
|
2339
2352
|
if (singleTransaction) {
|
|
2340
2353
|
transaction.commit((err) => {
|
|
2341
2354
|
if (err) {
|
|
2342
2355
|
reject(err);
|
|
2343
|
-
}
|
|
2356
|
+
}
|
|
2357
|
+
else {
|
|
2344
2358
|
resolve(infoValue);
|
|
2345
2359
|
}
|
|
2346
2360
|
});
|
|
2347
|
-
}
|
|
2361
|
+
}
|
|
2362
|
+
else {
|
|
2348
2363
|
resolve(infoValue);
|
|
2349
2364
|
}
|
|
2350
2365
|
});
|
|
2351
2366
|
};
|
|
2352
|
-
|
|
2353
2367
|
read();
|
|
2354
2368
|
});
|
|
2355
2369
|
});
|
|
2356
2370
|
});
|
|
2357
2371
|
};
|
|
2358
2372
|
}
|
|
2359
|
-
|
|
2360
2373
|
function fetch_blob_async(statement, id, name, row) {
|
|
2361
2374
|
const cbTransaction = (transaction, close, callback) => {
|
|
2362
2375
|
statement.connection._pending.push('openBlob');
|
|
2363
2376
|
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
2364
|
-
let e = new
|
|
2365
|
-
|
|
2377
|
+
let e = new events_1.default.EventEmitter();
|
|
2366
2378
|
e.pipe = (stream) => {
|
|
2367
2379
|
e.on('data', (chunk) => {
|
|
2368
2380
|
stream.write(chunk);
|
|
@@ -2371,98 +2383,110 @@ function fetch_blob_async(statement, id, name, row) {
|
|
|
2371
2383
|
stream.end();
|
|
2372
2384
|
});
|
|
2373
2385
|
};
|
|
2374
|
-
|
|
2375
2386
|
if (err) {
|
|
2376
2387
|
return callback(err, name, e, row);
|
|
2377
2388
|
}
|
|
2378
|
-
|
|
2379
2389
|
const read = () => {
|
|
2380
2390
|
statement.connection.getSegment(blob, (err, ret) => {
|
|
2381
|
-
|
|
2382
2391
|
if (err) {
|
|
2383
2392
|
transaction.rollback(() => {
|
|
2384
2393
|
e.emit('error', err);
|
|
2385
2394
|
});
|
|
2386
2395
|
return;
|
|
2387
2396
|
}
|
|
2388
|
-
|
|
2389
2397
|
if (ret.buffer) {
|
|
2390
|
-
const blr = new BlrReader(ret.buffer);
|
|
2398
|
+
const blr = new serialize_1.BlrReader(ret.buffer);
|
|
2391
2399
|
const data = blr.readSegment();
|
|
2392
|
-
|
|
2393
2400
|
e.emit('data', data);
|
|
2394
2401
|
}
|
|
2395
|
-
|
|
2396
2402
|
if (ret.handle !== 2) {
|
|
2397
2403
|
read();
|
|
2398
2404
|
return;
|
|
2399
2405
|
}
|
|
2400
|
-
|
|
2401
2406
|
statement.connection.closeBlob(blob);
|
|
2402
2407
|
if (close) {
|
|
2403
2408
|
transaction.commit((err) => {
|
|
2404
2409
|
if (err) {
|
|
2405
2410
|
e.emit('error', err);
|
|
2406
|
-
}
|
|
2411
|
+
}
|
|
2412
|
+
else {
|
|
2407
2413
|
e.emit('end');
|
|
2408
2414
|
}
|
|
2409
2415
|
e = null;
|
|
2410
2416
|
});
|
|
2411
|
-
}
|
|
2417
|
+
}
|
|
2418
|
+
else {
|
|
2412
2419
|
e.emit('end');
|
|
2413
2420
|
e = null;
|
|
2414
2421
|
}
|
|
2415
2422
|
});
|
|
2416
2423
|
};
|
|
2417
|
-
|
|
2418
2424
|
callback(err, name, e, row);
|
|
2419
2425
|
read();
|
|
2420
2426
|
});
|
|
2421
2427
|
};
|
|
2422
|
-
|
|
2423
2428
|
return (transaction, callback) => {
|
|
2424
2429
|
// callback(error, nameField, eventEmitter, row)
|
|
2425
2430
|
const singleTransaction = callback === undefined;
|
|
2431
|
+
const actualCallback = singleTransaction ? transaction : callback;
|
|
2432
|
+
const cacheKey = `${id.high}:${id.low}`;
|
|
2433
|
+
if (statement.connection._inlineBlobs && statement.connection._inlineBlobs.has(cacheKey)) {
|
|
2434
|
+
const data = statement.connection._inlineBlobs.get(cacheKey);
|
|
2435
|
+
let e = new events_1.default.EventEmitter();
|
|
2436
|
+
e.pipe = (stream) => {
|
|
2437
|
+
e.on('data', (chunk) => {
|
|
2438
|
+
stream.write(chunk);
|
|
2439
|
+
});
|
|
2440
|
+
e.on('end', () => {
|
|
2441
|
+
stream.end();
|
|
2442
|
+
});
|
|
2443
|
+
};
|
|
2444
|
+
actualCallback(null, name, e, row);
|
|
2445
|
+
setImmediate(() => {
|
|
2446
|
+
if (data) {
|
|
2447
|
+
e.emit('data', data);
|
|
2448
|
+
}
|
|
2449
|
+
e.emit('end');
|
|
2450
|
+
});
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2426
2453
|
if (singleTransaction) {
|
|
2427
2454
|
callback = transaction;
|
|
2428
|
-
statement.connection.startTransaction(
|
|
2455
|
+
statement.connection.startTransaction(const_1.default.ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
2429
2456
|
if (err) {
|
|
2430
2457
|
callback(err);
|
|
2431
2458
|
return;
|
|
2432
2459
|
}
|
|
2433
2460
|
cbTransaction(transaction, singleTransaction, callback);
|
|
2434
2461
|
});
|
|
2435
|
-
}
|
|
2462
|
+
}
|
|
2463
|
+
else {
|
|
2436
2464
|
cbTransaction(transaction, singleTransaction, callback);
|
|
2437
2465
|
}
|
|
2438
2466
|
};
|
|
2439
2467
|
}
|
|
2440
|
-
|
|
2441
2468
|
function doSynchronousLoop(data, processData, done) {
|
|
2442
2469
|
if (!data || !data.length) {
|
|
2443
2470
|
done();
|
|
2444
2471
|
return;
|
|
2445
2472
|
}
|
|
2446
|
-
|
|
2447
2473
|
const loop = (index) => {
|
|
2448
2474
|
processData(data[index], index, (err) => {
|
|
2449
2475
|
if (err) {
|
|
2450
2476
|
done(err);
|
|
2451
2477
|
return;
|
|
2452
2478
|
}
|
|
2453
|
-
|
|
2454
2479
|
const nextIndex = index + 1;
|
|
2455
2480
|
if (nextIndex < data.length) {
|
|
2456
2481
|
loop(nextIndex);
|
|
2457
|
-
}
|
|
2482
|
+
}
|
|
2483
|
+
else {
|
|
2458
2484
|
done();
|
|
2459
2485
|
}
|
|
2460
2486
|
});
|
|
2461
2487
|
};
|
|
2462
|
-
|
|
2463
2488
|
loop(0);
|
|
2464
2489
|
}
|
|
2465
|
-
|
|
2466
2490
|
function executeStreamRow(custom, row, index, output, next) {
|
|
2467
2491
|
let done = false;
|
|
2468
2492
|
const finish = (err) => {
|
|
@@ -2472,47 +2496,40 @@ function executeStreamRow(custom, row, index, output, next) {
|
|
|
2472
2496
|
done = true;
|
|
2473
2497
|
next(err);
|
|
2474
2498
|
};
|
|
2475
|
-
|
|
2476
2499
|
try {
|
|
2477
2500
|
const ret = custom.on(row, index, output, finish);
|
|
2478
2501
|
if (custom.on.length < 4) {
|
|
2479
2502
|
if (ret && typeof ret.then === 'function') {
|
|
2480
2503
|
ret.then(() => finish()).catch(finish);
|
|
2481
|
-
}
|
|
2504
|
+
}
|
|
2505
|
+
else {
|
|
2482
2506
|
finish();
|
|
2483
2507
|
}
|
|
2484
|
-
}
|
|
2508
|
+
}
|
|
2509
|
+
else if (ret && typeof ret.then === 'function') {
|
|
2485
2510
|
ret.catch(finish);
|
|
2486
2511
|
}
|
|
2487
|
-
}
|
|
2512
|
+
}
|
|
2513
|
+
catch (err) {
|
|
2488
2514
|
finish(err);
|
|
2489
2515
|
}
|
|
2490
2516
|
}
|
|
2491
|
-
|
|
2492
2517
|
function bufferReader(buffer, max, writer, cb, beg, end) {
|
|
2493
|
-
|
|
2494
2518
|
if (!beg)
|
|
2495
2519
|
beg = 0;
|
|
2496
|
-
|
|
2497
2520
|
if (!end)
|
|
2498
2521
|
end = max;
|
|
2499
|
-
|
|
2500
2522
|
if (end >= buffer.length)
|
|
2501
2523
|
end = undefined;
|
|
2502
|
-
|
|
2503
2524
|
var b = buffer.slice(beg, end);
|
|
2504
|
-
|
|
2505
|
-
writer(b, function() {
|
|
2506
|
-
|
|
2525
|
+
writer(b, function () {
|
|
2507
2526
|
if (end === undefined) {
|
|
2508
2527
|
cb();
|
|
2509
2528
|
return;
|
|
2510
2529
|
}
|
|
2511
|
-
|
|
2512
2530
|
bufferReader(buffer, max, writer, cb, beg + max, end + max);
|
|
2513
2531
|
});
|
|
2514
2532
|
}
|
|
2515
|
-
|
|
2516
2533
|
/**
|
|
2517
2534
|
* Parse dbCryptConfig option and convert to bytes.
|
|
2518
2535
|
* Supports:
|
|
@@ -2524,20 +2541,23 @@ function parseDbCryptConfig(config) {
|
|
|
2524
2541
|
if (!config) {
|
|
2525
2542
|
return Buffer.alloc(0);
|
|
2526
2543
|
}
|
|
2527
|
-
|
|
2528
2544
|
// Check if it's a base64 encoded value
|
|
2529
2545
|
if (config.startsWith('base64:')) {
|
|
2530
2546
|
const base64Value = config.substring(7);
|
|
2531
2547
|
try {
|
|
2532
2548
|
return Buffer.from(base64Value, 'base64');
|
|
2533
|
-
}
|
|
2549
|
+
}
|
|
2550
|
+
catch (e) {
|
|
2534
2551
|
console.error('Failed to decode base64 dbCryptConfig, returning empty buffer:', e);
|
|
2535
2552
|
return Buffer.alloc(0);
|
|
2536
2553
|
}
|
|
2537
2554
|
}
|
|
2538
|
-
|
|
2539
2555
|
// Plain string - encode as UTF-8
|
|
2540
2556
|
return Buffer.from(config, 'utf8');
|
|
2541
2557
|
}
|
|
2542
|
-
|
|
2558
|
+
Connection.decodeResponse = decodeResponse;
|
|
2559
|
+
Connection.fetch_blob_async_transaction = fetch_blob_async_transaction;
|
|
2560
|
+
Connection.fetch_blob_async = fetch_blob_async;
|
|
2561
|
+
Connection.parseValueIfJson = parseValueIfJson;
|
|
2562
|
+
Connection.describe = describe;
|
|
2543
2563
|
module.exports = Connection;
|