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
@@ -45,10 +45,18 @@ class Capabilities {
45
45
  this.charsetId = constants.TNS_CHARSET_UTF8;
46
46
  this.compileCaps = Buffer.alloc(constants.TNS_CCAP_MAX);
47
47
  this.runtimeCaps = Buffer.alloc(constants.TNS_RCAP_MAX);
48
+ this.dbTzOffset = null;
49
+
50
+ // Region-form DBTIMEZONE values are represented by an Oracle region ID in
51
+ // TTC. dbTzRegion holds the corresponding name obtained from DBTIMEZONE
52
+ // so LTZ operations can report that this unsupported configuration is used.
53
+ this.dbTzRegion = null;
48
54
  this.initCompileCaps(nscon);
49
55
  this.initRuntimeCaps();
50
56
  this.maxStringSize = 0;
51
57
  this.supportsEndUserSecurityContext = false;
58
+ this.supportsServerOtelTracing = false;
59
+ this.supportsTxnPriority = false;
52
60
  }
53
61
 
54
62
  adjustForServerCompileCaps(serverCaps, nscon) {
@@ -65,18 +73,34 @@ class Capabilities {
65
73
  nscon.endOfRequestSupport = false;
66
74
  }
67
75
  const bpIndex = constants.TNS_CCAP_FEATURE_BACKPORT2;
68
- if (bpIndex < serverCaps.length &&
69
- (serverCaps[bpIndex] & constants.TNS_CCAP_END_USER_SEC_CTX_PIGGYBACK)) {
70
- this.supportsEndUserSecurityContext = true;
76
+ if (bpIndex < serverCaps.length) {
77
+ if (serverCaps[bpIndex] & constants.TNS_CCAP_END_USER_SEC_CTX_PIGGYBACK) {
78
+ this.supportsEndUserSecurityContext = true;
79
+ }
80
+ if (serverCaps[bpIndex] &
81
+ constants.TNS_CCAP_TXN_PRIORITY_ALTSESS) {
82
+ this.supportsTxnPriority = true;
83
+ }
71
84
  }
72
85
  }
73
86
 
74
87
  adjustForServerRuntimeCaps(serverCaps) {
88
+ // TZ_EX adds timezone fields to the TTIDTY request and response. Only
89
+ // advertise it when TTIPRO confirms that the server understands those
90
+ // fields; otherwise datatype negotiation would be decoded out of sync.
91
+ if (serverCaps.length <= constants.TNS_RCAP_TZ ||
92
+ !(serverCaps[constants.TNS_RCAP_TZ] & constants.TNS_RCAP_TZ_EX)) {
93
+ this.runtimeCaps[constants.TNS_RCAP_TZ] = 0;
94
+ }
75
95
  if (serverCaps[constants.TNS_RCAP_TTC] & constants.TNS_RCAP_TTC_32K) {
76
96
  this.maxStringSize = 32767;
77
97
  } else {
78
98
  this.maxStringSize = 4000;
79
99
  }
100
+ this.supportsServerOtelTracing =
101
+ constants.TNS_RCAP_OTEL < serverCaps.length &&
102
+ (serverCaps[constants.TNS_RCAP_OTEL] &
103
+ constants.TNS_RCAP_OTEL_SUPPORTED) !== 0;
80
104
  }
81
105
 
82
106
  initCompileCaps(nscon) {
@@ -134,13 +158,16 @@ class Capabilities {
134
158
  constants.TNS_CCAP_PIPELINING_SUPPORT |
135
159
  constants.TNS_CCAP_PIPELINING_BREAK |
136
160
  constants.TNS_CCAP_TTC5_SESSIONLESS_TXNS;
161
+ this.compileCaps[constants.TNS_CCAP_FEATURE_BACKPORT2] =
162
+ constants.TNS_CCAP_TXN_PRIORITY_ALTSESS |
163
+ constants.TNS_CCAP_END_USER_SEC_CTX_PIGGYBACK;
137
164
  this.compileCaps[constants.TNS_CCAP_VECTOR_FEATURES] =
138
165
  constants.TNS_CCAP_VECTOR_FEATURE_BINARY | constants.TNS_CCAP_VECTOR_FEATURE_SPARSE;
139
- this.compileCaps[constants.TNS_CCAP_FEATURE_BACKPORT2] = constants.TNS_CCAP_END_USER_SEC_CTX_PIGGYBACK;
140
166
  }
141
167
 
142
168
  initRuntimeCaps() {
143
169
  this.runtimeCaps[constants.TNS_RCAP_COMPAT] = constants.TNS_RCAP_COMPAT_81;
170
+ this.runtimeCaps[constants.TNS_RCAP_TZ] = constants.TNS_RCAP_TZ_EX;
144
171
  this.runtimeCaps[constants.TNS_RCAP_TTC] =
145
172
  constants.TNS_RCAP_TTC_ZERO_COPY | constants.TNS_RCAP_TTC_32K;
146
173
  }
@@ -155,6 +182,12 @@ class Capabilities {
155
182
  errors.throwErr(errors.ERR_CHAR_CS_NOT_SUPPORTED, this.charsetId);
156
183
  }
157
184
 
185
+ assertTxnPrioritySupported() {
186
+ if (!this.supportsTxnPriority) {
187
+ errors.throwErr(errors.ERR_TXN_PRIORITY_NOT_SUPPORTED);
188
+ }
189
+ }
190
+
158
191
  }
159
192
 
160
193
  module.exports = Capabilities;
@@ -411,6 +411,7 @@ module.exports = {
411
411
  TNS_DATA_TYPE_PLBGN: 661,
412
412
  TNS_DATA_TYPE_UDS: 663,
413
413
  TNS_DATA_TYPE_PLOP: 665,
414
+ TNS_DATA_TYPE_ALTSESS: 668,
414
415
  TNS_DATA_TYPE_KVE: 669,
415
416
  TNS_DATA_TYPE_EUSC: 670,
416
417
 
@@ -429,6 +430,7 @@ module.exports = {
429
430
  TNS_MSG_TYPE_PARAMETER: 8,
430
431
  TNS_MSG_TYPE_STATUS: 9,
431
432
  TNS_MSG_TYPE_IO_VECTOR: 11,
433
+ TNS_MSG_TYPE_OAC: 13,
432
434
  TNS_MSG_TYPE_LOB_DATA: 14,
433
435
  TNS_MSG_TYPE_WARNING: 15,
434
436
  TNS_MSG_TYPE_DESCRIBE_INFO: 16,
@@ -449,6 +451,16 @@ module.exports = {
449
451
  TNS_KEYWORD_NUM_TRANSACTION_ID: 201,
450
452
  TNS_KEYWORD_PDBNAME: 197, // Container Name
451
453
  TNS_KEYWORD_DBNAME: 179, // Global DB Name
454
+ TNS_KEYWORD_MODULE: 184,
455
+ TNS_KEYWORD_ACTION: 185,
456
+ TNS_KEYWORD_CLIENT_INFO: 186,
457
+ TNS_KEYWORD_CLIENT_ID: 198,
458
+ TNS_KEYWORD_NUM_TXN_PRIORITY: 204,
459
+
460
+ // key/value flags
461
+ // Empty txnPriority uses the same reset semantics as OCI
462
+ // KPD_TXNPROP_PRI_RESET.
463
+ TNS_KVAL_FLAG_TXN_PRIORITY_DEFAULT: 0x0001,
452
464
 
453
465
  // bind flags
454
466
  TNS_BIND_USE_INDICATORS: 0x0001,
@@ -538,9 +550,12 @@ module.exports = {
538
550
  // end-to-end metrics
539
551
  TNS_END_TO_END_ACTION: 0x0010,
540
552
  TNS_END_TO_END_CLIENT_IDENTIFIER: 0x0001,
553
+ TNS_END_TO_END_ECID: 0x0020,
541
554
  TNS_END_TO_END_CLIENT_INFO: 0x0100,
542
555
  TNS_END_TO_END_DBOP: 0x0200,
543
556
  TNS_END_TO_END_MODULE: 0x0008,
557
+ TNS_END_TO_END_OTEL_RESET: 0x0400,
558
+ TNS_END_TO_END_OTEL_TRACE: 0x80000000,
544
559
 
545
560
  // versions
546
561
  TNS_VERSION_MIN_ACCEPTED: 315,
@@ -560,6 +575,7 @@ module.exports = {
560
575
  TNS_FUNC_FETCH: 5,
561
576
  TNS_FUNC_LOB_OP: 96,
562
577
  TNS_FUNC_LOGOFF: 9,
578
+ TNS_FUNC_NOTIFY: 187,
563
579
  TNS_FUNC_PING: 147,
564
580
  TNS_FUNC_PIPELINE_BEGIN: 199,
565
581
  TNS_FUNC_PIPELINE_END: 200,
@@ -568,15 +584,17 @@ module.exports = {
568
584
  TNS_FUNC_REEXECUTE: 4,
569
585
  TNS_FUNC_REEXECUTE_AND_FETCH: 78,
570
586
  TNS_FUNC_SET_SCHEMA: 152,
587
+ TNS_FUNC_SUBSCRIBE: 125,
571
588
  TNS_FUNC_SESSION_GET: 162,
572
589
  TNS_FUNC_SESSION_RELEASE: 163,
573
590
  TNS_FUNC_SESSION_STATE: 176, // piggyback fn
574
- TNS_FUNC_CANCEL_ALL: 120, // piggyback fn
591
+ TNS_FUNC_CANCEL_CURSORS: 120, // piggyback fn
575
592
  TNS_FUNC_TPC_TXN_SWITCH: 103,
576
593
  TNS_FUNC_TPC_TXN_CHANGE_STATE: 104,
577
594
  TNS_FUNC_AQ_ENQ: 121,
578
595
  TNS_FUNC_AQ_DEQ: 122,
579
596
  TNS_FUNC_ARRAY_AQ: 145,
597
+ TNS_FUNC_ALTSESS: 204,
580
598
 
581
599
  // character sets and encodings
582
600
  TNS_CHARSET_UTF8: 873,
@@ -677,17 +695,22 @@ module.exports = {
677
695
  TNS_CCAP_VECTOR_FEATURE_SPARSE: 0x02,
678
696
  TNS_CCAP_TTC5_SESSIONLESS_TXNS: 0x20,
679
697
  TNS_CCAP_OCI3_OCSSYNC: 0x20,
698
+ TNS_CCAP_TXN_PRIORITY_ALTSESS: 0x01,
680
699
  TNS_CCAP_END_USER_SEC_CTX_PIGGYBACK: 0x02,
681
700
 
682
701
  // runtime capability indices
683
702
  TNS_RCAP_COMPAT: 0,
703
+ TNS_RCAP_TZ: 1,
684
704
  TNS_RCAP_TTC: 6,
705
+ TNS_RCAP_OTEL: 12,
685
706
  TNS_RCAP_MAX: 7,
686
707
 
687
708
  // runtime capability values
688
709
  TNS_RCAP_COMPAT_81: 2,
710
+ TNS_RCAP_TZ_EX: 0x01,
689
711
  TNS_RCAP_TTC_ZERO_COPY: 0x01,
690
712
  TNS_RCAP_TTC_32K: 0x04,
713
+ TNS_RCAP_OTEL_SUPPORTED: 0x01,
691
714
 
692
715
  /** Verifier types. */
693
716
  /** SHA1 (salted). */
@@ -788,6 +811,31 @@ module.exports = {
788
811
  TNS_KPD_AQ_BUFMSG: 0x02,
789
812
  TNS_KPD_AQ_EITHER: 0x10,
790
813
 
814
+ // subscription opcodes
815
+ TNS_SUBSCR_OP_REGISTER: 1,
816
+ TNS_SUBSCR_OP_UNREGISTER: 2,
817
+
818
+ // subscription modes/constants
819
+ TNS_INIT_KPNDRREQ: 1,
820
+ TNS_SUBSCR_MODE_CLIENT_INITIATED: 4,
821
+ TNS_SUBSCR_CLIENT_ID_LEN: 29,
822
+ TNS_SUBSCR_STOP_NOTIF: 0x04,
823
+
824
+ // subscription quality of service flags
825
+ TNS_SUBSCR_QOS_RELIABLE: 0x01,
826
+ TNS_SUBSCR_QOS_PAYLOAD: 0x02,
827
+ TNS_SUBSCR_QOS_REPLICATE: 0x04,
828
+ TNS_SUBSCR_QOS_SECURE: 0x08,
829
+ TNS_SUBSCR_QOS_PURGE_ON_NTFN: 0x10,
830
+ TNS_SUBSCR_QOS_MULTICBK: 0x20,
831
+ TNS_SUBSCR_QOS_ASYNC_DEQ: 0x200,
832
+ TNS_SUBSCR_QOS_AUTO_ACK: 0x400,
833
+ TNS_SUBSCR_QOS_TX_ACK: 0x800,
834
+
835
+ // subscription flags
836
+ TNS_SUBSCR_FLAGS_INCLUDE_ROWIDS: 0x10,
837
+ TNS_SUBSCR_FLAGS_QUERY: 0x20,
838
+
791
839
  TNS_AQ_MESSAGE_ID_LENGTH: 16,
792
840
  TNS_AQ_MESSAGE_VERSION: 1,
793
841
 
@@ -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
  //
@@ -117,6 +117,7 @@ class AuthMessage extends Message {
117
117
  }
118
118
  this.appContext = config.appContext;
119
119
  this.setAuthMode(config);
120
+ this.txnPriority = config.txnPriority;
120
121
  }
121
122
 
122
123
  setAuthMode(config) {
@@ -155,13 +156,13 @@ class AuthMessage extends Message {
155
156
  }
156
157
  }
157
158
 
158
- getAlterTimezoneStatement() {
159
- let sign, tzRepr;
159
+ getAlterSessionStatement() {
160
+ let sign, stmt, tzRepr;
160
161
  if (process.env.ORA_SDTZ) {
161
162
  tzRepr = process.env.ORA_SDTZ;
162
163
  // LOCAL and DBTIMEZONE are SQL keywords and must not be quoted.
163
164
  if (["LOCAL", "DBTIMEZONE"].includes(tzRepr.toUpperCase())) {
164
- return `ALTER SESSION SET TIME_ZONE =${tzRepr}\x00`;
165
+ stmt = `ALTER SESSION SET TIME_ZONE =${tzRepr}`;
165
166
  }
166
167
  } else {
167
168
  const date = new Date();
@@ -177,7 +178,16 @@ class AuthMessage extends Message {
177
178
  tzHour = tzHour.toLocaleString('en-US', {minimumIntegerDigits: 2});
178
179
  tzRepr = `${sign}${tzHour}:${tzMinutes}`;
179
180
  }
180
- return `ALTER SESSION SET TIME_ZONE =${parser.enquoteLiteral(tzRepr)}\x00`;
181
+
182
+ if (stmt === undefined) {
183
+ stmt = `ALTER SESSION SET TIME_ZONE =${parser.enquoteLiteral(tzRepr)}`;
184
+ }
185
+ if (this.txnPriority) {
186
+ this.conn._protocol.caps.assertTxnPrioritySupported();
187
+ stmt += ` TXN_PRIORITY = ${parser.enquoteLiteral(this.txnPriority)}`;
188
+ }
189
+
190
+ return `${stmt}\x00`;
181
191
  }
182
192
 
183
193
  encode(buf) {
@@ -290,7 +300,8 @@ class AuthMessage extends Message {
290
300
  this.driverName ?? constants.DRIVER_NAME);
291
301
  buf.writeKeyValue("SESSION_CLIENT_VERSION",
292
302
  constants.CLIENT_VERSION.toString());
293
- buf.writeKeyValue("AUTH_ALTER_SESSION", this.getAlterTimezoneStatement(), 1);
303
+ buf.writeKeyValue("AUTH_ALTER_SESSION",
304
+ this.getAlterSessionStatement(), 1);
294
305
  }
295
306
  if (this.encodedPassword) {
296
307
  buf.writeKeyValue("AUTH_PASSWORD", this.encodedPassword);
@@ -452,6 +452,16 @@ class Message {
452
452
  this.connection.dbName = keyTextValue;
453
453
  } else if (keywordNum === constants.TNS_KEYWORD_PDBNAME) {
454
454
  this.connection.pdbName = keyTextValue;
455
+ } else if (keywordNum === constants.TNS_KEYWORD_ACTION) {
456
+ this.connection._action = keyTextValue;
457
+ } else if (keywordNum === constants.TNS_KEYWORD_CLIENT_INFO) {
458
+ this.connection._clientInfo = keyTextValue;
459
+ } else if (keywordNum === constants.TNS_KEYWORD_MODULE) {
460
+ this.connection._module = keyTextValue;
461
+ } else if (keywordNum === constants.TNS_KEYWORD_CLIENT_ID) {
462
+ this.connection._clientIdentifier = keyTextValue;
463
+ } else if (keywordNum === constants.TNS_KEYWORD_NUM_TXN_PRIORITY) {
464
+ this.connection._txnPriority = keyTextValue;
455
465
  }
456
466
  }
457
467
  buf.skipUB4(); // skip overall flags
@@ -530,18 +540,27 @@ class Message {
530
540
  this._writeCurrentSchemaPiggyback(buf);
531
541
  }
532
542
  this._writeApplicationContextPiggyback(buf);
533
- if (this.connection.statementCache._cursorsToClose.size > 0 && !this.connection._drcpEstablishSession) {
543
+ if (!this.connection._drcpEstablishSession) {
534
544
  // skip closing cursors when '_drcpEstablishSession = true' Since we don't know whether the same session
535
545
  // is in use. We can not send the information across until after the session information has been returned
536
546
  // (on the first round trip).
537
- this.writeCloseCursorsPiggyBack(buf);
547
+ if (this.connection.statementCache._cursorsToClose.size > 0) {
548
+ this.writeCursorsPiggyBack(buf, constants.TNS_FUNC_CLOSE_CURSORS,
549
+ this.connection.statementCache._cursorsToClose);
550
+ }
551
+ if (this.connection.statementCache._cursorsToCancel.size > 0) {
552
+ this.writeCursorsPiggyBack(buf, constants.TNS_FUNC_CANCEL_CURSORS,
553
+ this.connection.statementCache._cursorsToCancel);
554
+ }
538
555
  }
539
556
  if (
540
557
  this.connection._actionModified ||
541
558
  this.connection._clientIdentifierModified ||
559
+ this.connection._ecidModified ||
542
560
  this.connection._dbOpModified ||
543
561
  this.connection._clientInfoModified ||
544
- this.connection._moduleModified
562
+ this.connection._moduleModified ||
563
+ this.connection._otelModified
545
564
  ) {
546
565
  this._writeEndToEndPiggybacks(buf);
547
566
  }
@@ -553,6 +572,10 @@ class Message {
553
572
  this.connection._sessionlessData.piggyback.encode(buf);
554
573
  this.connection._sessionlessData.piggyback = null;
555
574
  }
575
+ if (this.connection._txnPriorityModified) {
576
+ this.connection._protocol.caps.assertTxnPrioritySupported();
577
+ this._writeAltSessPiggyback(buf);
578
+ }
556
579
  }
557
580
 
558
581
  writePiggybackHeader(buf, functionCode) {
@@ -565,10 +588,10 @@ class Message {
565
588
  }
566
589
  }
567
590
 
568
- writeCloseCursorsPiggyBack(buf) {
569
- this.writePiggybackHeader(buf, constants.TNS_FUNC_CLOSE_CURSORS);
591
+ writeCursorsPiggyBack(buf, functionCode, cursors) {
592
+ this.writePiggybackHeader(buf, functionCode);
570
593
  buf.writeUInt8(1);
571
- this.connection.statementCache.writeCursorsToClose(buf);
594
+ this.connection.statementCache.writeCursors(buf, cursors);
572
595
  }
573
596
 
574
597
  writeCloseTempLobsPiggyback(buf) {
@@ -638,6 +661,9 @@ class Message {
638
661
  if (this.connection._clientIdentifierModified) {
639
662
  flags |= constants.TNS_END_TO_END_CLIENT_IDENTIFIER;
640
663
  }
664
+ if (this.connection._ecidModified) {
665
+ flags |= constants.TNS_END_TO_END_ECID;
666
+ }
641
667
  if (this.connection._clientInfoModified) {
642
668
  flags |= constants.TNS_END_TO_END_CLIENT_INFO;
643
669
  }
@@ -647,20 +673,25 @@ class Message {
647
673
  if (this.connection._dbOpModified) {
648
674
  flags |= constants.TNS_END_TO_END_DBOP;
649
675
  }
676
+ if (this.connection._otelModified) {
677
+ flags |= constants.TNS_END_TO_END_OTEL_RESET;
678
+ flags |= this._getOtelFlags();
679
+ }
650
680
 
651
681
  // write initial packet data
652
682
  this.writePiggybackHeader(buf, constants.TNS_FUNC_SET_END_TO_END_ATTR);
653
683
  buf.writeUInt8(0); // pointer (cidnam)
654
684
  buf.writeUInt8(0); // pointer (cidser)
655
- buf.writeUB4(flags);
685
+
686
+ // Coerce to unsigned since JS bitwise operators produce signed 32-bit
687
+ // values, and OTEL trace uses the high bit.
688
+ buf.writeUB4(flags >>> 0);
656
689
 
657
690
  const clientIdentifierBytes = this.writeEndEndTraceValue(buf, this.connection._clientIdentifier, this.connection._clientIdentifierModified);
658
691
  const moduleBytes = this.writeEndEndTraceValue(buf, this.connection._module, this.connection._moduleModified);
659
692
  const actionBytes = this.writeEndEndTraceValue(buf, this.connection._action, this.connection._actionModified);
660
-
693
+ const ecidBytes = this.writeEndEndTraceValue(buf, this.connection._ecid, this.connection._ecidModified);
661
694
  // write unsupported bits
662
- buf.writeUInt8(0); // pointer (cideci)
663
- buf.writeUB4(0); // length (cideci)
664
695
  buf.writeUInt8(0); // cidcct
665
696
  buf.writeUB4(0); // cidecs
666
697
 
@@ -682,6 +713,9 @@ class Message {
682
713
  if (this.connection._actionModified && this.connection._action) {
683
714
  buf.writeBytesWithLength(actionBytes);
684
715
  }
716
+ if (this.connection._ecidModified && this.connection._ecid) {
717
+ buf.writeBytesWithLength(ecidBytes);
718
+ }
685
719
  if (this.connection._clientInfoModified && this.connection._clientInfo) {
686
720
  buf.writeBytesWithLength(clientInfoBytes);
687
721
  }
@@ -689,17 +723,24 @@ class Message {
689
723
  buf.writeBytesWithLength(dbOpBytes);
690
724
  }
691
725
 
692
- // reset flags and values
726
+ // Safely retain the values and clear only their modified flags.
727
+ // This avoids resending stale values, while preserving ACTION
728
+ // because it is sent with MODULE updates.
693
729
  this.connection._actionModified = false;
694
- this.connection._action = "";
730
+ this.connection._ecidModified = false;
695
731
  this.connection._clientIdentifierModified = false;
696
- this.connection._clientIdentifier = "";
697
732
  this.connection._clientInfoModified = false;
698
- this.connection._clientInfo = "";
699
733
  this.connection._dbOpModified = false;
700
- this.connection._dbOp = "";
701
734
  this.connection._moduleModified = false;
702
- this.connection._module = "";
735
+ this.connection._otelModified = false;
736
+ }
737
+
738
+ _getOtelFlags() {
739
+ let flags = 0;
740
+ if (this.connection.databaseOpenTelemetryTracing) {
741
+ flags |= constants.TNS_END_TO_END_OTEL_TRACE;
742
+ }
743
+ return flags >>> 0;
703
744
  }
704
745
 
705
746
  writeEndEndTraceValue(buf, value, modified) {
@@ -762,6 +803,23 @@ class Message {
762
803
  }
763
804
  }
764
805
 
806
+ _writeAltSessPiggyback(buf) {
807
+ const pendingTxnPriority = this.connection._pendingTxnPriority ?? "";
808
+ const flags = (pendingTxnPriority === "") ?
809
+ constants.TNS_KVAL_FLAG_TXN_PRIORITY_DEFAULT : 0;
810
+
811
+ this.writePiggybackHeader(buf, constants.TNS_FUNC_ALTSESS);
812
+
813
+ // OALTSESS uses DTYALTSESS, which wraps a KVAL array carrying the
814
+ // alter-session key/value pairs to apply on the server.
815
+ buf.writeUB4(0); // kpdAltSessFlg
816
+ buf.writeUInt8(1); // ptr to KVAL array
817
+ buf.writeUB4(1); // number of key/value pairs
818
+ buf.writeKeyValue("TXN_PRIORITY", pendingTxnPriority, flags);
819
+ this.connection._pendingTxnPriority = undefined;
820
+ this.connection._txnPriorityModified = false;
821
+ }
822
+
765
823
  // Called when an error is encountered during decode of RPC
766
824
  saveDeferredErr() {
767
825
  if (!this.deferredErr) {
@@ -26,9 +26,23 @@
26
26
 
27
27
  'use strict';
28
28
 
29
+ const { Buffer } = require('buffer');
29
30
  const constants = require("../constants.js");
31
+ const dataHandlerConstants = require("../../../impl/datahandlers/constants.js");
30
32
  const Message = require("./base.js");
31
33
 
34
+ // TTIDTY carries the client's time zone as an 11-byte INTERVAL DAY TO SECOND
35
+ // value. A zero day field is followed by the biased hour and minute offset;
36
+ // the remaining five bytes use the TTC time-zone trailer representation.
37
+ const TTIDTY_TIME_ZONE_TRAILER = Buffer.from([0x80, 0, 0, 0, 0]);
38
+
39
+ // In the server's 11-byte DBTIMEZONE interval, byte 4 holds either the biased
40
+ // hour offset or a region-ID marker. Oracle clients identify a region when
41
+ // this byte is greater than 120 (181 - the hour bias of 60 - 1). The region ID
42
+ // itself is encoded in bytes 2 and 3. node-oracledb currently obtains the
43
+ // region name with DBTIMEZONE, since it has no Oracle region-ID mapping table.
44
+ const TTIDTY_TIME_ZONE_REGION_ID_THRESHOLD = 120;
45
+
32
46
  /**
33
47
  * Does Datatype Negotiation
34
48
  *
@@ -40,6 +54,19 @@ class DataTypeMessage extends Message {
40
54
 
41
55
  processMessage(buf, messageType) {
42
56
  if (messageType === constants.TNS_MSG_TYPE_DATA_TYPES) {
57
+ if (buf.caps.runtimeCaps[constants.TNS_RCAP_TZ] ===
58
+ constants.TNS_RCAP_TZ_EX) {
59
+ // TZ_EX adds the database time zone before the negotiated datatype
60
+ // list. It uses the same 11-byte INTERVAL DAY TO SECOND layout as the
61
+ // client value written below.
62
+ const dbTimeZone = buf.readBytes(11);
63
+ if (dbTimeZone[4] <= TTIDTY_TIME_ZONE_REGION_ID_THRESHOLD) {
64
+ // Fixed offsets encode hours and minutes with a bias of 60.
65
+ buf.caps.dbTzOffset = (dbTimeZone[4] -
66
+ dataHandlerConstants.TNS_DURATION_OFFSET) * 60 +
67
+ dbTimeZone[5] - dataHandlerConstants.TNS_DURATION_OFFSET;
68
+ }
69
+ }
43
70
  while (true) {
44
71
  const dataType = buf.readUInt16BE();
45
72
  if (dataType === 0)
@@ -62,6 +89,24 @@ class DataTypeMessage extends Message {
62
89
  constants.TNS_ENCODING_CONV_LENGTH);
63
90
  buf.writeBytesWithLength(buf.caps.compileCaps);
64
91
  buf.writeBytesWithLength(buf.caps.runtimeCaps);
92
+ if (buf.caps.runtimeCaps[constants.TNS_RCAP_TZ] ===
93
+ constants.TNS_RCAP_TZ_EX) {
94
+ // Advertise the Node process's current fixed UTC offset. The server
95
+ // uses this client value while performing datatype negotiation and
96
+ // returns its DBTIMEZONE using the corresponding interval layout.
97
+ //
98
+ // Date#getTimezoneOffset() uses the opposite sign convention
99
+ // (UTC - local time), so negate it before encoding the offset for TTIDTY.
100
+ const timeZoneOffset = -new Date().getTimezoneOffset();
101
+ const timeZone = Buffer.alloc(11);
102
+ timeZone.writeUInt32BE(dataHandlerConstants.TNS_DURATION_MID, 0);
103
+ timeZone[4] = Math.trunc(timeZoneOffset / 60) +
104
+ dataHandlerConstants.TNS_DURATION_OFFSET;
105
+ timeZone[5] = timeZoneOffset % 60 +
106
+ dataHandlerConstants.TNS_DURATION_OFFSET;
107
+ TTIDTY_TIME_ZONE_TRAILER.copy(timeZone, 6);
108
+ buf.writeBytes(timeZone);
109
+ }
65
110
  for (const val of dataTypes) {
66
111
  buf.writeUInt16BE(val[0]);
67
112
  buf.writeUInt16BE(val[1]);
@@ -399,6 +444,7 @@ const dataTypes = [
399
444
  [constants.TNS_DATA_TYPE_PLEND, constants.TNS_DATA_TYPE_PLEND, constants.TNS_TYPE_REP_UNIVERSAL],
400
445
  [constants.TNS_DATA_TYPE_PLBGN, constants.TNS_DATA_TYPE_PLBGN, constants.TNS_TYPE_REP_UNIVERSAL],
401
446
  [constants.TNS_DATA_TYPE_PLOP, constants.TNS_DATA_TYPE_PLOP, constants.TNS_TYPE_REP_UNIVERSAL],
447
+ [constants.TNS_DATA_TYPE_ALTSESS, constants.TNS_DATA_TYPE_ALTSESS, constants.TNS_TYPE_REP_UNIVERSAL],
402
448
  [constants.TNS_DATA_TYPE_KVE, constants.TNS_DATA_TYPE_KVE, constants.TNS_TYPE_REP_UNIVERSAL],
403
449
  [constants.TNS_DATA_TYPE_EUSC, constants.TNS_DATA_TYPE_EUSC, constants.TNS_TYPE_REP_UNIVERSAL]
404
450
  ];
@@ -93,13 +93,14 @@ class DirectPathPiece {
93
93
 
94
94
  class PieceBuffer extends BaseBuffer {
95
95
  constructor(connection) {
96
- super(Buffer.alloc(constants.TNS_DPLS_MAX_PIECE_SIZE));
96
+ const caps = connection._protocol.caps;
97
+ super(Buffer.alloc(constants.TNS_DPLS_MAX_PIECE_SIZE), caps);
97
98
  this.connection = connection;
98
99
  this.currentPiece = null;
99
100
  this.totalPieceLength = 0;
100
101
  this.pieces = [];
101
102
  this._encodingTempBuf = new BaseBuffer(
102
- Buffer.alloc(constants.TNS_DPLS_MAX_BUFFER_SIZE_FACTOR)
103
+ Buffer.alloc(constants.TNS_DPLS_MAX_BUFFER_SIZE_FACTOR), caps
103
104
  );
104
105
  }
105
106
 
@@ -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
  //
@@ -65,6 +65,8 @@ class ExecuteMessage extends MessageWithData {
65
65
  let execFlags = 0;
66
66
  let numParams = 0;
67
67
  let numIters = 1;
68
+ let registrationIdMsb = 0;
69
+ let registrationIdLsb = 0;
68
70
  // Configuring the options field thats send to the server
69
71
  const stmt = this.statement;
70
72
  const params = stmt.bindInfoList;
@@ -123,6 +125,10 @@ class ExecuteMessage extends MessageWithData {
123
125
  this._handleSuspendSessionless();
124
126
  }
125
127
 
128
+ registrationIdMsb = Number((this.statement._registrationId >> 32n) &
129
+ 0xffffffffn);
130
+ registrationIdLsb = Number(this.statement._registrationId & 0xffffffffn);
131
+
126
132
  this.writeFunctionHeader(buf);
127
133
  buf.writeUB4(options); // execute options
128
134
  buf.writeUB4(stmt.cursorId); // cursor id
@@ -159,14 +165,14 @@ class ExecuteMessage extends MessageWithData {
159
165
  buf.writeUInt8(0);
160
166
  buf.writeUB4(0);
161
167
  }
162
- buf.writeUB4(0); // registration id
168
+ buf.writeUB4(registrationIdLsb);
163
169
  buf.writeUInt8(0); // pointer (al8objlist)
164
170
  buf.writeUInt8(1); // pointer (al8objlen)
165
171
  buf.writeUInt8(0); // pointer (al8blv)
166
172
  buf.writeUB4(0); // al8blv
167
173
  buf.writeUInt8(0); // pointer (al8dnam)
168
174
  buf.writeUB4(0); // al8dnaml
169
- buf.writeUB4(0); // al8regid_msb
175
+ buf.writeUB4(registrationIdMsb);
170
176
  if (this.arrayDmlRowCounts) {
171
177
  buf.writeUInt8(1); // pointer (al8pidmlrc)
172
178
  buf.writeUB4(this.numExecs); // al8pidmlrcbl
@@ -323,7 +329,7 @@ class ExecuteMessage extends MessageWithData {
323
329
  const stmt = this.statement;
324
330
  if (stmt.cursorId !== 0 && !stmt.requiresFullExecute && !this.parseOnly
325
331
  && !stmt.requiresDefine && !stmt.noPrefetch && !stmt.isDdl
326
- && !this.batchErrors) {
332
+ && !this.batchErrors && stmt._registrationId === 0n) {
327
333
  if (stmt.isQuery && this.options.prefetchRows > 0) {
328
334
  this.functionCode = constants.TNS_FUNC_REEXECUTE_AND_FETCH;
329
335
  } else {
@@ -41,6 +41,8 @@ const PingMessage = require('./ping.js');
41
41
  const ProtocolMessage = require('./protocol.js');
42
42
  const RollbackMessage = require('./rollback.js');
43
43
  const SessionReleaseMessage = require('./sessionRelease.js');
44
+ const SubscrMessage = require('./subscribe.js');
45
+ const NotifyMessage = require('./notification.js');
44
46
  const FastAuthMessage = require('./fastAuth.js');
45
47
  const TransactionChangeStateMessage = require('./transactionChangeState.js');
46
48
  const TransactionSwitchMessage = require('./transactionSwitch.js');
@@ -62,6 +64,8 @@ module.exports = {
62
64
  ProtocolMessage,
63
65
  RollbackMessage,
64
66
  SessionReleaseMessage,
67
+ SubscrMessage,
68
+ NotifyMessage,
65
69
  TransactionChangeStateMessage,
66
70
  TransactionSwitchMessage
67
71
  };