oracledb 6.3.0 → 6.5.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 (71) hide show
  1. package/LICENSE.txt +1 -1
  2. package/NOTICE.txt +1 -1
  3. package/README.md +3 -3
  4. package/build/Release/oracledb-6.5.0-darwin-x64.node +0 -0
  5. package/build/Release/oracledb-6.5.0-darwin-x64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-6.5.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-6.5.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-6.5.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.5.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-6.5.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.5.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-6.5.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/examples/README.md +3 -0
  14. package/lib/aqQueue.js +8 -8
  15. package/lib/connection.js +65 -22
  16. package/lib/constants.js +7 -1
  17. package/lib/dbObject.js +72 -1
  18. package/lib/errors.js +51 -10
  19. package/lib/impl/connection.js +2 -1
  20. package/lib/{thin/protocol → impl/datahandlers}/buffer.js +36 -32
  21. package/lib/impl/datahandlers/constants.js +106 -0
  22. package/lib/{thin/protocol → impl/datahandlers}/oson.js +320 -151
  23. package/lib/impl/datahandlers/vector.js +137 -0
  24. package/lib/impl/pool.js +9 -0
  25. package/lib/impl/resultset.js +34 -17
  26. package/lib/lob.js +22 -6
  27. package/lib/oracledb.js +35 -1
  28. package/lib/pool.js +17 -2
  29. package/lib/poolStatistics.js +3 -1
  30. package/lib/settings.js +31 -6
  31. package/lib/sodaDocCursor.js +14 -1
  32. package/lib/thin/connection.js +120 -193
  33. package/lib/thin/dbObject.js +4 -2
  34. package/lib/thin/lob.js +6 -6
  35. package/lib/thin/pool.js +84 -10
  36. package/lib/thin/protocol/capabilities.js +20 -6
  37. package/lib/thin/protocol/constants.js +34 -54
  38. package/lib/thin/protocol/messages/auth.js +2 -2
  39. package/lib/thin/protocol/messages/base.js +28 -27
  40. package/lib/thin/protocol/messages/dataType.js +4 -2
  41. package/lib/thin/protocol/messages/execute.js +5 -1
  42. package/lib/thin/protocol/messages/{connectionCookie.js → fastAuth.js} +18 -16
  43. package/lib/thin/protocol/messages/fetch.js +4 -0
  44. package/lib/thin/protocol/messages/index.js +2 -2
  45. package/lib/thin/protocol/messages/protocol.js +9 -1
  46. package/lib/thin/protocol/messages/withData.js +40 -11
  47. package/lib/thin/protocol/packet.js +93 -8
  48. package/lib/thin/protocol/protocol.js +10 -5
  49. package/lib/thin/protocol/utils.js +11 -18
  50. package/lib/thin/sqlnet/constants.js +5 -2
  51. package/lib/thin/sqlnet/ezConnectResolver.js +9 -5
  52. package/lib/thin/sqlnet/navNodes.js +4 -3
  53. package/lib/thin/sqlnet/networkSession.js +27 -4
  54. package/lib/thin/sqlnet/packet.js +2 -5
  55. package/lib/thin/statement.js +43 -7
  56. package/lib/thin/statementCache.js +190 -0
  57. package/lib/thin/util.js +2 -2
  58. package/lib/transformer.js +21 -6
  59. package/lib/types.js +21 -3
  60. package/lib/util.js +30 -1
  61. package/lib/version.js +2 -2
  62. package/package.json +1 -1
  63. package/build/Release/oracledb-6.3.0-darwin-x64.node +0 -0
  64. package/build/Release/oracledb-6.3.0-darwin-x64.node-buildinfo.txt +0 -1
  65. package/build/Release/oracledb-6.3.0-js-buildinfo.txt +0 -1
  66. package/build/Release/oracledb-6.3.0-linux-arm64.node +0 -0
  67. package/build/Release/oracledb-6.3.0-linux-arm64.node-buildinfo.txt +0 -1
  68. package/build/Release/oracledb-6.3.0-linux-x64.node +0 -0
  69. package/build/Release/oracledb-6.3.0-linux-x64.node-buildinfo.txt +0 -1
  70. package/build/Release/oracledb-6.3.0-win32-x64.node +0 -0
  71. package/build/Release/oracledb-6.3.0-win32-x64.node-buildinfo.txt +0 -1
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2023 Oracle and/or its affiliates.
1
+ // Copyright (c) 2023, 2024, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -31,46 +31,48 @@ const Message = require("./base.js");
31
31
 
