oracledb 7.0.1 → 26.0.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 (74) hide show
  1. package/README.md +16 -6
  2. package/build/Release/oracledb-26.0.0-darwin-arm64.node +0 -0
  3. package/build/Release/oracledb-26.0.0-darwin-arm64.node-buildinfo.txt +1 -0
  4. package/build/Release/oracledb-26.0.0-js-buildinfo.txt +1 -0
  5. package/build/Release/oracledb-26.0.0-linux-arm64.node +0 -0
  6. package/build/Release/oracledb-26.0.0-linux-arm64.node-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-26.0.0-linux-x64.node +0 -0
  8. package/build/Release/oracledb-26.0.0-linux-x64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-26.0.0-win32-x64.node +0 -0
  10. package/build/Release/oracledb-26.0.0-win32-x64.node-buildinfo.txt +1 -0
  11. package/lib/connection.js +71 -8
  12. package/lib/constants.js +4 -0
  13. package/lib/endUserSecurityContext.js +20 -8
  14. package/lib/errors.js +70 -5
  15. package/lib/impl/connection.js +36 -0
  16. package/lib/impl/datahandlers/buffer.js +91 -18
  17. package/lib/impl/datahandlers/oson.js +3 -2
  18. package/lib/impl/resultset.js +32 -11
  19. package/lib/oracledb.js +34 -0
  20. package/lib/pool.js +6 -2
  21. package/lib/queryStream.js +13 -5
  22. package/lib/resultset.js +10 -3
  23. package/lib/securityContextProvider.js +206 -0
  24. package/lib/thin/aq.js +2 -3
  25. package/lib/thin/connection.js +381 -19
  26. package/lib/thin/dbObject.js +17 -8
  27. package/lib/thin/pool.js +3 -2
  28. package/lib/thin/protocol/capabilities.js +37 -4
  29. package/lib/thin/protocol/constants.js +49 -1
  30. package/lib/thin/protocol/messages/auth.js +17 -6
  31. package/lib/thin/protocol/messages/base.js +74 -16
  32. package/lib/thin/protocol/messages/dataType.js +46 -0
  33. package/lib/thin/protocol/messages/directPathLoadStream.js +3 -2
  34. package/lib/thin/protocol/messages/execute.js +10 -4
  35. package/lib/thin/protocol/messages/index.js +4 -0
  36. package/lib/thin/protocol/messages/notification.js +281 -0
  37. package/lib/thin/protocol/messages/subscribe.js +181 -0
  38. package/lib/thin/protocol/messages/withData.js +21 -7
  39. package/lib/thin/protocol/packet.js +2 -4
  40. package/lib/thin/protocol/protocol.js +7 -4
  41. package/lib/thin/resultSet.js +40 -20
  42. package/lib/thin/sqlnet/ezConnectResolver.js +7 -0
  43. package/lib/thin/sqlnet/navNodes.js +3 -3
  44. package/lib/thin/sqlnet/ntTcp.js +24 -8
  45. package/lib/thin/statement.js +6 -1
  46. package/lib/thin/statementCache.js +34 -6
  47. package/lib/thin/subscr.js +363 -0
  48. package/lib/transformer.js +60 -17
  49. package/lib/util.js +46 -8
  50. package/lib/version.js +2 -2
  51. package/package.json +1 -1
  52. package/plugins/configProviders/gcpstorage/index.js +121 -0
  53. package/plugins/configProviders/ociobject/index.js +1 -1
  54. package/plugins/token/cache.js +154 -0
  55. package/plugins/token/endUserSecurityProvider/index.js +377 -0
  56. package/plugins/token/extensionAzure/index.js +160 -28
  57. package/plugins/token/extensionOci/index.js +221 -16
  58. package/plugins/vectorsdk/OracleVecDB.js +346 -0
  59. package/plugins/vectorsdk/index.js +49 -0
  60. package/plugins/vectorsdk/utils.js +370 -0
  61. package/plugins/vectorsdk/vectorEmbedding.js +223 -0
  62. package/plugins/vectorsdk/vectorIndex.js +177 -0
  63. package/plugins/vectorsdk/vectorRecords.js +406 -0
  64. package/plugins/vectorsdk/vectorSchema.js +408 -0
  65. package/plugins/vectorsdk/vectorSearch.js +538 -0
  66. package/build/Release/oracledb-7.0.1-darwin-arm64.node +0 -0
  67. package/build/Release/oracledb-7.0.1-darwin-arm64.node-buildinfo.txt +0 -1
  68. package/build/Release/oracledb-7.0.1-js-buildinfo.txt +0 -1
  69. package/build/Release/oracledb-7.0.1-linux-arm64.node +0 -0
  70. package/build/Release/oracledb-7.0.1-linux-arm64.node-buildinfo.txt +0 -1
  71. package/build/Release/oracledb-7.0.1-linux-x64.node +0 -0
  72. package/build/Release/oracledb-7.0.1-linux-x64.node-buildinfo.txt +0 -1
  73. package/build/Release/oracledb-7.0.1-win32-x64.node +0 -0
  74. package/build/Release/oracledb-7.0.1-win32-x64.node-buildinfo.txt +0 -1
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2025, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -44,7 +44,7 @@ class BaseBuffer {
44
44
  // The initializer is either an integer specifying the size of the buffer, or
45
45
  // an existing Buffer, which is used directly.
46
46
  //---------------------------------------------------------------------------
47
- constructor(initializer) {
47
+ constructor(initializer, caps) {
48
48
  if (typeof initializer === 'number') {
49
49
  this.buf = Buffer.alloc(initializer);
50
50
  this.size = 0;
@@ -54,6 +54,7 @@ class BaseBuffer {
54
54
  this.size = this.maxSize = initializer.length;
55
55
  }
56
56
  this.pos = 0;
57
+ this.caps = caps;
57
58
  }
58
59
 
59
60
  //---------------------------------------------------------------------------
@@ -84,29 +85,42 @@ class BaseBuffer {
84
85
  // Read an integer from the buffer of the specified maximum size and returns
85
86
  // it. The signed flag indicates whether the value is allowed to be signed or
86
87
  // not and the skip flag indicates whether the data should simply be skipped.
88
+ // The asBigInt flag indicates whether the value should be returned as a
89
+ // BigInt instead of a Number.
87
90
  //---------------------------------------------------------------------------
88
- _readInteger(maxSize, signed, skip) {
91
+ _readInteger(maxSize, signed, skip, asBigInt = false) {
89
92
  let isNegative = false;
90
93
  let size = this.readUInt8();
91
94
  if (size === 0) {
92
- return 0;
95
+ return asBigInt ? 0n : 0;
93
96
  } else if (size & 0x80) {
94
97
  if (!signed) {
95
- errors.throwErr(errors.ERR_UNEXPECTED_NEGATIVE_INTEGER, this.pos, this.packetNum);
98
+ errors.throwErr(errors.ERR_UNEXPECTED_NEGATIVE_INTEGER, this.pos,
99
+ this.packetNum);
96
100
  }
97
101
  isNegative = true;
98
102
  size = size & 0x7f;
99
103
  }
100
104
  if (size > maxSize) {
101
- errors.throwErr(errors.ERR_INTEGER_TOO_LARGE, size, maxSize, this.pos, this.packetNum);
105
+ errors.throwErr(errors.ERR_INTEGER_TOO_LARGE, size, maxSize, this.pos,
106
+ this.packetNum);
102
107
  }
103
108
  if (skip) {
104
109
  this.skipBytes(size);
110
+ return;
111
+ }
112
+
113
+ const buf = this.readBytes(size);
114
+ let value;
115
+ if (asBigInt) {
116
+ value = 0n;
117
+ for (const byte of buf) {
118
+ value = (value << 8n) | BigInt(byte);
119
+ }
105
120
  } else {
106
- const buf = this.readBytes(size);
107
- const value = buf.readUIntBE(0, size);
108
- return (isNegative) ? -value : value;
121
+ value = buf.readUIntBE(0, size);
109
122
  }
123
+ return isNegative ? -value : value;
110
124
  }
111
125
 
112
126
  //---------------------------------------------------------------------------
@@ -175,17 +189,22 @@ class BaseBuffer {
175
189
  // assumed at this point that the size of the buffer is either 7 bytes (date
176
190
  // or compressed timestamp), 11 bytes (timestamp) or 13 bytes (timestamp with
177
191
  // time zone). Time zone information is discarded because Node.js uses UTC
178
- // timestamps and the server returns the data in that format, too. The Date
179
- // type in Node.js doesn't support time zone information.
192
+ // timestamps. TIMESTAMP WITH LOCAL TIME ZONE is returned in the database
193
+ // time zone and needs its offset to produce the original UTC instant.
180
194
  //---------------------------------------------------------------------------
181
- parseOracleDate(buf, useLocalTime = true) {
195
+ parseOracleDate(buf, useLocalTime = true, useDbTz = false) {
182
196
  let fseconds = 0;
183
197
  if (buf.length >= 11) {
184
198
  fseconds = Math.floor(buf.readUInt32BE(7) / (1000 * 1000));
185
199
  }
186
200
  const year = (buf[0] - 100) * 100 + buf[1] - 100;
201
+ if (useDbTz && this.caps?.dbTzRegion) {
202
+ errors.throwErr(errors.ERR_TIMESTAMP_LTZ_REGION_NOT_SUPPORTED,
203
+ this.caps.dbTzRegion);
204
+ }
205
+ const offset = useDbTz ? this.caps?.dbTzOffset ?? 0 : 0;
187
206
  return nodbUtil.makeDate(useLocalTime, year, buf[2], buf[3], buf[4] - 1,
188
- buf[5] - 1, buf[6] - 1, fseconds, 0);
207
+ buf[5] - 1, buf[6] - 1, fseconds, offset);
189
208
  }
190
209
 
191
210
  //---------------------------------------------------------------------------
@@ -475,12 +494,12 @@ class BaseBuffer {
475
494
  // Reads an Oracle date from the buffer and returns a Date or a String,
476
495
  // depending on the desired type.
477
496
  //---------------------------------------------------------------------------
478
- readOracleDate(useLocalTime) {
497
+ readOracleDate(useLocalTime, useDbTz = false) {
479
498
  const buf = this.readBytesWithLength();
480
499
  if (!buf) {
481
500
  return null;
482
501
  }
483
- return this.parseOracleDate(buf, useLocalTime);
502
+ return this.parseOracleDate(buf, useLocalTime, useDbTz);
484
503
  }
485
504
 
486
505
  //---------------------------------------------------------------------------
@@ -609,6 +628,17 @@ class BaseBuffer {
609
628
  return this._readInteger(8, false, false);
610
629
  }
611
630
 
631
+ //---------------------------------------------------------------------------
632
+ // readUB8BigInt()
633
+ //
634
+ // Reads an unsigned, variable length integer of up to 8 bytes in length as
635
+ // a BigInt. This preserves values that cannot safely be represented by a
636
+ // JavaScript Number.
637
+ //---------------------------------------------------------------------------
638
+ readUB8BigInt() {
639
+ return this._readInteger(8, false, false, true);
640
+ }
641
+
612
642
  //---------------------------------------------------------------------------
613
643
  // readUInt8()
614
644
  //
@@ -856,6 +886,16 @@ class BaseBuffer {
856
886
  writeOracleDate(date, type, writeLength = true) {
857
887
  let fsec;
858
888
  let length = type._bufferSizeFactor;
889
+ if (type === types.DB_TYPE_TIMESTAMP_LTZ) {
890
+ if (this.caps?.dbTzRegion) {
891
+ errors.throwErr(errors.ERR_TIMESTAMP_LTZ_REGION_NOT_SUPPORTED,
892
+ this.caps.dbTzRegion);
893
+ }
894
+ const offset = this.caps?.dbTzOffset;
895
+ if (offset !== null && offset !== undefined) {
896
+ date = new Date(date.getTime() + offset * 60000);
897
+ }
898
+ }
859
899
  if (length > 7) {
860
900
  fsec = date.getUTCMilliseconds() * 1000 * 1000;
861
901
  if (fsec === 0 && length <= 11)
@@ -1123,6 +1163,29 @@ class BaseBuffer {
1123
1163
  }
1124
1164
  }
1125
1165
 
1166
+ //---------------------------------------------------------------------------
1167
+ // writeUB8BigInt()
1168
+ //
1169
+ // Writes an unsigned BigInt in variable length format, up to eight bytes.
1170
+ //---------------------------------------------------------------------------
1171
+ writeUB8BigInt(value) {
1172
+ if (value === 0n) {
1173
+ this.writeUInt8(0);
1174
+ } else if (value <= 0xffn) {
1175
+ this.writeUInt8(1);
1176
+ this.writeUInt8(Number(value));
1177
+ } else if (value <= 0xffffn) {
1178
+ this.writeUInt8(2);
1179
+ this.writeUInt16BE(Number(value));
1180
+ } else if (value <= 0xffffffffn) {
1181
+ this.writeUInt8(4);
1182
+ this.writeUInt32BE(Number(value));
1183
+ } else {
1184
+ this.writeUInt8(8);
1185
+ this.writeBigUInt64BE(value);
1186
+ }
1187
+ }
1188
+
1126
1189
  //---------------------------------------------------------------------------
1127
1190
  // writeUInt8()
1128
1191
  //
@@ -1175,6 +1238,16 @@ class BaseBuffer {
1175
1238
  this.buf.writeUInt32BE(n, pos + 4);
1176
1239
  }
1177
1240
 
1241
+ //---------------------------------------------------------------------------
1242
+ // writeBigUInt64BE()
1243
+ //
1244
+ // Writes an unsigned BigInt value up to 64 bits in big endian order.
1245
+ //---------------------------------------------------------------------------
1246
+ writeBigUInt64BE(n) {
1247
+ const pos = this.reserveBytes(8);
1248
+ this.buf.writeBigUInt64BE(n, pos);
1249
+ }
1250
+
1178
1251
  //---------------------------------------------------------------------------
1179
1252
  // writeUInt16LE()
1180
1253
  //
@@ -1194,11 +1267,11 @@ class GrowableBuffer extends BaseBuffer {
1194
1267
  //
1195
1268
  // Initializes the buffer with an initial fixed chunk size.
1196
1269
  //---------------------------------------------------------------------------
1197
- constructor(initializer) {
1270
+ constructor(initializer, caps) {
1198
1271
  if (initializer) {
1199
- super(initializer);
1272
+ super(initializer, caps);
1200
1273
  } else {
1201
- super(constants.BUFFER_CHUNK_SIZE);
1274
+ super(constants.BUFFER_CHUNK_SIZE, caps);
1202
1275
  this.size = this.maxSize;
1203
1276
  }
1204
1277
  }
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2023, 2025, Oracle and/or its affiliates.
1
+ // Copyright (c) 2023, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -754,7 +754,8 @@ class OsonEncoder extends GrowableBuffer {
754
754
  this.maxFieldNameSize = maxFieldNameSize;
755
755
 
756
756
  // determine the flags to use
757
- let flags = constants.TNS_JSON_FLAG_INLINE_LEAF;
757
+ let flags = constants.TNS_JSON_FLAG_INLINE_LEAF |
758
+ constants.TNS_JSON_FLAG_LEN_IN_PCODE;
758
759
  if (Array.isArray(value) || (value && Array.isArray(value.fields))) {
759
760
  // examine all values recursively to determine the unique set of field
760
761
  // names and whether they need to be added to the long field names
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2025, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -200,6 +200,17 @@ class ResultSetImpl extends BaseImpl {
200
200
  return this._parentObj;
201
201
  }
202
202
 
203
+ //---------------------------------------------------------------------------
204
+ // _getDbObjectType()
205
+ //
206
+ // Return the object identifying the object type. These are cached by fully
207
+ // qualified name and by OID (thin mode only).
208
+ //---------------------------------------------------------------------------
209
+ _getDbObjectType(schema, name, packageName, oid) {
210
+ return this._getConnImpl()._getDbObjectType(schema, name, packageName,
211
+ oid);
212
+ }
213
+
203
214
  //---------------------------------------------------------------------------
204
215
  // _setup()
205
216
  //
@@ -210,7 +221,7 @@ class ResultSetImpl extends BaseImpl {
210
221
  //---------------------------------------------------------------------------
211
222
  _setup(options, metaData) {
212
223
  this._parentObj = options.connection._impl;
213
- this.metaData = metaData;
224
+ this.metaData = [];
214
225
  this.lobIndices = [];
215
226
  this.dbObjectIndices = [];
216
227
  this.nestedCursorIndices = [];
@@ -227,13 +238,23 @@ class ResultSetImpl extends BaseImpl {
227
238
  }
228
239
  }
229
240
  for (let i = 0; i < metaData.length; i++) {
230
- const info = metaData[i];
231
- if (info.dbTypeClass) {
232
- const cls = options.connection._getDbObjectClass(info.dbTypeClass);
233
- info.dbTypeClass = cls;
241
+ const fetchInfo = metaData[i];
242
+ if (fetchInfo.dbTypeClass) {
243
+ const cls = options.connection._getDbObjectClass(fetchInfo.dbTypeClass);
244
+ fetchInfo.dbTypeClass = cls;
234
245
  }
235
- nodbUtil.addTypeProperties(info, "dbType");
246
+ nodbUtil.addTypeProperties(fetchInfo, "dbType");
247
+
248
+ // Use a per-resultset metadata copy so any fetchTypeHandler or
249
+ // resultset-specific metadata mutations (for example renaming columns)
250
+ // do not leak back into the underlying statement metadata.
251
+ // This is also applied in thick mode for consistency, even though the
252
+ // extra copy is only needed to protect the thin-mode cached metadata.
253
+ const info = {...fetchInfo};
254
+ this.metaData.push(info);
236
255
  this._determineFetchType(info, options, metaData);
256
+ fetchInfo.fetchType = info.fetchType;
257
+ fetchInfo.converter = info.converter;
237
258
  if (info.fetchType === types.DB_TYPE_CURSOR) {
238
259
  this.nestedCursorIndices.push(i);
239
260
  } else if (info.fetchType === types.DB_TYPE_CLOB ||
@@ -281,7 +302,9 @@ class ResultSetImpl extends BaseImpl {
281
302
  //---------------------------------------------------------------------------
282
303
  // _getAllRows() [INTERNAL]
283
304
  //
284
- // Fetches all the rows from the database to use internally.
305
+ // Fetches all the rows from the database to use internally. getRows()
306
+ // already materializes and consumes each batch, so this method only
307
+ // accumulates the returned rows.
285
308
  //---------------------------------------------------------------------------
286
309
  async _getAllRows() {
287
310
  const fetchArraySize = 100;
@@ -290,10 +313,8 @@ class ResultSetImpl extends BaseImpl {
290
313
  while (true) {
291
314
  // constant default value for fetchArraySize
292
315
  const rows = await this.getRows(fetchArraySize, {});
293
- if (rows) {
294
- await this._processRows(rows, false);
316
+ if (rows)
295
317
  rowsFetched = rowsFetched.concat(rows);
296
- }
297
318
  if (rows.length < fetchArraySize) {
298
319
  break;
299
320
  }
package/lib/oracledb.js CHANGED
@@ -66,6 +66,7 @@ const SodaCollection = require('./sodaCollection.js');
66
66
  const SodaDocCursor = require('./sodaDocCursor.js');
67
67
  const SodaDocument = require('./sodaDocument.js');
68
68
  const SodaOperation = require('./sodaOperation.js');
69
+ const securityContextProviderModule = require('./securityContextProvider.js');
69
70
  const EndUserSecurityContext = require('./endUserSecurityContext.js');
70
71
 
71
72
  const poolCache = {};
@@ -417,6 +418,12 @@ async function _verifyOptions(options, inCreatePool) {
417
418
  outOptions.appContext = options.appContext;
418
419
  }
419
420
 
421
+ // txnPriority must be a supported value
422
+ if (options.txnPriority !== undefined) {
423
+ errors.assertTxnPriority(options.txnPriority);
424
+ outOptions.txnPriority = options.txnPriority;
425
+ }
426
+
420
427
  // check pool specific options
421
428
  if (inCreatePool) {
422
429
 
@@ -631,6 +638,11 @@ async function createPool(options) {
631
638
  errors.throwWrapErr(error, errors.ERR_CALLOUT_FN);
632
639
  }
633
640
  }
641
+ // Connect-string parsing can rebuild the options object and omit internal
642
+ // fields. Preserve the hook-provided unified-security state before that.
643
+ const securityContextProviderForPool = options._securityContextProvider;
644
+ // This is driver-only state and must not be passed to the implementation.
645
+ delete options._securityContextProvider;
634
646
  options = await _updateUserOptionsFromConnectString(options, true);
635
647
  const sessionCallback = options.sessionCallback;
636
648
  if (typeof sessionCallback === 'function')
@@ -715,6 +727,7 @@ async function createPool(options) {
715
727
  }
716
728
 
717
729
  pool._setup(options, poolAlias);
730
+ pool._securityContextProvider = securityContextProviderForPool;
718
731
  pool._sessionCallback = sessionCallback;
719
732
  pool.on('_afterPoolClose', () => {
720
733
  if (pool.poolAlias) {
@@ -781,6 +794,9 @@ async function getConnection(a1) {
781
794
  errors.throwWrapErr(error, errors.ERR_CALLOUT_FN);
782
795
  }
783
796
  }
797
+ const securityContextProviderForConnection = options._securityContextProvider;
798
+ // This is driver-only state and must not be passed to the implementation.
799
+ delete options._securityContextProvider;
784
800
  // create a standalone connection
785
801
  options = await _updateUserOptionsFromConnectString(options, false);
786
802
  settings.addToOptions(options,
@@ -799,6 +815,7 @@ async function getConnection(a1) {
799
815
  }
800
816
  const conn = new Connection();
801
817
  conn._impl = new impl.ConnectionImpl();
818
+ conn._impl._securityContextProvider = securityContextProviderForConnection;
802
819
 
803
820
  conn._impl._connectString = options.connectString;
804
821
  conn._impl._user = options.user;
@@ -1213,6 +1230,16 @@ function registerConfigurationProviderHook(configProvider, fn) {
1213
1230
  registeredConfigProviderHooks[configProvider] = fn;
1214
1231
  }
1215
1232
 
1233
+ //-----------------------------------------------------------------------------
1234
+ // getSecurityContextProvider()
1235
+ //
1236
+ // Exposes the internal security context provider helpers without requiring
1237
+ // callers to reference the module path directly.
1238
+ //-----------------------------------------------------------------------------
1239
+ function getSecurityContextProvider() {
1240
+ return securityContextProviderModule;
1241
+ }
1242
+
1216
1243
  //-----------------------------------------------------------------------------
1217
1244
  // enquoteLiteral()
1218
1245
  //
@@ -1302,6 +1329,7 @@ module.exports = {
1302
1329
  createPool: nodbUtil.callbackify(nodbUtil.wrapFn(createPool)),
1303
1330
  getNetworkServiceNames: nodbUtil.callbackify(nodbUtil.wrapFn(getNetworkServiceNames)),
1304
1331
  getPool,
1332
+ getSecurityContextProvider,
1305
1333
  initOracleClient,
1306
1334
  isQualifiedSqlName,
1307
1335
  isSimpleSqlName,
@@ -1500,6 +1528,12 @@ module.exports = {
1500
1528
  ARRAY: constants.OUT_FORMAT_ARRAY,
1501
1529
  OBJECT: constants.OUT_FORMAT_OBJECT,
1502
1530
 
1531
+ // txnPriority
1532
+ TXN_PRIORITY_HIGH: constants.TXN_PRIORITY_HIGH,
1533
+ TXN_PRIORITY_MEDIUM: constants.TXN_PRIORITY_MEDIUM,
1534
+ TXN_PRIORITY_LOW: constants.TXN_PRIORITY_LOW,
1535
+ TXN_PRIORITY_DEFAULT: constants.TXN_PRIORITY_DEFAULT,
1536
+
1503
1537
  // Trace Interface
1504
1538
  traceHandler,
1505
1539
 
package/lib/pool.js CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2016, 2025, Oracle and/or its affiliates.
1
+ // Copyright (c) 2016, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -115,6 +115,7 @@ class Pool extends EventEmitter {
115
115
  this._user = options.user;
116
116
  this._connectString = options.connectString;
117
117
  this._status = constants.POOL_STATUS_OPEN;
118
+ // Current number of connections that are out for processing or being used
118
119
  this._connectionsOut = 0;
119
120
  this._poolAlias = poolAlias;
120
121
  this._bgRequestHandler();
@@ -514,6 +515,9 @@ class Pool extends EventEmitter {
514
515
  this._connectionsOut += 1;
515
516
  this._pendingRequestQueue.delete(request);
516
517
  conn._impl = await this._impl.getConnection(request.options);
518
+ // Each acquired connection uses the provider configured for this pool.
519
+ // Pools can have distinct Azure, OCI, or custom OBO configurations.
520
+ conn._impl._securityContextProvider = this._securityContextProvider;
517
521
  conn._pool = this;
518
522
  await this._tagFixup(conn, request.options.tag);
519
523
  if (request.isWaiting)
@@ -572,12 +576,12 @@ class Pool extends EventEmitter {
572
576
  // _processRequest' to decrease connectionsOut & wake up _bgRequestWaiter
573
577
  //---------------------------------------------------------------------------
574
578
  async _release(impl, options) {
575
- this._connectionsOut -= 1;
576
579
  try {
577
580
  // Directly close the connection using the underlying connection impl
578
581
  if (impl)
579
582
  await impl.close(options);
580
583
  } finally {
584
+ this._connectionsOut -= 1;
581
585
  if (this._connectionsOut == 0)
582
586
  this.emit('_allCheckedIn');
583
587
  setImmediate(() => {
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2015, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2015, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -31,10 +31,11 @@ const { Readable } = require('stream');
31
31
 
32
32
  class QueryStream extends Readable {
33
33
 
34
- constructor(rs) {
34
+ constructor(rs, rowsPerDataEvent = 1) {
35
35
  super({ objectMode: true });
36
36
  this._fetching = false;
37
37
  this._numRows = 0;
38
+ this._rowsPerDataEvent = rowsPerDataEvent;
38
39
 
39
40
  // calling open via process.nextTick to allow event handlers to be
40
41
  // registered prior to the events being emitted
@@ -95,10 +96,17 @@ class QueryStream extends Readable {
95
96
  // created via ResultSet.toQueryStream()
96
97
  try {
97
98
  this._fetching = true;
99
+ const rows = [];
98
100
  this._resultSet._allowGetRowCall = true;
99
- const row = await this._resultSet.getRow();
100
- if (row) {
101
- this.push(row);
101
+ for (let i = 0; i < this._rowsPerDataEvent; i++) {
102
+ const row = await this._resultSet.getRow();
103
+ if (!row)
104
+ break;
105
+ rows.push(row);
106
+ this._resultSet._allowGetRowCall = true;
107
+ }
108
+ if (rows.length > 0) {
109
+ this.push(this._rowsPerDataEvent === 1 ? rows[0] : rows);
102
110
  } else {
103
111
  this.push(null);
104
112
  }
package/lib/resultset.js CHANGED
@@ -341,8 +341,15 @@ class ResultSet {
341
341
  //
342
342
  // Converts a result set to a QueryStream object.
343
343
  //---------------------------------------------------------------------------
344
- toQueryStream() {
345
- errors.assertArgCount(arguments, 0, 0);
344
+ toQueryStream(options) {
345
+ errors.assertArgCount(arguments, 0, 1);
346
+ if (arguments.length == 1) {
347
+ errors.assertParamValue(nodbUtil.isObject(options), 1);
348
+ options = {...options};
349
+ } else {
350
+ options = {};
351
+ }
352
+ errors.assertParamPropUnsignedIntNonZero(options, 1, "rowsPerDataEvent");
346
353
 
347
354
  if (this._processingStarted) {
348
355
  errors.throwErr(errors.ERR_CANNOT_CONVERT_RS_TO_STREAM);
@@ -354,7 +361,7 @@ class ResultSet {
354
361
 
355
362
  this._convertedToStream = true;
356
363
 
357
- return new QueryStream(this);
364
+ return new QueryStream(this, options.rowsPerDataEvent);
358
365
  }
359
366
 
360
367
  [Symbol.asyncIterator]() {