oracledb 6.7.2 → 6.9.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/LICENSE.txt +1 -1
- package/NOTICE.txt +1 -1
- package/README.md +39 -3
- package/build/Release/oracledb-6.9.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.9.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.9.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.9.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.9.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.9.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-win32-x64.node-buildinfo.txt +1 -0
- package/lib/aqMessage.js +10 -1
- package/lib/configProviders/file.js +72 -0
- package/lib/connection.js +153 -4
- package/lib/dbObject.js +51 -10
- package/lib/errors.js +144 -36
- package/lib/impl/connection.js +24 -1
- package/lib/impl/datahandlers/buffer.js +92 -1
- package/lib/impl/datahandlers/constants.js +2 -0
- package/lib/impl/datahandlers/oson.js +15 -1
- package/lib/impl/datahandlers/vector.js +72 -27
- package/lib/impl/pool.js +10 -1
- package/lib/impl/resultset.js +5 -4
- package/lib/lob.js +9 -1
- package/lib/oracledb.js +209 -20
- package/lib/pool.js +12 -1
- package/lib/poolStatistics.js +3 -1
- package/lib/settings.js +5 -1
- package/lib/thin/connection.js +130 -12
- package/lib/thin/dbObject.js +46 -13
- package/lib/thin/lob.js +2 -3
- package/lib/thin/pool.js +112 -31
- package/lib/thin/protocol/capabilities.js +8 -4
- package/lib/thin/protocol/constants.js +31 -1
- package/lib/thin/protocol/messages/auth.js +42 -6
- package/lib/thin/protocol/messages/base.js +98 -9
- package/lib/thin/protocol/messages/dataType.js +2 -1
- package/lib/thin/protocol/messages/execute.js +46 -4
- package/lib/thin/protocol/messages/fastAuth.js +6 -1
- package/lib/thin/protocol/messages/lobOp.js +5 -22
- package/lib/thin/protocol/messages/logOff.js +0 -1
- package/lib/thin/protocol/messages/sessionRelease.js +0 -1
- package/lib/thin/protocol/messages/transactionSwitch.js +12 -4
- package/lib/thin/protocol/messages/withData.js +10 -1
- package/lib/thin/protocol/packet.js +1 -1
- package/lib/thin/protocol/protocol.js +2 -1
- package/lib/thin/sqlnet/ANO.js +438 -0
- package/lib/thin/sqlnet/connStrategy.js +2 -1
- package/lib/thin/sqlnet/constants.js +5 -1
- package/lib/thin/sqlnet/ezConnectResolver.js +4 -2
- package/lib/thin/sqlnet/navNodes.js +22 -3
- package/lib/thin/sqlnet/networkSession.js +94 -16
- package/lib/thin/sqlnet/ntTcp.js +50 -3
- package/lib/thin/sqlnet/packet.js +32 -4
- package/lib/thin/sqlnet/sessionAtts.js +24 -2
- package/lib/thin/util.js +3 -8
- package/lib/transformer.js +13 -2
- package/lib/types.js +220 -8
- package/lib/util.js +77 -3
- package/lib/version.js +2 -2
- package/package/install.js +3 -3
- package/package/prunebinaries.js +6 -12
- package/package.json +2 -2
- package/{lib/configProviders/azure.js → plugins/configProviders/azure/index.js} +70 -63
- package/plugins/configProviders/azurevault/index.js +84 -0
- package/{lib → plugins}/configProviders/base.js +13 -3
- package/{lib/configProviders/ociobject.js → plugins/configProviders/ociobject/index.js} +43 -78
- package/plugins/configProviders/ocivault/index.js +100 -0
- package/plugins/token/extensionAzure/index.js +101 -0
- package/plugins/token/extensionOci/index.js +210 -0
- package/build/Release/oracledb-6.7.2-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.7.2-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.7.2-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.7.2-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.7.2-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.7.2-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.7.2-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.7.2-linux-x64.node +0 -0
- package/build/Release/oracledb-6.7.2-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.7.2-win32-x64.node +0 -0
- package/build/Release/oracledb-6.7.2-win32-x64.node-buildinfo.txt +0 -1
package/lib/thin/connection.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -85,6 +85,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
85
85
|
// immediate close of open socket on failure
|
|
86
86
|
// exception won't be thrown to user
|
|
87
87
|
this.nscon.disconnect(sqlNetConstants.NSFIMM);
|
|
88
|
+
// If connection is associated with a pool, we release it
|
|
89
|
+
if (this._pool)
|
|
90
|
+
await this._pool.release(this);
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -299,13 +302,20 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
299
302
|
}
|
|
300
303
|
|
|
301
304
|
// process the type code.
|
|
305
|
+
let tempPrecision, tempScale;
|
|
302
306
|
switch (attrType) {
|
|
303
307
|
case constants.TNS_OBJ_TDS_TYPE_NUMBER:
|
|
304
|
-
|
|
305
|
-
|
|
308
|
+
tempPrecision = buf.readInt8();
|
|
309
|
+
tempScale = buf.readInt8();
|
|
310
|
+
if (tempPrecision || tempScale) {
|
|
311
|
+
metaData.precision = tempPrecision;
|
|
312
|
+
metaData.scale = tempScale;
|
|
313
|
+
}
|
|
306
314
|
return types.DB_TYPE_NUMBER;
|
|
307
315
|
case constants.TNS_OBJ_TDS_TYPE_FLOAT:
|
|
308
|
-
|
|
316
|
+
tempPrecision = buf.readInt8();
|
|
317
|
+
if (tempPrecision)
|
|
318
|
+
metaData.precision = tempPrecision;
|
|
309
319
|
return types.DB_TYPE_NUMBER;
|
|
310
320
|
case constants.TNS_OBJ_TDS_TYPE_VARCHAR:
|
|
311
321
|
case constants.TNS_OBJ_TDS_TYPE_CHAR:
|
|
@@ -433,11 +443,24 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
433
443
|
case
|
|
434
444
|
when data_type in
|
|
435
445
|
('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2', 'RAW')
|
|
436
|
-
|
|
446
|
+
then data_length
|
|
437
447
|
else 0
|
|
438
448
|
end,
|
|
439
|
-
|
|
440
|
-
|
|
449
|
+
case
|
|
450
|
+
when data_precision is null and data_scale is null
|
|
451
|
+
then 0
|
|
452
|
+
when data_precision is null
|
|
453
|
+
then 38
|
|
454
|
+
else data_precision
|
|
455
|
+
end,
|
|
456
|
+
case
|
|
457
|
+
when data_precision is null and data_scale is null
|
|
458
|
+
and data_type = 'NUMBER'
|
|
459
|
+
then -127
|
|
460
|
+
when data_scale is null
|
|
461
|
+
then 0
|
|
462
|
+
else data_scale
|
|
463
|
+
end
|
|
441
464
|
from all_tab_cols
|
|
442
465
|
where owner = :owner
|
|
443
466
|
and table_name = :name
|
|
@@ -670,10 +693,36 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
670
693
|
this._partialDbObjectTypes.push(attr.typeClass);
|
|
671
694
|
}
|
|
672
695
|
} else {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
696
|
+
if (attrInfo.dataType === 'INTEGER' || attrInfo.dataType === 'SMALLINT') {
|
|
697
|
+
attr.type = types.DB_TYPE_NUMBER;
|
|
698
|
+
attr.precision = 38;
|
|
699
|
+
attr.scale = 0;
|
|
700
|
+
} else if (attrInfo.dataType === 'REAL') {
|
|
701
|
+
attr.type = types.DB_TYPE_NUMBER;
|
|
702
|
+
attr.precision = 63;
|
|
703
|
+
attr.scale = -127;
|
|
704
|
+
} else if (attrInfo.dataType === 'DOUBLE PRECISION' || attrInfo.dataType === 'FLOAT') {
|
|
705
|
+
attr.type = types.DB_TYPE_NUMBER;
|
|
706
|
+
// the database sends type name "FLOAT" instead of type name "REAL"
|
|
707
|
+
// when looking at table metadata but not when examining database
|
|
708
|
+
// object attribute metadata so account for that here
|
|
709
|
+
if (attrInfo.dataPrecision != null || attrInfo.dataPrecision != undefined)
|
|
710
|
+
attr.precision = Number(attrInfo.dataPrecision);
|
|
711
|
+
else
|
|
712
|
+
attr.precision = 126;
|
|
713
|
+
attr.scale = -127;
|
|
714
|
+
} else {
|
|
715
|
+
attr.type = types.getTypeByColumnTypeName(attrInfo.dataType);
|
|
716
|
+
if (attrInfo.maxSize != null || attrInfo.maxSize != undefined) {
|
|
717
|
+
const tempMaxSize = Number(attrInfo.maxSize);
|
|
718
|
+
if (tempMaxSize)
|
|
719
|
+
attr.maxSize = tempMaxSize;
|
|
720
|
+
}
|
|
721
|
+
if (attr.type === types.DB_TYPE_NUMBER) {
|
|
722
|
+
attr.precision = Number(attrInfo.dataPrecision);
|
|
723
|
+
attr.scale = Number(attrInfo.dataScale);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
677
726
|
}
|
|
678
727
|
attributes.push(attr);
|
|
679
728
|
}
|
|
@@ -715,6 +764,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
715
764
|
await this._protocol.breakMessage();
|
|
716
765
|
}
|
|
717
766
|
|
|
767
|
+
isCompressionEnabled() {
|
|
768
|
+
return this.nscon.compressionEnabled;
|
|
769
|
+
}
|
|
718
770
|
isHealthy() {
|
|
719
771
|
try {
|
|
720
772
|
if (this.nscon.recvInbandNotif() === 0)
|
|
@@ -769,6 +821,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
769
821
|
this.remoteAddress = '';
|
|
770
822
|
this.comboKey = null; // used in changePassword API
|
|
771
823
|
this.tpcContext = null;
|
|
824
|
+
this._sessionlessData = null;
|
|
772
825
|
|
|
773
826
|
this.nscon = new nsi();
|
|
774
827
|
finalizationRegistry.register(this, this.nscon);
|
|
@@ -839,7 +892,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
839
892
|
this.nscon.endOfRequestSupport = endOfRequestSupport;
|
|
840
893
|
await this._protocol._processMessage(authMessage);
|
|
841
894
|
}
|
|
842
|
-
if (!params.
|
|
895
|
+
if (!params.externalAuth) { // non-token Authentication
|
|
843
896
|
await this._protocol._processMessage(authMessage); // OAUTH
|
|
844
897
|
}
|
|
845
898
|
} catch (err) {
|
|
@@ -1230,6 +1283,55 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1230
1283
|
errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state);
|
|
1231
1284
|
}
|
|
1232
1285
|
}
|
|
1286
|
+
//---------------------------------------------------------------------------
|
|
1287
|
+
// Ensure no sessionless transaction was started through server procedure
|
|
1288
|
+
//---------------------------------------------------------------------------
|
|
1289
|
+
_validateSessionlessState() {
|
|
1290
|
+
if (this._sessionlessData?.startedOnServer) {
|
|
1291
|
+
errors.throwErr(errors.ERR_SESSIONLESS_DIFFERING_METHODS);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
//---------------------------------------------------------------------------
|
|
1296
|
+
// Begin/Resume a sessionless transaction with provided transactionId
|
|
1297
|
+
//---------------------------------------------------------------------------
|
|
1298
|
+
async startSessionlessTransaction(transactionId, timeout, flags,
|
|
1299
|
+
deferRoundTrip) {
|
|
1300
|
+
this._validateSessionlessState();
|
|
1301
|
+
if (this._sessionlessData)
|
|
1302
|
+
errors.throwErr(errors.ERR_SESSIONLESS_ALREADY_ACTIVE);
|
|
1303
|
+
const message = new messages.TransactionSwitchMessage(this);
|
|
1304
|
+
message.xid = {
|
|
1305
|
+
globalTransactionId: transactionId,
|
|
1306
|
+
branchQualifier: "",
|
|
1307
|
+
formatId: constants.TNS_TPC_TRANS_SESSIONLESS_FORMAT
|
|
1308
|
+
};
|
|
1309
|
+
message.timeout = timeout;
|
|
1310
|
+
message.operation = constants.TNS_TPC_TXN_START;
|
|
1311
|
+
message.flags = constants.TNS_TPC_TRANS_SESSIONLESS | flags;
|
|
1312
|
+
if (deferRoundTrip) {
|
|
1313
|
+
message.messageType = constants.TNS_MSG_TYPE_PIGGYBACK;
|
|
1314
|
+
this._sessionlessData = {
|
|
1315
|
+
piggyback: message,
|
|
1316
|
+
pending: true
|
|
1317
|
+
};
|
|
1318
|
+
} else {
|
|
1319
|
+
await this._protocol._processMessage(message);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
//---------------------------------------------------------------------------
|
|
1324
|
+
// Suspend the active sessionless transaction
|
|
1325
|
+
//---------------------------------------------------------------------------
|
|
1326
|
+
async suspendSessionlessTransaction() {
|
|
1327
|
+
this._validateSessionlessState();
|
|
1328
|
+
if (!this._sessionlessData)
|
|
1329
|
+
errors.throwErr(errors.ERR_SESSIONLESS_INACTIVE);
|
|
1330
|
+
const message = new messages.TransactionSwitchMessage(this);
|
|
1331
|
+
message.operation = constants.TNS_TPC_TXN_DETACH;
|
|
1332
|
+
message.flags = constants.TNS_TPC_TRANS_SESSIONLESS;
|
|
1333
|
+
await this._protocol._processMessage(message);
|
|
1334
|
+
}
|
|
1233
1335
|
|
|
1234
1336
|
|
|
1235
1337
|
//---------------------------------------------------------------------------
|
|
@@ -1270,6 +1372,14 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1270
1372
|
return this.internalName;
|
|
1271
1373
|
}
|
|
1272
1374
|
|
|
1375
|
+
//---------------------------------------------------------------------------
|
|
1376
|
+
// Returns the Logical Transaction ID (ltxid) associated with the connection.
|
|
1377
|
+
// Used with Oracle Database Transaction Guard feature.
|
|
1378
|
+
//---------------------------------------------------------------------------
|
|
1379
|
+
getLTXID() {
|
|
1380
|
+
return this._ltxid;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1273
1383
|
//---------------------------------------------------------------------------
|
|
1274
1384
|
// Returns the Oracle Database domain name associated with the connection.
|
|
1275
1385
|
//---------------------------------------------------------------------------
|
|
@@ -1312,6 +1422,14 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1312
1422
|
return this.maxOpenCursors;
|
|
1313
1423
|
}
|
|
1314
1424
|
|
|
1425
|
+
//---------------------------------------------------------------------------
|
|
1426
|
+
// Returns the maximum length of identifiers supported by the database to
|
|
1427
|
+
// which this connection has been established.
|
|
1428
|
+
//---------------------------------------------------------------------------
|
|
1429
|
+
getMaxIdentifierLength() {
|
|
1430
|
+
return this.maxIdentifierLength;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1315
1433
|
//---------------------------------------------------------------------------
|
|
1316
1434
|
// Returns the Oracle Database service name associated with the connection.
|
|
1317
1435
|
//---------------------------------------------------------------------------
|
package/lib/thin/dbObject.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2023,
|
|
1
|
+
// Copyright (c) 2023, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -55,10 +55,10 @@ class DbObjectPickleBuffer extends GrowableBuffer {
|
|
|
55
55
|
// Reads the next byte and checks to see if the value is atomically null. If
|
|
56
56
|
// not, the byte is returned to the buffer for further processing.
|
|
57
57
|
//---------------------------------------------------------------------------
|
|
58
|
-
getIsAtomicNull() {
|
|
58
|
+
getIsAtomicNull(isCollection) {
|
|
59
59
|
const value = this.readUInt8();
|
|
60
60
|
if (value === constants.TNS_OBJ_ATOMIC_NULL ||
|
|
61
|
-
|
|
61
|
+
(isCollection && value === constants.TNS_NULL_LENGTH_INDICATOR)) {
|
|
62
62
|
return true;
|
|
63
63
|
}
|
|
64
64
|
this.pos -= 1;
|
|
@@ -365,13 +365,10 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
365
365
|
// Unpacks a single value and returns it.
|
|
366
366
|
//---------------------------------------------------------------------------
|
|
367
367
|
_unpackValue(buf, type, typeClass) {
|
|
368
|
-
let isNull, obj, value;
|
|
368
|
+
let isNull, obj, value, isCollection;
|
|
369
369
|
switch (type) {
|
|
370
370
|
case types.DB_TYPE_NUMBER:
|
|
371
|
-
|
|
372
|
-
if (value !== null)
|
|
373
|
-
value = parseFloat(value);
|
|
374
|
-
return value;
|
|
371
|
+
return buf.readOracleNumber();
|
|
375
372
|
case types.DB_TYPE_BINARY_INTEGER:
|
|
376
373
|
return buf.readBinaryInteger();
|
|
377
374
|
case types.DB_TYPE_VARCHAR:
|
|
@@ -399,14 +396,16 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
399
396
|
return buf.readBool();
|
|
400
397
|
case types.DB_TYPE_OBJECT:
|
|
401
398
|
case types.DB_TYPE_XMLTYPE:
|
|
402
|
-
|
|
399
|
+
obj = new ThinDbObjectImpl(typeClass);
|
|
400
|
+
isCollection = obj._objType.isCollection ||
|
|
401
|
+
this._objType.isCollection;
|
|
402
|
+
isNull = buf.getIsAtomicNull(isCollection);
|
|
403
403
|
if (isNull)
|
|
404
404
|
return null;
|
|
405
|
-
obj = new ThinDbObjectImpl(typeClass);
|
|
406
405
|
if (obj._objType.isXmlType) {
|
|
407
406
|
return readXML(obj._objType._connection, buf.readBytesWithLength());
|
|
408
407
|
}
|
|
409
|
-
if (
|
|
408
|
+
if (isCollection) {
|
|
410
409
|
obj.packedData = Buffer.from(buf.readBytesWithLength());
|
|
411
410
|
} else {
|
|
412
411
|
obj._unpackDataFromBuf(buf);
|
|
@@ -429,7 +428,7 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
429
428
|
if (objType.maxNumElements > 0 &&
|
|
430
429
|
this.unpackedArray.length >= objType.maxNumElements) {
|
|
431
430
|
errors.throwErr(errors.ERR_INVALID_COLL_INDEX_SET,
|
|
432
|
-
this.unpackedArray.length, 0, objType.maxNumElements);
|
|
431
|
+
this.unpackedArray.length, 0, objType.maxNumElements - 1);
|
|
433
432
|
}
|
|
434
433
|
this.unpackedArray.push(value);
|
|
435
434
|
} else {
|
|
@@ -446,6 +445,26 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
446
445
|
}
|
|
447
446
|
}
|
|
448
447
|
|
|
448
|
+
//---------------------------------------------------------------------------
|
|
449
|
+
// copy
|
|
450
|
+
//
|
|
451
|
+
// Creates and returns a copy of the ThinDBObjectImpl object. The copy is
|
|
452
|
+
// independent of the original object that was copied.
|
|
453
|
+
//---------------------------------------------------------------------------
|
|
454
|
+
copy() {
|
|
455
|
+
// We send in marshalled data of the original object to the constructor
|
|
456
|
+
// when we create the object copy
|
|
457
|
+
const newObjImpl = new ThinDbObjectImpl(this._objType, this._getPackedData());
|
|
458
|
+
|
|
459
|
+
// Set other properties
|
|
460
|
+
newObjImpl.toid = this.toid;
|
|
461
|
+
newObjImpl.flags = this.flags;
|
|
462
|
+
newObjImpl.imageFlags = this.imageFlags;
|
|
463
|
+
newObjImpl.imageVersion = this.imageVersion;
|
|
464
|
+
|
|
465
|
+
return newObjImpl;
|
|
466
|
+
}
|
|
467
|
+
|
|
449
468
|
//---------------------------------------------------------------------------
|
|
450
469
|
// deleteElement()
|
|
451
470
|
//
|
|
@@ -459,7 +478,7 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
459
478
|
}
|
|
460
479
|
this.unpackedArray.splice(index, 1);
|
|
461
480
|
} else {
|
|
462
|
-
this.
|
|
481
|
+
this.unpackedAssocKeys = undefined;
|
|
463
482
|
this.unpackedAssocArray.delete(index);
|
|
464
483
|
}
|
|
465
484
|
}
|
|
@@ -610,6 +629,20 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
610
629
|
return result;
|
|
611
630
|
}
|
|
612
631
|
|
|
632
|
+
//---------------------------------------------------------------------------
|
|
633
|
+
// getLength
|
|
634
|
+
//
|
|
635
|
+
// Gets the size of the database object if it is a collection. Else returns
|
|
636
|
+
// undefined.
|
|
637
|
+
//---------------------------------------------------------------------------
|
|
638
|
+
getLength() {
|
|
639
|
+
this._ensureUnpacked();
|
|
640
|
+
if (this.unpackedArray)
|
|
641
|
+
return this.unpackedArray.length;
|
|
642
|
+
if (this.unpackedAssocArray)
|
|
643
|
+
return this.unpackedAssocArray.size;
|
|
644
|
+
}
|
|
645
|
+
|
|
613
646
|
//---------------------------------------------------------------------------
|
|
614
647
|
// hasElement()
|
|
615
648
|
//
|
package/lib/thin/lob.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -220,10 +220,9 @@ class ThinLobImpl extends LobImpl {
|
|
|
220
220
|
const options = {
|
|
221
221
|
operation: constants.TNS_LOB_OP_CREATE_TEMP,
|
|
222
222
|
sourceLobImpl: this,
|
|
223
|
-
amount: constants.TNS_DURATION_SESSION,
|
|
224
223
|
destOffset: dbType._oraTypeNum,
|
|
225
224
|
sourceOffset: dbType._csfrm,
|
|
226
|
-
|
|
225
|
+
destLength: constants.TNS_DURATION_SESSION
|
|
227
226
|
};
|
|
228
227
|
await this._sendMessage(options);
|
|
229
228
|
await this._getChunkSizeAsync();
|
package/lib/thin/pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -35,7 +35,6 @@ const util = require('../util.js');
|
|
|
35
35
|
const thinUtil = require('./util.js');
|
|
36
36
|
const {getConnectionInfo} = require('./sqlnet/networkSession.js');
|
|
37
37
|
const crypto = require('crypto');
|
|
38
|
-
const EventEmitter = require('events');
|
|
39
38
|
const Timers = require('timers');
|
|
40
39
|
|
|
41
40
|
class ThinPoolImpl extends PoolImpl {
|
|
@@ -57,6 +56,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
57
56
|
this._poolTimeout = params.poolTimeout;
|
|
58
57
|
this._poolPingInterval = params.poolPingInterval;
|
|
59
58
|
this._poolPingTimeout = params.poolPingTimeout;
|
|
59
|
+
this._maxLifetimeSession = params.maxLifetimeSession || 0;
|
|
60
60
|
this._stmtCacheSize = params.stmtCacheSize;
|
|
61
61
|
|
|
62
62
|
// The user Config filterd from common layer is cached except
|
|
@@ -77,6 +77,9 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
77
77
|
this._schedulerJob = null;
|
|
78
78
|
this._poolCloseWaiter = null;
|
|
79
79
|
this._pendingRequests = [];
|
|
80
|
+
this._connsToDrop = [];
|
|
81
|
+
this._bgCleaner = null;
|
|
82
|
+
this._poolCloseCleaner = null;
|
|
80
83
|
|
|
81
84
|
// password obfuscation
|
|
82
85
|
if (this._password !== undefined) {
|
|
@@ -117,11 +120,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
117
120
|
this._accessTokenConfig = params.accessTokenConfig;
|
|
118
121
|
this._isDRCPEnabled = false;
|
|
119
122
|
this._implicitPool = null;
|
|
120
|
-
this.eventEmitter = new EventEmitter();
|
|
121
|
-
// listener to remove dead or idle connections
|
|
122
|
-
this.eventEmitter.on('_removePoolConnection', async (connImpl) => {
|
|
123
|
-
await this._destroy(connImpl);
|
|
124
|
-
});
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
//---------------------------------------------------------------------------
|
|
@@ -142,6 +140,9 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
142
140
|
// create a background task. It will create minimum connections in the pool
|
|
143
141
|
// and expand the pool as required.
|
|
144
142
|
this.bgThreadFunc();
|
|
143
|
+
// create a background task to remove connections that are to in
|
|
144
|
+
// _connsToDrop, reason for dropping may be poolTimeout or poolMax decrease
|
|
145
|
+
this._bgConnCleaner();
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
//---------------------------------------------------------------------------
|
|
@@ -197,7 +198,11 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
197
198
|
protocolUtil.getDeobfuscatedValue(this._token, this._obfuscatedToken);
|
|
198
199
|
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
199
200
|
if (typeof this._accessTokenFn === 'function') {
|
|
200
|
-
|
|
201
|
+
try {
|
|
202
|
+
accessToken = await this._accessTokenFn(true, this._accessTokenConfig);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
errors.throwWrapErr(error, errors.ERR_ACCESS_TOKEN);
|
|
205
|
+
}
|
|
201
206
|
if (typeof accessToken === 'string') {
|
|
202
207
|
clonedAttrs.token = accessToken;
|
|
203
208
|
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
@@ -211,7 +216,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
211
216
|
}
|
|
212
217
|
} else if (typeof accessToken === 'object') {
|
|
213
218
|
clonedAttrs.token = accessToken.token;
|
|
214
|
-
clonedAttrs.privateKey = accessToken.privateKey;
|
|
219
|
+
clonedAttrs.privateKey = util.denormalizePrivateKey(accessToken.privateKey);
|
|
215
220
|
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
216
221
|
// IAM token is expired
|
|
217
222
|
errors.throwErr(errors.ERR_TOKEN_HAS_EXPIRED);
|
|
@@ -250,9 +255,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
250
255
|
// destroy connection when pool close operation is called
|
|
251
256
|
//---------------------------------------------------------------------------
|
|
252
257
|
async _destroy(connection) {
|
|
253
|
-
|
|
254
|
-
connection.
|
|
255
|
-
|
|
258
|
+
try {
|
|
259
|
+
if (connection.nscon.ntAdapter.connected) {
|
|
260
|
+
connection._dropSess = true;
|
|
261
|
+
await connection.close();
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
return;
|
|
256
265
|
}
|
|
257
266
|
}
|
|
258
267
|
|
|
@@ -286,7 +295,12 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
286
295
|
await this._destroy(conn);
|
|
287
296
|
}
|
|
288
297
|
|
|
289
|
-
|
|
298
|
+
// Let the bgCleaner destroy all connsToDrop and stop
|
|
299
|
+
await new Promise((resolve) => {
|
|
300
|
+
this._poolCloseCleaner = resolve;
|
|
301
|
+
if (this._bgCleaner)
|
|
302
|
+
this._bgCleaner();
|
|
303
|
+
});
|
|
290
304
|
}
|
|
291
305
|
|
|
292
306
|
//---------------------------------------------------------------------------
|
|
@@ -352,6 +366,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
352
366
|
return this._poolTimeout;
|
|
353
367
|
}
|
|
354
368
|
|
|
369
|
+
//---------------------------------------------------------------------------
|
|
370
|
+
// returns the pool max lifetime for a session (seconds)
|
|
371
|
+
//---------------------------------------------------------------------------
|
|
372
|
+
getMaxLifetimeSession() {
|
|
373
|
+
return this._maxLifetimeSession;
|
|
374
|
+
}
|
|
375
|
+
|
|
355
376
|
//---------------------------------------------------------------------------
|
|
356
377
|
// returns whether the SODA metadata cache is enabled or not
|
|
357
378
|
//---------------------------------------------------------------------------
|
|
@@ -395,10 +416,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
395
416
|
break;
|
|
396
417
|
}
|
|
397
418
|
|
|
398
|
-
this.
|
|
419
|
+
this._connsToDrop.push(conn);
|
|
399
420
|
this._freeConnectionList.shift();
|
|
400
421
|
}
|
|
401
422
|
|
|
423
|
+
// call cleaner for destroying connections added to _connsToDrop
|
|
424
|
+
if (this._bgCleaner)
|
|
425
|
+
this._bgCleaner();
|
|
402
426
|
this._schedulerJob = null;
|
|
403
427
|
this._setScheduler();
|
|
404
428
|
}
|
|
@@ -434,15 +458,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
434
458
|
|
|
435
459
|
// continue until a close request is received
|
|
436
460
|
while (!this._poolCloseWaiter) {
|
|
437
|
-
// eliminate connections that exceed the poolMax (this should only happen
|
|
438
|
-
// after a reconfiguration has taken place where the maximum number of
|
|
439
|
-
// connections is reduced)
|
|
440
|
-
let numToDestroy = this._poolMax - this.getConnectionsOpen();
|
|
441
|
-
while (numToDestroy > 0 && this._freeConnectionList.length > 0) {
|
|
442
|
-
const connToBeRemoved = this._freeConnectionList.shift();
|
|
443
|
-
this.eventEmitter.emit('_removePoolConnection', connToBeRemoved);
|
|
444
|
-
numToDestroy--;
|
|
445
|
-
}
|
|
446
461
|
|
|
447
462
|
const numToCreate = this._getNumConnsToCreate();
|
|
448
463
|
// connection creation is going on serially and not concurrently
|
|
@@ -455,6 +470,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
455
470
|
await conn.connect(config);
|
|
456
471
|
conn._newSession = true;
|
|
457
472
|
conn._dropSess = false;
|
|
473
|
+
conn._creationTime = Date.now();
|
|
458
474
|
conn._lastTimeUsed = Date.now();
|
|
459
475
|
this._freeConnectionList.push(conn);
|
|
460
476
|
} catch (err) {
|
|
@@ -487,7 +503,8 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
487
503
|
}
|
|
488
504
|
|
|
489
505
|
// if no pending requests, wait for pending requests to appear!
|
|
490
|
-
if (this._pendingRequests.length == 0 || this._bgErr)
|
|
506
|
+
if ((this._pendingRequests.length == 0 || this._bgErr) &&
|
|
507
|
+
this.getConnectionsOpen() >= this._poolMin) {
|
|
491
508
|
await new Promise((resolve) => {
|
|
492
509
|
this.bgWaiter = resolve;
|
|
493
510
|
});
|
|
@@ -499,6 +516,27 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
499
516
|
this._poolCloseWaiter();
|
|
500
517
|
}
|
|
501
518
|
|
|
519
|
+
//---------------------------------------------------------------------------
|
|
520
|
+
// _bgConnCleaner()
|
|
521
|
+
// Method which stays in the stack and performs cleanup whenever a connection
|
|
522
|
+
// gets added for cleanup to _connsToDrop
|
|
523
|
+
// acquire a connection from connection pool
|
|
524
|
+
//---------------------------------------------------------------------------
|
|
525
|
+
async _bgConnCleaner() {
|
|
526
|
+
// run until a pool.close() is issued
|
|
527
|
+
while (!this._poolCloseCleaner) {
|
|
528
|
+
|
|
529
|
+
// wait for _bgCleaner to be called for cleanup
|
|
530
|
+
if (this._connsToDrop.length == 0)
|
|
531
|
+
await new Promise(resolve => this._bgCleaner = resolve);
|
|
532
|
+
|
|
533
|
+
// destroy connections in _connsToDrop
|
|
534
|
+
while (this._connsToDrop.length)
|
|
535
|
+
await this._destroy(this._connsToDrop.pop());
|
|
536
|
+
}
|
|
537
|
+
this._poolCloseCleaner();
|
|
538
|
+
}
|
|
539
|
+
|
|
502
540
|
//---------------------------------------------------------------------------
|
|
503
541
|
// acquire()
|
|
504
542
|
//
|
|
@@ -510,9 +548,10 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
510
548
|
while (this._freeConnectionList.length > 0) {
|
|
511
549
|
const conn = this._freeConnectionList.pop();
|
|
512
550
|
|
|
513
|
-
// if connection is unhealthy,
|
|
514
|
-
|
|
515
|
-
|
|
551
|
+
// drop from the pool if the connection is unhealthy, or if the
|
|
552
|
+
// connection's lifetime exceeds maxLifetimeSession
|
|
553
|
+
if (!this._shouldRetainInPool(conn)) {
|
|
554
|
+
this._invokeBgCleaner(conn);
|
|
516
555
|
continue;
|
|
517
556
|
}
|
|
518
557
|
|
|
@@ -591,11 +630,11 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
591
630
|
if (conn.nscon.connected) {
|
|
592
631
|
conn._lastTimeUsed = Date.now();
|
|
593
632
|
conn._newSession = false;
|
|
594
|
-
if ((this.
|
|
595
|
-
|
|
633
|
+
if ((this.getConnectionsOpen() < this._poolMax) &&
|
|
634
|
+
this._shouldRetainInPool(conn)) {
|
|
596
635
|
this._freeConnectionList.push(conn);
|
|
597
636
|
} else {
|
|
598
|
-
this.
|
|
637
|
+
this._invokeBgCleaner(conn);
|
|
599
638
|
}
|
|
600
639
|
}
|
|
601
640
|
|
|
@@ -648,9 +687,51 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
648
687
|
this._poolMin = params.poolMin;
|
|
649
688
|
}
|
|
650
689
|
|
|
651
|
-
if (
|
|
690
|
+
if (params.maxLifetimeSession !== undefined) {
|
|
691
|
+
this._maxLifetimeSession = params.maxLifetimeSession;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
let numToDestroy = this.getConnectionsOpen() - this._poolMax;
|
|
695
|
+
while (this._freeConnectionList.length && numToDestroy > 0) {
|
|
696
|
+
const conn = this._freeConnectionList.pop();
|
|
697
|
+
this._connsToDrop.push(conn);
|
|
698
|
+
numToDestroy--;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// call cleanup for destroying connections in _connsToDrop
|
|
702
|
+
if (this._bgCleaner)
|
|
703
|
+
this._bgCleaner();
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
//---------------------------------------------------------------------------
|
|
707
|
+
// _invokeBgCleaner()
|
|
708
|
+
//
|
|
709
|
+
// drop conn and invoke the bgCleaner while also ensuring min connections
|
|
710
|
+
//---------------------------------------------------------------------------
|
|
711
|
+
_invokeBgCleaner(conn) {
|
|
712
|
+
this._connsToDrop.push(conn);
|
|
713
|
+
if (this._bgCleaner)
|
|
714
|
+
this._bgCleaner();
|
|
715
|
+
|
|
716
|
+
// ensure min connections are maintained in pool
|
|
717
|
+
if ((this.getConnectionsOpen() < this._poolMin) && this.bgWaiter)
|
|
652
718
|
this.bgWaiter();
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
//---------------------------------------------------------------------------
|
|
722
|
+
// _shouldRetainInPool()
|
|
723
|
+
//
|
|
724
|
+
// returns true if the connection should be retained in pool
|
|
725
|
+
//---------------------------------------------------------------------------
|
|
726
|
+
_shouldRetainInPool(conn) {
|
|
727
|
+
if (!conn.isHealthy())
|
|
728
|
+
return false;
|
|
729
|
+
// check if maxLifetimeSession of conn has expired
|
|
730
|
+
if (this._maxLifetimeSession !== 0) {
|
|
731
|
+
if ((Date.now() - conn._creationTime) > (this._maxLifetimeSession * 1000))
|
|
732
|
+
return false;
|
|
653
733
|
}
|
|
734
|
+
return true;
|
|
654
735
|
}
|
|
655
736
|
}
|
|
656
737
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -104,11 +104,14 @@ class Capabilities {
|
|
|
104
104
|
constants.TNS_CCAP_LOB2_QUASI | constants.TNS_CCAP_LOB2_2GB_PREFETCH;
|
|
105
105
|
this.compileCaps[constants.TNS_CCAP_TTC3] =
|
|
106
106
|
constants.TNS_CCAP_IMPLICIT_RESULTS | constants.TNS_CCAP_BIG_CHUNK_CLR |
|
|
107
|
-
constants.TNS_CCAP_KEEP_OUT_ORDER;
|
|
107
|
+
constants.TNS_CCAP_KEEP_OUT_ORDER | constants.TNS_CCAP_LTXID;
|
|
108
|
+
this.compileCaps[constants.TNS_CCAP_OCI3] = constants.TNS_CCAP_OCI3_OCSSYNC;
|
|
108
109
|
this.compileCaps[constants.TNS_CCAP_TTC2] = constants.TNS_CCAP_ZLNP;
|
|
109
110
|
this.compileCaps[constants.TNS_CCAP_OCI2] = constants.TNS_CCAP_DRCP;
|
|
110
111
|
this.compileCaps[constants.TNS_CCAP_CLIENT_FN] =
|
|
111
112
|
constants.TNS_CCAP_CLIENT_FN_MAX;
|
|
113
|
+
this.compileCaps[constants.TNS_CCAP_SESS_SIGNATURE_VERSION] =
|
|
114
|
+
constants.TNS_CCAP_FIELD_VERSION_12_2;
|
|
112
115
|
this.compileCaps[constants.TNS_CCAP_TTC4] =
|
|
113
116
|
constants.TNS_CCAP_INBAND_NOTIFICATION;
|
|
114
117
|
if (nscon.endOfRequestSupport) {
|
|
@@ -117,9 +120,10 @@ class Capabilities {
|
|
|
117
120
|
this.compileCaps[constants.TNS_CCAP_CTB_FEATURE_BACKPORT] =
|
|
118
121
|
constants.TNS_CCAP_CTB_IMPLICIT_POOL;
|
|
119
122
|
this.compileCaps[constants.TNS_CCAP_TTC5] =
|
|
120
|
-
constants.TNS_CCAP_VECTOR_SUPPORT
|
|
123
|
+
constants.TNS_CCAP_VECTOR_SUPPORT |
|
|
124
|
+
constants.TNS_CCAP_TTC5_SESSIONLESS_TXNS;
|
|
121
125
|
this.compileCaps[constants.TNS_CCAP_VECTOR_FEATURES] =
|
|
122
|
-
constants.TNS_CCAP_VECTOR_FEATURE_BINARY;
|
|
126
|
+
constants.TNS_CCAP_VECTOR_FEATURE_BINARY | constants.TNS_CCAP_VECTOR_FEATURE_SPARSE;
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
initRuntimeCaps() {
|