32
32
  /**
33
33
  * Executes a Fast Negotiation RPC function.
34
- * It sends Protocol Negotiation, Cookie Message, Datatype Negotiation
34
+ * It sends Protocol Negotiation, Datatype Negotiation
35
35
  * and OSESS Key RPC in single round trip.
36
36
  *
37
- * @class ConnectionCookieMessage
37
+ * @class FastAuthMessage
38
38
  * @extends {Message}
39
39
  */
40
- class ConnectionCookieMessage extends Message {
40
+ class FastAuthMessage extends Message {
41
41
 
42
42
  /**
43
- * Serializes the ConnectionCookieMessage function arguments
43
+ * Serializes the FastAuthMessage function arguments
44
44
  *
45
45
  * @param {object} buf input arguments
46
46
  */
47
47
  encode(buf) {
48
+ buf.writeUInt8(constants.TNS_MSG_TYPE_FAST_AUTH);
49
+ buf.writeUInt8(1); // Fast Auth version
50
+ buf.writeUInt8(constants.TNS_SERVER_CONVERTS_CHARS); // flag 1
51
+ buf.writeUInt8(0); // flag 2
48
52
  this.protocolMessage.encode(buf);
49
- buf.writeUInt8(constants.TNS_MSG_TYPE_COOKIE);
50
- buf.writeUInt8(1); // cookie version
51
- buf.writeUInt8(this.cookie.protocolVersion);
52
- buf.writeUInt16LE(this.cookie.charsetID);
53
- buf.writeUInt8(this.cookie.flags);
54
- buf.writeUInt16LE(this.cookie.ncharsetID);
55
- buf.writeBytesWithLength(this.cookie.serverBanner);
56
- buf.writeBytesWithLength(this.cookie.compileCaps);
57
- buf.writeBytesWithLength(this.cookie.runtimeCaps);
53
+ buf.writeUInt16BE(0); // server charset (unused)
54
+ buf.writeUInt8(0); // server charset flag (unused)
55
+ buf.writeUInt16BE(0); // server ncharset (unused)
56
+ buf.caps.ttcFieldVersion = constants.TNS_CCAP_FIELD_VERSION_19_1_EXT_1;
57
+ buf.writeUInt8(buf.caps.ttcFieldVersion);
58
58
  this.dataTypeMessage.encode(buf);
59
59
  this.authMessage.encode(buf);
60
+ buf.caps.ttcFieldVersion = constants.TNS_CCAP_FIELD_VERSION_MAX;
60
61
  }
61
62
 
62
63
  processMessage(buf, messageType) {
63
64
  if (messageType === constants.TNS_MSG_TYPE_RENEGOTIATE) {
64
- this.cookie.populated = false;
65
+ this.reNegotiate = true;
65
66
  } else if (messageType === constants.TNS_MSG_TYPE_PROTOCOL) {
66
67
  this.protocolMessage.processMessage(buf, messageType);
67
68
  } else if (messageType === constants.TNS_MSG_TYPE_DATA_TYPES) {
68
69
  this.dataTypeMessage.processMessage(buf, messageType);
69
70
  } else {
70
71
  this.authMessage.processMessage(buf, messageType);
72
+ this.endOfResponse = this.authMessage.endOfResponse;
71
73
  }
72
74
  }
73
75
 
74
76
  }
75
77
 
76
- module.exports = ConnectionCookieMessage;
78
+ module.exports = FastAuthMessage;
@@ -28,6 +28,7 @@
28
28
 
29
29
  const constants = require("../constants.js");
30
30
  const MessageWithData = require("./withData.js");
31
+ const errors = require("../../../errors.js");
31
32
 
32
33
  /**
33
34
  * Executes OFETCH RPC
@@ -51,6 +52,9 @@ class FetchMessage extends MessageWithData {
51
52
  //-------------------------------------------------------------------------
52
53
  encode(buf) {
53
54
  this.writeFunctionHeader(buf);
55
+ if (this.statement.cursorId === 0) {
56
+ errors.throwErr(errors.ERR_CURSOR_HAS_BEEN_CLOSED);
57
+ }
54
58
  buf.writeUB4(this.statement.cursorId);
55
59
  buf.writeUB4(this.options.fetchArraySize);
56
60
  }
@@ -37,12 +37,12 @@ const PingMessage = require('./ping.js');
37
37
  const ProtocolMessage = require('./protocol.js');
38
38
  const RollbackMessage = require('./rollback.js');
39
39
  const SessionReleaseMessage = require('./sessionRelease.js');
40
- const ConnectionCookieMessage = require('./connectionCookie.js');
40
+ const FastAuthMessage = require('./fastAuth.js');
41
41
 
42
42
  module.exports = {
43
43
  AuthMessage,
44
44
  CommitMessage,
45
- ConnectionCookieMessage,
45
+ FastAuthMessage,
46
46
  DataTypeMessage,
47
47
  ExecuteMessage,
48
48
  FetchMessage,
@@ -53,6 +53,7 @@ class ProtocolMessage extends Message {
53
53
  processMessage(buf, messageType) {
54
54
  if (messageType === constants.TNS_MSG_TYPE_PROTOCOL) {
55
55
  this.processProtocolInfo(buf);
56
+ this.endOfResponse = !this.connection.nscon.endOfRequestSupport;
56
57
  } else {
57
58
  super.processMessage(buf, messageType);
58
59
  }
@@ -75,7 +76,14 @@ class ProtocolMessage extends Message {
75
76
  const serverCompileCaps = buf.readBytesWithLength();
76
77
  if (serverCompileCaps) {
77
78
  this.serverCompileCaps = Buffer.from(serverCompileCaps);
78
- buf.caps.adjustForServerCompileCaps(this.serverCompileCaps);
79
+ buf.caps.adjustForServerCompileCaps(this.serverCompileCaps, this.connection.nscon);
80
+
81
+ // Set the maximum OSON field name size
82
+ if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) {
83
+ this.connection._osonMaxFieldNameSize = 65535;
84
+ } else {
85
+ this.connection._osonMaxFieldNameSize = 255;
86
+ }
79
87
  }
80
88
  const serverRunTimeCaps = buf.readBytesWithLength();
81
89
  if (serverRunTimeCaps) {
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -85,6 +85,7 @@ class MessageWithData extends Message {
85
85
  this.processIOVector(buf);
86
86
  } else if (messageType === constants.TNS_MSG_TYPE_FLUSH_OUT_BINDS) {
87
87
  this.flushOutBinds = true;
88
+ this.endOfResponse = true;
88
89
  } else if (messageType === constants.TNS_MSG_TYPE_ERROR) {
89
90
  this.processErrorInfo(buf);
90
91
  } else {
@@ -92,10 +93,6 @@ class MessageWithData extends Message {
92
93
  }
93
94
  }
94
95
 
95
- hasMoreData() {
96
- return !this.processedError && !this.flushOutBinds;
97
- }
98
-
99
96
  processErrorInfo(buf) {
100
97
  super.processErrorInfo(buf);
101
98
  if (this.errorInfo.cursorId !== 0) {
@@ -117,7 +114,7 @@ class MessageWithData extends Message {
117
114
  this.errorOccurred = false;
118
115
  this.statement.moreRowsToFetch = false;
119
116
  } else if (this.errorInfo.num !== 0 && this.errorInfo.cursorId !== 0) {
120
- this.connection.statementCache.delete(this.statement.sql);
117
+ this.connection.statementCache._cachedStatements.delete(this.statement.sql);
121
118
  this.statement.returnToCache = false;
122
119
  }
123
120
  if (this.errorInfo.batchErrors) {
@@ -148,15 +145,16 @@ class MessageWithData extends Message {
148
145
  buf.skipUB1();
149
146
  }
150
147
  resultSet.metadata = [];
148
+ const metadata = [];
149
+ const queryVars = [];
151
150
  for (let i = 0; i < statement.numQueryVars; i++) {
152
151
  const variable = this.processColumnInfo(buf, i + 1);
153
152
  if (prevQueryVars && i < prevQueryVars.length) {
154
153
  this._adjustFetchType(prevQueryVars[i], variable);
155
154
  }
156
- statement.queryVars.push(variable);
157
- resultSet.metadata.push(variable.fetchInfo);
155
+ queryVars.push(variable);
156
+ metadata.push(variable.fetchInfo);
158
157
  }
159
-
160
158
  let numBytes = buf.readUB4();
161
159
  if (numBytes > 0) {
162
160
  buf.skipBytesChunked(); // current date
@@ -170,6 +168,13 @@ class MessageWithData extends Message {
170
168
  buf.skipBytesChunked();
171
169
  }
172
170
 
171
+ /*
172
+ * The message state(resultSet) and statement state(queryVars) is modified
173
+ * at end of the DescribeInfo function so that an OutOfPacketsError
174
+ * won't cause partial information state to be stored.
175
+ */
176
+ resultSet.metadata = metadata;
177
+ statement.queryVars = queryVars;
173
178
  this.resultSetsToSetup.push(resultSet);
174
179
  }
