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.
Files changed (70) hide show
  1. package/LICENSE.txt +1 -1
  2. package/NOTICE.txt +1 -1
  3. package/README.md +3 -3
  4. package/build/Release/oracledb-6.4.0-darwin-x64.node +0 -0
  5. package/build/Release/oracledb-6.4.0-darwin-x64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-6.4.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-6.4.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-6.4.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.4.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-6.4.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.4.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-6.4.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/examples/README.md +29 -8
  14. package/examples/dbconfig.js +50 -26
  15. package/examples/example.js +6 -4
  16. package/lib/aqQueue.js +8 -8
  17. package/lib/connection.js +121 -9
  18. package/lib/constants.js +7 -1
  19. package/lib/dbObject.js +72 -1
  20. package/lib/errors.js +45 -8
  21. package/lib/future.js +53 -0
  22. package/lib/impl/connection.js +56 -0
  23. package/lib/{thin/protocol → impl/datahandlers}/buffer.js +51 -39
  24. package/lib/impl/datahandlers/constants.js +105 -0
  25. package/lib/{thin/protocol → impl/datahandlers}/oson.js +19 -1
  26. package/lib/impl/datahandlers/vector.js +156 -0
  27. package/lib/impl/pool.js +14 -3
  28. package/lib/impl/resultset.js +65 -11
  29. package/lib/lob.js +22 -6
  30. package/lib/oracledb.js +47 -8
  31. package/lib/pool.js +20 -1
  32. package/lib/poolStatistics.js +3 -1
  33. package/lib/settings.js +30 -6
  34. package/lib/sodaDocCursor.js +14 -1
  35. package/lib/thin/connection.js +146 -146
  36. package/lib/thin/dbObject.js +49 -3
  37. package/lib/thin/index.js +1 -1
  38. package/lib/thin/lob.js +6 -6
  39. package/lib/thin/pool.js +25 -6
  40. package/lib/thin/protocol/capabilities.js +6 -2
  41. package/lib/thin/protocol/constants.js +50 -65
  42. package/lib/thin/protocol/messages/auth.js +6 -2
  43. package/lib/thin/protocol/messages/base.js +50 -32
  44. package/lib/thin/protocol/messages/dataType.js +10 -6
  45. package/lib/thin/protocol/messages/lobOp.js +7 -8
  46. package/lib/thin/protocol/messages/withData.js +91 -24
  47. package/lib/thin/protocol/packet.js +58 -4
  48. package/lib/thin/protocol/utils.js +1 -1
  49. package/lib/thin/sqlnet/connStrategy.js +8 -4
  50. package/lib/thin/sqlnet/constants.js +138 -138
  51. package/lib/thin/sqlnet/navNodes.js +5 -5
  52. package/lib/thin/sqlnet/networkSession.js +22 -3
  53. package/lib/thin/sqlnet/ntTcp.js +7 -7
  54. package/lib/thin/statement.js +8 -8
  55. package/lib/thin/statementCache.js +167 -0
  56. package/lib/thin/util.js +15 -4
  57. package/lib/transformer.js +13 -4
  58. package/lib/types.js +17 -2
  59. package/lib/util.js +37 -0
  60. package/lib/version.js +2 -2
  61. package/package.json +1 -1
  62. package/build/Release/oracledb-6.2.0-darwin-x64.node +0 -0
  63. package/build/Release/oracledb-6.2.0-darwin-x64.node-buildinfo.txt +0 -1
  64. package/build/Release/oracledb-6.2.0-js-buildinfo.txt +0 -1
  65. package/build/Release/oracledb-6.2.0-linux-arm64.node +0 -0
  66. package/build/Release/oracledb-6.2.0-linux-arm64.node-buildinfo.txt +0 -1
  67. package/build/Release/oracledb-6.2.0-linux-x64.node +0 -0
  68. package/build/Release/oracledb-6.2.0-linux-x64.node-buildinfo.txt +0 -1
  69. package/build/Release/oracledb-6.2.0-win32-x64.node +0 -0
  70. package/build/Release/oracledb-6.2.0-win32-x64.node-buildinfo.txt +0 -1
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
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('./protocol/buffer.js');
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
- // _determineElementObjType()
96
+ // _getElementTypeObj()
98
97
  //
