oracledb 6.2.0 → 6.4.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 +3 -3
- package/build/Release/oracledb-6.4.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.4.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.4.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.4.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.4.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/README.md +29 -8
- package/examples/dbconfig.js +50 -26
- package/examples/example.js +6 -4
- package/lib/aqQueue.js +8 -8
- package/lib/connection.js +121 -9
- package/lib/constants.js +7 -1
- package/lib/dbObject.js +72 -1
- package/lib/errors.js +45 -8
- package/lib/future.js +53 -0
- package/lib/impl/connection.js +56 -0
- package/lib/{thin/protocol → impl/datahandlers}/buffer.js +51 -39
- package/lib/impl/datahandlers/constants.js +105 -0
- package/lib/{thin/protocol → impl/datahandlers}/oson.js +19 -1
- package/lib/impl/datahandlers/vector.js +156 -0
- package/lib/impl/pool.js +14 -3
- package/lib/impl/resultset.js +65 -11
- package/lib/lob.js +22 -6
- package/lib/oracledb.js +47 -8
- package/lib/pool.js +20 -1
- package/lib/poolStatistics.js +3 -1
- package/lib/settings.js +30 -6
- package/lib/sodaDocCursor.js +14 -1
- package/lib/thin/connection.js +146 -146
- package/lib/thin/dbObject.js +49 -3
- package/lib/thin/index.js +1 -1
- package/lib/thin/lob.js +6 -6
- package/lib/thin/pool.js +25 -6
- package/lib/thin/protocol/capabilities.js +6 -2
- package/lib/thin/protocol/constants.js +50 -65
- package/lib/thin/protocol/messages/auth.js +6 -2
- package/lib/thin/protocol/messages/base.js +50 -32
- package/lib/thin/protocol/messages/dataType.js +10 -6
- package/lib/thin/protocol/messages/lobOp.js +7 -8
- package/lib/thin/protocol/messages/withData.js +91 -24
- package/lib/thin/protocol/packet.js +58 -4
- package/lib/thin/protocol/utils.js +1 -1
- package/lib/thin/sqlnet/connStrategy.js +8 -4
- package/lib/thin/sqlnet/constants.js +138 -138
- package/lib/thin/sqlnet/navNodes.js +5 -5
- package/lib/thin/sqlnet/networkSession.js +22 -3
- package/lib/thin/sqlnet/ntTcp.js +7 -7
- package/lib/thin/statement.js +8 -8
- package/lib/thin/statementCache.js +167 -0
- package/lib/thin/util.js +15 -4
- package/lib/transformer.js +13 -4
- package/lib/types.js +17 -2
- package/lib/util.js +37 -0
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/build/Release/oracledb-6.2.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.2.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.2.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.2.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.2.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.2.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.2.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.2.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.2.0-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, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -31,8 +31,8 @@ const ConnectionImpl = require('../impl/connection.js');
|
|
|
31
31
|
const ThinResultSetImpl = require('./resultSet.js');
|
|
32
32
|
const ThinLobImpl = require("./lob.js");
|
|
33
33
|
const Protocol = require("./protocol/protocol.js");
|
|
34
|
-
const { BaseBuffer } = require('
|
|
35
|
-
const {NetworkSession:nsi} = require("./sqlnet/networkSession.js");
|
|
34
|
+
const { BaseBuffer } = require('../impl/datahandlers/buffer.js');
|
|
35
|
+
const {NetworkSession: nsi} = require("./sqlnet/networkSession.js");
|
|
36
36
|
const { Statement } = require("./statement");
|
|
37
37
|
const thinUtil = require('./util');
|
|
38
38
|
const sqlNetConstants = require('./sqlnet/constants.js');
|
|
@@ -41,6 +41,7 @@ const process = require('process');
|
|
|
41
41
|
const types = require('../types.js');
|
|
42
42
|
const errors = require("../errors.js");
|
|
43
43
|
const messages = require('./protocol/messages');
|
|
44
|
+
const StatementCache = require('./statementCache.js');
|
|
44
45
|
|
|
45
46
|
const finalizationRegistry = new global.FinalizationRegistry((heldValue) => {
|
|
46
47
|
heldValue.disconnect();
|
|
@@ -63,12 +64,10 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
63
64
|
if (this._protocol.txnInProgress) {
|
|
64
65
|
await this.rollback();
|
|
65
66
|
}
|
|
66
|
-
this._protocol.callTimeout = 0; // not applicable for close
|
|
67
67
|
if (this._drcpEnabled) {
|
|
68
68
|
await this._sessRelease();
|
|
69
69
|
this._drcpEstablishSession = true;
|
|
70
70
|
}
|
|
71
|
-
|
|
72
71
|
if (this._pool && !this._dropSess) {
|
|
73
72
|
await this._pool.release(this);
|
|
74
73
|
} else {
|
|
@@ -94,13 +93,13 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
//---------------------------------------------------------------------------
|
|
97
|
-
//
|
|
96
|
+
// _getElementTypeObj()
|
|
98
97
|
//
|
|
99
|
-
//
|
|
98
|
+
// Get the element type's object type. This is needed when processing
|
|
100
99
|
// collections with an object as the element type since this information is
|
|
101
100
|
// not available in the TDS.
|
|
102
101
|
//---------------------------------------------------------------------------
|
|
103
|
-
async
|
|
102
|
+
async _getElementTypeObj(info) {
|
|
104
103
|
const binds = [
|
|
105
104
|
{
|
|
106
105
|
name: "owner",
|
|
@@ -206,6 +205,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
206
205
|
|
|
207
206
|
// process results
|
|
208
207
|
const result = {};
|
|
208
|
+
if (message.warning) {
|
|
209
|
+
result.warning = message.warning;
|
|
210
|
+
}
|
|
209
211
|
if (statement.numQueryVars > 0) {
|
|
210
212
|
result.resultSet = message.resultSet;
|
|
211
213
|
} else {
|
|
@@ -252,60 +254,77 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
252
254
|
}
|
|
253
255
|
|
|
254
256
|
//---------------------------------------------------------------------------
|
|
255
|
-
//
|
|
257
|
+
// _parseTDSAttr()
|
|
256
258
|
//
|
|
257
|
-
//
|
|
259
|
+
// Returns the DB type and fills metadata from the TDS buffer.
|
|
258
260
|
//---------------------------------------------------------------------------
|
|
259
|
-
|
|
260
|
-
let oraTypeNum, csfrm;
|
|
261
|
-
|
|
261
|
+
_parseTDSAttr(buf, metaData) {
|
|
262
|
+
let oraTypeNum, csfrm, attrType;
|
|
263
|
+
|
|
264
|
+
// skip until a type code that is of interest
|
|
265
|
+
for (;;) {
|
|
266
|
+
attrType = buf.readUInt8();
|
|
267
|
+
if (attrType === constants.TNS_OBJ_TDS_TYPE_EMBED_ADT_INFO) {
|
|
268
|
+
buf.skipBytes(1); // flags
|
|
269
|
+
} else if (attrType !== constants.TNS_OBJ_TDS_TYPE_SUBTYPE_MARKER) {
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// process the type code.
|
|
262
275
|
switch (attrType) {
|
|
263
276
|
case constants.TNS_OBJ_TDS_TYPE_NUMBER:
|
|
277
|
+
metaData.precision = buf.readInt8();
|
|
278
|
+
metaData.scale = buf.readInt8();
|
|
279
|
+
return types.DB_TYPE_NUMBER;
|
|
264
280
|
case constants.TNS_OBJ_TDS_TYPE_FLOAT:
|
|
265
|
-
|
|
266
|
-
|
|
281
|
+
metaData.precision = buf.readInt8();
|
|
282
|
+
return types.DB_TYPE_NUMBER;
|
|
267
283
|
case constants.TNS_OBJ_TDS_TYPE_VARCHAR:
|
|
268
284
|
case constants.TNS_OBJ_TDS_TYPE_CHAR:
|
|
269
|
-
|
|
285
|
+
metaData.maxSize = buf.readUInt16BE(); // maximum length
|
|
270
286
|
oraTypeNum = (attrType === constants.TNS_OBJ_TDS_TYPE_VARCHAR) ?
|
|
271
287
|
constants.TNS_DATA_TYPE_VARCHAR : constants.TNS_DATA_TYPE_CHAR;
|
|
272
288
|
csfrm = buf.readUInt8();
|
|
273
|
-
|
|
274
|
-
|
|
289
|
+
csfrm = csfrm & 0x7f;
|
|
290
|
+
buf.skipBytes(2); // character set
|
|
291
|
+
return types.getTypeByOraTypeNum(oraTypeNum, csfrm);
|
|
275
292
|
case constants.TNS_OBJ_TDS_TYPE_RAW:
|
|
276
|
-
|
|
277
|
-
|
|
293
|
+
metaData.maxSize = buf.readUInt16BE(); // maximum length
|
|
294
|
+
return types.DB_TYPE_RAW;
|
|
278
295
|
case constants.TNS_OBJ_TDS_TYPE_BINARY_FLOAT:
|
|
279
|
-
|
|
280
|
-
break;
|
|
296
|
+
return types.DB_TYPE_BINARY_FLOAT;
|
|
281
297
|
case constants.TNS_OBJ_TDS_TYPE_BINARY_DOUBLE:
|
|
282
|
-
|
|
283
|
-
break;
|
|
298
|
+
return types.DB_TYPE_BINARY_DOUBLE;
|
|
284
299
|
case constants.TNS_OBJ_TDS_TYPE_DATE:
|
|
285
|
-
|
|
286
|
-
break;
|
|
300
|
+
return types.DB_TYPE_DATE;
|
|
287
301
|
case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP:
|
|
288
|
-
|
|
289
|
-
|
|
302
|
+
buf.skipBytes(1); // precision
|
|
303
|
+
return types.DB_TYPE_TIMESTAMP;
|
|
290
304
|
case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP_LTZ:
|
|
291
|
-
|
|
292
|
-
|
|
305
|
+
buf.skipBytes(1); // precision
|
|
306
|
+
return types.DB_TYPE_TIMESTAMP_LTZ;
|
|
293
307
|
case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP_TZ:
|
|
294
|
-
|
|
295
|
-
|
|
308
|
+
buf.skipBytes(1); // precision
|
|
309
|
+
return types.DB_TYPE_TIMESTAMP_TZ;
|
|
296
310
|
case constants.TNS_OBJ_TDS_TYPE_BOOLEAN:
|
|
297
|
-
|
|
298
|
-
break;
|
|
311
|
+
return types.DB_TYPE_BOOLEAN;
|
|
299
312
|
case constants.TNS_OBJ_TDS_TYPE_CLOB:
|
|
300
|
-
|
|
301
|
-
break;
|
|
313
|
+
return types.DB_TYPE_CLOB;
|
|
302
314
|
case constants.TNS_OBJ_TDS_TYPE_BLOB:
|
|
303
|
-
|
|
304
|
-
break;
|
|
315
|
+
return types.DB_TYPE_BLOB;
|
|
305
316
|
case constants.TNS_OBJ_TDS_TYPE_OBJ:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
buf.skipBytes(5);
|
|
318
|
+
return types.DB_TYPE_OBJECT;
|
|
319
|
+
case constants.TNS_OBJ_TDS_TYPE_START_EMBED_ADT:
|
|
320
|
+
// loop until end type, TNS_OBJ_TDS_TYPE_END_EMBED_ADT
|
|
321
|
+
// is received.
|
|
322
|
+
while (this._parseTDSAttr(buf, {}) !== 0) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
return types.DB_TYPE_OBJECT;
|
|
326
|
+
case constants.TNS_OBJ_TDS_TYPE_END_EMBED_ADT:
|
|
327
|
+
return 0;
|
|
309
328
|
default:
|
|
310
329
|
errors.throwErr(errors.ERR_TDS_TYPE_NOT_SUPPORTED, attrType);
|
|
311
330
|
}
|
|
@@ -314,12 +333,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
314
333
|
//---------------------------------------------------------------------------
|
|
315
334
|
// _parseTDS()
|
|
316
335
|
//
|
|
317
|
-
// Parses the TDS
|
|
318
|
-
// if the TDS is determined to be for an object type, the remaining
|
|
319
|
-
// information is ignored.
|
|
336
|
+
// Parses the TDS (type descriptor segment) for the type.
|
|
320
337
|
//---------------------------------------------------------------------------
|
|
321
338
|
async _parseTDS(tds, info) {
|
|
322
|
-
|
|
323
339
|
// parse initial TDS bytes
|
|
324
340
|
const buf = new TDSBuffer(tds);
|
|
325
341
|
buf.skipBytes(4); // end offset
|
|
@@ -329,10 +345,6 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
329
345
|
// if the number of attributes exceeds 1, the type cannot refer to a
|
|
330
346
|
// collection, so nothing further needs to be done
|
|
331
347
|
const numAttrs = buf.readUInt16BE();
|
|
332
|
-
if (numAttrs > 1) {
|
|
333
|
-
info.isCollection = false;
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
348
|
|
|
337
349
|
// continue parsing TDS bytes to discover if type refers to a collection
|
|
338
350
|
buf.skipBytes(1); // TDS attributes?
|
|
@@ -340,23 +352,41 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
340
352
|
buf.skipBytes(2); // ADT number (always zero)
|
|
341
353
|
buf.skipBytes(4); // offset to index table
|
|
342
354
|
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (info.collectionType === constants.TNS_OBJ_PLSQL_INDEX_TABLE) {
|
|
355
|
-
info.collectionFlags = constants.TNS_OBJ_HAS_INDEXES;
|
|
355
|
+
// check to see if type refers to a collection (only one attribute is
|
|
356
|
+
// present in that case).
|
|
357
|
+
info.isCollection = false;
|
|
358
|
+
if (numAttrs === 1) {
|
|
359
|
+
const pos = buf.pos;
|
|
360
|
+
const attrType = buf.readUInt8();
|
|
361
|
+
if (attrType === constants.TNS_OBJ_TDS_TYPE_COLL) {
|
|
362
|
+
info.isCollection = true;
|
|
363
|
+
} else {
|
|
364
|
+
buf.pos = pos;
|
|
365
|
+
}
|
|
356
366
|
}
|
|
357
|
-
buf.pos = elementPos;
|
|
358
367
|
|
|
359
|
-
|
|
368
|
+
// Handle collections
|
|
369
|
+
if (info.isCollection) {
|
|
370
|
+
// continue parsing TDS to determine element type
|
|
371
|
+
const elementPos = buf.readUInt32BE();
|
|
372
|
+
info.maxNumElements = buf.readUInt32BE();
|
|
373
|
+
info.collectionType = buf.readUInt8();
|
|
374
|
+
if (info.collectionType === constants.TNS_OBJ_PLSQL_INDEX_TABLE) {
|
|
375
|
+
info.collectionFlags = constants.TNS_OBJ_HAS_INDEXES;
|
|
376
|
+
}
|
|
377
|
+
buf.pos = elementPos;
|
|
378
|
+
info.elementTypeInfo = {};
|
|
379
|
+
info.elementType = this._parseTDSAttr(buf, info.elementTypeInfo);
|
|
380
|
+
if (info.elementType === types.DB_TYPE_OBJECT) {
|
|
381
|
+
await this._getElementTypeObj(info);
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
if (info.attributes) { // skip for XML type as it has no attributes.
|
|
385
|
+
for (const attr of info.attributes) {
|
|
386
|
+
this._parseTDSAttr(buf, attr);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
360
390
|
}
|
|
361
391
|
|
|
362
392
|
//---------------------------------------------------------------------------
|
|
@@ -482,9 +512,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
482
512
|
|
|
483
513
|
// process TDS and attributes cursor
|
|
484
514
|
info.version = result.outBinds.version;
|
|
485
|
-
await this._parseTDS(result.outBinds.tds, info);
|
|
486
515
|
const attrRows = await result.outBinds.attrs_rc.getRows(1000, {});
|
|
487
516
|
if (attrRows.length > 0) {
|
|
517
|
+
// Its an object not a collection.
|
|
488
518
|
info.attributes = [];
|
|
489
519
|
for (const row of attrRows) {
|
|
490
520
|
const attr = { name: row[1] };
|
|
@@ -500,8 +530,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
500
530
|
info.attributes.push(attr);
|
|
501
531
|
}
|
|
502
532
|
}
|
|
503
|
-
info.partial = false;
|
|
504
533
|
|
|
534
|
+
await this._parseTDS(result.outBinds.tds, info);
|
|
535
|
+
info.partial = false;
|
|
505
536
|
return info;
|
|
506
537
|
|
|
507
538
|
}
|
|
@@ -596,11 +627,8 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
596
627
|
this.statementCache = null;
|
|
597
628
|
this.currentSchema = "";
|
|
598
629
|
this.invokeSessionCallback = true;
|
|
599
|
-
this.statementCache = new Map();
|
|
600
630
|
this.statementCacheSize = params.stmtCacheSize;
|
|
601
|
-
this._numCursorsToClose = 0;
|
|
602
631
|
this._currentSchemaModified = false;
|
|
603
|
-
this._cursorsToClose = new Set();
|
|
604
632
|
this._tempLobsToClose = [];
|
|
605
633
|
this._tempLobsTotalSize = 0;
|
|
606
634
|
this._drcpEstablishSession = false;
|
|
@@ -704,6 +732,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
704
732
|
throw err;
|
|
705
733
|
}
|
|
706
734
|
|
|
735
|
+
this.statementCache = new StatementCache(this.statementCacheSize);
|
|
707
736
|
// maintain a list of partially populated database object types
|
|
708
737
|
this._partialDbObjectTypes = [];
|
|
709
738
|
|
|
@@ -716,51 +745,10 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
716
745
|
}
|
|
717
746
|
|
|
718
747
|
//---------------------------------------------------------------------------
|
|
719
|
-
//
|
|
748
|
+
// Return the statement to the statement cache, if applicable
|
|
720
749
|
//---------------------------------------------------------------------------
|
|
721
750
|
_returnStatement(statement) {
|
|
722
|
-
|
|
723
|
-
statement.bindInfoList.forEach(bindInfo => {
|
|
724
|
-
bindInfo.bindVar = null;
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
if (statement.queryVars) {
|
|
728
|
-
statement.queryVars.forEach(queryVar => {
|
|
729
|
-
queryVar.values.fill(null);
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
if (statement.returnToCache) {
|
|
733
|
-
statement.inUse = false;
|
|
734
|
-
} else if (statement.cursorId !== 0) {
|
|
735
|
-
this._addCursorToClose(statement.cursorId);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
//---------------------------------------------------------------------------
|
|
740
|
-
// Adds the cursors that needs to be closed to the _cursorsToClose set
|
|
741
|
-
//---------------------------------------------------------------------------
|
|
742
|
-
_addCursorToClose(cursorId) {
|
|
743
|
-
if (this._cursorsToClose.has(cursorId)) {
|
|
744
|
-
const reason = `attempt to close cursor ${cursorId} twice`;
|
|
745
|
-
errors.throwErr(errors.ERR_INTERNAL, reason);
|
|
746
|
-
}
|
|
747
|
-
this._cursorsToClose.add(cursorId);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
//---------------------------------------------------------------------------
|
|
751
|
-
// Adjusts the statement cache to remove least recently used statements
|
|
752
|
-
//---------------------------------------------------------------------------
|
|
753
|
-
_adjustStatementCache() {
|
|
754
|
-
while (this.statementCache.size > this.statementCacheSize) {
|
|
755
|
-
const sql = this.statementCache.keys().next().value;
|
|
756
|
-
const stmt = this.statementCache.get(sql);
|
|
757
|
-
this.statementCache.delete(sql);
|
|
758
|
-
if (stmt.inUse) {
|
|
759
|
-
stmt.returnToCache = false;
|
|
760
|
-
} else if (stmt.cursorId !== 0) {
|
|
761
|
-
this._addCursorToClose(stmt.cursorId);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
751
|
+
this.statementCache.returnStatement(statement);
|
|
764
752
|
}
|
|
765
753
|
|
|
766
754
|
//---------------------------------------------------------------------------
|
|
@@ -870,14 +858,6 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
870
858
|
return resultSet;
|
|
871
859
|
}
|
|
872
860
|
|
|
873
|
-
//---------------------------------------------------------------------------
|
|
874
|
-
// Clears the statement cache for the connection
|
|
875
|
-
//---------------------------------------------------------------------------
|
|
876
|
-
resetStatementCache() {
|
|
877
|
-
this.statementCache.clear();
|
|
878
|
-
this._cursorsToClose.clear();
|
|
879
|
-
}
|
|
880
|
-
|
|
881
861
|
//---------------------------------------------------------------------------
|
|
882
862
|
// getDbObjectClass()
|
|
883
863
|
//
|
|
@@ -942,31 +922,10 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
942
922
|
// new session is going to be used.
|
|
943
923
|
//---------------------------------------------------------------------------
|
|
944
924
|
_getStatement(sql, cacheStatement = false) {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
statement = new Statement();
|
|
948
|
-
statement._prepare(sql);
|
|
949
|
-
if (cacheStatement && !this._drcpEstablishSession && !statement.isDdl &&
|
|
950
|
-
this.statementCacheSize > 0) {
|
|
951
|
-
statement.returnToCache = true;
|
|
952
|
-
this.statementCache.set(sql, statement);
|
|
953
|
-
this._adjustStatementCache();
|
|
954
|
-
}
|
|
955
|
-
} else if (statement.inUse || !cacheStatement ||
|
|
956
|
-
this._drcpEstablishSession) {
|
|
957
|
-
if (!cacheStatement) {
|
|
958
|
-
this.statementCache.delete(sql);
|
|
959
|
-
statement.returnToCache = false;
|
|
960
|
-
}
|
|
961
|
-
if (statement.inUse || this._drcpEstablishSession) {
|
|
962
|
-
statement = statement._copy();
|
|
963
|
-
}
|
|
964
|
-
} else {
|
|
965
|
-
this.statementCache.delete(sql);
|
|
966
|
-
this.statementCache.set(sql, statement);
|
|
925
|
+
if (this._drcpEstablishSession) {
|
|
926
|
+
cacheStatement = false;
|
|
967
927
|
}
|
|
968
|
-
|
|
969
|
-
return statement;
|
|
928
|
+
return this.statementCache.getStatement(sql, cacheStatement);
|
|
970
929
|
}
|
|
971
930
|
|
|
972
931
|
//---------------------------------------------------------------------------
|
|
@@ -1061,7 +1020,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1061
1020
|
// the connection object
|
|
1062
1021
|
//---------------------------------------------------------------------------
|
|
1063
1022
|
getStmtCacheSize() {
|
|
1064
|
-
return this.
|
|
1023
|
+
return this.statementCache._maxSize;
|
|
1065
1024
|
}
|
|
1066
1025
|
|
|
1067
1026
|
setCallTimeout(timeout) {
|
|
@@ -1085,6 +1044,47 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1085
1044
|
getInstanceName() {
|
|
1086
1045
|
return this.instanceName;
|
|
1087
1046
|
}
|
|
1088
|
-
}
|
|
1089
1047
|
|
|
1048
|
+
//---------------------------------------------------------------------------
|
|
1049
|
+
// Returns the Oracle Database domain name associated with the connection.
|
|
1050
|
+
//---------------------------------------------------------------------------
|
|
1051
|
+
getDbDomain() {
|
|
1052
|
+
return this.dbDomain;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
//---------------------------------------------------------------------------
|
|
1056
|
+
// Returns the Oracle Database name associated with the connection.
|
|
1057
|
+
//---------------------------------------------------------------------------
|
|
1058
|
+
getDbName() {
|
|
1059
|
+
return this.dbName;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
//---------------------------------------------------------------------------
|
|
1063
|
+
// Returns maximum number of cursors that can be opened in one session.
|
|
1064
|
+
//---------------------------------------------------------------------------
|
|
1065
|
+
getMaxOpenCursors() {
|
|
1066
|
+
return this.maxOpenCursors;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
//---------------------------------------------------------------------------
|
|
1070
|
+
// Returns the Oracle Database service name associated with the connection.
|
|
1071
|
+
//---------------------------------------------------------------------------
|
|
1072
|
+
getServiceName() {
|
|
1073
|
+
return this.serviceName;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
//---------------------------------------------------------------------------
|
|
1077
|
+
// Returns boolean based on this._protocol.txnInProgress value.
|
|
1078
|
+
//---------------------------------------------------------------------------
|
|
1079
|
+
getTransactionInProgress() {
|
|
1080
|
+
return this._protocol.txnInProgress === constants.TNS_TXN_IN_PROGRESS;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
//---------------------------------------------------------------------------
|
|
1084
|
+
// Returns the warning object.
|
|
1085
|
+
//---------------------------------------------------------------------------
|
|
1086
|
+
getWarning() {
|
|
1087
|
+
return this.warning;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
1090
|
module.exports = ThinConnectionImpl;
|
package/lib/thin/dbObject.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2023, Oracle and/or its affiliates.
|
|
1
|
+
// Copyright (c) 2023, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -31,7 +31,8 @@ const constants = require('./protocol/constants.js');
|
|
|
31
31
|
const errors = require('../errors.js');
|
|
32
32
|
const types = require('../types.js');
|
|
33
33
|
const DbObjectImpl = require('../impl/dbObject.js');
|
|
34
|
-
const { GrowableBuffer } = require('
|
|
34
|
+
const { GrowableBuffer } = require('../impl/datahandlers/buffer.js');
|
|
35
|
+
const ThinLobImpl = require('./lob.js');
|
|
35
36
|
|
|
36
37
|
class DbObjectPickleBuffer extends GrowableBuffer {
|
|
37
38
|
|
|
@@ -125,6 +126,16 @@ class DbObjectPickleBuffer extends GrowableBuffer {
|
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
//---------------------------------------------------------------------------
|
|
130
|
+
// _writeRawBytesAndLength()
|
|
131
|
+
//
|
|
132
|
+
// Writes the length in the format required before
|
|
133
|
+
// writing the bytes.
|
|
134
|
+
//---------------------------------------------------------------------------
|
|
135
|
+
_writeRawBytesAndLength(value, numBytes) {
|
|
136
|
+
this.writeLength(numBytes);
|
|
137
|
+
this.writeBytes(value);
|
|
138
|
+
}
|
|
128
139
|
}
|
|
129
140
|
|
|
130
141
|
class ThinDbObjectImpl extends DbObjectImpl {
|
|
@@ -269,9 +280,11 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
269
280
|
buf.writeBytesWithLength(value);
|
|
270
281
|
break;
|
|
271
282
|
case types.DB_TYPE_BINARY_DOUBLE:
|
|
283
|
+
buf.writeUInt8(8);
|
|
272
284
|
buf.writeBinaryDouble(value);
|
|
273
285
|
break;
|
|
274
286
|
case types.DB_TYPE_BINARY_FLOAT:
|
|
287
|
+
buf.writeUInt8(4);
|
|
275
288
|
buf.writeBinaryFloat(value);
|
|
276
289
|
break;
|
|
277
290
|
case types.DB_TYPE_DATE:
|
|
@@ -642,4 +655,37 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
642
655
|
|
|
643
656
|
}
|
|
644
657
|
|
|
645
|
-
|
|
658
|
+
//---------------------------------------------------------------------------
|
|
659
|
+
// readXML()
|
|
660
|
+
//
|
|
661
|
+
// Decodes the raw Bytes to XML string or LOB object.
|
|
662
|
+
//
|
|
663
|
+
//---------------------------------------------------------------------------
|
|
664
|
+
function readXML(conn, buf) {
|
|
665
|
+
let colValue;
|
|
666
|
+
|
|
667
|
+
const xmlObj = new DbObjectPickleBuffer(buf);
|
|
668
|
+
const tempobj = {};
|
|
669
|
+
xmlObj.readHeader(tempobj);
|
|
670
|
+
xmlObj.skipBytes(1);
|
|
671
|
+
const xmlflag = xmlObj.readUInt32BE();
|
|
672
|
+
if (xmlflag & constants.TNS_XML_TYPE_FLAG_SKIP_NEXT_4) {
|
|
673
|
+
xmlObj.skipBytes(4);
|
|
674
|
+
}
|
|
675
|
+
const numBytesLeft = xmlObj.numBytesLeft();
|
|
676
|
+
const ptr = xmlObj.readBytes(numBytesLeft);
|
|
677
|
+
if (xmlflag & constants.TNS_XML_TYPE_STRING) {
|
|
678
|
+
colValue = ptr.toString();
|
|
679
|
+
} else if (xmlflag & constants.TNS_XML_TYPE_LOB) {
|
|
680
|
+
const lobImpl = new ThinLobImpl();
|
|
681
|
+
const locator = Buffer.from(ptr);
|
|
682
|
+
lobImpl.init(conn, locator, types.DB_TYPE_CLOB, 0, 0);
|
|
683
|
+
colValue = lobImpl;
|
|
684
|
+
} else {
|
|
685
|
+
// We only support String and Clob type.
|
|
686
|
+
errors.throwErr(errors.ERR_UNEXPECTED_XML_TYPE, xmlflag);
|
|
687
|
+
}
|
|
688
|
+
return colValue;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
module.exports = { ThinDbObjectImpl, readXML };
|
package/lib/thin/index.js
CHANGED
|
@@ -30,7 +30,7 @@ const ThinConnectionImpl = require('./connection.js');
|
|
|
30
30
|
const ThinResultSetImpl = require('./resultSet.js');
|
|
31
31
|
const ThinPoolImpl = require('./pool.js');
|
|
32
32
|
const ThinLobImpl = require('./lob.js');
|
|
33
|
-
const ThinDbObjectImpl = require('./dbObject.js');
|
|
33
|
+
const { ThinDbObjectImpl } = require('./dbObject.js');
|
|
34
34
|
|
|
35
35
|
const impl = require('../impl');
|
|
36
36
|
impl.ConnectionImpl = ThinConnectionImpl;
|
package/lib/thin/lob.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -89,11 +89,11 @@ class ThinLobImpl extends LobImpl {
|
|
|
89
89
|
return this.dbType;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
async getData() {
|
|
93
|
-
if (
|
|
94
|
-
|
|
92
|
+
async getData(offset = 1, len = this._length) {
|
|
93
|
+
if (!len) {
|
|
94
|
+
len = this._length;
|
|
95
95
|
}
|
|
96
|
-
return await this.read(
|
|
96
|
+
return await this.read(offset, len);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
async read(offset, length) {
|
|
@@ -157,7 +157,7 @@ class ThinLobImpl extends LobImpl {
|
|
|
157
157
|
|
|
158
158
|
checkConn() {
|
|
159
159
|
if (!this.conn.nscon.connected)
|
|
160
|
-
errors.throwErr(errors.
|
|
160
|
+
errors.throwErr(errors.ERR_INVALID_CONNECTION);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
close() {
|
package/lib/thin/pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -53,6 +53,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
53
53
|
this._poolIncrement = params.poolIncrement;
|
|
54
54
|
this._poolTimeout = params.poolTimeout;
|
|
55
55
|
this._poolPingInterval = params.poolPingInterval;
|
|
56
|
+
this._poolPingTimeout = params.poolPingTimeout;
|
|
56
57
|
this._stmtCacheSize = params.stmtCacheSize;
|
|
57
58
|
|
|
58
59
|
// The user Config filterd from common layer is cached except
|
|
@@ -102,6 +103,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
102
103
|
this._userConfig.privateKey = null;
|
|
103
104
|
}
|
|
104
105
|
this._accessTokenFn = params.accessTokenFn;
|
|
106
|
+
this._accessTokenConfig = params.accessTokenConfig;
|
|
105
107
|
this._isDRCPEnabled = false;
|
|
106
108
|
this.eventEmitter = new EventEmitter();
|
|
107
109
|
// listener to remove dead or idle connections
|
|
@@ -176,7 +178,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
176
178
|
protocolUtil.getDeobfuscatedValue(this._token, this._obfuscatedToken);
|
|
177
179
|
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
178
180
|
if (typeof this._accessTokenFn === 'function') {
|
|
179
|
-
accessToken = await this._accessTokenFn(true);
|
|
181
|
+
accessToken = await this._accessTokenFn(true, this._accessTokenConfig);
|
|
180
182
|
if (typeof accessToken === 'string') {
|
|
181
183
|
clonedAttrs.token = accessToken;
|
|
182
184
|
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
@@ -199,7 +201,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
199
201
|
const objToken = protocolUtil.setObfuscatedValue(clonedAttrs.token);
|
|
200
202
|
this._token = objToken.value;
|
|
201
203
|
this._obfuscatedToken = objToken.obfuscatedValue;
|
|
202
|
-
|
|
203
204
|
const objKey = protocolUtil.setObfuscatedValue(clonedAttrs.privateKey);
|
|
204
205
|
this._privateKey = objKey.value;
|
|
205
206
|
this._obfuscatedPrivateKey = objKey.obfuscatedValue;
|
|
@@ -318,6 +319,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
318
319
|
return this._poolPingInterval;
|
|
319
320
|
}
|
|
320
321
|
|
|
322
|
+
//---------------------------------------------------------------------------
|
|
323
|
+
// returns the pool ping Timeout (milliseconds)
|
|
324
|
+
//---------------------------------------------------------------------------
|
|
325
|
+
getPoolPingTimeout() {
|
|
326
|
+
return this._poolPingTimeout;
|
|
327
|
+
}
|
|
328
|
+
|
|
321
329
|
//---------------------------------------------------------------------------
|
|
322
330
|
// returns the pool timeout
|
|
323
331
|
//---------------------------------------------------------------------------
|
|
@@ -363,13 +371,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
363
371
|
_scanIdleConnection() {
|
|
364
372
|
while ((this._usedConnectionList.size + this._freeConnectionList.length) >
|
|
365
373
|
this._poolMin && this._freeConnectionList.length > 0) {
|
|
366
|
-
const conn = this._freeConnectionList[
|
|
374
|
+
const conn = this._freeConnectionList[0];
|
|
367
375
|
if (Date.now() - conn._lastTimeUsed < this._poolTimeout * 1000) {
|
|
368
376
|
break;
|
|
369
377
|
}
|
|
370
378
|
|
|
371
379
|
this.eventEmitter.emit('_removePoolConnection', conn);
|
|
372
|
-
this._freeConnectionList.
|
|
380
|
+
this._freeConnectionList.shift();
|
|
373
381
|
}
|
|
374
382
|
|
|
375
383
|
this._schedulerJob = null;
|
|
@@ -495,11 +503,21 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
495
503
|
requiresPing = true;
|
|
496
504
|
}
|
|
497
505
|
if (requiresPing) {
|
|
506
|
+
let pingTimer;
|
|
498
507
|
try {
|
|
508
|
+
if (this._poolPingTimeout) {
|
|
509
|
+
pingTimer = setTimeout(() => {
|
|
510
|
+
// force disconnect causes ping task to unblock
|
|
511
|
+
// and return.
|
|
512
|
+
conn.nscon.forceDisconnect();
|
|
513
|
+
}, this._poolPingTimeout);
|
|
514
|
+
}
|
|
499
515
|
await conn.ping();
|
|
500
516
|
} catch {
|
|
501
|
-
|
|
517
|
+
conn.nscon.forceDisconnect();
|
|
502
518
|
continue;
|
|
519
|
+
} finally {
|
|
520
|
+
clearTimeout(pingTimer);
|
|
503
521
|
}
|
|
504
522
|
}
|
|
505
523
|
|
|
@@ -541,6 +559,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
541
559
|
|
|
542
560
|
// release connection to connection pool
|
|
543
561
|
release(conn) {
|
|
562
|
+
conn.warning = undefined;
|
|
544
563
|
this._usedConnectionList.delete(conn);
|
|
545
564
|
if (conn.nscon.connected) {
|
|
546
565
|
conn._lastTimeUsed = Date.now();
|