175
180
 
@@ -223,6 +228,7 @@ class MessageWithData extends Message {
223
228
  nullable: nullable
224
229
  };
225
230
  fetchInfo.isJson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_JSON);
231
+ fetchInfo.isOson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_OSON);
226
232
  if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) {
227
233
  numBytes = buf.readUB4();
228
234
  if (numBytes > 0) {
@@ -254,6 +260,19 @@ class MessageWithData extends Message {
254
260
  buf.skipUB4(); // flags
255
261
  }
256
262
  }
263
+ if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_4) {
264
+ const dimensions = buf.readUB4();
265
+ const vectorFormat = buf.readUInt8();
266
+ const vectorFlags = buf.readUInt8();
267
+ if (fetchInfo.dbType === types.DB_TYPE_VECTOR) {
268
+ if (!(vectorFlags & constants.VECTOR_META_FLAG_FLEXIBLE_DIM)) {
269
+ fetchInfo.vectorDimensions = dimensions;
270
+ }
271
+ if (vectorFormat !== constants.VECTOR_FORMAT_FLEX) {
272
+ fetchInfo.vectorFormat = vectorFormat;
273
+ }
274
+ }
275
+ }
257
276
 
258
277
  switch (fetchInfo.dbType) {
259
278
  case types.DB_TYPE_VARCHAR:
@@ -481,6 +500,8 @@ class MessageWithData extends Message {
481
500
  }
482
501
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) {
483
502
  colValue = buf.readOson();
503
+ } else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) {
504
+ colValue = buf.readVector();
484
505
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_INT_NAMED) {
485
506
  const obj = buf.readDbObject();
486
507
  if (obj.packedData) {
@@ -589,7 +610,8 @@ class MessageWithData extends Message {
589
610
  if (variable.type === types.DB_TYPE_CLOB ||
590
611
  variable.type === types.DB_TYPE_NCLOB ||
591
612
  variable.type === types.DB_TYPE_BLOB ||
592
- variable.type === types.DB_TYPE_JSON) {
613
+ variable.type === types.DB_TYPE_JSON ||
614
+ variable.type === types.DB_TYPE_VECTOR) {
593
615
  if (variable.type !== variable.fetchInfo.fetchType) {
594
616
  variable.type = variable.fetchInfo.fetchType;
595
617
  variable.maxSize = constants.TNS_MAX_LONG_LENGTH;
@@ -674,6 +696,9 @@ class MessageWithData extends Message {
674
696
  } else if (variable.type === types.DB_TYPE_JSON) {
675
697
  contFlag = constants.TNS_LOB_PREFETCH_FLAG;
676
698
  maxSize = lobPrefetchLength = constants.TNS_JSON_MAX_LENGTH;
699
+ } else if (variable.type === types.DB_TYPE_VECTOR) {
700
+ contFlag = constants.TNS_LOB_PREFETCH_FLAG;
701
+ maxSize = lobPrefetchLength = constants.TNS_VECTOR_MAX_LENGTH;
677
702
  }
678
703
  buf.writeUInt8(oraTypeNum);
679
704
  buf.writeUInt8(flag);
@@ -794,8 +819,10 @@ class MessageWithData extends Message {
794
819
  ) {
795
820
  buf.writeOracleDate(value, variable.type);
796
821
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_BINARY_DOUBLE) {
822
+ buf.writeUInt8(8);
797
823
  buf.writeBinaryDouble(value);
798
824
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_BINARY_FLOAT) {
825
+ buf.writeUInt8(4);
799
826
  buf.writeBinaryFloat(value);
800
827
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_CURSOR) {
801
828
  let cursor = value;
@@ -822,7 +849,9 @@ class MessageWithData extends Message {
822
849
  } else if ([constants.TNS_DATA_TYPE_ROWID, constants.TNS_DATA_TYPE_UROWID].includes(oraTypeNum)) {
823
850
  buf.writeBytesWithLength(Buffer.from(value));
824
851
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) {
825
- buf.writeOson(value);
852
+ buf.writeOson(value, this.connection._osonMaxFieldNameSize);
853
+ } else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) {
854
+ buf.writeVector(value);
826
855
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_INT_NAMED) {
827
856
  buf.writeDbObject(value);
828
857
  } else {
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -26,14 +26,18 @@
26
26
 
27
27
  'use strict';
28
28
 
29
- const { BaseBuffer } = require('./buffer.js');
29
+ const { BaseBuffer } = require('../../impl/datahandlers/buffer.js');
30
30
  const { Buffer } = require('buffer');
31
- const constants = require("./constants.js");
32
- const oson = require('./oson.js');
31
+ const constants = require('./constants.js');
32
+ const oson = require('../../impl/datahandlers/oson.js');
33
33
  const utils = require('./utils.js');
34
+ const vector = require('../../impl/datahandlers/vector.js');
34
35
  const errors = require("../../errors.js");
35
36
 
36
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
+ const MSG_TYPE_OFFSET = 11;
37
41
 
38
42
  /**
39
43
  * Class used for byte chunks used in the ChunkedBytesBuffer.
@@ -289,14 +293,38 @@ class ReadPacket extends BaseBuffer {
289
293
  this.packetNum = packet.num;
290
294
  }
291
295
 
292
- async waitForPackets() {
293
- const packet = await this.nsi.recvPacket();
296
+ /**
297
+ * Read packets from network.
298
+ * If checkRequestBoundary is passed as true, it
299
+ * would read all packets until end of request
300
+ * boundary is seen in nwk header.
301
+ */
302
+ async waitForPackets(checkRequestBoundary = false) {
303
+ let packet = await this.nsi.recvPacket();
294
304
  if (!this.savedPackets) {
295
305
  this.savedPackets = [packet];
296
306
  this.savedPacketPos = 0;
297
307
  } else {
298
308
  this.savedPackets.push(packet);
299
309
  }
310
+ 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;
316
+ }
317
+
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
+ }
324
+ packet = await this.nsi.recvPacket();
325
+ this.savedPackets.push(packet);
326
+ }
327
+ }
300
328
  this.startPacket(this.savedPackets[this.savedPacketPos++]);
301
329
  }
302
330
 
@@ -395,6 +423,22 @@ class ReadPacket extends BaseBuffer {
395
423
  return {rba, partitionID, blockNum, slotNum};
396
424
  }
397
425
 
426
+ /**
427
+ * Reads VECTOR data (QLocator followed by data) and decodes it into a
428
+ * JavaScript object.
429
+ */
430
+ readVector() {
431
+ const numBytes = this.readUB4();
432
+ if (numBytes === 0) {
433
+ return null;
434
+ }
435
+ this.skipUB8(); // size (unused)
436
+ this.skipUB4(); // chunk size (unused)
437
+ const decoder = new vector.VectorDecoder(this.readBytesWithLength());
438
+ this.skipBytesChunked(); // locator (unused)
439
+ return decoder.decode();
440
+ }
441
+
398
442
  skipBytesChunked() {
399
443
  const numBytes = this.readUInt8();
400
444
  if (numBytes === 0 || numBytes === constants.TNS_NULL_LENGTH_INDICATOR) {
@@ -478,6 +522,13 @@ class WritePacket extends BaseBuffer {
478
522
  if (!finalPacket) {
479
523
  buf = Buffer.from(buf);
480
524
  this.startPacket();
525
+ } 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);
529
+ }
530
+ if (!this.nsi.ntAdapter) {
531
+ errors.throwErr(errors.ERR_INVALID_CONNECTION);
481
532
  }
482
533
  this.nsi.ntAdapter.send(buf);
483
534
  }
@@ -525,9 +576,9 @@ class WritePacket extends BaseBuffer {
525
576
  * Encodes a JavaScript object into OSON and then writes it (QLocator
526
577
  * followed by data) to the buffer.
527
578
  */
528
- writeOson(value) {
579
+ writeOson(value, osonMaxFieldSize) {
529
580
  const encoder = new oson.OsonEncoder();
530
- const buf = encoder.encode(value);
581
+ const buf = encoder.encode(value, osonMaxFieldSize);
531
582
  this.writeQLocator(buf.length);
532
583
  this.writeBytesWithLength(buf);
533
584
  }
@@ -537,6 +588,40 @@ class WritePacket extends BaseBuffer {
537
588
  this.protocol.sequenceId = (this.protocol.sequenceId + 1) % 256;
538
589
  }
539
590
 
591
+ /**
592
+ * Encodes a JavaScript object into VECTOR data and then writes it (QLocator
593
+ * followed by data) to the buffer.
594
+ */
595
+ writeVector(value) {
596
+ const encoder = new vector.VectorEncoder();
597
+ const buf = encoder.encode(value);
598
+ this.writeQLocator(buf.length);
599
+ this.writeBytesWithLength(buf);
600
+ }
601
+
602
+ //---------------------------------------------------------------------------
603
+ // writeQLocator()
604
+ //
605
+ // Writes a QLocator. QLocators are always 40 bytes in length.
606
+ //---------------------------------------------------------------------------
607
+ writeQLocator(numBytes) {
608
+ this.writeUB4(40); // QLocator length
609
+ this.writeUInt8(40); // repeated length
610
+ this.writeUInt16BE(38); // internal length
611
+ this.writeUInt16BE(constants.TNS_LOB_QLOCATOR_VERSION);
612
+ this.writeUInt8(constants.TNS_LOB_LOC_FLAGS_VALUE_BASED |
613
+ constants.TNS_LOB_LOC_FLAGS_BLOB | constants.TNS_LOB_LOC_FLAGS_ABSTRACT);
614
+ this.writeUInt8(constants.TNS_LOB_LOC_FLAGS_INIT);
615
+ this.writeUInt16BE(0); // additional flags
616
+ this.writeUInt16BE(1); // byt1
617
+ this.writeUInt64BE(numBytes);
618
+ this.writeUInt16BE(0); // unused
619
+ this.writeUInt16BE(0); // csid
620
+ this.writeUInt16BE(0); // unused
621
+ this.writeUInt64BE(0); // unused
622
+ this.writeUInt64BE(0); // unused
623
+ }
624
+
540
625
  }
541
626
 
542
627
  module.exports = {
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -49,7 +49,7 @@ class Protocol {
49
49
  * Compile and Runtime capabilities negotiated with Server
50
50
  * @type {object}
51
51
  */
52
- this.caps = new Capabilities(conn.nscon.sAtts.version);
52
+ this.caps = new Capabilities(conn.nscon);
53
53
  this.writeBuf = new WritePacket(conn.nscon, this.caps, this);
54
54
  this.readBuf = new ReadPacket(conn.nscon, this.caps);
55
55
  this.callTimeout = 0;
@@ -67,11 +67,11 @@ class Protocol {
67
67
  */
68
68
  async _decodeMessage(message) {
69
69
  message.preProcess();
70
- await this.readBuf.waitForPackets();
70
+ await this.readBuf.waitForPackets(true);
71
71
  while (true) { // eslint-disable-line
72
72
  if (this.nsi.isBreak) {
73
73
  await this.resetMessage();
74
- delete this.readBuf.savedBuffers;
74
+ delete this.readBuf.savedPackets;
75
75
  await this.readBuf.waitForPackets();
76
76
  }
77
77
  try {
@@ -164,7 +164,12 @@ class Protocol {
164
164
  if (message.flushOutBinds) {
165
165
  await this.flushOutBindMessage(message);
166
166
  }
167
- this.txnInProgress = message.callStatus & constants.TNS_TXN_IN_PROGRESS;
167
+ this.txnInProgress = Boolean(message.callStatus & constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
168
+ // processes the call status flags returned by the server.
169
+ if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
170
+ message.connection.statementCache.clearCursors();
171
+ }
172
+
168
173
  if (message.errorOccurred) {
169
174
  if (callTimeoutExpired) {
170
175
  errors.throwErr(errors.ERR_CALL_TIMEOUT_EXCEEDED, this.callTimeout);
@@ -52,30 +52,23 @@ function encodeRowID(rowID) {
52
52
  }
53
53
  }
54
54
 
55
- // obfuscate value and clear memory for Buffers as they are from Buffer pool
56
- // and are possible to stay longer
55
+ // obfuscate value
57
56
  function setObfuscatedValue(value) {
58
- const buf = crypto.randomBytes(Buffer.byteLength(value));
59
- const bytes = Buffer.from(value, 'utf8');
60
- const len = Buffer.byteLength(value);
61
-
62
- const arr = [];
63
- for (let i = 0; i < len; i++) {
64
- arr.push(buf[i] ^ bytes[i]);
57
+ const valueBytes = Buffer.from(value);
58
+ const obfuscatedBytes = crypto.randomBytes(valueBytes.length);
59
+ for (let i = 0; i < valueBytes.length; i++) {
60
+ valueBytes[i] = obfuscatedBytes[i] ^ valueBytes[i];
65
61
  }
66
- bytes.fill(0);
67
- return {obfuscatedValue: buf, value: arr};
62
+ return {obfuscatedValue: obfuscatedBytes, value: valueBytes};
68
63
  }
69
64
 
70
- // returns the Deobfuscated value, after removing the obfuscation
65
+ // returns the deobfuscated value, after removing the obfuscation
71
66
  // and clear memory of temporary Buffers coming from Buffer pool
72
- function getDeobfuscatedValue(value, obfuscatedValue) {
73
- const arr = [];
74
- for (let i = 0; i < value.length; i++) {
75
- arr.push(value[i] ^ obfuscatedValue[i]);
67
+ function getDeobfuscatedValue(valueBytes, obfuscatedBytes) {
68
+ const buf = Buffer.from(valueBytes);
69
+ for (let i = 0; i < valueBytes.length; i++) {
70
+ buf[i] = valueBytes[i] ^ obfuscatedBytes[i];
76
71
  }
77
- const buf = Buffer.from(arr);
78
- arr.fill(0);
79
72
  const retVal = buf.toString();
80
73
  buf.fill(0);
81
74
  return retVal;
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -107,7 +107,8 @@ module.exports = {
107
107
  NSGRAW: 0x1000, // I/O is direct to/from transport
108
108
  TNS_VERSION_DESIRED: 319,
109
109
  TNS_VERSION_MINIMUM: 300,
110
- TNS_VERSION_MIN_UUID: 319,
110
+ TNS_VERSION_MIN_DATA_FLAGS: 318,
111
+ TNS_VERSION_MIN_END_OF_RESPONSE: 319,
111
112
  TNS_UUID_OFFSET: 45,
112
113
 
113
114
  /* Accept Packet */
@@ -143,6 +144,8 @@ module.exports = {
143
144
  // Accept flag2
144
145
  NSPACOOB: 0x00000001, // OOB support check at connection time
145
146
  NSGPCHKSCMD: 0x01000000, // Support for Poll and Check logic
147
+ TNS_ACCEPT_FLAG_HAS_END_OF_REQUEST: 0x02000000,
148
+ TNS_ACCEPT_FLAG_FAST_AUTH: 0x10000000, // Support Fast Auth
146
149
 
147
150
  /* Redirect packet */
148
151
  NSPRDLEN: 8, // Length of redirect data
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1
+ // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -164,6 +164,7 @@ class EZConnectResolver {
164
164
  const poolConnectionClass = this.urlProps.get("POOL_CONNECTION_CLASS");
165
165
  const poolPurity = this.urlProps.get("POOL_PURITY");
166
166
  const serviceTag = this.urlProps.get("SERVICE_TAG");
167
+ const poolBoundary = this.urlProps.get("POOL_BOUNDARY");
167
168
 
168
169
  const parts = [];
169
170
  if (serviceName)
@@ -182,6 +183,8 @@ class EZConnectResolver {
182
183
  parts.push(`(SERVICE_TAG=${serviceTag})`);
183
184
  if (connectionIdPrefix)
184
185
  parts.push(`(CONNECTION_ID_PREFIX=${connectionIdPrefix})`);
186
+ if (poolBoundary)
187
+ parts.push(`(POOL_BOUNDARY=${poolBoundary})`);
185
188
  return `(CONNECT_DATA=${parts.join("")})`;
186
189
  }
187
190
 
@@ -211,17 +214,17 @@ class EZConnectResolver {
211
214
  let naddr = 0;
212
215
  // ; groups the user into a ADDRESS_LIST
213
216
  const addressLists = hostInfo.split(";");
214
- for (const addressList in addressLists) {
217
+ for (const addressList of addressLists) {
215
218
  let addressNodeCount = 0;
216
219
  const addressListBuilder = new Array();
217
- for (const match of addressLists[addressList].matchAll(HOSTNAMES_PATTERN)) {
220
+ for (const match of addressList.matchAll(HOSTNAMES_PATTERN)) {
218
221
  const hostnames = (match.groups.hostnames).split(',');
219
222
  let port = match.groups.port;
220
223
  if (port == null) {
221
224
  port = '1521'; //default port
222
225
  }
223
- for (const hname in hostnames) {
224
- addressListBuilder.push(this.getAddrStr(hostnames[hname], port, protocol, proxyInfo));
226
+ for (const hname of hostnames) {
227
+ addressListBuilder.push(this.getAddrStr(hname, port, protocol, proxyInfo));
225
228
  addressNodeCount++;
226
229
  }
227
230
  }
@@ -455,6 +458,7 @@ class EZConnectResolver {
455
458
  aliasMap.set("pool_purity", "POOL_PURITY");
456
459
  aliasMap.set("service_tag", "SERVICE_TAG");
457
460
  aliasMap.set("connection_id_prefix", "CONNECTION_ID_PREFIX");
461
+ aliasMap.set("pool_boundary", "POOL_BOUNDARY");
458
462
  return aliasMap;
459
463
  }
460
464
  }module.exports = EZConnectResolver;
@@ -486,7 +486,7 @@ class NavAddress extends Address {
486
486
  if (!net.isIP(this.host)) {
487
487
  try {
488
488
  addresses = await dnsPromises.lookup(this.host, options);
489
- for (const addr in addresses) {
489
+ for (const addr of addresses) {
490
490
  const co = new ConnOption();
491
491
  co.hostname = this.host;
492
492
  co.port = this.port;
@@ -499,7 +499,7 @@ class NavAddress extends Address {
499
499
  co.CNdata.push('(address=(protocol=' + this.prot + ')(host=' + this.host + ')(port=' + this.port + '))');
500
500
  else
501
501
  co.CNdata.push(this.toString());
502
- co.host = addresses[addr].address;
502
+ co.host = addr.address;
503
503
  co.addr = this.addr;
504
504
  cs.getcurrentDescription().addConnectOption(co);
505
505
  }
@@ -777,7 +777,8 @@ class NavDescription extends Description {
777
777
  if (this.connectData == null) {
778
778
  this.connectData = "(SERVICE_NAME=)";
779
779
  }
780
- const cid = `(CID=(PROGRAM=${cInfo.program})(HOST=${cInfo.hostName})(USER=${cInfo.userName}))`;
780
+ const pgmName = "\"'" + cInfo.program + "'\"";
781
+ const cid = `(CID=(PROGRAM=${pgmName})(HOST=${cInfo.hostName})(USER=${cInfo.userName}))`;
781
782
  cOpts[i].CNdata.push(NavSchemaObject.CD);
782
783
  cOpts[i].CNdata.push(this.connectData);
783
784
  cOpts[i].CNdata.push(cid);