oracledb 6.7.2 → 6.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE.txt +1 -1
  2. package/NOTICE.txt +1 -1
  3. package/README.md +39 -3
  4. package/build/Release/oracledb-6.9.0-darwin-arm64.node +0 -0
  5. package/build/Release/oracledb-6.9.0-darwin-arm64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-6.9.0-darwin-x64.node +0 -0
  7. package/build/Release/oracledb-6.9.0-darwin-x64.node-buildinfo.txt +1 -0
  8. package/build/Release/oracledb-6.9.0-js-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.9.0-linux-arm64.node +0 -0
  10. package/build/Release/oracledb-6.9.0-linux-arm64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.9.0-linux-x64.node +0 -0
  12. package/build/Release/oracledb-6.9.0-linux-x64.node-buildinfo.txt +1 -0
  13. package/build/Release/oracledb-6.9.0-win32-x64.node +0 -0
  14. package/build/Release/oracledb-6.9.0-win32-x64.node-buildinfo.txt +1 -0
  15. package/lib/aqMessage.js +10 -1
  16. package/lib/configProviders/file.js +72 -0
  17. package/lib/connection.js +153 -4
  18. package/lib/dbObject.js +51 -10
  19. package/lib/errors.js +144 -36
  20. package/lib/impl/connection.js +24 -1
  21. package/lib/impl/datahandlers/buffer.js +92 -1
  22. package/lib/impl/datahandlers/constants.js +2 -0
  23. package/lib/impl/datahandlers/oson.js +15 -1
  24. package/lib/impl/datahandlers/vector.js +72 -27
  25. package/lib/impl/pool.js +10 -1
  26. package/lib/impl/resultset.js +5 -4
  27. package/lib/lob.js +9 -1
  28. package/lib/oracledb.js +209 -20
  29. package/lib/pool.js +12 -1
  30. package/lib/poolStatistics.js +3 -1
  31. package/lib/settings.js +5 -1
  32. package/lib/thin/connection.js +130 -12
  33. package/lib/thin/dbObject.js +46 -13
  34. package/lib/thin/lob.js +2 -3
  35. package/lib/thin/pool.js +112 -31
  36. package/lib/thin/protocol/capabilities.js +8 -4
  37. package/lib/thin/protocol/constants.js +31 -1
  38. package/lib/thin/protocol/messages/auth.js +42 -6
  39. package/lib/thin/protocol/messages/base.js +98 -9
  40. package/lib/thin/protocol/messages/dataType.js +2 -1
  41. package/lib/thin/protocol/messages/execute.js +46 -4
  42. package/lib/thin/protocol/messages/fastAuth.js +6 -1
  43. package/lib/thin/protocol/messages/lobOp.js +5 -22
  44. package/lib/thin/protocol/messages/logOff.js +0 -1
  45. package/lib/thin/protocol/messages/sessionRelease.js +0 -1
  46. package/lib/thin/protocol/messages/transactionSwitch.js +12 -4
  47. package/lib/thin/protocol/messages/withData.js +10 -1
  48. package/lib/thin/protocol/packet.js +1 -1
  49. package/lib/thin/protocol/protocol.js +2 -1
  50. package/lib/thin/sqlnet/ANO.js +438 -0
  51. package/lib/thin/sqlnet/connStrategy.js +2 -1
  52. package/lib/thin/sqlnet/constants.js +5 -1
  53. package/lib/thin/sqlnet/ezConnectResolver.js +4 -2
  54. package/lib/thin/sqlnet/navNodes.js +22 -3
  55. package/lib/thin/sqlnet/networkSession.js +94 -16
  56. package/lib/thin/sqlnet/ntTcp.js +50 -3
  57. package/lib/thin/sqlnet/packet.js +32 -4
  58. package/lib/thin/sqlnet/sessionAtts.js +24 -2
  59. package/lib/thin/util.js +3 -8
  60. package/lib/transformer.js +13 -2
  61. package/lib/types.js +220 -8
  62. package/lib/util.js +77 -3
  63. package/lib/version.js +2 -2
  64. package/package/install.js +3 -3
  65. package/package/prunebinaries.js +6 -12
  66. package/package.json +2 -2
  67. package/{lib/configProviders/azure.js → plugins/configProviders/azure/index.js} +70 -63
  68. package/plugins/configProviders/azurevault/index.js +84 -0
  69. package/{lib → plugins}/configProviders/base.js +13 -3
  70. package/{lib/configProviders/ociobject.js → plugins/configProviders/ociobject/index.js} +43 -78
  71. package/plugins/configProviders/ocivault/index.js +100 -0
  72. package/plugins/token/extensionAzure/index.js +101 -0
  73. package/plugins/token/extensionOci/index.js +210 -0
  74. package/build/Release/oracledb-6.7.2-darwin-arm64.node +0 -0
  75. package/build/Release/oracledb-6.7.2-darwin-arm64.node-buildinfo.txt +0 -1
  76. package/build/Release/oracledb-6.7.2-darwin-x64.node +0 -0
  77. package/build/Release/oracledb-6.7.2-darwin-x64.node-buildinfo.txt +0 -1
  78. package/build/Release/oracledb-6.7.2-js-buildinfo.txt +0 -1
  79. package/build/Release/oracledb-6.7.2-linux-arm64.node +0 -0
  80. package/build/Release/oracledb-6.7.2-linux-arm64.node-buildinfo.txt +0 -1
  81. package/build/Release/oracledb-6.7.2-linux-x64.node +0 -0
  82. package/build/Release/oracledb-6.7.2-linux-x64.node-buildinfo.txt +0 -1
  83. package/build/Release/oracledb-6.7.2-win32-x64.node +0 -0
  84. package/build/Release/oracledb-6.7.2-win32-x64.node-buildinfo.txt +0 -1
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2024, Oracle and/or its affiliates.
1
+ // Copyright (c) 2024, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -30,6 +30,7 @@ const { BaseBuffer, GrowableBuffer } = require('./buffer.js');
30
30
  const { Buffer } = require('buffer');
