oracledb 6.8.0 → 6.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -3
- package/build/Release/oracledb-6.10.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.10.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.10.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-win32-x64.node-buildinfo.txt +1 -0
- package/lib/aqDeqOptions.js +18 -1
- package/lib/aqMessage.js +10 -1
- package/lib/aqQueue.js +10 -6
- package/lib/configProviders/file.js +72 -0
- package/lib/connection.js +93 -4
- package/lib/dbObject.js +34 -4
- package/lib/errors.js +70 -35
- package/lib/impl/aqDeqOptions.js +10 -1
- package/lib/impl/connection.js +9 -0
- package/lib/impl/datahandlers/buffer.js +49 -0
- package/lib/impl/datahandlers/oson.js +7 -2
- package/lib/impl/pool.js +10 -1
- package/lib/impl/resultset.js +5 -4
- package/lib/impl/sodaDocument.js +5 -14
- package/lib/lob.js +9 -1
- package/lib/oracledb.js +152 -30
- package/lib/pool.js +199 -147
- package/lib/poolStatistics.js +4 -2
- package/lib/sodaCollection.js +12 -8
- package/lib/sodaDatabase.js +35 -8
- package/lib/sodaDocument.js +24 -6
- package/lib/sodaOperation.js +7 -6
- package/lib/thin/aq.js +475 -0
- package/lib/thin/connection.js +171 -14
- package/lib/thin/dbObject.js +8 -6
- package/lib/thin/lob.js +2 -3
- package/lib/thin/pool.js +105 -28
- package/lib/thin/protocol/capabilities.js +10 -4
- package/lib/thin/protocol/constants.js +90 -1
- package/lib/thin/protocol/encryptDecrypt.js +2 -2
- package/lib/thin/protocol/messages/aqArray.js +238 -0
- package/lib/thin/protocol/messages/aqBase.js +305 -0
- package/lib/thin/protocol/messages/aqDeq.js +164 -0
- package/lib/thin/protocol/messages/aqEnq.js +135 -0
- package/lib/thin/protocol/messages/auth.js +25 -27
- 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/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 +3 -3
- package/lib/thin/protocol/packet.js +6 -5
- package/lib/thin/protocol/protocol.js +2 -1
- package/lib/thin/sqlnet/connStrategy.js +2 -1
- package/lib/thin/sqlnet/navNodes.js +1 -1
- package/lib/thin/sqlnet/networkSession.js +10 -4
- package/lib/thin/sqlnet/packet.js +2 -1
- package/lib/thin/sqlnet/sessionAtts.js +2 -3
- package/lib/types.js +6 -11
- package/lib/util.js +72 -11
- package/lib/version.js +1 -1
- 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} +73 -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/extensionOci/index.js +71 -35
- package/build/Release/oracledb-6.8.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.8.0-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.8.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.8.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.8.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.8.0-win32-x64.node-buildinfo.txt +0 -1
package/lib/thin/connection.js
CHANGED
|
@@ -42,6 +42,7 @@ const types = require('../types.js');
|
|
|
42
42
|
const errors = require("../errors.js");
|
|
43
43
|
const messages = require('./protocol/messages');
|
|
44
44
|
const StatementCache = require('./statementCache.js');
|
|
45
|
+
const { ThinQueueImpl } = require('./aq.js');
|
|
45
46
|
|
|
46
47
|
const finalizationRegistry = new global.FinalizationRegistry((heldValue) => {
|
|
47
48
|
heldValue.disconnect();
|
|
@@ -85,6 +86,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
85
86
|
// immediate close of open socket on failure
|
|
86
87
|
// exception won't be thrown to user
|
|
87
88
|
this.nscon.disconnect(sqlNetConstants.NSFIMM);
|
|
89
|
+
// If connection is associated with a pool, we release it
|
|
90
|
+
if (this._pool)
|
|
91
|
+
await this._pool.release(this);
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -167,7 +171,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
167
171
|
//
|
|
168
172
|
// Calls the RPC that executes a SQL statement and returns the results.
|
|
169
173
|
//---------------------------------------------------------------------------
|
|
170
|
-
async _execute(statement, numIters, binds, options, executeManyFlag) {
|
|
174
|
+
async _execute(statement, numIters, binds, options, executeManyFlag, internalTempLobs = []) {
|
|
171
175
|
|
|
172
176
|
// Throw error if executeMany is not called on a DML statement or PL/SQL
|
|
173
177
|
if (executeManyFlag && statement.isQuery) {
|
|
@@ -191,7 +195,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
191
195
|
}
|
|
192
196
|
|
|
193
197
|
for (let i = 0; i < binds.length; i++) {
|
|
194
|
-
await this._bind(statement, binds[i], i + 1);
|
|
198
|
+
await this._bind(statement, binds[i], i + 1, internalTempLobs);
|
|
195
199
|
}
|
|
196
200
|
if (statement.isPlSql && (options.batchErrors || options.dmlRowCounts)) {
|
|
197
201
|
errors.throwErr(errors.ERR_EXEC_MODE_ONLY_FOR_DML);
|
|
@@ -299,13 +303,20 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
299
303
|
}
|
|
300
304
|
|
|
301
305
|
// process the type code.
|
|
306
|
+
let tempPrecision, tempScale;
|
|
302
307
|
switch (attrType) {
|
|
303
308
|
case constants.TNS_OBJ_TDS_TYPE_NUMBER:
|
|
304
|
-
|
|
305
|
-
|
|
309
|
+
tempPrecision = buf.readInt8();
|
|
310
|
+
tempScale = buf.readInt8();
|
|
311
|
+
if (tempPrecision || tempScale) {
|
|
312
|
+
metaData.precision = tempPrecision;
|
|
313
|
+
metaData.scale = tempScale;
|
|
314
|
+
}
|
|
306
315
|
return types.DB_TYPE_NUMBER;
|
|
307
316
|
case constants.TNS_OBJ_TDS_TYPE_FLOAT:
|
|
308
|
-
|
|
317
|
+
tempPrecision = buf.readInt8();
|
|
318
|
+
if (tempPrecision)
|
|
319
|
+
metaData.precision = tempPrecision;
|
|
309
320
|
return types.DB_TYPE_NUMBER;
|
|
310
321
|
case constants.TNS_OBJ_TDS_TYPE_VARCHAR:
|
|
311
322
|
case constants.TNS_OBJ_TDS_TYPE_CHAR:
|
|
@@ -433,11 +444,24 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
433
444
|
case
|
|
434
445
|
when data_type in
|
|
435
446
|
('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2', 'RAW')
|
|
436
|
-
|
|
447
|
+
then data_length
|
|
437
448
|
else 0
|
|
438
449
|
end,
|
|
439
|
-
|
|
440
|
-
|
|
450
|
+
case
|
|
451
|
+
when data_precision is null and data_scale is null
|
|
452
|
+
then 0
|
|
453
|
+
when data_precision is null
|
|
454
|
+
then 38
|
|
455
|
+
else data_precision
|
|
456
|
+
end,
|
|
457
|
+
case
|
|
458
|
+
when data_precision is null and data_scale is null
|
|
459
|
+
and data_type = 'NUMBER'
|
|
460
|
+
then -127
|
|
461
|
+
when data_scale is null
|
|
462
|
+
then 0
|
|
463
|
+
else data_scale
|
|
464
|
+
end
|
|
441
465
|
from all_tab_cols
|
|
442
466
|
where owner = :owner
|
|
443
467
|
and table_name = :name
|
|
@@ -670,10 +694,36 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
670
694
|
this._partialDbObjectTypes.push(attr.typeClass);
|
|
671
695
|
}
|
|
672
696
|
} else {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
697
|
+
if (attrInfo.dataType === 'INTEGER' || attrInfo.dataType === 'SMALLINT') {
|
|
698
|
+
attr.type = types.DB_TYPE_NUMBER;
|
|
699
|
+
attr.precision = 38;
|
|
700
|
+
attr.scale = 0;
|
|
701
|
+
} else if (attrInfo.dataType === 'REAL') {
|
|
702
|
+
attr.type = types.DB_TYPE_NUMBER;
|
|
703
|
+
attr.precision = 63;
|
|
704
|
+
attr.scale = -127;
|
|
705
|
+
} else if (attrInfo.dataType === 'DOUBLE PRECISION' || attrInfo.dataType === 'FLOAT') {
|
|
706
|
+
attr.type = types.DB_TYPE_NUMBER;
|
|
707
|
+
// the database sends type name "FLOAT" instead of type name "REAL"
|
|
708
|
+
// when looking at table metadata but not when examining database
|
|
709
|
+
// object attribute metadata so account for that here
|
|
710
|
+
if (attrInfo.dataPrecision != null || attrInfo.dataPrecision != undefined)
|
|
711
|
+
attr.precision = Number(attrInfo.dataPrecision);
|
|
712
|
+
else
|
|
713
|
+
attr.precision = 126;
|
|
714
|
+
attr.scale = -127;
|
|
715
|
+
} else {
|
|
716
|
+
attr.type = types.getTypeByColumnTypeName(attrInfo.dataType);
|
|
717
|
+
if (attrInfo.maxSize != null || attrInfo.maxSize != undefined) {
|
|
718
|
+
const tempMaxSize = Number(attrInfo.maxSize);
|
|
719
|
+
if (tempMaxSize)
|
|
720
|
+
attr.maxSize = tempMaxSize;
|
|
721
|
+
}
|
|
722
|
+
if (attr.type === types.DB_TYPE_NUMBER) {
|
|
723
|
+
attr.precision = Number(attrInfo.dataPrecision);
|
|
724
|
+
attr.scale = Number(attrInfo.dataScale);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
677
727
|
}
|
|
678
728
|
attributes.push(attr);
|
|
679
729
|
}
|
|
@@ -732,6 +782,36 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
732
782
|
return (this._pool) ? true : false;
|
|
733
783
|
}
|
|
734
784
|
|
|
785
|
+
_postConnect(authMessage) {
|
|
786
|
+
let releaseNum;
|
|
787
|
+
let updateNum;
|
|
788
|
+
let portReleaseNum;
|
|
789
|
+
let portUpdateNum;
|
|
790
|
+
|
|
791
|
+
this.dbDomain = authMessage.sessionData['AUTH_SC_DB_DOMAIN'];
|
|
792
|
+
this.dbName = authMessage.sessionData['AUTH_DBNAME'];
|
|
793
|
+
this.maxOpenCursors = Number(authMessage.sessionData['AUTH_MAX_OPEN_CURSORS'] || 0);
|
|
794
|
+
this.serviceName = authMessage.sessionData['AUTH_SC_SERVICE_NAME'];
|
|
795
|
+
this.instanceName = authMessage.sessionData['AUTH_INSTANCENAME'];
|
|
796
|
+
this.maxIdentifierLength = Number(authMessage.sessionData['AUTH_MAX_IDEN_LENGTH'] || 30);
|
|
797
|
+
const fullVersionNum = Number(authMessage.sessionData['AUTH_VERSION_NO']);
|
|
798
|
+
const versionNum = (fullVersionNum >> 24) & 0xFF;
|
|
799
|
+
this.warning = authMessage.warning;
|
|
800
|
+
if (this._protocol.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_18_1_EXT_1) {
|
|
801
|
+
releaseNum = (fullVersionNum >> 16) & 0xFF;
|
|
802
|
+
updateNum = (fullVersionNum >> 12) & 0x0F;
|
|
803
|
+
portReleaseNum = (fullVersionNum >> 4) & 0xFF;
|
|
804
|
+
portUpdateNum = fullVersionNum & 0x0F;
|
|
805
|
+
} else {
|
|
806
|
+
releaseNum = (fullVersionNum >> 20) & 0x0F;
|
|
807
|
+
updateNum = (fullVersionNum >> 12) & 0xFF;
|
|
808
|
+
portReleaseNum = (fullVersionNum >> 8) & 0x0F;
|
|
809
|
+
portUpdateNum = fullVersionNum & 0xFF;
|
|
810
|
+
}
|
|
811
|
+
this.serverVersionString = versionNum + '.' + releaseNum + '.' + updateNum + '.' + portReleaseNum + '.' + portUpdateNum;
|
|
812
|
+
this.serverVersion = versionNum * 100000000 + releaseNum * 1000000 + updateNum * 10000 + portReleaseNum * 100 + portUpdateNum * 1;
|
|
813
|
+
}
|
|
814
|
+
|
|
735
815
|
/**
|
|
736
816
|
*
|
|
737
817
|
* @param {object} params Configuration of the connection
|
|
@@ -772,6 +852,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
772
852
|
this.remoteAddress = '';
|
|
773
853
|
this.comboKey = null; // used in changePassword API
|
|
774
854
|
this.tpcContext = null;
|
|
855
|
+
this._sessionlessData = null;
|
|
775
856
|
|
|
776
857
|
this.nscon = new nsi();
|
|
777
858
|
finalizationRegistry.register(this, this.nscon);
|
|
@@ -845,6 +926,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
845
926
|
if (!params.externalAuth) { // non-token Authentication
|
|
846
927
|
await this._protocol._processMessage(authMessage); // OAUTH
|
|
847
928
|
}
|
|
929
|
+
this._postConnect(authMessage);
|
|
848
930
|
} catch (err) {
|
|
849
931
|
this.nscon.disconnect();
|
|
850
932
|
throw err;
|
|
@@ -885,7 +967,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
885
967
|
//---------------------------------------------------------------------------
|
|
886
968
|
// Binds the values by user to the statement object
|
|
887
969
|
//---------------------------------------------------------------------------
|
|
888
|
-
async _bind(stmt, variable, pos = 0) {
|
|
970
|
+
async _bind(stmt, variable, pos = 0, internalTempLobs = []) {
|
|
889
971
|
const bindInfoDict = stmt.bindInfoDict;
|
|
890
972
|
const bindInfoList = stmt.bindInfoList;
|
|
891
973
|
|
|
@@ -927,6 +1009,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
927
1009
|
if (val && val.length > 0) {
|
|
928
1010
|
const lobImpl = new ThinLobImpl();
|
|
929
1011
|
await lobImpl.create(this, variable.type);
|
|
1012
|
+
internalTempLobs.push(lobImpl);
|
|
930
1013
|
await lobImpl.write(1, val);
|
|
931
1014
|
variable.values[index] = lobImpl;
|
|
932
1015
|
} else {
|
|
@@ -1021,12 +1104,19 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1021
1104
|
//---------------------------------------------------------------------------
|
|
1022
1105
|
async execute(sql, numIters, binds, options, executeManyFlag) {
|
|
1023
1106
|
const statement = this._prepare(sql, options);
|
|
1107
|
+
const internalTempLobs = [];
|
|
1024
1108
|
try {
|
|
1025
1109
|
return await this._execute(statement, numIters, binds, options,
|
|
1026
|
-
executeManyFlag);
|
|
1110
|
+
executeManyFlag, internalTempLobs);
|
|
1027
1111
|
} catch (err) {
|
|
1028
1112
|
this._returnStatement(statement);
|
|
1029
1113
|
throw err;
|
|
1114
|
+
} finally {
|
|
1115
|
+
// Add to freelist which will be sent in piggyback fashion
|
|
1116
|
+
for (const lob of internalTempLobs) {
|
|
1117
|
+
this._tempLobsToClose.push(lob._locator);
|
|
1118
|
+
this._tempLobsTotalSize += lob._locator.length;
|
|
1119
|
+
}
|
|
1030
1120
|
}
|
|
1031
1121
|
}
|
|
1032
1122
|
|
|
@@ -1233,6 +1323,55 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1233
1323
|
errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state);
|
|
1234
1324
|
}
|
|
1235
1325
|
}
|
|
1326
|
+
//---------------------------------------------------------------------------
|
|
1327
|
+
// Ensure no sessionless transaction was started through server procedure
|
|
1328
|
+
//---------------------------------------------------------------------------
|
|
1329
|
+
_validateSessionlessState() {
|
|
1330
|
+
if (this._sessionlessData?.startedOnServer) {
|
|
1331
|
+
errors.throwErr(errors.ERR_SESSIONLESS_DIFFERING_METHODS);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
//---------------------------------------------------------------------------
|
|
1336
|
+
// Begin/Resume a sessionless transaction with provided transactionId
|
|
1337
|
+
//---------------------------------------------------------------------------
|
|
1338
|
+
async startSessionlessTransaction(transactionId, timeout, flags,
|
|
1339
|
+
deferRoundTrip) {
|
|
1340
|
+
this._validateSessionlessState();
|
|
1341
|
+
if (this._sessionlessData)
|
|
1342
|
+
errors.throwErr(errors.ERR_SESSIONLESS_ALREADY_ACTIVE);
|
|
1343
|
+
const message = new messages.TransactionSwitchMessage(this);
|
|
1344
|
+
message.xid = {
|
|
1345
|
+
globalTransactionId: transactionId,
|
|
1346
|
+
branchQualifier: "",
|
|
1347
|
+
formatId: constants.TNS_TPC_TRANS_SESSIONLESS_FORMAT
|
|
1348
|
+
};
|
|
1349
|
+
message.timeout = timeout;
|
|
1350
|
+
message.operation = constants.TNS_TPC_TXN_START;
|
|
1351
|
+
message.flags = constants.TNS_TPC_TRANS_SESSIONLESS | flags;
|
|
1352
|
+
if (deferRoundTrip) {
|
|
1353
|
+
message.messageType = constants.TNS_MSG_TYPE_PIGGYBACK;
|
|
1354
|
+
this._sessionlessData = {
|
|
1355
|
+
piggyback: message,
|
|
1356
|
+
pending: true
|
|
1357
|
+
};
|
|
1358
|
+
} else {
|
|
1359
|
+
await this._protocol._processMessage(message);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
//---------------------------------------------------------------------------
|
|
1364
|
+
// Suspend the active sessionless transaction
|
|
1365
|
+
//---------------------------------------------------------------------------
|
|
1366
|
+
async suspendSessionlessTransaction() {
|
|
1367
|
+
this._validateSessionlessState();
|
|
1368
|
+
if (!this._sessionlessData)
|
|
1369
|
+
errors.throwErr(errors.ERR_SESSIONLESS_INACTIVE);
|
|
1370
|
+
const message = new messages.TransactionSwitchMessage(this);
|
|
1371
|
+
message.operation = constants.TNS_TPC_TXN_DETACH;
|
|
1372
|
+
message.flags = constants.TNS_TPC_TRANS_SESSIONLESS;
|
|
1373
|
+
await this._protocol._processMessage(message);
|
|
1374
|
+
}
|
|
1236
1375
|
|
|
1237
1376
|
|
|
1238
1377
|
//---------------------------------------------------------------------------
|
|
@@ -1273,6 +1412,14 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1273
1412
|
return this.internalName;
|
|
1274
1413
|
}
|
|
1275
1414
|
|
|
1415
|
+
//---------------------------------------------------------------------------
|
|
1416
|
+
// Returns the Logical Transaction ID (ltxid) associated with the connection.
|
|
1417
|
+
// Used with Oracle Database Transaction Guard feature.
|
|
1418
|
+
//---------------------------------------------------------------------------
|
|
1419
|
+
getLTXID() {
|
|
1420
|
+
return this._ltxid;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1276
1423
|
//---------------------------------------------------------------------------
|
|
1277
1424
|
// Returns the Oracle Database domain name associated with the connection.
|
|
1278
1425
|
//---------------------------------------------------------------------------
|
|
@@ -1343,5 +1490,15 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1343
1490
|
getWarning() {
|
|
1344
1491
|
return this.warning;
|
|
1345
1492
|
}
|
|
1493
|
+
|
|
1494
|
+
//---------------------------------------------------------------------------
|
|
1495
|
+
// getQueue()
|
|
1496
|
+
//
|
|
1497
|
+
// Returns a queue for use with advanced queuing.
|
|
1498
|
+
//---------------------------------------------------------------------------
|
|
1499
|
+
getQueue(name, payloadTypeClass, payloadType) {
|
|
1500
|
+
return new ThinQueueImpl(this, name, payloadTypeClass, payloadType);
|
|
1501
|
+
}
|
|
1346
1502
|
}
|
|
1503
|
+
|
|
1347
1504
|
module.exports = ThinConnectionImpl;
|
package/lib/thin/dbObject.js
CHANGED
|
@@ -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,7 +365,7 @@ 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
371
|
return buf.readOracleNumber();
|
|
@@ -396,14 +396,16 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
396
396
|
return buf.readBool();
|
|
397
397
|
case types.DB_TYPE_OBJECT:
|
|
398
398
|
case types.DB_TYPE_XMLTYPE:
|
|
399
|
-
|
|
399
|
+
obj = new ThinDbObjectImpl(typeClass);
|
|
400
|
+
isCollection = obj._objType.isCollection ||
|
|
401
|
+
this._objType.isCollection;
|
|
402
|
+
isNull = buf.getIsAtomicNull(isCollection);
|
|
400
403
|
if (isNull)
|
|
401
404
|
return null;
|
|
402
|
-
obj = new ThinDbObjectImpl(typeClass);
|
|
403
405
|
if (obj._objType.isXmlType) {
|
|
404
406
|
return readXML(obj._objType._connection, buf.readBytesWithLength());
|
|
405
407
|
}
|
|
406
|
-
if (
|
|
408
|
+
if (isCollection) {
|
|
407
409
|
obj.packedData = Buffer.from(buf.readBytesWithLength());
|
|
408
410
|
} else {
|
|
409
411
|
obj._unpackDataFromBuf(buf);
|
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
|
@@ -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
|
//---------------------------------------------------------------------------
|
|
@@ -254,9 +255,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
254
255
|
// destroy connection when pool close operation is called
|
|
255
256
|
//---------------------------------------------------------------------------
|
|
256
257
|
async _destroy(connection) {
|
|
257
|
-
|
|
258
|
-
connection.
|
|
259
|
-
|
|
258
|
+
try {
|
|
259
|
+
if (connection.nscon.ntAdapter.connected) {
|
|
260
|
+
connection._dropSess = true;
|
|
261
|
+
await connection.close();
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
return;
|
|
260
265
|
}
|
|
261
266
|
}
|
|
262
267
|
|
|
@@ -290,7 +295,12 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
290
295
|
await this._destroy(conn);
|
|
291
296
|
}
|
|
292
297
|
|
|
293
|
-
|
|
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
|
+
});
|
|
294
304
|
}
|
|
295
305
|
|
|
296
306
|
//---------------------------------------------------------------------------
|
|
@@ -356,6 +366,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
356
366
|
return this._poolTimeout;
|
|
357
367
|
}
|
|
358
368
|
|
|
369
|
+
//---------------------------------------------------------------------------
|
|
370
|
+
// returns the pool max lifetime for a session (seconds)
|
|
371
|
+
//---------------------------------------------------------------------------
|
|
372
|
+
getMaxLifetimeSession() {
|
|
373
|
+
return this._maxLifetimeSession;
|
|
374
|
+
}
|
|
375
|
+
|
|
359
376
|
//---------------------------------------------------------------------------
|
|
360
377
|
// returns whether the SODA metadata cache is enabled or not
|
|
361
378
|
//---------------------------------------------------------------------------
|
|
@@ -399,10 +416,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
399
416
|
break;
|
|
400
417
|
}
|
|
401
418
|
|
|
402
|
-
this.
|
|
419
|
+
this._connsToDrop.push(conn);
|
|
403
420
|
this._freeConnectionList.shift();
|
|
404
421
|
}
|
|
405
422
|
|
|
423
|
+
// call cleaner for destroying connections added to _connsToDrop
|
|
424
|
+
if (this._bgCleaner)
|
|
425
|
+
this._bgCleaner();
|
|
406
426
|
this._schedulerJob = null;
|
|
407
427
|
this._setScheduler();
|
|
408
428
|
}
|
|
@@ -438,15 +458,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
438
458
|
|
|
439
459
|
// continue until a close request is received
|
|
440
460
|
while (!this._poolCloseWaiter) {
|
|
441
|
-
// eliminate connections that exceed the poolMax (this should only happen
|
|
442
|
-
// after a reconfiguration has taken place where the maximum number of
|
|
443
|
-
// connections is reduced)
|
|
444
|
-
let numToDestroy = this._poolMax - this.getConnectionsOpen();
|
|
445
|
-
while (numToDestroy > 0 && this._freeConnectionList.length > 0) {
|
|
446
|
-
const connToBeRemoved = this._freeConnectionList.shift();
|
|
447
|
-
this.eventEmitter.emit('_removePoolConnection', connToBeRemoved);
|
|
448
|
-
numToDestroy--;
|
|
449
|
-
}
|
|
450
461
|
|
|
451
462
|
const numToCreate = this._getNumConnsToCreate();
|
|
452
463
|
// connection creation is going on serially and not concurrently
|
|
@@ -459,6 +470,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
459
470
|
await conn.connect(config);
|
|
460
471
|
conn._newSession = true;
|
|
461
472
|
conn._dropSess = false;
|
|
473
|
+
conn._creationTime = Date.now();
|
|
462
474
|
conn._lastTimeUsed = Date.now();
|
|
463
475
|
this._freeConnectionList.push(conn);
|
|
464
476
|
} catch (err) {
|
|
@@ -491,7 +503,8 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
491
503
|
}
|
|
492
504
|
|
|
493
505
|
// if no pending requests, wait for pending requests to appear!
|
|
494
|
-
if (this._pendingRequests.length == 0 || this._bgErr)
|
|
506
|
+
if ((this._pendingRequests.length == 0 || this._bgErr) &&
|
|
507
|
+
this.getConnectionsOpen() >= this._poolMin) {
|
|
495
508
|
await new Promise((resolve) => {
|
|
496
509
|
this.bgWaiter = resolve;
|
|
497
510
|
});
|
|
@@ -503,6 +516,27 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
503
516
|
this._poolCloseWaiter();
|
|
504
517
|
}
|
|
505
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
|
+
|
|
506
540
|
//---------------------------------------------------------------------------
|
|
507
541
|
// acquire()
|
|
508
542
|
//
|
|
@@ -514,9 +548,10 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
514
548
|
while (this._freeConnectionList.length > 0) {
|
|
515
549
|
const conn = this._freeConnectionList.pop();
|
|
516
550
|
|
|
517
|
-
// if connection is unhealthy,
|
|
518
|
-
|
|
519
|
-
|
|
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);
|
|
520
555
|
continue;
|
|
521
556
|
}
|
|
522
557
|
|
|
@@ -595,11 +630,11 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
595
630
|
if (conn.nscon.connected) {
|
|
596
631
|
conn._lastTimeUsed = Date.now();
|
|
597
632
|
conn._newSession = false;
|
|
598
|
-
if ((this.
|
|
599
|
-
|
|
633
|
+
if ((this.getConnectionsOpen() < this._poolMax) &&
|
|
634
|
+
this._shouldRetainInPool(conn)) {
|
|
600
635
|
this._freeConnectionList.push(conn);
|
|
601
636
|
} else {
|
|
602
|
-
this.
|
|
637
|
+
this._invokeBgCleaner(conn);
|
|
603
638
|
}
|
|
604
639
|
}
|
|
605
640
|
|
|
@@ -652,9 +687,51 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
652
687
|
this._poolMin = params.poolMin;
|
|
653
688
|
}
|
|
654
689
|
|
|
655
|
-
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)
|
|
656
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;
|
|
657
733
|
}
|
|
734
|
+
return true;
|
|
658
735
|
}
|
|
659
736
|
}
|
|
660
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
|
//
|
|
@@ -81,6 +81,7 @@ class Capabilities {
|
|
|
81
81
|
constants.TNS_CCAP_O9LOGON_LONG_PASSWORD;
|
|
82
82
|
this.compileCaps[constants.TNS_CCAP_FIELD_VERSION] = this.ttcFieldVersion;
|
|
83
83
|
this.compileCaps[constants.TNS_CCAP_SERVER_DEFINE_CONV] = 1;
|
|
84
|
+
this.compileCaps[constants.TNS_CCAP_DEQUEUE_WITH_SELECTOR] = 1;
|
|
84
85
|
this.compileCaps[constants.TNS_CCAP_TTC1] =
|
|
85
86
|
constants.TNS_CCAP_FAST_BVEC | constants.TNS_CCAP_END_OF_CALL_STATUS |
|
|
86
87
|
constants.TNS_CCAP_IND_RCD;
|
|
@@ -104,20 +105,25 @@ class Capabilities {
|
|
|
104
105
|
constants.TNS_CCAP_LOB2_QUASI | constants.TNS_CCAP_LOB2_2GB_PREFETCH;
|
|
105
106
|
this.compileCaps[constants.TNS_CCAP_TTC3] =
|
|
106
107
|
constants.TNS_CCAP_IMPLICIT_RESULTS | constants.TNS_CCAP_BIG_CHUNK_CLR |
|
|
107
|
-
constants.TNS_CCAP_KEEP_OUT_ORDER;
|
|
108
|
+
constants.TNS_CCAP_KEEP_OUT_ORDER | constants.TNS_CCAP_LTXID;
|
|
109
|
+
this.compileCaps[constants.TNS_CCAP_OCI3] = constants.TNS_CCAP_OCI3_OCSSYNC;
|
|
108
110
|
this.compileCaps[constants.TNS_CCAP_TTC2] = constants.TNS_CCAP_ZLNP;
|
|
109
111
|
this.compileCaps[constants.TNS_CCAP_OCI2] = constants.TNS_CCAP_DRCP;
|
|
110
112
|
this.compileCaps[constants.TNS_CCAP_CLIENT_FN] =
|
|
111
113
|
constants.TNS_CCAP_CLIENT_FN_MAX;
|
|
114
|
+
this.compileCaps[constants.TNS_CCAP_SESS_SIGNATURE_VERSION] =
|
|
115
|
+
constants.TNS_CCAP_FIELD_VERSION_12_2;
|
|
112
116
|
this.compileCaps[constants.TNS_CCAP_TTC4] =
|
|
113
117
|
constants.TNS_CCAP_INBAND_NOTIFICATION;
|
|
114
118
|
if (nscon.endOfRequestSupport) {
|
|
115
119
|
this.compileCaps[constants.TNS_CCAP_TTC4] |= constants.TNS_CCAP_END_OF_REQUEST;
|
|
116
120
|
}
|
|
117
121
|
this.compileCaps[constants.TNS_CCAP_CTB_FEATURE_BACKPORT] =
|
|
118
|
-
constants.TNS_CCAP_CTB_IMPLICIT_POOL
|
|
122
|
+
constants.TNS_CCAP_CTB_IMPLICIT_POOL |
|
|
123
|
+
constants.TNS_CCAP_CTB_OAUTH_MSG_ON_ERR;
|
|
119
124
|
this.compileCaps[constants.TNS_CCAP_TTC5] =
|
|
120
|
-
constants.TNS_CCAP_VECTOR_SUPPORT
|
|
125
|
+
constants.TNS_CCAP_VECTOR_SUPPORT |
|
|
126
|
+
constants.TNS_CCAP_TTC5_SESSIONLESS_TXNS;
|
|
121
127
|
this.compileCaps[constants.TNS_CCAP_VECTOR_FEATURES] =
|
|
122
128
|
constants.TNS_CCAP_VECTOR_FEATURE_BINARY | constants.TNS_CCAP_VECTOR_FEATURE_SPARSE;
|
|
123
129
|
}
|