oracledb 6.10.0 → 7.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 (84) hide show
  1. package/LICENSE.txt +1 -1
  2. package/NOTICE.txt +1 -1
  3. package/README.md +9 -9
  4. package/build/Release/oracledb-7.0.0-darwin-arm64.node +0 -0
  5. package/build/Release/oracledb-7.0.0-darwin-arm64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-7.0.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-7.0.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-7.0.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-7.0.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-7.0.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-7.0.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-7.0.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/eslint.config.js +39 -0
  14. package/lib/connection.js +412 -37
  15. package/lib/endUserSecurityContext.js +176 -0
  16. package/lib/errors.js +86 -5
  17. package/lib/impl/connection.js +76 -2
  18. package/lib/impl/datahandlers/buffer.js +19 -5
  19. package/lib/impl/datahandlers/vector.js +25 -5
  20. package/lib/impl/lob.js +9 -0
  21. package/lib/impl/parserHelpers.js +443 -0
  22. package/lib/impl/resultset.js +1 -1
  23. package/lib/lob.js +27 -14
  24. package/lib/obfuscation.js +97 -0
  25. package/lib/oracledb.js +148 -43
  26. package/lib/parser.js +204 -0
  27. package/lib/pipeline.js +113 -0
  28. package/lib/pool.js +16 -1
  29. package/lib/resultset.js +42 -21
  30. package/lib/settings.js +1 -0
  31. package/lib/thin/connection.js +467 -53
  32. package/lib/thin/dbObject.js +7 -1
  33. package/lib/thin/lob.js +20 -1
  34. package/lib/thin/pool.js +42 -62
  35. package/lib/thin/protocol/capabilities.js +18 -3
  36. package/lib/thin/protocol/constants.js +82 -2
  37. package/lib/thin/protocol/encryptDecrypt.js +43 -8
  38. package/lib/thin/protocol/messages/auth.js +6 -1
  39. package/lib/thin/protocol/messages/base.js +245 -4
  40. package/lib/thin/protocol/messages/dataType.js +8 -3
  41. package/lib/thin/protocol/messages/directPathLoadStream.js +377 -0
  42. package/lib/thin/protocol/messages/directPathOp.js +65 -0
  43. package/lib/thin/protocol/messages/directPathPrepare.js +158 -0
  44. package/lib/thin/protocol/messages/endPipeline.js +56 -0
  45. package/lib/thin/protocol/messages/execute.js +9 -7
  46. package/lib/thin/protocol/messages/index.js +9 -1
  47. package/lib/thin/protocol/messages/protocol.js +2 -2
  48. package/lib/thin/protocol/messages/withData.js +8 -140
  49. package/lib/thin/protocol/packet.js +115 -24
  50. package/lib/thin/protocol/protocol.js +110 -25
  51. package/lib/thin/protocol/utils.js +1 -26
  52. package/lib/thin/resultSet.js +13 -19
  53. package/lib/thin/sqlnet/ezConnectResolver.js +2 -2
  54. package/lib/thin/sqlnet/networkSession.js +62 -40
  55. package/lib/thin/sqlnet/ntTcp.js +24 -0
  56. package/lib/thin/sqlnet/nvStrToNvPair.js +50 -25
  57. package/lib/thin/sqlnet/packet.js +25 -4
  58. package/lib/thin/sqlnet/paramParser.js +10 -7
  59. package/lib/thin/statementCache.js +2 -4
  60. package/lib/traceHandler.js +59 -2
  61. package/lib/transformer.js +8 -3
  62. package/lib/types.js +35 -21
  63. package/lib/util.js +6 -6
  64. package/lib/version.js +3 -3
  65. package/package/install.js +5 -5
  66. package/package/prunebinaries.js +1 -1
  67. package/package.json +1 -1
  68. package/plugins/configProviders/awsCommon.js +125 -0
  69. package/plugins/configProviders/awss3/index.js +138 -0
  70. package/plugins/configProviders/awssecretsmanager/index.js +147 -0
  71. package/plugins/configProviders/azure/index.js +4 -5
  72. package/plugins/token/extensionAzure/index.js +0 -1
  73. package/plugins/token/extensionOci/index.js +0 -1
  74. package/build/Release/oracledb-6.10.0-darwin-arm64.node +0 -0
  75. package/build/Release/oracledb-6.10.0-darwin-arm64.node-buildinfo.txt +0 -1
  76. package/build/Release/oracledb-6.10.0-darwin-x64.node +0 -0
  77. package/build/Release/oracledb-6.10.0-darwin-x64.node-buildinfo.txt +0 -1
  78. package/build/Release/oracledb-6.10.0-js-buildinfo.txt +0 -1
  79. package/build/Release/oracledb-6.10.0-linux-arm64.node +0 -0
  80. package/build/Release/oracledb-6.10.0-linux-arm64.node-buildinfo.txt +0 -1
  81. package/build/Release/oracledb-6.10.0-linux-x64.node +0 -0
  82. package/build/Release/oracledb-6.10.0-linux-x64.node-buildinfo.txt +0 -1
  83. package/build/Release/oracledb-6.10.0-win32-x64.node +0 -0
  84. package/build/Release/oracledb-6.10.0-win32-x64.node-buildinfo.txt +0 -1