99
- // Determine the element type's object type. This is needed when processing
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 _determineElementObjType(info) {
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
- // _parseElementType()
257
+ // _parseTDSAttr()
256
258
  //
257
- // Parses the element type from the TDS buffer.
259
+ // Returns the DB type and fills metadata from the TDS buffer.
258
260
  //---------------------------------------------------------------------------
259
- async _parseElementType(buf, info) {
260
- let oraTypeNum, csfrm;
261
- const attrType = buf.readUInt8();
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
- info.elementType = types.DB_TYPE_NUMBER;
266
- break;
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
- info.maxSize = buf.readUInt16BE();
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
- info.elementType = types.getTypeByOraTypeNum(oraTypeNum, csfrm);
274
- break;
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
- info.elementType = types.DB_TYPE_RAW;
277
- break;
293
+ metaData.maxSize = buf.readUInt16BE(); // maximum length
294
+ return types.DB_TYPE_RAW;
278
295
  case constants.TNS_OBJ_TDS_TYPE_BINARY_FLOAT:
279
- info.elementType = types.DB_TYPE_BINARY_FLOAT;
280
- break;
296
+ return types.DB_TYPE_BINARY_FLOAT;
281
297
  case constants.TNS_OBJ_TDS_TYPE_BINARY_DOUBLE:
282
- info.elementType = types.DB_TYPE_BINARY_DOUBLE;
283
- break;
298
+ return types.DB_TYPE_BINARY_DOUBLE;
284
299
  case constants.TNS_OBJ_TDS_TYPE_DATE:
285
- info.elementType = types.DB_TYPE_DATE;
286
- break;
300
+ return types.DB_TYPE_DATE;
287
301
  case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP:
288
- info.elementType = types.DB_TYPE_TIMESTAMP;
289
- break;
302
+ buf.skipBytes(1); // precision
303
+ return types.DB_TYPE_TIMESTAMP;
290
304
  case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP_LTZ:
291
- info.elementType = types.DB_TYPE_TIMESTAMP_LTZ;
292
- break;
305
+ buf.skipBytes(1); // precision
306
+ return types.DB_TYPE_TIMESTAMP_LTZ;
293
307
  case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP_TZ:
294
- info.elementType = types.DB_TYPE_TIMESTAMP_TZ;
295
- break;
308
+ buf.skipBytes(1); // precision
309
+ return types.DB_TYPE_TIMESTAMP_TZ;
296
310
  case constants.TNS_OBJ_TDS_TYPE_BOOLEAN:
297
- info.elementType = types.DB_TYPE_BOOLEAN;
298
- break;
311
+ return types.DB_TYPE_BOOLEAN;
299
312
  case constants.TNS_OBJ_TDS_TYPE_CLOB:
300
- this._determineElementTypeCharsetForm(info);
301
- break;
313
+ return types.DB_TYPE_CLOB;
302
314
  case constants.TNS_OBJ_TDS_TYPE_BLOB:
303
- info.elementType = types.DB_TYPE_BLOB;
304
- break;
315
+ return types.DB_TYPE_BLOB;
305
316
  case constants.TNS_OBJ_TDS_TYPE_OBJ:
306
- info.elementType = types.DB_TYPE_OBJECT;
307
- await this._determineElementObjType(info);
308
- break;
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 for the type. This is only needed for collection types, so
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
- // if type of first attribute is not a collection, nothing further needs
344
- // to be done
345
- const attrType = buf.readUInt8();
346
- info.isCollection = (attrType === constants.TNS_OBJ_TDS_TYPE_COLL);
347
- if (!info.isCollection)
348
- return;
349
-
350
- // continue parsing TDS to determine element type
351
- const elementPos = buf.readUInt32BE();
352
- info.maxNumElements = buf.readUInt32BE();
353
- info.collectionType = buf.readUInt8();
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
- await this._parseElementType(buf, info);
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
- // Sets that a statement is no longer in use
748
+ // Return the statement to the statement cache, if applicable
720
749
  //---------------------------------------------------------------------------
721
750
  _returnStatement(statement) {
722
- if (statement.bindInfoList) {
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
- let statement = this.statementCache.get(sql);
946
- if (!statement) {
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
- statement.inUse = true;
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.statementCacheSize;
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;
@@ -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('./protocol/buffer.js');
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
- module.exports = ThinDbObjectImpl;
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, 2023, Oracle and/or its affiliates.
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 (this._length < 0) {
94
- errors.throwErr(errors.ERR_INVALID_LOB);
92
+ async getData(offset = 1, len = this._length) {
93
+ if (!len) {
94
+ len = this._length;
95
95
  }
96
- return await this.read(1, this._length);
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.ERR_LOB_CLOSED);
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, 2023, Oracle and/or its affiliates.
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[this._freeConnectionList.length - 1];
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.pop();
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
- this.eventEmitter.emit('_removePoolConnection', conn);
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();