oracledb 6.0.3 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/Release/oracledb-6.1.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/example.js +0 -1
- package/lib/aqQueue.js +40 -26
- package/lib/connection.js +15 -3
- package/lib/errors.js +10 -6
- package/lib/impl/connection.js +9 -0
- package/lib/impl/resultset.js +7 -4
- package/lib/oracledb.js +15 -12
- package/lib/pool.js +7 -1
- package/lib/sodaCollection.js +1 -1
- package/lib/thin/connection.js +92 -30
- package/lib/thin/pool.js +153 -68
- package/lib/thin/protocol/buffer.js +19 -1
- package/lib/thin/protocol/constants.js +3 -14
- package/lib/thin/protocol/encryptDecrypt.js +17 -17
- package/lib/thin/protocol/messages/auth.js +21 -23
- package/lib/thin/protocol/messages/base.js +22 -45
- package/lib/thin/protocol/messages/connectionCookie.js +76 -0
- package/lib/thin/protocol/messages/dataType.js +13 -9
- package/lib/thin/protocol/messages/execute.js +7 -7
- package/lib/thin/protocol/messages/index.js +2 -0
- package/lib/thin/protocol/messages/protocol.js +31 -20
- package/lib/thin/protocol/messages/withData.js +49 -43
- package/lib/thin/protocol/oson.js +4 -4
- package/lib/thin/protocol/packet.js +31 -10
- package/lib/thin/protocol/utils.js +2 -2
- package/lib/thin/resultSet.js +6 -6
- package/lib/thin/sqlnet/connStrategy.js +130 -5
- package/lib/thin/sqlnet/constants.js +2 -0
- package/lib/thin/sqlnet/ezConnectResolver.js +20 -19
- package/lib/thin/sqlnet/navNodes.js +32 -25
- package/lib/thin/sqlnet/networkSession.js +35 -30
- package/lib/thin/sqlnet/ntTcp.js +30 -14
- package/lib/thin/sqlnet/nvStrToNvPair.js +16 -16
- package/lib/thin/sqlnet/packet.js +9 -2
- package/lib/thin/sqlnet/paramParser.js +9 -9
- package/lib/thin/sqlnet/sessionAtts.js +4 -0
- package/lib/thin/statement.js +3 -3
- package/lib/thin/util.js +7 -8
- package/lib/transformer.js +3 -1
- package/lib/util.js +0 -13
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/build/Release/oracledb-6.0.3-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.0.3-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.0.3-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-linux-x64.node +0 -0
- package/build/Release/oracledb-6.0.3-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.3-win32-x64.node +0 -0
- package/build/Release/oracledb-6.0.3-win32-x64.node-buildinfo.txt +0 -1
|
@@ -31,6 +31,7 @@ const { Buffer } = require('buffer');
|
|
|
31
31
|
const constants = require("./constants.js");
|
|
32
32
|
const oson = require('./oson.js');
|
|
33
33
|
const utils = require('./utils.js');
|
|
34
|
+
const errors = require("../../errors.js");
|
|
34
35
|
|
|
35
36
|
const TNS_BASE64_ALPHABET_ARRAY = Buffer.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 'utf8');
|
|
36
37
|
|
|
@@ -324,23 +325,23 @@ class ReadPacket extends BaseBuffer {
|
|
|
324
325
|
|
|
325
326
|
// Handle physical rowid
|
|
326
327
|
if (buf && buf[0] === 1) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
const rba = buf.readUInt32BE(1);
|
|
329
|
+
const partitionID = buf.readUInt16BE(5);
|
|
330
|
+
const blockNum = buf.readUInt32BE(7);
|
|
331
|
+
const slotNum = buf.readUInt16BE(11);
|
|
331
332
|
return utils.encodeRowID({rba, partitionID, blockNum, slotNum});
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
// handle logical rowid
|
|
335
336
|
let outputLen = Math.floor(inputLen / 3) * 4;
|
|
336
|
-
|
|
337
|
+
const remainder = inputLen % 3;
|
|
337
338
|
if (remainder === 1) {
|
|
338
339
|
outputLen += 1;
|
|
339
340
|
} else if (remainder === 2) {
|
|
340
341
|
outputLen += 3;
|
|
341
342
|
}
|
|
342
343
|
|
|
343
|
-
|
|
344
|
+
const outputValue = Buffer.alloc(outputLen);
|
|
344
345
|
inputLen -= 1;
|
|
345
346
|
outputValue[0] = 42;
|
|
346
347
|
outputOffset += 1;
|
|
@@ -385,16 +386,19 @@ class ReadPacket extends BaseBuffer {
|
|
|
385
386
|
}
|
|
386
387
|
|
|
387
388
|
readRowID() {
|
|
388
|
-
|
|
389
|
-
|
|
389
|
+
const rba = this.readUB4();
|
|
390
|
+
const partitionID = this.readUB2();
|
|
390
391
|
this.skipUB1();
|
|
391
|
-
|
|
392
|
-
|
|
392
|
+
const blockNum = this.readUB4();
|
|
393
|
+
const slotNum = this.readUB2();
|
|
393
394
|
return {rba, partitionID, blockNum, slotNum};
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
skipBytesChunked() {
|
|
397
398
|
const numBytes = this.readUInt8();
|
|
399
|
+
if (numBytes === 0 || numBytes === constants.TNS_NULL_LENGTH_INDICATOR) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
398
402
|
if (numBytes !== constants.TNS_LONG_LENGTH_INDICATOR) {
|
|
399
403
|
this.skipBytes(numBytes);
|
|
400
404
|
} else {
|
|
@@ -407,6 +411,23 @@ class ReadPacket extends BaseBuffer {
|
|
|
407
411
|
}
|
|
408
412
|
}
|
|
409
413
|
|
|
414
|
+
readNullTerminatedBytes(maxSize = 50) {
|
|
415
|
+
let offset = 0;
|
|
416
|
+
const tmp = Buffer.allocUnsafe(maxSize);
|
|
417
|
+
while (offset < maxSize) {
|
|
418
|
+
tmp[offset] = this.readUInt8();
|
|
419
|
+
if (tmp[offset] === 0) {
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
offset = offset + 1;
|
|
423
|
+
}
|
|
424
|
+
if (offset === maxSize) {
|
|
425
|
+
const reason = `Byte Arrray Exceeded MaxSize ${maxSize}`;
|
|
426
|
+
errors.throwErr(errors.ERR_INTERNAL, reason);
|
|
427
|
+
}
|
|
428
|
+
return tmp.subarray(0, offset + 1);
|
|
429
|
+
}
|
|
430
|
+
|
|
410
431
|
}
|
|
411
432
|
|
|
412
433
|
|
|
@@ -43,7 +43,7 @@ function _convertBase64(result, value, size, offset) {
|
|
|
43
43
|
function encodeRowID(rowID) {
|
|
44
44
|
let offset = 0;
|
|
45
45
|
if (rowID.rba !== 0 || rowID.partitionID !== 0 || rowID.blockNum !== 0 || rowID.slotNum != 0) {
|
|
46
|
-
|
|
46
|
+
const result = Buffer.alloc(constants.TNS_MAX_ROWID_LENGTH);
|
|
47
47
|
offset = _convertBase64(result, rowID.rba, 6, offset);
|
|
48
48
|
offset = _convertBase64(result, rowID.partitionID, 3, offset);
|
|
49
49
|
offset = _convertBase64(result, rowID.blockNum, 6, offset);
|
|
@@ -59,7 +59,7 @@ function setObfuscatedValue(value) {
|
|
|
59
59
|
const bytes = Buffer.from(value, 'utf8');
|
|
60
60
|
const len = Buffer.byteLength(value);
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const arr = [];
|
|
63
63
|
for (let i = 0; i < len; i++) {
|
|
64
64
|
arr.push(buf[i] ^ bytes[i]);
|
|
65
65
|
}
|
package/lib/thin/resultSet.js
CHANGED
|
@@ -68,10 +68,10 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
68
68
|
// Returns rows fetched to the common layer in array format
|
|
69
69
|
//---------------------------------------------------------------------------
|
|
70
70
|
_processRows(numRowsFetched) {
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
const rows = [];
|
|
72
|
+
const bufferRowIndex = this.statement.bufferRowIndex;
|
|
73
73
|
for (let row = bufferRowIndex; row < bufferRowIndex + numRowsFetched; row++) {
|
|
74
|
-
|
|
74
|
+
const rowObj = [];
|
|
75
75
|
for (let col = 0; col < this.statement.numQueryVars; col++) {
|
|
76
76
|
rowObj.push(this.statement.queryVars[col].values[row]);
|
|
77
77
|
}
|
|
@@ -99,13 +99,13 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
99
99
|
} else {
|
|
100
100
|
// We fetch for the required number of row
|
|
101
101
|
options.fetchArraySize = options.fetchArraySize - (this.statement.bufferRowCount - this.statement.bufferRowIndex);
|
|
102
|
-
|
|
102
|
+
const prevBufferRowCount = this.statement.bufferRowCount;
|
|
103
103
|
if (this.statement.moreRowsToFetch && options.fetchArraySize > 0) {
|
|
104
104
|
await this._fetchMoreRows(options);
|
|
105
105
|
}
|
|
106
106
|
options.fetchArraySize = numRows || this.options.fetchArraySize;
|
|
107
107
|
if (prevBufferRowCount === this.statement.bufferRowCount) {
|
|
108
|
-
|
|
108
|
+
const numRowsFetched = this.statement.bufferRowCount - this.statement.bufferRowIndex;
|
|
109
109
|
this.statement.bufferRowCount = 0;
|
|
110
110
|
if (numRowsFetched > 0) {
|
|
111
111
|
return this._processRows(numRowsFetched);
|
|
@@ -113,7 +113,7 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
113
113
|
return [];
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
const numRowsFetched = this.statement.bufferRowCount - this.statement.bufferRowIndex;
|
|
117
117
|
return this._processRows(numRowsFetched);
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -54,6 +54,7 @@ class ConnectDescription {
|
|
|
54
54
|
class ConnStrategy {
|
|
55
55
|
constructor() {
|
|
56
56
|
this.nextOptToTry = 0;
|
|
57
|
+
this.reorderDescriptionList = 0;
|
|
57
58
|
this.retryCount = 0;
|
|
58
59
|
this.lastRetryCounter = 0;
|
|
59
60
|
this.lastRetryConnectDescription = 0;
|
|
@@ -95,9 +96,13 @@ class ConnStrategy {
|
|
|
95
96
|
this.retryCount = config.retryCount;
|
|
96
97
|
}
|
|
97
98
|
}
|
|
99
|
+
if (!this.reorderDescriptionList) {
|
|
100
|
+
this.descriptionList = SOLE_INST_DHCACHE.reorderDescriptionList(this.descriptionList);
|
|
101
|
+
this.reorderDescriptionList = true;
|
|
102
|
+
}
|
|
98
103
|
/* We try the address list at least once and upto (1 + retryCount) times */
|
|
99
104
|
for (let d = this.lastRetryConnectDescription; d < this.descriptionList.length; d++) {
|
|
100
|
-
|
|
105
|
+
const desc = this.descriptionList[d];
|
|
101
106
|
let cOpts = new Array();
|
|
102
107
|
cOpts = desc.getConnectOptions();
|
|
103
108
|
let delay = desc.delayInMillis;
|
|
@@ -108,8 +113,13 @@ class ConnStrategy {
|
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
for (let i = this.lastRetryCounter; i <= this.retryCount; ++i) {
|
|
116
|
+
//Conn options must be reordered only when all options are tried
|
|
117
|
+
// i.e for retry and before the first try.
|
|
118
|
+
if (this.nextOptToTry == 0) {
|
|
119
|
+
cOpts = SOLE_INST_DHCACHE.reorderAddresses(cOpts);
|
|
120
|
+
}
|
|
111
121
|
while (this.nextOptToTry < cOpts.length) {
|
|
112
|
-
|
|
122
|
+
const copt = cOpts[this.nextOptToTry];
|
|
113
123
|
this.lastRetryCounter = i;
|
|
114
124
|
this.lastRetryConnectDescription = d;
|
|
115
125
|
this.nextOptToTry++;
|
|
@@ -150,7 +160,7 @@ async function createNode(str) {
|
|
|
150
160
|
else
|
|
151
161
|
nvpair = str; //Already a NVPair
|
|
152
162
|
|
|
153
|
-
|
|
163
|
+
const arg = nvpair.name.toUpperCase();
|
|
154
164
|
let navobj = null;
|
|
155
165
|
switch (arg) {
|
|
156
166
|
case "ADDRESS":
|
|
@@ -170,8 +180,123 @@ async function createNode(str) {
|
|
|
170
180
|
`unknown top element ${arg}`);
|
|
171
181
|
}
|
|
172
182
|
navobj.initFromNVPair(nvpair);
|
|
173
|
-
|
|
183
|
+
const cs = new ConnStrategy();
|
|
174
184
|
await navobj.navigate(cs);
|
|
175
185
|
return cs;
|
|
176
186
|
}
|
|
177
|
-
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class DownHostsCache {
|
|
190
|
+
|
|
191
|
+
constructor() {
|
|
192
|
+
// Timeout for each item in the cache
|
|
193
|
+
this.DOWN_HOSTS_TIMEOUT = 600;
|
|
194
|
+
// Minimum amount of time between each refresh
|
|
195
|
+
this.MIN_TIME_BETWEEN_REFRESH = 60;
|
|
196
|
+
// DownHostsCache Map
|
|
197
|
+
this.downHostsCacheMap = new Map();
|
|
198
|
+
// Last Refresh Time
|
|
199
|
+
this.lastRefreshTime = 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Add an address to the cache
|
|
204
|
+
*
|
|
205
|
+
* @param connOption
|
|
206
|
+
* address to be cached
|
|
207
|
+
* @return Map with address as key and time of insertion as value
|
|
208
|
+
*/
|
|
209
|
+
markDownHost(addr) {
|
|
210
|
+
return this.downHostsCacheMap.set(addr, Date.now());
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Remove elements older than DownHostsTimeout
|
|
214
|
+
refreshCache() {
|
|
215
|
+
if (Date.now() - this.MIN_TIME_BETWEEN_REFRESH * 1000 > this.lastRefreshTime) {
|
|
216
|
+
this.downHostsCacheMap.forEach((value, key) => {
|
|
217
|
+
const entryTime = value;
|
|
218
|
+
if (entryTime != null && ((Date.now() - this.DOWN_HOSTS_TIMEOUT * 1000) > entryTime)) {
|
|
219
|
+
this.downHostsCacheMap.delete(key);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
this.lastRefreshTime = Date.now();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Reorder addresses such that cached elements
|
|
228
|
+
* occur at the end of the array.
|
|
229
|
+
*/
|
|
230
|
+
reorderAddresses(cOpts) {
|
|
231
|
+
this.refreshCache();
|
|
232
|
+
|
|
233
|
+
let topIdx = 0, btmIdx = cOpts.length - 1;
|
|
234
|
+
|
|
235
|
+
while (topIdx < btmIdx) {
|
|
236
|
+
|
|
237
|
+
// increment topIdx if the address is not cached
|
|
238
|
+
while (topIdx <= btmIdx
|
|
239
|
+
&& !this.isDownHostsCached(cOpts[topIdx]))
|
|
240
|
+
topIdx++;
|
|
241
|
+
|
|
242
|
+
// decrement btmIdx if address is cached
|
|
243
|
+
while (btmIdx >= topIdx
|
|
244
|
+
&& this.isDownHostsCached(cOpts[btmIdx]))
|
|
245
|
+
btmIdx--;
|
|
246
|
+
|
|
247
|
+
// swap cached with uncached
|
|
248
|
+
if (topIdx < btmIdx)
|
|
249
|
+
[cOpts[topIdx], cOpts[btmIdx]] = [cOpts[btmIdx], cOpts[topIdx]];
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
return cOpts;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Return if a desc is cached.
|
|
256
|
+
* A desc is cached if all the connection options(addresses)
|
|
257
|
+
* in that description are cached.
|
|
258
|
+
*/
|
|
259
|
+
isDownDescCached(desc) {
|
|
260
|
+
const cOpts = desc.getConnectOptions();
|
|
261
|
+
for (let i = 0; i < cOpts.length; i++) {
|
|
262
|
+
if (!this.isDownHostsCached(cOpts[i]))
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Reorder description list such that description with all connection options in downcache
|
|
269
|
+
* is pushed to the end of the description list
|
|
270
|
+
*/
|
|
271
|
+
reorderDescriptionList(descs) {
|
|
272
|
+
this.refreshCache();
|
|
273
|
+
|
|
274
|
+
let topIdx = 0, btmIdx = descs.length - 1;
|
|
275
|
+
|
|
276
|
+
while (topIdx < btmIdx) {
|
|
277
|
+
|
|
278
|
+
// increment topIdx if the desc is not cached
|
|
279
|
+
while (topIdx <= btmIdx
|
|
280
|
+
&& !this.isDownDescCached(descs[topIdx]))
|
|
281
|
+
topIdx++;
|
|
282
|
+
|
|
283
|
+
// decrement btmIdx if desc is cached
|
|
284
|
+
while (btmIdx >= topIdx
|
|
285
|
+
&& this.isDownDescCached(descs[btmIdx]))
|
|
286
|
+
btmIdx--;
|
|
287
|
+
|
|
288
|
+
// swap cached with uncached
|
|
289
|
+
if (topIdx < btmIdx) {
|
|
290
|
+
[descs[topIdx], descs[btmIdx]] = [descs[btmIdx], descs[topIdx]];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return descs;
|
|
294
|
+
}
|
|
295
|
+
// Return if a host is cached
|
|
296
|
+
isDownHostsCached(copt) {
|
|
297
|
+
return this.downHostsCacheMap.has(copt.host);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Single instance
|
|
301
|
+
const SOLE_INST_DHCACHE = new DownHostsCache();
|
|
302
|
+
module.exports = { createNode, SOLE_INST_DHCACHE };
|
|
@@ -107,6 +107,8 @@ module.exports = {
|
|
|
107
107
|
NSGRAW : 0x1000, // I/O is direct to/from transport
|
|
108
108
|
TNS_VERSION_DESIRED : 319,
|
|
109
109
|
TNS_VERSION_MINIMUM : 300,
|
|
110
|
+
TNS_VERSION_MIN_UUID : 319,
|
|
111
|
+
TNS_UUID_OFFSET : 45,
|
|
110
112
|
|
|
111
113
|
/* Accept Packet */
|
|
112
114
|
NSPACVSN : 8, // connection version
|
|
@@ -71,7 +71,7 @@ const DESCRIPTION_PARAMS = ["ENABLE", "FAILOVER", "LOAD_BALANCE",
|
|
|
71
71
|
class EZConnectResolver {
|
|
72
72
|
constructor(url) {
|
|
73
73
|
this.URL_PROPS_ALIAS = this.initializeUrlAlias();
|
|
74
|
-
|
|
74
|
+
const jdbcUrlPrefix = url.indexOf('@');
|
|
75
75
|
if (jdbcUrlPrefix != -1) {
|
|
76
76
|
this.url = url.substring(jdbcUrlPrefix + 1);
|
|
77
77
|
this.urlPrefix = url.substring(0, jdbcUrlPrefix + 1);
|
|
@@ -125,7 +125,7 @@ class EZConnectResolver {
|
|
|
125
125
|
// URL is in the following format
|
|
126
126
|
// [protocol://]host1[,host13][:port1][,host2:port2][/service_name][:server][/instance_name]
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
const urlWithoutWhiteSpaces = url.replace(/\s/g, "");
|
|
129
129
|
let bool = 0;
|
|
130
130
|
let protocol = null, hostInfo = null, serviceName = null, serverMode = null, instanceName = null;
|
|
131
131
|
for (const match of urlWithoutWhiteSpaces.matchAll(EZ_URL_PATTERN)) {
|
|
@@ -153,7 +153,7 @@ class EZConnectResolver {
|
|
|
153
153
|
const addressInfo =
|
|
154
154
|
await this.buildAddressList(hostInfo, protocol, proxyHost, proxyPort);
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
const connectionIdPrefix =
|
|
157
157
|
this.urlProps.get("CONNECTION_ID_PREFIX");
|
|
158
158
|
// Build the available information in TNS format.
|
|
159
159
|
const parts = [];
|
|
@@ -214,7 +214,7 @@ class EZConnectResolver {
|
|
|
214
214
|
proxyHost, proxyPort) {
|
|
215
215
|
let shost = '';
|
|
216
216
|
let ipcnt = 0;
|
|
217
|
-
|
|
217
|
+
const builder = new Array();
|
|
218
218
|
let proxyInfo = '';
|
|
219
219
|
if (proxyHost != null) {
|
|
220
220
|
if (proxyPort != null) {
|
|
@@ -227,17 +227,17 @@ class EZConnectResolver {
|
|
|
227
227
|
if (protocol == null) protocol = 'TCP';
|
|
228
228
|
let naddr = 0;
|
|
229
229
|
// ; groups the user into a ADDRESS_LIST
|
|
230
|
-
|
|
231
|
-
for (
|
|
230
|
+
const addressLists = hostInfo.split(";");
|
|
231
|
+
for (const addressList in addressLists) {
|
|
232
232
|
let addressNodeCount = 0;
|
|
233
|
-
|
|
233
|
+
const addressListBuilder = new Array();
|
|
234
234
|
for (const match of addressLists[addressList].matchAll(HOSTNAMES_PATTERN)) {
|
|
235
|
-
|
|
235
|
+
const hostnames = (match.groups.hostnames).split(',');
|
|
236
236
|
let port = match.groups.port;
|
|
237
237
|
if (port == null) {
|
|
238
238
|
port = '1521' + '';
|
|
239
239
|
}
|
|
240
|
-
for (
|
|
240
|
+
for (const hname in hostnames) {
|
|
241
241
|
addressListBuilder.push(this.getAddrStr(hostnames[hname], port, protocol, proxyInfo));
|
|
242
242
|
shost = hostnames[hname];
|
|
243
243
|
addressNodeCount++;
|
|
@@ -300,7 +300,7 @@ class EZConnectResolver {
|
|
|
300
300
|
buildDescriptionParams() {
|
|
301
301
|
if (this.urlProps.size === 0)
|
|
302
302
|
return '';
|
|
303
|
-
|
|
303
|
+
const builder = new Array();
|
|
304
304
|
this.urlProps.forEach(function(v, k) {
|
|
305
305
|
if (DESCRIPTION_PARAMS.includes(k)) // Add only if it is a DESCRIPTION node parameter
|
|
306
306
|
builder.push(`(${k}=${v})`);
|
|
@@ -318,10 +318,11 @@ class EZConnectResolver {
|
|
|
318
318
|
if (protocol != null && protocol.toLowerCase() == "tcps") {
|
|
319
319
|
// In EZConnect format if the DN match is not specified the enable it
|
|
320
320
|
// by default for TCPS protocol.
|
|
321
|
-
const serverDNMatch = this.urlProps.get("SSL_SERVER_DN_MATCH")
|
|
321
|
+
const serverDNMatch = this.urlProps.get("SSL_SERVER_DN_MATCH");
|
|
322
322
|
const serverCertDN = this.urlProps.get("SSL_SERVER_CERT_DN");
|
|
323
323
|
const walletDir = this.urlProps.get("MY_WALLET_DIRECTORY");
|
|
324
|
-
|
|
324
|
+
if (serverDNMatch != null)
|
|
325
|
+
securityInfo.push(`(SSL_SERVER_DN_MATCH=${serverDNMatch})`);
|
|
325
326
|
if (serverCertDN != null)
|
|
326
327
|
securityInfo.push(`(SSL_SERVER_CERT_DN=${serverCertDN}})`);
|
|
327
328
|
if (walletDir != null)
|
|
@@ -342,8 +343,8 @@ class EZConnectResolver {
|
|
|
342
343
|
* @return the parsed URL which does not contain the extended settings part.
|
|
343
344
|
*/
|
|
344
345
|
parseExtendedSettings(urlStr) {
|
|
345
|
-
|
|
346
|
-
|
|
346
|
+
const urlBytes = Array.from(urlStr.trim());
|
|
347
|
+
const extendedSettingsIndex = this.findExtendedSettingPosition(urlBytes);
|
|
347
348
|
|
|
348
349
|
if (extendedSettingsIndex == -1) {
|
|
349
350
|
return urlStr; // No extended settings configuration found
|
|
@@ -360,7 +361,7 @@ class EZConnectResolver {
|
|
|
360
361
|
parseExtendedProperties(urlChars, extIndex) {
|
|
361
362
|
let key = null;
|
|
362
363
|
let value = null;
|
|
363
|
-
|
|
364
|
+
const token = new Array(urlChars.length);
|
|
364
365
|
let tokenIndx = 0;
|
|
365
366
|
let indices = '';
|
|
366
367
|
for (let i = extIndex; i < urlChars.length; i++) {
|
|
@@ -421,7 +422,7 @@ class EZConnectResolver {
|
|
|
421
422
|
parseQuotedString(startIndex, urlChars, tokenIndex, token) {
|
|
422
423
|
let i = startIndex + 1; // look for closing '"' from the next index
|
|
423
424
|
while (i < urlChars.length) {
|
|
424
|
-
|
|
425
|
+
const curChar = urlChars[i];
|
|
425
426
|
if (curChar == EXT_DOUBLE_QT) {
|
|
426
427
|
// Got the " which ends the quoted block, so break the loop
|
|
427
428
|
// Return the new indices, caller would resume from this new indices.
|
|
@@ -439,8 +440,8 @@ class EZConnectResolver {
|
|
|
439
440
|
* @param value
|
|
440
441
|
*/
|
|
441
442
|
addParam(key, value) {
|
|
442
|
-
|
|
443
|
-
|
|
443
|
+
const aliasKeyName = key.toLowerCase();
|
|
444
|
+
const propertyName = this.URL_PROPS_ALIAS.get(aliasKeyName);
|
|
444
445
|
if (propertyName != null) {
|
|
445
446
|
// if it is an URL alias then add to URL props
|
|
446
447
|
this.urlProps.set(propertyName, value);
|
|
@@ -465,7 +466,7 @@ class EZConnectResolver {
|
|
|
465
466
|
* @return url alias map
|
|
466
467
|
*/
|
|
467
468
|
initializeUrlAlias() {
|
|
468
|
-
|
|
469
|
+
const aliasMap = new Map();
|
|
469
470
|
aliasMap.set("enable", "ENABLE");
|
|
470
471
|
aliasMap.set("failover", "FAILOVER");
|
|
471
472
|
aliasMap.set("load_balance", "LOAD_BALANCE");
|
|
@@ -58,7 +58,7 @@ class Address {
|
|
|
58
58
|
* (ie, "(ADDRESS=(DESCRIPTION=...)) and ")
|
|
59
59
|
*/
|
|
60
60
|
initFromString(s) {
|
|
61
|
-
|
|
61
|
+
const nvp = createNVPair(s);
|
|
62
62
|
this.initFromNVPair(nvp);
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -70,11 +70,11 @@ class Address {
|
|
|
70
70
|
initFromNVPair(nvp) {
|
|
71
71
|
if (nvp == null || !(nvp.name.toUpperCase() == "ADDRESS"))
|
|
72
72
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
const protnvp = findNVPairRecurse(nvp, 'protocol');
|
|
74
|
+
const portnvp = findNVPairRecurse(nvp, 'port');
|
|
75
|
+
const hostnvp = findNVPairRecurse(nvp, 'host');
|
|
76
|
+
const httpsProxyNVP = findNVPairRecurse(nvp, 'https_proxy');
|
|
77
|
+
const httpsProxyPortNVP = findNVPairRecurse(nvp, 'https_proxy_port');
|
|
78
78
|
|
|
79
79
|
if (portnvp)
|
|
80
80
|
this.port = portnvp.atom;
|
|
@@ -121,7 +121,7 @@ class AddressList {
|
|
|
121
121
|
* (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
122
122
|
*/
|
|
123
123
|
initFromString(s) {
|
|
124
|
-
|
|
124
|
+
const nvp = createNVPair(s);
|
|
125
125
|
this.initFromNVPair(nvp);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -134,7 +134,7 @@ class AddressList {
|
|
|
134
134
|
/* for each child of "ADDRESS_LIST", create child or set SR/LB/FO */
|
|
135
135
|
this.children = [];
|
|
136
136
|
let childnv, child;
|
|
137
|
-
|
|
137
|
+
const listsize = nvp.getListSize();
|
|
138
138
|
if (listsize == 0) /* atom can not be valid */
|
|
139
139
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
140
140
|
|
|
@@ -216,7 +216,7 @@ class Description {
|
|
|
216
216
|
* Error thrown if invalid syntax (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
217
217
|
*/
|
|
218
218
|
initFromString(s) {
|
|
219
|
-
|
|
219
|
+
const nvp = createNVPair(s);
|
|
220
220
|
this.initFromNVPair(nvp);
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -227,7 +227,7 @@ class Description {
|
|
|
227
227
|
*/
|
|
228
228
|
//errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
229
229
|
initFromNVPair(nvp) {
|
|
230
|
-
|
|
230
|
+
const listsize = nvp.getListSize();
|
|
231
231
|
let childnv, child;
|
|
232
232
|
if (listsize == 0) // atom can not be valid
|
|
233
233
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
@@ -256,7 +256,7 @@ class Description {
|
|
|
256
256
|
this.children.push(child);
|
|
257
257
|
} else if (childnv.name.toUpperCase() == "CONNECT_DATA") {
|
|
258
258
|
let tmpnv;
|
|
259
|
-
|
|
259
|
+
const listsize = childnv.getListSize();
|
|
260
260
|
for (let i = 0; i < listsize; i++) {
|
|
261
261
|
tmpnv = childnv.getListElement(i);
|
|
262
262
|
if (tmpnv.name.toUpperCase() == "CONNECTION_ID_PREFIX") {
|
|
@@ -294,7 +294,7 @@ class Description {
|
|
|
294
294
|
if (childnv.atom > 0)
|
|
295
295
|
this.params.expireTime = childnv.atom;
|
|
296
296
|
} else if (childnv.name.toUpperCase() == "SECURITY") {
|
|
297
|
-
|
|
297
|
+
const listsize = childnv.getListSize();
|
|
298
298
|
let tmpnv;
|
|
299
299
|
for (let i = 0; i < listsize; i++) {
|
|
300
300
|
tmpnv = childnv.getListElement(i);
|
|
@@ -304,6 +304,10 @@ class Description {
|
|
|
304
304
|
this.params.sslServerDNMatch = (tmpnv.atom.toLowerCase() == "yes"
|
|
305
305
|
|| tmpnv.atom.toLowerCase() == "on"
|
|
306
306
|
|| tmpnv.atom.toLowerCase() == "true");
|
|
307
|
+
} else if (tmpnv.name.toUpperCase() == "SSL_ALLOW_WEAK_DN_MATCH") {
|
|
308
|
+
this.params.sslAllowWeakDNMatch = (tmpnv.atom.toLowerCase() == "yes"
|
|
309
|
+
|| tmpnv.atom.toLowerCase() == "on"
|
|
310
|
+
|| tmpnv.atom.toLowerCase() == "true");
|
|
307
311
|
} else if ((tmpnv.name.toUpperCase() == "WALLET_LOCATION") || (tmpnv.name.toUpperCase() == "MY_WALLET_DIRECTORY")) {
|
|
308
312
|
this.params.walletLocation = tmpnv.atom;
|
|
309
313
|
}
|
|
@@ -360,7 +364,7 @@ class DescriptionList {
|
|
|
360
364
|
* (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
361
365
|
*/
|
|
362
366
|
initFromString(s) {
|
|
363
|
-
|
|
367
|
+
const nvp = createNVPair(s);
|
|
364
368
|
this.initFromNVPair(nvp);
|
|
365
369
|
}
|
|
366
370
|
|
|
@@ -370,7 +374,7 @@ class DescriptionList {
|
|
|
370
374
|
* (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
371
375
|
*/
|
|
372
376
|
initFromNVPair(nvp) {
|
|
373
|
-
|
|
377
|
+
const listsize = nvp.getListSize();
|
|
374
378
|
let child, childnv;
|
|
375
379
|
if (listsize == 0) /* atom can not be valid */
|
|
376
380
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
@@ -482,8 +486,8 @@ class NavAddress extends Address {
|
|
|
482
486
|
if (!net.isIP(this.host)) {
|
|
483
487
|
try {
|
|
484
488
|
addresses = await dnsPromises.lookup(this.host, options);
|
|
485
|
-
for (
|
|
486
|
-
|
|
489
|
+
for (const addr in addresses) {
|
|
490
|
+
const co = new ConnOption();
|
|
487
491
|
co.hostname = this.host;
|
|
488
492
|
co.port = this.port;
|
|
489
493
|
co.protocol = this.prot;
|
|
@@ -503,7 +507,7 @@ class NavAddress extends Address {
|
|
|
503
507
|
// do nothing
|
|
504
508
|
}
|
|
505
509
|
} else {
|
|
506
|
-
|
|
510
|
+
const co = new ConnOption();
|
|
507
511
|
co.hostname = this.host;
|
|
508
512
|
co.port = this.port;
|
|
509
513
|
co.protocol = this.prot;
|
|
@@ -530,7 +534,7 @@ class NavAddress extends Address {
|
|
|
530
534
|
* Address. Constructing a string is mainly needed when source route is ON.
|
|
531
535
|
*/
|
|
532
536
|
addToString(cs) {
|
|
533
|
-
|
|
537
|
+
const NVString = this.toString();
|
|
534
538
|
let cOpts = new Array();
|
|
535
539
|
cOpts = cs.getcurrentDescription().getConnectOptions();
|
|
536
540
|
for (let i = 0;i < cOpts.length; i++) {
|
|
@@ -589,7 +593,7 @@ class NavAddressList extends AddressList {
|
|
|
589
593
|
|
|
590
594
|
}
|
|
591
595
|
addToString(cs) {
|
|
592
|
-
|
|
596
|
+
const NVString = this.toString();
|
|
593
597
|
let cOpts = new Array();
|
|
594
598
|
cOpts = cs.getcurrentDescription().getConnectOptions();
|
|
595
599
|
for (let i = 0;i < cOpts.length; i++) {
|
|
@@ -631,7 +635,7 @@ class NavAddressList extends AddressList {
|
|
|
631
635
|
|
|
632
636
|
closeNVPair(cs) {
|
|
633
637
|
let cOpts = new Array();
|
|
634
|
-
|
|
638
|
+
const childS = this.getChildrenSize();
|
|
635
639
|
if (cs.getcurrentDescription() != null) {
|
|
636
640
|
cOpts = cs.getcurrentDescription().getConnectOptions();
|
|
637
641
|
let numChildren = 0;
|
|
@@ -682,7 +686,7 @@ class NavDescription extends Description {
|
|
|
682
686
|
async navigate(cs) {
|
|
683
687
|
cs.sBuf.length = 0; //reset
|
|
684
688
|
cs.sBuf.push("(DESCRIPTION=");
|
|
685
|
-
|
|
689
|
+
const desc = cs.newConnectionDescription(); //connectiondescription
|
|
686
690
|
if (this.retryCount != null) {
|
|
687
691
|
cs.retryCount = this.getIntValue(this.retryCount, cs.retryCount);
|
|
688
692
|
desc.retryCount = cs.retryCount;
|
|
@@ -711,7 +715,7 @@ class NavDescription extends Description {
|
|
|
711
715
|
if ('enable' in this.params) {
|
|
712
716
|
cs.sBuf.push("(ENABLE=" + this.params.enable + ")");
|
|
713
717
|
}
|
|
714
|
-
if (('sslServerCertDN' in this.params) || ('sslServerDNMatch' in this.params) || ('walletLocation' in this.params)) {
|
|
718
|
+
if (('sslServerCertDN' in this.params) || ('sslServerDNMatch' in this.params) || ('walletLocation' in this.params) || ('sslAllowWeakDNMatch' in this.params)) {
|
|
715
719
|
cs.sBuf.push("(SECURITY=");
|
|
716
720
|
if ('sslServerCertDN' in this.params) {
|
|
717
721
|
cs.sBuf.push("(SSL_SERVER_CERT_DN=" + this.params.sslServerCertDN + ")");
|
|
@@ -719,6 +723,9 @@ class NavDescription extends Description {
|
|
|
719
723
|
if ('sslServerDNMatch' in this.params) {
|
|
720
724
|
cs.sBuf.push("(SSL_SERVER_DN_MATCH=" + this.params.sslServerDNMatch + ")");
|
|
721
725
|
}
|
|
726
|
+
if ('sslAllowWeakDNMatch' in this.params) {
|
|
727
|
+
cs.sBuf.push("(SSL_ALLOW_WEAK_DN_MATCH=" + this.params.sslAllowWeakDNMatch + ")");
|
|
728
|
+
}
|
|
722
729
|
if ('walletLocation' in this.params) {
|
|
723
730
|
cs.sBuf.push("(WALLET_LOCATION=" + this.params.walletLocation + ")");
|
|
724
731
|
}
|
|
@@ -834,10 +841,10 @@ class NavDescriptionList extends DescriptionList {
|
|
|
834
841
|
*/
|
|
835
842
|
static setActiveChildren(children, failover, loadBalance) {
|
|
836
843
|
let randNumber;
|
|
837
|
-
|
|
844
|
+
const listSize = children.length;
|
|
838
845
|
let tmpChildren = new Array();
|
|
839
|
-
|
|
840
|
-
|
|
846
|
+
const rand = Math.floor(Math.random() * 10);
|
|
847
|
+
const arr = new Array(listSize).fill(false);
|
|
841
848
|
|
|
842
849
|
if (failover) {
|
|
843
850
|
if (loadBalance) {
|