@@ -56,13 +56,13 @@ class ExecuteMessage extends MessageWithData {
56
56
  }
57
57
 
58
58
  //-------------------------------------------------------------------------
59
- // writeReExecuteMessage()
59
+ // writeExecuteMessage()
60
60
  //
61
61
  // Write the message for a full execute.
62
62
  //-------------------------------------------------------------------------
63
63
  writeExecuteMessage(buf) {
64
64
  let options = 0x0;
65
- let dmlOptions = 0;
65
+ let execFlags = 0;
66
66
  let numParams = 0;
67
67
  let numIters = 1;
68
68
  // Configuring the options field thats send to the server
@@ -70,7 +70,7 @@ class ExecuteMessage extends MessageWithData {
70
70
  const params = stmt.bindInfoList;
71
71
 
72
72
  if (this.noImplicitRelease) {
73
- dmlOptions |= constants.TNS_EXEC_OPTION_NO_IMPL_REL;
73
+ execFlags |= constants.TNS_EXEC_OPTION_NO_IMPL_REL;
74
74
  }
75
75
 
76
76
  if (!stmt.requiresDefine && !this.parseOnly && params) {
@@ -79,7 +79,7 @@ class ExecuteMessage extends MessageWithData {
79
79
  if (stmt.requiresDefine) {
80
80
  options |= constants.TNS_EXEC_OPTION_DEFINE;
81
81
  } else if (!this.parseOnly && stmt.sql) {
82
- dmlOptions |= constants.TNS_EXEC_OPTION_IMPLICIT_RESULTSET;
82
+ execFlags |= constants.TNS_EXEC_OPTION_IMPLICIT_RESULTSET;
83
83
  options |= constants.TNS_EXEC_OPTION_EXECUTE;
84
84
  }
85
85
  if (stmt.cursorId === 0 || stmt.isDdl) {
@@ -111,7 +111,7 @@ class ExecuteMessage extends MessageWithData {
111
111
  options |= constants.TNS_EXEC_OPTION_BATCH_ERRORS;
112
112
  }
113
113
  if (this.arrayDmlRowCounts) {
114
- dmlOptions |= constants.TNS_EXEC_OPTION_DML_ROWCOUNTS;
114
+ execFlags |= constants.TNS_EXEC_OPTION_DML_ROWCOUNTS;
115
115
  }
116
116
  if (this.options.autoCommit) {
117
117
  options |= constants.TNS_EXEC_OPTION_COMMIT;
@@ -213,7 +213,7 @@ class ExecuteMessage extends MessageWithData {
213
213
  buf.writeUB4(0); // al8i4[6] SCN (part 2)
214
214
  buf.writeUB4((stmt.isQuery) ? 1 : 0); // al8i4[7] is query
215
215
  buf.writeUB4(0); // al8i4[8]
216
- buf.writeUB4(dmlOptions); // al8i4[9] DML row counts/implicit
216
+ buf.writeUB4(execFlags); // al8i4[9] DML row counts/implicit
217
217
  buf.writeUB4(0); // al8i4[10]
218
218
  buf.writeUB4(0); // al8i4[11]
219
219
  buf.writeUB4(0); // al8i4[12]
@@ -321,7 +321,9 @@ class ExecuteMessage extends MessageWithData {
321
321
  // no rows have yet been sent so the header information needs to be sent
322
322
  if (this.currentRow === 0) {
323
323
  const stmt = this.statement;
324
- if (stmt.cursorId !== 0 && !stmt.requiresFullExecute && !this.parseOnly && !stmt.requiresDefine && !stmt.noPrefetch && !stmt.isDdl && !this.batchErrors) {
324
+ if (stmt.cursorId !== 0 && !stmt.requiresFullExecute && !this.parseOnly
325
+ && !stmt.requiresDefine && !stmt.noPrefetch && !stmt.isDdl
326
+ && !this.batchErrors) {
325
327
  if (stmt.isQuery && this.options.prefetchRows > 0) {
326
328
  this.functionCode = constants.TNS_FUNC_REEXECUTE_AND_FETCH;
327
329
  } else {
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2023, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -29,7 +29,11 @@
29
29
  const AuthMessage = require('./auth.js');
30
30
  const CommitMessage = require('./commit.js');
31
31
  const DataTypeMessage = require('./dataType.js');
32
+ const DirectPathPrepareMessage = require('./directPathPrepare.js');
33
+ const DirectPathLoadStreamMessage = require('./directPathLoadStream.js');
34
+ const DirectPathOpMessage = require('./directPathOp.js');
32
35
  const ExecuteMessage = require('./execute.js');
36
+ const EndPipelineMessage = require('./endPipeline.js');
33
37
  const FetchMessage = require('./fetch.js');
34
38
  const LobOpMessage = require('./lobOp.js');
35
39
  const LogOffMessage = require('./logOff.js');
@@ -46,7 +50,11 @@ module.exports = {
46
50
  CommitMessage,
47
51
  FastAuthMessage,
48
52
  DataTypeMessage,
53
+ DirectPathPrepareMessage,
54
+ DirectPathLoadStreamMessage,
55
+ DirectPathOpMessage,
49
56
  ExecuteMessage,
57
+ EndPipelineMessage,
50
58
  FetchMessage,
51
59
  LobOpMessage,
52
60
  LogOffMessage,
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -63,7 +63,7 @@ class ProtocolMessage extends Message {
63
63
  this.serverVersion = buf.readUInt8();
64
64
  buf.skipUB1();
65
65
  this.serverBanner = buf.readNullTerminatedBytes(48);
66
- buf.caps.charSetID = buf.readUInt16LE();
66
+ buf.caps.charsetId = buf.readUInt16LE();
67
67
  this.serverFlags = buf.readUInt8();
68
68
  const num_elem = buf.readUInt16LE();
69
69
  if (num_elem > 0) { // skip elements
@@ -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
  //
@@ -58,6 +58,7 @@ class MessageWithData extends Message {
58
58
  this.parseOnly = false;
59
59
  this.resultSetsToSetup = [];
60
60
  this.deferredErr = null;
61
+ this.postProcessDone = false;
61
62
  }
62
63
 
63
64
  /**
@@ -189,145 +190,6 @@ class MessageWithData extends Message {
189
190
  this.resultSetsToSetup.push(resultSet);
190
191
  }
191
192
 
192
- processColumnInfo(buf, columnNum) {
193
- const dataType = buf.readUInt8();
194
- buf.skipUB1(); // flags
195
- const precision = buf.readInt8();
196
- const scale = buf.readInt8();
197
- const maxSize = buf.readUB4();
198
- buf.skipUB4(); // max number of array elements
199
- buf.skipUB8(); // cont flags
200
- let oid;
201
- let numBytes = buf.readUB4(); // OID
202
- if (numBytes > 0) {
203
- oid = Buffer.from(buf.readBytesWithLength());
204
- }
205
- buf.skipUB2(); // version
206
- buf.skipUB2(); // character set id
207
- const csfrm = buf.readUInt8(); // character set form
208
- let size = buf.readUB4();
209
- if (dataType === constants.TNS_DATA_TYPE_RAW) {
210
- size = maxSize;
211
- }
212
- if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_12_2) {
213
- buf.skipUB4(); // oaccolid
214
- }
215
- const nullable = Boolean(buf.readUInt8());
216
- buf.skipUB1(); // v7 length of name
217
- let name;
218
- numBytes = buf.readUB4();
219
- if (numBytes > 0) {
220
- name = buf.readStr(constants.CSFRM_IMPLICIT);
221
- }
222
- let schema;
223
- numBytes = buf.readUB4();
224
- if (numBytes > 0) {
225
- schema = buf.readStr(constants.CSFRM_IMPLICIT);
226
- }
227
- numBytes = buf.readUB4();
228
- let typeName;
229
- if (numBytes > 0) {
230
- typeName = buf.readStr(constants.CSFRM_IMPLICIT);
231
- }
232
- buf.skipUB2(); // column position
233
- const udsFlags = buf.readUB4(); // uds flag
234
-
235
- // build metadata
236
- const fetchInfo = {
237
- name: name,
238
- dbColumnName: name,
239
- dbType: types.getTypeByOraTypeNum(dataType, csfrm),
240
- nullable: nullable
241
- };
242
- fetchInfo.isJson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_JSON);
243
- fetchInfo.isOson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_OSON);
244
- if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) {
245
- numBytes = buf.readUB4();
246
- if (numBytes > 0) {
247
- fetchInfo.domainSchema = buf.readStr(constants.CSFRM_IMPLICIT);
248
- }
249
- numBytes = buf.readUB4();
250
- if (numBytes > 0) {
251
- fetchInfo.domainName = buf.readStr(constants.CSFRM_IMPLICIT);
252
- }
253
- }
254
- if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1_EXT_3) {
255
- if (buf.readUB4() > 0) {
256
- fetchInfo.annotations = {};
257
- buf.skipUB1();
258
- const numAnnotations = buf.readUB4();
259
- buf.skipUB1();
260
- let key, value;
261
- for (let i = 0; i < numAnnotations; i++) {
262
- buf.skipUB4();
263
- value = "";
264
- key = buf.readStr(constants.CSFRM_IMPLICIT);
265
- numBytes = buf.readUB4();
266
- if (numBytes > 0) {
267
- value = buf.readStr(constants.CSFRM_IMPLICIT);
268
- }
269
- fetchInfo.annotations[key] = value;
270
- buf.skipUB4(); // flags
271
- }
272
- buf.skipUB4(); // flags
273
- }
274
- }
275
- if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_4) {
276
- const dimensions = buf.readUB4();
277
- const vectorFormat = buf.readUInt8();
278
- const vectorFlags = buf.readUInt8();
279
- if (fetchInfo.dbType === types.DB_TYPE_VECTOR) {
280
- if (!(vectorFlags & constants.VECTOR_META_FLAG_FLEXIBLE_DIM)) {
281
- fetchInfo.vectorDimensions = dimensions;
282
- }
283
- fetchInfo.isSparseVector = Boolean(vectorFlags & constants.VECTOR_META_FLAG_SPARSE);
284
- if (vectorFormat !== constants.VECTOR_FORMAT_FLEX) {
285
- fetchInfo.vectorFormat = vectorFormat;
286
- }
287
- }
288
- }
289
-
290
- switch (fetchInfo.dbType) {
291
- case types.DB_TYPE_VARCHAR:
292
- case types.DB_TYPE_NVARCHAR:
293
- case types.DB_TYPE_CHAR:
294
- case types.DB_TYPE_NCHAR:
295
- case types.DB_TYPE_RAW:
296
- fetchInfo.byteSize = size;
297
- break;
298
- case types.DB_TYPE_NUMBER:
299
- fetchInfo.precision = precision;
300
- break;
301
- case types.DB_TYPE_TIMESTAMP:
302
- case types.DB_TYPE_TIMESTAMP_TZ:
303
- case types.DB_TYPE_TIMESTAMP_LTZ:
304
- fetchInfo.precision = scale;
305
- break;
306
- case types.DB_TYPE_OBJECT:
307
- fetchInfo.dbTypeClass = this.connection._getDbObjectType(schema,
308
- typeName, undefined, oid);
309
- if (fetchInfo.dbTypeClass.partial) {
310
- this.connection._partialDbObjectTypes.push(fetchInfo.dbTypeClass);
311
- }
312
- if (fetchInfo.dbTypeClass.isXmlType) {
313
- fetchInfo.dbType = types.DB_TYPE_XMLTYPE;
314
- }
315
- break;
316
- default:
317
- break;
318
- }
319
- if (fetchInfo.dbType === types.DB_TYPE_NUMBER) {
320
- fetchInfo.scale = scale;
321
- }
322
- return {
323
- fetchInfo: fetchInfo,
324
- type: fetchInfo.dbType,
325
- maxSize: maxSize,
326
- columnNum: columnNum,
327
- values: new Array(this.options.fetchArraySize)
328
- };
329
- }
330
-
331
193
  processRowHeader(buf) {
332
194
  buf.skipUB1(); // flags
333
195
  buf.skipUB2(); // num requests
@@ -607,10 +469,16 @@ class MessageWithData extends Message {
607
469
  }
608
470
 
609
471
  async postProcess() {
472
+ if (this.postProcessDone) {
473
+ return;
474
+ }
475
+
610
476
  if (this.deferredErr) {
611
477
  throw this.deferredErr;
612
478
  }
613
479
 
480
+ this.postProcessDone = true;
481
+
614
482
  if (this.outVariables) {
615
483
  for (const variable of this.outVariables) {
616
484
  if (variable.isArray) {
@@ -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
  //
@@ -35,8 +35,6 @@ const vector = require('../../impl/datahandlers/vector.js');
35
35
  const errors = require("../../errors.js");
36
36
 
37
37
  const TNS_BASE64_ALPHABET_ARRAY = Buffer.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 'utf8');
38
- const FAST_AUTH_END_OF_RPC_VALUE = 0x800;
39
- const FAST_AUTH_END_OF_RPC_OFFSET = 0x8;
40
38
  const MSG_TYPE_OFFSET = 11;
41
39
 
42
40
  /**
@@ -161,7 +159,7 @@ class ReadPacket extends BaseBuffer {
161
159
  return this.readBytes(numBytes);
162
160
  }
163
161
  this.chunkedBytesBuf.startChunkedRead();
164
- while (true) { // eslint-disable-line
162
+ while (true) {
165
163
  const numBytesInChunk = this.readUB4();
166
164
  if (numBytesInChunk === 0) {
167
165
  break;
@@ -293,6 +291,51 @@ class ReadPacket extends BaseBuffer {
293
291
  this.packetNum = packet.num;
294
292
  }
295
293
 
294
+ /**
295
+ * It is used in pipeline mode to ignore reading packets
296
+ * if client detects a protocol error.
297
+ */
298
+ resetPackets() {
299
+ this.savedPackets = [];
300
+ this.savedPacketPos = 0;
301
+ this.savedPos = 0;
302
+ }
303
+
304
+ /**
305
+ * Discards the remaining responses after the pipeline has
306
+ * encountered an exception in ABORT_ON_ERROR mode
307
+ */
308
+ async discardPipelineResponses(num) {
309
+ while (num > 0) {
310
+ await this.waitForPackets(true);
311
+ num--;
312
+ }
313
+ this.resetPackets();
314
+ }
315
+
316
+ _isEndOfResponse(packet) {
317
+ // In pipeline mode, when a DML operation fails due to invalid RETURNING
318
+ // binds, we may receive a partial response followed by a break packet
319
+ // before the full response arrives. Such break packets are ignored.
320
+ //
321
+ // In non-pipeline mode, return true if the packet is not a data packet.
322
+ if (packet.type !== constants.TNS_PACKET_TYPE_DATA) {
323
+ return !this.nsi.pipelineEnabled;
324
+ }
325
+
326
+ // End-of-response marker
327
+ if (packet.buf.readUInt16BE(8) &
328
+ constants.TNS_DATA_FLAGS_END_OF_RESPONSE) {
329
+ return true;
330
+ }
331
+
332
+ // Single-byte 1D packet
333
+ return (
334
+ packet.buf.length === MSG_TYPE_OFFSET &&
335
+ packet.buf[MSG_TYPE_OFFSET - 1] === constants.TNS_MSG_TYPE_END_OF_REQUEST
336
+ );
337
+ }
338
+
296
339
  /**
297
340
  * Read packets from network.
298
341
  * If checkRequestBoundary is passed as true, it
@@ -308,21 +351,24 @@ class ReadPacket extends BaseBuffer {
308
351
  this.savedPackets.push(packet);
309
352
  }
310
353
  if (checkRequestBoundary && this.nsi.endOfRequestSupport) {
311
- while (packet.type === constants.TNS_PACKET_TYPE_DATA) {
312
- // End Marker
313
- if ((packet.buf.readUInt16BE(8) &
314
- constants.TNS_DATA_FLAGS_END_OF_REQUEST)) {
315
- break;
354
+ while (!this._isEndOfResponse(packet)) {
355
+ if (
356
+ packet.type !== constants.TNS_PACKET_TYPE_DATA &&
357
+ this.nsi.isBreak
358
+ ) {
359
+ // For pipeline Mode only, we issue a dummy reset to the sqlnet layer
360
+ // to set state, `this.isBreak = this.isReset = false;`
361
+ await this.nsi.reset();
362
+
363
+ this.resetPackets();
316
364
  }
317
365
 
318
- // Single Byte 1D packet
319
- if (packet.buf.length === MSG_TYPE_OFFSET &&
320
- packet.buf[MSG_TYPE_OFFSET - 1] ===
321
- constants.TNS_MSG_TYPE_END_OF_REQUEST) {
322
- break;
323
- }
366
+ // Read new packet.
324
367
  packet = await this.nsi.recvPacket();
325
- this.savedPackets.push(packet);
368
+
369
+ if (!this.nsi.isBreak) {
370
+ this.savedPackets.push(packet);
371
+ }
326
372
  }
327
373
  }
328
374
  this.startPacket(this.savedPackets[this.savedPacketPos++]);
@@ -447,7 +493,7 @@ class ReadPacket extends BaseBuffer {
447
493
  if (numBytes !== constants.TNS_LONG_LENGTH_INDICATOR) {
448
494
  this.skipBytes(numBytes);
449
495
  } else {
450
- while (true) { // eslint-disable-line
496
+ while (true) {
451
497
  const tempNumBytes = this.readUB4();
452
498
  if (tempNumBytes === 0)
453
499
  break;
@@ -491,6 +537,33 @@ class WritePacket extends BaseBuffer {
491
537
  this.packetType = constants.TNS_PACKET_TYPE_DATA;
492
538
  this.caps = caps;
493
539
  this.nsi = nsi;
540
+ this._dataFlags = 0;
541
+ this.tokenNum = 0;
542
+ }
543
+
544
+ _asBuffer(input) {
545
+ if (Buffer.isBuffer(input)) {
546
+ return input;
547
+ }
548
+ if (typeof input === 'string') {
549
+ return Buffer.from(input);
550
+ }
551
+ errors.throwErr(errors.ERR_INTERNAL, 'Expected Buffer or string');
552
+ }
553
+
554
+ // Writes a 32-bit length, writeUB4 followed by the field if present.
555
+ // For Null input, We just write length as 0.
556
+ _writeBytesWithTwoLengths(input) {
557
+ if (input == null) {
558
+ this.writeUB4(0);
559
+ return;
560
+ }
561
+ const buf = this._asBuffer(input);
562
+ const length = buf.length;
563
+ this.writeUB4(length);
564
+ if (length > 0) {
565
+ this.writeBytesWithLength(buf);
566
+ }
494
567
  }
495
568
 
496
569
  /**
@@ -518,37 +591,48 @@ class WritePacket extends BaseBuffer {
518
591
  this.writeUInt8(this.packetType);
519
592
  this.writeUInt8(0);
520
593
  this.writeUInt16BE(0);
594
+ let flags = this._dataFlags;
521
595
  let buf = this.buf.subarray(0, size);
522
596
  if (!finalPacket) {
523
597
  buf = Buffer.from(buf);
524
598
  this.startPacket();
525
599
  } else {
526
- // Write End of RPC bit in last packet used only for fastAuth Message.
527
- this.buf.writeUInt16BE(FAST_AUTH_END_OF_RPC_VALUE,
528
- FAST_AUTH_END_OF_RPC_OFFSET);
600
+ if (this.nsi.pipelineEnabled) {
601
+ // For pipeline mode, next operation would start writing
602
+ // into this.buf. Hence create a copy so that it wont
603
+ // overwrite the contents given to stream.write().
604
+ buf = Buffer.from(buf);
605
+ }
606
+ // Write End of RPC bit in last packet used only for fastAuth Message
607
+ // and in pipeline mode.
608
+ flags |= constants.TNS_DATA_FLAGS_END_OF_REQUEST;
529
609
  }
530
610
  if (!this.nsi.ntAdapter) {
531
611
  errors.throwErr(errors.ERR_INVALID_CONNECTION);
532
612
  }
613
+ if (this.packetType === constants.TNS_PACKET_TYPE_DATA) {
614
+ buf.writeUInt16BE(flags, constants.TNS_DATA_FLAGS_OFFSET);
615
+ }
533
616
  this.nsi.sendPacket(buf);
534
617
  }
535
618
 
536
619
  /**
537
620
  * Starts a packet.
538
621
  */
539
- startPacket(dataFlags = 0) {
622
+ startPacket() {
540
623
  this.pos = constants.PACKET_HEADER_SIZE;
541
624
  if (this.packetType === constants.TNS_PACKET_TYPE_DATA) {
542
- this.writeUInt16BE(dataFlags);
625
+ this.writeUInt16BE(this._dataFlags);
543
626
  }
544
627
  }
545
628
 
546
629
  /**
547
630
  * Starts a database request.
548
631
  */
549
- startRequest(packetType, dataFlags = 0) {
632
+ startRequest(packetType) {
550
633
  this.packetType = packetType;
551
- this.startPacket(dataFlags);
634
+ this._dataFlags = 0;
635
+ this.startPacket();
552
636
  }
553
637
 
554
638
  /**
@@ -572,6 +656,13 @@ class WritePacket extends BaseBuffer {
572
656
  this.writeUB4(flags);
573
657
  }
574
658
 
659
+ writeStrKeywordValuePair(key, valueBytes, flags = 0, text) {
660
+ this.writeUB4(flags);
661
+ this._writeBytesWithTwoLengths(key);
662
+ this._writeBytesWithTwoLengths(text);
663
+ this._writeBytesWithTwoLengths(valueBytes);
664
+ }
665
+
575
666
  /**
576
667
  * Encodes a JavaScript object into OSON and then writes it (QLocator
577
668
  * followed by data) to the buffer.
@@ -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
  //
@@ -69,7 +69,7 @@ class Protocol {
69
69
  async _decodeMessage(message) {
70
70
  message.preProcess();
71
71
  await this.readBuf.waitForPackets(true);
72
- while (true) { // eslint-disable-line
72
+ while (true) {
73
73
  if (this.nsi.isBreak) {
74
74
  await this.resetMessage();
75
75
  delete this.readBuf.savedPackets;
@@ -89,7 +89,31 @@ class Protocol {
89
89
  throw (err);
90
90
  }
91
91
  }
92
- await message.postProcess();
92
+ }
93
+
94
+ async _processPipelineMessage(messageObj, connImpl, continueOnError) {
95
+ let opProcessed = false;
96
+ const { message } = messageObj;
97
+ await this.readBuf.waitForPackets(true);
98
+ try {
99
+ message.preProcess();
100
+ message.decode(this.readBuf);
101
+ opProcessed = true;
102
+ this._checkAndRaiseException(message);
103
+ } catch (err) {
104
+ if (!opProcessed && !this.connInProgress &&
105
+ err.code !== errors.ERR_CONNECTION_CLOSED_CODE) {
106
+ this.readBuf.resetPackets();
107
+ }
108
+ if (messageObj.statement)
109
+ connImpl._returnStatement(messageObj.statement);
110
+ if (!continueOnError) {
111
+ err.opProcessed = opProcessed;
112
+ throw (err);
113
+ }
114
+ messageObj.pipelineResultImpl.error = err;
115
+ }
116
+ return opProcessed;
93
117
  }
94
118
 
95
119
  /**
@@ -112,6 +136,59 @@ class Protocol {
112
136
  this.writeBuf.endRequest();
113
137
  }
114
138
 
139
+ _raiseException(message) {
140
+ let err = new Error(message.errorInfo.message);
141
+ err.offset = message.errorInfo.pos;
142
+ err.errorNum = message.errorInfo.num;
143
+ err.isRecoverable = message.errorInfo.isRecoverable;
144
+ err = errors.transformErr(err);
145
+ if (err.code === errors.ERR_CONNECTION_CLOSED_CODE) {
146
+ this.nsi.disconnect();
147
+ }
148
+ throw err;
149
+ }
150
+
151
+ _checkAndRaiseException(message) {
152
+ if (message.errorOccurred) {
153
+ this._raiseException(message);
154
+ }
155
+ }
156
+ /**
157
+ * Called when all messages for the pipeline have been sent to the
158
+ * database. An end pipeline message is sent to the database and then
159
+ * the responses to all of the messages are processed.
160
+ */
161
+ async endPipeline(messagesForPipeline, endMessage, connImpl,
162
+ continueOnError) {
163
+ await this._encodeMessage(endMessage);
164
+
165
+ // required for cleanup of response packets
166
+ let numResponsesToDiscard = messagesForPipeline.length + 1;
167
+ try {
168
+ for (const messageObj of messagesForPipeline) {
169
+ const opProcessed = await this._processPipelineMessage(
170
+ messageObj, connImpl, continueOnError);
171
+ if (opProcessed)
172
+ numResponsesToDiscard--;
173
+ }
174
+
175
+ // Process the final message
176
+ await this.readBuf.waitForPackets(true);
177
+ endMessage.process(this.readBuf);
178
+ this._checkAndRaiseException(endMessage);
179
+ numResponsesToDiscard = 0;
180
+
181
+ } catch (err) {
182
+
183
+ // If an operation response was already consumed before failure, account
184
+ // for it before discarding the remaining pipeline responses.
185
+ if (err.opProcessed)
186
+ numResponsesToDiscard--;
187
+ await this.readBuf.discardPipelineResponses(numResponsesToDiscard);
188
+ throw (err);
189
+ }
190
+ }
191
+
115
192
  async _recoverFromError(caughtErr, message) {
116
193
  /*
117
194
  * We have NJS error(protocol related) detected during packet write/read
@@ -119,11 +196,16 @@ class Protocol {
119
196
  * response as ORA-1013 from the server.
120
197
  */
121
198
  try {
122
- this.breakMessage();
123
- this._breakInProgress = false;
124
- await this.resetMessage();
125
- await this.readBuf.waitForPackets();
126
- message.decode(this.readBuf);
199
+ if (message.isPipeline) {
200
+ // We just cleanup all pending response packets
201
+ this.readBuf.resetPackets();
202
+ } else {
203
+ this.breakMessage();
204
+ this._breakInProgress = false;
205
+ await this.resetMessage();
206
+ await this.readBuf.waitForPackets();
207
+ message.decode(this.readBuf);
208
+ }
127
209
  } catch (err) { // Recovery failed
128
210
  this.nsi.disconnect();
129
211
  const newErr = errors.getErr(errors.ERR_CONNECTION_CLOSED);
@@ -134,6 +216,18 @@ class Protocol {
134
216
  }
135
217
  }
136
218
 
219
+ async _processCallStatus(message) {
220
+ if (message.flushOutBinds) {
221
+ await this.flushOutBindMessage(message);
222
+ }
223
+ this.txnInProgress = Boolean(message.callStatus &
224
+ constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
225
+ // processes the call status flags returned by the server.
226
+ if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
227
+ message.connection.statementCache.clearCursors();
228
+ }
229
+ }
230
+
137
231
  /**
138
232
  *
139
233
  * @param {object} message The RPC dynamic structure specific to the RPC
@@ -159,6 +253,11 @@ class Protocol {
159
253
  if (traceEnabled) {
160
254
  traceContext.operation = `oracledb.${message.constructor.name}`;
161
255
  traceInstance.onBeginRoundTrip(traceContext);
256
+ if (traceContext.userContext?.traceParent) {
257
+ // The traceParent is set from instrumentation module.
258
+ message.connection.appContext('CLIENTCONTEXT',
259
+ [{ ora$opentelem$tracectx: traceContext.userContext.traceParent }]);
260
+ }
162
261
  }
163
262
  await this._encodeMessage(message);
164
263
  if (message.messageType !== constants.TNS_MSG_TYPE_ONEWAY_FN) {
@@ -184,14 +283,7 @@ class Protocol {
184
283
  traceInstance.onEndRoundTrip(traceContext);
185
284
  }
186
285
  }
187
- if (message.flushOutBinds) {
188
- await this.flushOutBindMessage(message);
189
- }
190
- this.txnInProgress = Boolean(message.callStatus & constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
191
- // processes the call status flags returned by the server.
192
- if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
193
- message.connection.statementCache.clearCursors();
194
- }
286
+ await this._processCallStatus(message);
195
287
 
196
288
  if (message.errorOccurred) {
197
289
  if (callTimeoutExpired) {
@@ -201,16 +293,9 @@ class Protocol {
201
293
  message.errorOccurred = false;
202
294
  return await this._processMessage(message);
203
295
  }
204
- let err = new Error(message.errorInfo.message);
205
- err.offset = message.errorInfo.pos;
206
- err.errorNum = message.errorInfo.num;
207
- err.isRecoverable = message.errorInfo.isRecoverable;
208
- err = errors.transformErr(err);
209
- if (err.code === errors.ERR_CONNECTION_CLOSED_CODE) {
210
- this.nsi.disconnect();
211
- }
212
- throw err;
296
+ this._raiseException(message);
213
297
  }
298
+ await message.postProcess();
214
299
  }
215
300
 
216
301
  async flushOutBindMessage(message) {