31
31
  const constants = require("./constants.js");
32
32
  const errors = require("../../errors.js");
33
+ const types = require("../../types.js");
33
34
 
34
35
  /**
35
36
  * Class used for decoding
@@ -50,68 +51,83 @@ class VectorDecoder extends BaseBuffer {
50
51
  errors.throwErr(errors.ERR_UNEXPECTED_DATA,
51
52
  Buffer.from([magicByte]).toString('hex'));
52
53
  const version = this.readUInt8();
53
- if (version > constants.TNS_VECTOR_VERSION_WITH_BINARY)
54
+ if (version > constants.TNS_VECTOR_VERSION_WITH_SPARSE)
54
55
  errors.throwErr(errors.ERR_VECTOR_VERSION_NOT_SUPPORTED, version);
55
56
  const flags = this.readUInt16BE();
56
57
  const vectorFormat = this.readUInt8();
57
58
  let numElements = this.readUInt32BE();
58
- let elementSize, result;
59
+ let elementSize, value, sparseValue;
60
+
61
+ // For binary vector, NORM will never be present but space for NORM is reserved to keep
62
+ // same header lengh across the different vector formats.
63
+ if (vectorFormat === constants.VECTOR_FORMAT_BINARY || flags & constants.TNS_VECTOR_FLAG_NORM)
64
+ this.skipBytes(8);
65
+
66
+ let sparseFormat;
67
+ if (flags & constants.TNS_VECTOR_FLAG_SPARSE) {
68
+ sparseFormat = true;
69
+ sparseValue = {};
70
+ sparseValue.numDimensions = numElements; // vector dimensions.
71
+ numElements = this.readUInt16BE(); // actual elements.
72
+ sparseValue.indices = new Uint32Array(numElements);
73
+ for (let i = 0; i < numElements; i++) {
74
+ sparseValue.indices[i] = this.readUInt32BE();
75
+ }
76
+ }
77
+
59
78
  if (vectorFormat === constants.VECTOR_FORMAT_FLOAT32) {
60
79
  elementSize = 4;
61
- result = new Float32Array(numElements);
80
+ value = new Float32Array(numElements);
62
81
  } else if (vectorFormat === constants.VECTOR_FORMAT_FLOAT64) {
63
82
  elementSize = 8;
64
- result = new Float64Array(numElements);
83
+ value = new Float64Array(numElements);
65
84
  } else if (vectorFormat === constants.VECTOR_FORMAT_INT8) {
66
85
  elementSize = 1;
67
- result = new Int8Array(numElements);
86
+ value = new Int8Array(numElements);
68
87
  } else if (vectorFormat === constants.VECTOR_FORMAT_BINARY) {
69
88
  elementSize = 1;
70
89
  // The number of dimensions are assumed to be multiple of 8.
71
90
  numElements = numElements / 8;
72
- result = new Uint8Array(numElements);
91
+ value = new Uint8Array(numElements);
73
92
  } else {
74
93
  errors.throwErr(errors.ERR_VECTOR_FORMAT_NOT_SUPPORTED, vectorFormat);
75
94
  }
76
95
 
77
- // For binary vector, NORM will never be present but space for NORM is reserved to keep
78
- // same header lengh across the different vector formats.
79
- if (vectorFormat === constants.VECTOR_FORMAT_BINARY || flags & constants.TNS_VECTOR_FLAG_NORM)
80
- this.skipBytes(8);
96
+ if (sparseFormat) {
97
+ sparseValue.values = value;
98
+ }
81
99
 
82
100
  // parse data
101
+ let res;
83
102
  for (let i = 0; i < numElements; i++) {
84
103
  const buf = this.readBytes(elementSize);
85
104
  if (vectorFormat === constants.VECTOR_FORMAT_FLOAT32) {
86
- result[i] = this.parseBinaryFloat(buf);
105
+ res = this.parseBinaryFloat(buf);
87
106
  } else if (vectorFormat === constants.VECTOR_FORMAT_FLOAT64) {
88
- result[i] = this.parseBinaryDouble(buf);
107
+ res = this.parseBinaryDouble(buf);
89
108
  } else {
90
- result[i] = buf[0];
109
+ res = buf[0];
91
110
  }
111
+ value[i] = res;
92
112
  }
93
113
 
94
- return result;
114
+ return sparseFormat ? types.SparseVector.create(sparseValue) : value;
95
115
  }
96
116
 
97
117
  }
98
118
 
99
119
  class VectorEncoder extends GrowableBuffer {
100
120
 
101
- //---------------------------------------------------------------------------
102
- // encode()
103
- //
104
- // Encodes the value as OSON and returns a buffer containing the OSON bytes.
105
- //---------------------------------------------------------------------------
106
- encode(value) {
107
-
108
- // determine some basic information about the vector
109
- let vectorFormat = constants.VECTOR_FORMAT_FLOAT32;
110
- let writeFn = this.writeBinaryFloat.bind(this);
121
+ // Writes Header from value.
122
+ // It returns function to serialize the value.
123
+ // sparseVal is provided for SparseVector.
124
+ _updateVectorHeader(value, sparseVal) {
125
+ let flags = constants.TNS_VECTOR_FLAG_NORMSRC
126
+ | constants.TNS_VECTOR_FLAG_NORM; // NORM is present and reserve space.
111
127
  let numElements = value.length;
112
128
  let vectorVersion = constants.TNS_VECTOR_VERSION_BASE;
113
- let flags = constants.TNS_VECTOR_FLAG_NORMSRC
114
- | constants.TNS_VECTOR_FLAG_NORM; // NORM is present and reserve space.
129
+ let vectorFormat = constants.VECTOR_FORMAT_FLOAT32;
130
+ let writeFn = this.writeBinaryFloat.bind(this);
115
131
 
116
132
  if (Array.isArray(value) || value instanceof Float64Array) {
117
133
  vectorFormat = constants.VECTOR_FORMAT_FLOAT64;
@@ -127,6 +143,11 @@ class VectorEncoder extends GrowableBuffer {
127
143
  flags = constants.TNS_VECTOR_FLAG_NORMSRC; // only space is reserved.
128
144
  writeFn = this.writeUInt8.bind(this);
129
145
  }
146
+ if (sparseVal && sparseVal instanceof types.SparseVector) {
147
+ vectorVersion = constants.TNS_VECTOR_VERSION_WITH_SPARSE;
148
+ numElements = sparseVal.numDimensions;
149
+ flags |= constants.TNS_VECTOR_FLAG_SPARSE;
150
+ }
130
151
 
131
152
  // write header
132
153
  this.writeUInt8(constants.TNS_VECTOR_MAGIC_BYTE);
@@ -135,6 +156,30 @@ class VectorEncoder extends GrowableBuffer {
135
156
  this.writeUInt8(vectorFormat);
136
157
  this.writeUInt32BE(numElements);
137
158
  this.reserveBytes(8);
159
+ return writeFn;
160
+ }
161
+
162
+ //---------------------------------------------------------------------------
163
+ // encode()
164
+ //
165
+ // Encodes the value as OSON and returns a buffer containing the OSON bytes.
166
+ //---------------------------------------------------------------------------
167
+ encode(value) {
168
+ let writeFn;
169
+
170
+ if (value instanceof types.SparseVector) {
171
+ writeFn = this._updateVectorHeader(value.values, value);
172
+ const numElements = value.indices.length;
173
+ this.writeUInt16BE(numElements);
174
+
175
+ // Write indices
176
+ value.indices.forEach((element) => {
177
+ this.writeUInt32BE(element);
178
+ });
179
+ value = value.values;
180
+ } else {
181
+ writeFn = this._updateVectorHeader(value);
182
+ }
138
183
 
139
184
  // write data
140
185
  value.forEach((element) => {
package/lib/impl/pool.js CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -165,6 +165,15 @@ class PoolImpl {
165
165
  errors.throwNotImplemented("getting the pool timeout");
166
166
  }
167
167
 
168
+ //---------------------------------------------------------------------------
169
+ // getMaxLifetimeSession()
170
+ //
171
+ // Returns the pool max lifetime for a session.
172
+ //---------------------------------------------------------------------------
173
+ getMaxLifetimeSession() {
174
+ errors.throwNotImplemented("getting the pool max lifetime");
175
+ }
176
+
168
177
  //---------------------------------------------------------------------------
169
178
  // getStmtCacheSize()
170
179
  //
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -43,8 +43,9 @@ class ResultSetImpl extends BaseImpl {
43
43
  // _determineFetchType()
44
44
  //
45
45
  // Determine the fetch type to use for the specified metadata.
46
+ // Param rowsetMetaData includes metadata of all the columns fetched.
46
47
  //---------------------------------------------------------------------------
47
- _determineFetchType(metadata, options) {
48
+ _determineFetchType(metadata, options, rowsetMetaData) {
48
49
 
49
50
  // clear any previous fetch type and converter functions that may have been
50
51
  // retained
@@ -54,7 +55,7 @@ class ResultSetImpl extends BaseImpl {
54
55
  // if a fetch type handler is specified, call it; if no value (undefined)
55
56
  // is returned, the normal processing takes place
56
57
  if (options.fetchTypeHandler) {
57
- const result = options.fetchTypeHandler(metadata);
58
+ const result = options.fetchTypeHandler(metadata, rowsetMetaData);
58
59
  if (result !== undefined) {
59
60
  errors.assert(typeof result === 'object',
60
61
  errors.ERR_FETCH_TYPE_HANDLER_RETURN_VALUE);
@@ -232,7 +233,7 @@ class ResultSetImpl extends BaseImpl {
232
233
  info.dbTypeClass = cls;
233
234
  }
234
235
  nodbUtil.addTypeProperties(info, "dbType");
235
- this._determineFetchType(info, options);
236
+ this._determineFetchType(info, options, metaData);
236
237
  if (info.fetchType === types.DB_TYPE_CURSOR) {
237
238
  this.nestedCursorIndices.push(i);
238
239
  } else if (info.fetchType === types.DB_TYPE_CLOB ||
package/lib/lob.js CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2016, 2024, Oracle and/or its affiliates.
1
+ // Copyright (c) 2016, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -246,6 +246,14 @@ class Lob extends Duplex {
246
246
  this._checkIsBfile();
247
247
  errors.assertArgCount(arguments, 1, 1);
248
248
  errors.assertParamValue(nodbUtil.isObject(a1), 1);
249
+ errors.assertParamValue(Object.hasOwn(a1, "dirName"), 1);
250
+ errors.assertParamValue(Object.hasOwn(a1, "fileName"), 1);
251
+ errors.assertPropValue(
252
+ a1.dirName != "" && a1.dirName != null, "dirName"
253
+ );
254
+ errors.assertPropValue(
255
+ a1.fileName != "" && a1.fileName != null, "fileName"
256
+ );
249
257
  this._impl.setDirFileName(a1);
250
258
  }
251
259
 
package/lib/oracledb.js CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2015, 2024, Oracle and/or its affiliates.
1
+ // Copyright (c) 2015, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -34,15 +34,15 @@ const impl = require('./impl');
34
34
  const process = require('process');
35
35
  const util = require('util');
36
36
 
37
- // This version of node-oracledb works with Node.js 14.6 or later.
37
+ // This version of node-oracledb works with Node.js 14.17 or later.
38
38
  // Note: the checked version is the minimum required for Node-API
39
39
  // compatibility. When new Node.js versions are released, older Node.js
40
40
  // versions are dropped from the node-oracledb test plan.
41
41
  //
42
42
  // Keep this code in sync with package/install.js
43
43
  const vs = process.version.substring(1).split(".").map(Number);
44
- errors.assert(vs[0] > 14 || (vs[0] === 14 && vs[1] >= 6),
45
- errors.ERR_NODE_TOO_OLD, nodbUtil.PACKAGE_JSON_VERSION, "14.6");
44
+ errors.assert(vs[0] > 14 || (vs[0] === 14 && vs[1] >= 17),
45
+ errors.ERR_NODE_TOO_OLD, nodbUtil.PACKAGE_JSON_VERSION, "14.17");
46
46
 
47
47
  const AqDeqOptions = require('./aqDeqOptions.js');
48
48
  const AqEnqOptions = require('./aqEnqOptions.js');
@@ -67,6 +67,8 @@ const SodaOperation = require('./sodaOperation.js');
67
67
  const poolCache = {};
68
68
  const tempUsedPoolAliases = {};
69
69
  const defaultPoolAlias = 'default';
70
+ const registeredHooks = [];
71
+ const registeredConfigProviderHooks = new Map();
70
72
  let configProviderCache;
71
73
 
72
74
  // save arguments for call to initOracleClient()
@@ -188,6 +190,18 @@ async function _verifyOptions(options, inCreatePool) {
188
190
  "walletLocation");
189
191
  outOptions.walletLocation = options.walletLocation;
190
192
  }
193
+ if (options.networkCompression !== undefined) {
194
+ errors.assertParamPropValue(typeof options.networkCompression === 'boolean', 1,
195
+ "networkCompression");
196
+ outOptions.networkCompression = options.networkCompression;
197
+ outOptions.networkCompressionLevels = [];
198
+ outOptions.networkCompressionLevels.push('high');
199
+ }
200
+
201
+ if (options.networkCompressionThreshold !== undefined) {
202
+ errors.assertParamPropValue(Number.isInteger(options.networkCompressionThreshold), 1, "networkCompressionThreshold");
203
+ outOptions.networkCompressionThreshold = options.networkCompressionThreshold;
204
+ }
191
205
 
192
206
  //wallet content must be a string
193
207
  if (options.walletContent !== undefined) {
@@ -362,6 +376,22 @@ async function _verifyOptions(options, inCreatePool) {
362
376
  outOptions.terminal = options.terminal;
363
377
  }
364
378
 
379
+ // useSNI must be a boolean
380
+ if (options.useSNI !== undefined) {
381
+ errors.assertParamPropValue(typeof options.useSNI === 'boolean', 1,
382
+ "useSNI");
383
+ outOptions.useSNI = options.useSNI;
384
+ }
385
+
386
+ // appContext must be an array of array values. The element arrays should
387
+ // have 3 string values (namespace, name and value).
388
+ if (options.appContext !== undefined) {
389
+ const value = options.appContext;
390
+ errors.assertParamPropValue(nodbUtil.isAppContext(value), 1,
391
+ "appContext");
392
+ outOptions.appContext = options.appContext;
393
+ }
394
+
365
395
  // check pool specific options
366
396
  if (inCreatePool) {
367
397
 
@@ -415,6 +445,13 @@ async function _verifyOptions(options, inCreatePool) {
415
445
  outOptions.poolPingTimeout = options.poolPingTimeout;
416
446
  }
417
447
 
448
+ // maxLifeTime must be an unsigned integer
449
+ if (options.maxLifetimeSession !== undefined) {
450
+ errors.assertParamPropValue(Number.isInteger(options.maxLifetimeSession) &&
451
+ options.maxLifetimeSession >= 0, 1, "maxLifetimeSession");
452
+ outOptions.maxLifetimeSession = options.maxLifetimeSession;
453
+ }
454
+
418
455
  // homogeneous must be a boolean (and defaults to True)
419
456
  outOptions.homogeneous = true;
420
457
  if (options.homogeneous !== undefined) {
@@ -513,9 +550,13 @@ async function _verifyOptions(options, inCreatePool) {
513
550
  if (typeof options.accessToken === 'function') {
514
551
  outOptions.accessTokenFn = options.accessToken;
515
552
  outOptions.accessTokenConfig = options.accessTokenConfig;
516
- accessToken = await options.accessToken(false, options.accessTokenConfig);
517
- if (!nodbUtil.isTokenValid(accessToken)) {
518
- accessToken = await options.accessToken(true, options.accessTokenConfig);
553
+ try {
554
+ accessToken = await options.accessToken(false, outOptions.accessTokenConfig);
555
+ if (!nodbUtil.isTokenValid(accessToken)) {
556
+ accessToken = await options.accessToken(true, outOptions.accessTokenConfig);
557
+ }
558
+ } catch (error) {
559
+ errors.throwWrapErr(error, errors.ERR_ACCESS_TOKEN);
519
560
  }
520
561
  } else {
521
562
  accessToken = options.accessToken;
@@ -568,6 +609,18 @@ async function createPool(options) {
568
609
  // check arguments
569
610
  errors.assertArgCount(arguments, 1, 1);
570
611
  errors.assertParamValue(nodbUtil.isObject(options), 1);
612
+
613
+ // this will invoke hookFn() written in application side.
614
+ // for token based auth it will generate access token and save it in options.
615
+ for (const hookFn of registeredHooks) {
616
+ // eslint-disable-next-line no-useless-catch
617
+ try {
618
+ await hookFn(options);
619
+ } catch (error) {
620
+ errors.throwWrapErr(error, errors.ERR_CALLOUT_FN);
621
+ }
622
+ }
623
+
571
624
  options = await _verifyOptions(options, true);
572
625
  const sessionCallback = options.sessionCallback;
573
626
  if (typeof sessionCallback === 'function')
@@ -700,6 +753,17 @@ async function getConnection(a1) {
700
753
  return await pool.getConnection(options);
701
754
  }
702
755
 
756
+ // this will invoke hookFn() written in application side.
757
+ // for token based auth it will generate access token and save it in options.
758
+ for (const hookFn of registeredHooks) {
759
+ // eslint-disable-next-line no-useless-catch
760
+ try {
761
+ await hookFn(options);
762
+ } catch (error) {
763
+ errors.throwWrapErr(error, errors.ERR_CALLOUT_FN);
764
+ }
765
+ }
766
+
703
767
  // create a standalone connection
704
768
  options = await _verifyOptions(options, false);
705
769
  settings.addToOptions(options,
@@ -841,6 +905,84 @@ async function shutdown(a1, a2) {
841
905
  await conn.close();
842
906
  }
843
907
 
908
+ async function _setConfigParameters(obj, credential, configProvider) {
909
+ const configObject = {};
910
+ const pmSection = 'njs';
911
+ const params = obj[pmSection];
912
+ for (const key in params) {
913
+ const val = params[key];
914
+ configObject[key] = val;
915
+ }
916
+ configObject.connectString = obj.connect_descriptor;
917
+ if (!configObject.connectString)
918
+ errors.throwErr(errors.ERR_CONFIG_PROVIDER_FAILED_TO_RETRIEVE_CONFIG, 'connect_descriptor must be set');
919
+
920
+ configObject.user = obj.user;
921
+ if (obj.password) {
922
+ configObject.password = await _retrieveParamValueFromVault(obj['password'], credential, configProvider);
923
+ }
924
+ if (obj.wallet_location) {
925
+ // retrieve wallet_location
926
+ configObject.walletContent = await _retrieveParamValueFromVault(obj['wallet_location'], credential, configProvider);
927
+ //only Pem file supported
928
+ if (!nodbUtil.isPemFile(configObject.walletContent))
929
+ errors.throwErr(errors.ERR_WALLET_TYPE_NOT_SUPPORTED);
930
+ }
931
+ return configObject;
932
+ }
933
+
934
+ async function _retrieveParamValueFromVault(paramObj, credential, configProvider) {
935
+ const paramMap = new Map();
936
+ const auth = paramObj.authentication;
937
+ if (auth) {
938
+ for (const key in auth) {
939
+ if (key == 'method')
940
+ paramMap.set('authentication', auth[key]);
941
+ const val = auth[key];
942
+ paramMap.set(key.toLowerCase(), val);
943
+ }
944
+ }
945
+ const args = {};
946
+ if (paramObj.type == "base64") {
947
+ console.log("WARNING: Base64 Encoding in a JSON Password should only be used in development environments");
948
+ return Buffer.from(paramObj.value, "base64").toString("utf-8");
949
+ } else if (paramObj.type == "text") {
950
+ if (configProvider == 'azurevault' || configProvider == 'ocivault') {
951
+ console.log("WARNING: Plain Text in a JSON Password should only be used in development environments");
952
+ return paramObj.value;
953
+ } else
954
+ errors.throwErr(errors.ERR_CONFIG_PROVIDER_PARAM_TYPE, 'password type text is only allowed in ocivault and azurevault');
955
+ } else if (paramObj.type == "azurevault") {
956
+ paramMap.set('azuresecreturl', paramObj.value);
957
+ if (!(configProvider == 'azure' || configProvider == 'azurevault'))
958
+ credential = null;
959
+ const hookFn = registeredConfigProviderHooks['azurevault'];
960
+ if (hookFn == undefined)
961
+ errors.throwErr(errors.ERR_REGISTER_HOOKFN_CONFIGPROVIDER, 'azurevault');
962
+ args.credential = credential;
963
+ args.paramMap = paramMap;
964
+ const vaultReturn = await hookFn(args);
965
+ const paramValue = vaultReturn[0];
966
+ return paramValue;
967
+
968
+ } else if (paramObj.type == "ocivault") {
969
+
970
+ paramMap.set('ocidvault', paramObj.value);
971
+ if (!(configProvider == 'ociobject' || configProvider == 'ocivault'))
972
+ credential = null;
973
+ const hookFn = registeredConfigProviderHooks['ocivault'];
974
+ if (hookFn == undefined)
975
+ errors.throwErr(errors.ERR_REGISTER_HOOKFN_CONFIGPROVIDER, 'ocivault');
976
+ const args = {};
977
+ args.credential = credential;
978
+ args.paramMap = paramMap;
979
+ const vaultReturn = await hookFn(args);
980
+ const paramValue = vaultReturn[0];
981
+ return paramValue;
982
+ } else {
983
+ errors.throwErr(errors.ERR_CONFIG_PROVIDER_PARAM_TYPE, 'password/wallet_location');
984
+ }
985
+ }
844
986
  //-----------------------------------------------------------------------------
845
987
  // _checkConfigProvider()
846
988
  //
@@ -881,23 +1023,27 @@ async function _checkConfigProvider(options) {
881
1023
  if (match) {
882
1024
  const provider = match.groups.provider;
883
1025
  const provider_arg = match.groups.provider_arg;
884
- let configPckg;
885
- try {
886
- configPckg = require('./configProviders/' + provider);
887
- } catch (err) {
888
- errors.throwErr(errors.ERR_CONFIG_PROVIDER_NOT_SUPPORTED, provider);
889
- }
890
- const configProvider = new configPckg(provider_arg, urlExtendedPart);
891
- try {
892
- configProvider.init();
893
- } catch (err) {
894
- errors.throwErr(errors.ERR_CONFIG_PROVIDER_LOAD_FAILED, err.message);
895
- }
1026
+ const hookFn = registeredConfigProviderHooks[provider];
1027
+ if (hookFn == undefined)
1028
+ errors.throwErr(errors.ERR_REGISTER_HOOKFN_CONFIGPROVIDER, provider);
1029
+ const args = {};
1030
+ args.provider_arg = provider_arg;
1031
+ args.urlExtendedPart = urlExtendedPart;
1032
+
896
1033
  try {
1034
+ // hookFn returns an array with first element as the config stored in the configProvider
1035
+ // second being the credential to the configProvider
1036
+ const configProviderReturn = await hookFn(args);
1037
+ secondOpts = configProviderReturn[0];
897
1038
  if (!configProviderCache) {
898
1039
  configProviderCache = new Map();
899
1040
  }
900
- secondOpts = await configProvider.returnConfig();
1041
+ if (!secondOpts) {
1042
+ errors.throwErr(errors.ERR_CONFIG_PROVIDER_FAILED_TO_RETRIEVE_CONFIG, 'no configuration found in ' + provider);
1043
+ }
1044
+ if (provider != 'azure')
1045
+ secondOpts = await _setConfigParameters(secondOpts, configProviderReturn[1], provider);
1046
+
901
1047
  // obfuscate password & walletcontent and store config in the cache
902
1048
  const cacheOpts = { ...secondOpts};
903
1049
  if (secondOpts.password)
@@ -998,6 +1144,31 @@ async function startup(a1, a2) {
998
1144
  await conn.close();
999
1145
  }
1000
1146
 
1147
+ //-----------------------------------------------------------------------------
1148
+ // registerProcessConfigurationHook()
1149
+ //
1150
+ // Registers extension modules and registered modules will be called and
1151
+ // executed during pool and standalone connection creation.
1152
+ //-----------------------------------------------------------------------------
1153
+ function registerProcessConfigurationHook(fn) {
1154
+ errors.assertArgCount(arguments, 1, 1);
1155
+ errors.assertParamValue(typeof fn === 'function', 1);
1156
+ registeredHooks.push(fn);
1157
+ }
1158
+
1159
+ //-----------------------------------------------------------------------------
1160
+ // registerConfigurationProviderHook()
1161
+ //
1162
+ // Registers Configuration Provider plugin modules and registered modules will
1163
+ // be called and executed during pool and standalone connection creation.
1164
+ //-----------------------------------------------------------------------------
1165
+ function registerConfigurationProviderHook(configProvider, fn) {
1166
+ errors.assertArgCount(arguments, 2, 2);
1167
+ errors.assertParamValue(typeof fn === 'function', 1);
1168
+ errors.assertParamValue(typeof configProvider === 'string', 1);
1169
+ registeredConfigProviderHooks[configProvider] = fn;
1170
+ }
1171
+
1001
1172
  // module exports
1002
1173
  module.exports = {
1003
1174
 
@@ -1018,6 +1189,9 @@ module.exports = {
1018
1189
  SodaDocCursor,
1019
1190
  SodaDocument,
1020
1191
  SodaOperation,
1192
+ SparseVector: types.SparseVector,
1193
+ IntervalYM: types.IntervalYM,
1194
+ IntervalDS: types.IntervalDS,
1021
1195
 
1022
1196
  // top-level functions
1023
1197
  getConnection: nodbUtil.callbackify(nodbUtil.wrapFn(getConnection)),
@@ -1025,6 +1199,8 @@ module.exports = {
1025
1199
  getNetworkServiceNames: nodbUtil.callbackify(nodbUtil.wrapFn(getNetworkServiceNames)),
1026
1200
  getPool,
1027
1201
  initOracleClient,
1202
+ registerProcessConfigurationHook,
1203
+ registerConfigurationProviderHook,
1028
1204
  shutdown: nodbUtil.callbackify(nodbUtil.wrapFn(shutdown)),
1029
1205
  startup: nodbUtil.callbackify(nodbUtil.wrapFn(startup)),
1030
1206
 
@@ -1269,6 +1445,10 @@ module.exports = {
1269
1445
  return settings.fetchTypeHandler;
1270
1446
  },
1271
1447
 
1448
+ get dbObjectTypeHandler() {
1449
+ return settings.dbObjectTypeHandler;
1450
+ },
1451
+
1272
1452
  get lobPrefetchSize() {
1273
1453
  return settings.lobPrefetchSize;
1274
1454
  },
@@ -1329,6 +1509,7 @@ module.exports = {
1329
1509
  return settings.configProviderCacheTimeout;
1330
1510
  },
1331
1511
 
1512
+
1332
1513
  get thin() {
1333
1514
  return settings.thin;
1334
1515
  },
@@ -1413,6 +1594,13 @@ module.exports = {
1413
1594
  settings.fetchTypeHandler = value;
1414
1595
  },
1415
1596
 
1597
+ set dbObjectTypeHandler(value) {
1598
+ if (value !== undefined) {
1599
+ errors.assertPropValue(typeof value === 'function', "dbObjectTypeHandler");
1600
+ }
1601
+ settings.dbObjectTypeHandler = value;
1602
+ },
1603
+
1416
1604
  set lobPrefetchSize(value) {
1417
1605
  errors.assertPropValue(Number.isInteger(value) && value >= 0,
1418
1606
  "lobPrefetchSize");
@@ -1509,6 +1697,7 @@ module.exports = {
1509
1697
  errors.assertPropValue(typeof value === 'string', "terminal");
1510
1698
  settings.terminal = value;
1511
1699
  },
1700
+
1512
1701
  set configProviderCacheTimeout(value) {
1513
1702
  errors.assertPropValue(Number.isInteger(value) && value >= 0,
1514
1703
  "configProviderCacheTimeout");
package/lib/pool.js CHANGED
@@ -653,6 +653,15 @@ class Pool extends EventEmitter {
653
653
  return this._impl.getPoolTimeout();
654
654
  }
655
655
 
656
+ //---------------------------------------------------------------------------
657
+ // maxLifetimeSession
658
+ //
659
+ // Property for the max allowed lifetime of a session in the pool.
660
+ //---------------------------------------------------------------------------
661
+ get maxLifetimeSession() {
662
+ return this._impl.getMaxLifetimeSession();
663
+ }
664
+
656
665
  //---------------------------------------------------------------------------
657
666
  // queueMax
658
667
  //
@@ -693,6 +702,7 @@ class Pool extends EventEmitter {
693
702
  errors.assertParamPropUnsignedInt(options, 1, "poolIncrement");
694
703
  errors.assertParamPropInt(options, 1, "poolPingInterval");
695
704
  errors.assertParamPropUnsignedInt(options, 1, "poolTimeout");
705
+ errors.assertParamPropUnsignedInt(options, 1, "maxLifetimeSession");
696
706
  errors.assertParamPropUnsignedInt(options, 1, "stmtCacheSize");
697
707
  errors.assertParamPropBool(options, 1, "sodaMetaDataCache");
698
708
 
@@ -708,7 +718,8 @@ class Pool extends EventEmitter {
708
718
  this._status = constants.POOL_STATUS_RECONFIGURING;
709
719
  try {
710
720
  // poolMin/poolMax/poolIncrement/poolPingInterval/poolTimeout/
711
- // poolMaxPerShard/stmtCacheSize/sodaMetaDataCache parameters
721
+ // poolMaxPerShard/stmtCacheSize/sodaMetaDataCache/maxLifetimeSession
722
+ // parameters
712
723
  await this._impl.reconfigure(options);
713
724
 
714
725
  // pool JS parameters: queueMax, queueTimeout, enableStatistics,
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2021, 2024, Oracle and/or its affiliates.
1
+ // Copyright (c) 2021, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -74,6 +74,7 @@ class PoolStatistics {
74
74
  this.poolPingInterval = pool.poolPingInterval;
75
75
  this.poolPingTimeout = pool.poolPingTimeout;
76
76
  this.poolTimeout = pool.poolTimeout;
77
+ this.maxLifetimeSession = pool.maxLifetimeSession;
77
78
  this.queueMax = pool.queueMax;
78
79
  this.queueTimeout = pool.queueTimeout;
79
80
  this.sodaMetaDataCache = pool.sodaMetaDataCache;
@@ -127,6 +128,7 @@ class PoolStatistics {
127
128
  console.log('...poolPingInterval (seconds):', this.poolPingInterval);
128
129
  console.log('...poolPingTimeout (milliseconds):', this.poolPingTimeout);
129
130
  console.log('...poolTimeout (seconds):', this.poolTimeout);
131
+ console.log('...maxLifetimeSession (seconds):', this.maxLifetimeSession);
130
132
  console.log('...queueMax:', this.queueMax);
131
133
  console.log('...queueTimeout (milliseconds):', this.queueTimeout);
132
134
  console.log('...sessionCallback:', this.sessionCallback);
package/lib/settings.js CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2025, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -64,7 +64,11 @@ class Settings {
64
64
  this.thinDriverInitialized = false;
65
65
  this.createFetchTypeMap(this.fetchAsString, this.fetchAsBuffer);
66
66
  this.fetchTypeHandler = undefined;
67
+ this.dbObjectTypeHandler = undefined;
67
68
  this._JsonId = types.JsonId;
69
+ this._SparseVector = types.SparseVector;
70
+ this._IntervalYM = types.IntervalYM;
71
+ this._IntervalDS = types.IntervalDS;
68
72
  }
69
73
 
70
74
  //---------------------------------------------------------------------------