oracledb 6.2.0 → 6.4.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 (70) 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.4.0-darwin-x64.node +0 -0
  5. package/build/Release/oracledb-6.4.0-darwin-x64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-6.4.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-6.4.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-6.4.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.4.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-6.4.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.4.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-6.4.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/examples/README.md +29 -8
  14. package/examples/dbconfig.js +50 -26
  15. package/examples/example.js +6 -4
  16. package/lib/aqQueue.js +8 -8
  17. package/lib/connection.js +121 -9
  18. package/lib/constants.js +7 -1
  19. package/lib/dbObject.js +72 -1
  20. package/lib/errors.js +45 -8
  21. package/lib/future.js +53 -0
  22. package/lib/impl/connection.js +56 -0
  23. package/lib/{thin/protocol → impl/datahandlers}/buffer.js +51 -39
  24. package/lib/impl/datahandlers/constants.js +105 -0
  25. package/lib/{thin/protocol → impl/datahandlers}/oson.js +19 -1
  26. package/lib/impl/datahandlers/vector.js +156 -0
  27. package/lib/impl/pool.js +14 -3
  28. package/lib/impl/resultset.js +65 -11
  29. package/lib/lob.js +22 -6
  30. package/lib/oracledb.js +47 -8
  31. package/lib/pool.js +20 -1
  32. package/lib/poolStatistics.js +3 -1
  33. package/lib/settings.js +30 -6
  34. package/lib/sodaDocCursor.js +14 -1
  35. package/lib/thin/connection.js +146 -146
  36. package/lib/thin/dbObject.js +49 -3
  37. package/lib/thin/index.js +1 -1
  38. package/lib/thin/lob.js +6 -6
  39. package/lib/thin/pool.js +25 -6
  40. package/lib/thin/protocol/capabilities.js +6 -2
  41. package/lib/thin/protocol/constants.js +50 -65
  42. package/lib/thin/protocol/messages/auth.js +6 -2
  43. package/lib/thin/protocol/messages/base.js +50 -32
  44. package/lib/thin/protocol/messages/dataType.js +10 -6
  45. package/lib/thin/protocol/messages/lobOp.js +7 -8
  46. package/lib/thin/protocol/messages/withData.js +91 -24
  47. package/lib/thin/protocol/packet.js +58 -4
  48. package/lib/thin/protocol/utils.js +1 -1
  49. package/lib/thin/sqlnet/connStrategy.js +8 -4
  50. package/lib/thin/sqlnet/constants.js +138 -138
  51. package/lib/thin/sqlnet/navNodes.js +5 -5
  52. package/lib/thin/sqlnet/networkSession.js +22 -3
  53. package/lib/thin/sqlnet/ntTcp.js +7 -7
  54. package/lib/thin/statement.js +8 -8
  55. package/lib/thin/statementCache.js +167 -0
  56. package/lib/thin/util.js +15 -4
  57. package/lib/transformer.js +13 -4
  58. package/lib/types.js +17 -2
  59. package/lib/util.js +37 -0
  60. package/lib/version.js +2 -2
  61. package/package.json +1 -1
  62. package/build/Release/oracledb-6.2.0-darwin-x64.node +0 -0
  63. package/build/Release/oracledb-6.2.0-darwin-x64.node-buildinfo.txt +0 -1
  64. package/build/Release/oracledb-6.2.0-js-buildinfo.txt +0 -1
  65. package/build/Release/oracledb-6.2.0-linux-arm64.node +0 -0
  66. package/build/Release/oracledb-6.2.0-linux-arm64.node-buildinfo.txt +0 -1
  67. package/build/Release/oracledb-6.2.0-linux-x64.node +0 -0
  68. package/build/Release/oracledb-6.2.0-linux-x64.node-buildinfo.txt +0 -1
  69. package/build/Release/oracledb-6.2.0-win32-x64.node +0 -0
  70. package/build/Release/oracledb-6.2.0-win32-x64.node-buildinfo.txt +0 -1
@@ -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
  //
@@ -30,7 +30,7 @@ const { Buffer } = require('buffer');
30
30
  const utils = require("../utils");
31
31
  const constants = require("../constants.js");
32
32
  const Message = require("./base.js");
33
- const ThinDbObjectImpl = require("../../dbObject.js");
33
+ const { ThinDbObjectImpl, readXML } = require("../../dbObject.js");
34
34
  const ThinLobImpl = require("../../lob.js");
35
35
  const errors = require('../../../errors');
36
36
  const types = require('../../../types.js');
@@ -117,7 +117,7 @@ class MessageWithData extends Message {
117
117
  this.errorOccurred = false;
118
118
  this.statement.moreRowsToFetch = false;
119
119
  } else if (this.errorInfo.num !== 0 && this.errorInfo.cursorId !== 0) {
120
- this.connection.statementCache.delete(this.statement.sql);
120
+ this.connection.statementCache._cachedStatements.delete(this.statement.sql);
121
121
  this.statement.returnToCache = false;
122
122
  }
123
123
  if (this.errorInfo.batchErrors) {
@@ -148,15 +148,16 @@ class MessageWithData extends Message {
148
148
  buf.skipUB1();
149
149
  }
150
150
  resultSet.metadata = [];
151
+ const metadata = [];
152
+ const queryVars = [];
151
153
  for (let i = 0; i < statement.numQueryVars; i++) {
152
154
  const variable = this.processColumnInfo(buf, i + 1);
153
155
  if (prevQueryVars && i < prevQueryVars.length) {
154
156
  this._adjustFetchType(prevQueryVars[i], variable);
155
157
  }
156
- statement.queryVars.push(variable);
157
- resultSet.metadata.push(variable.fetchInfo);
158
+ queryVars.push(variable);
159
+ metadata.push(variable.fetchInfo);
158
160
  }
159
-
160
161
  let numBytes = buf.readUB4();
161
162
  if (numBytes > 0) {
162
163
  buf.skipBytesChunked(); // current date
@@ -170,6 +171,13 @@ class MessageWithData extends Message {
170
171
  buf.skipBytesChunked();
171
172
  }
172
173
 
174
+ /*
175
+ * The message state(resultSet) and statement state(queryVars) is modified
176
+ * at end of the DescribeInfo function so that an OutOfPacketsError
177
+ * won't cause partial information state to be stored.
178
+ */
179
+ resultSet.metadata = metadata;
180
+ statement.queryVars = queryVars;
173
181
  this.resultSetsToSetup.push(resultSet);
174
182
  }
175
183
 
@@ -177,19 +185,10 @@ class MessageWithData extends Message {
177
185
  const dataType = buf.readUInt8();
178
186
  buf.skipUB1(); // flags
179
187
  const precision = buf.readInt8();
180
- let scale;
181
- if (dataType === constants.TNS_DATA_TYPE_NUMBER ||
182
- dataType === constants.TNS_DATA_TYPE_INTERVAL_DS ||
183
- dataType === constants.TNS_DATA_TYPE_TIMESTAMP ||
184
- dataType === constants.TNS_DATA_TYPE_TIMESTAMP_LTZ ||
185
- dataType === constants.TNS_DATA_TYPE_TIMESTAMP_TZ) {
186
- scale = buf.readSB2();
187
- } else {
188
- scale = buf.readInt8();
189
- }
188
+ const scale = buf.readInt8();
190
189
  const maxSize = buf.readUB4();
191
190
  buf.skipUB4(); // max number of array elements
192
- buf.skipUB4(); // cont flags
191
+ buf.skipUB8(); // cont flags
193
192
  let oid;
194
193
  let numBytes = buf.readUB4(); // OID
195
194
  if (numBytes > 0) {
@@ -223,7 +222,7 @@ class MessageWithData extends Message {
223
222
  typeName = buf.readStr(constants.CSFRM_IMPLICIT);
224
223
  }
225
224
  buf.skipUB2(); // column position
226
- buf.skipUB4(); // uds flag
225
+ const udsFlags = buf.readUB4(); // uds flag
227
226
 
228
227
  // build metadata
229
228
  const fetchInfo = {
@@ -231,6 +230,53 @@ class MessageWithData extends Message {
231
230
  dbType: types.getTypeByOraTypeNum(dataType, csfrm),
232
231
  nullable: nullable
233
232
  };
233
+ fetchInfo.isJson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_JSON);
234
+ fetchInfo.isOson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_OSON);
235
+ if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) {
236
+ numBytes = buf.readUB4();
237
+ if (numBytes > 0) {
238
+ fetchInfo.domainSchema = buf.readStr(constants.CSFRM_IMPLICIT);
239
+ }
240
+ numBytes = buf.readUB4();
241
+ if (numBytes > 0) {
242
+ fetchInfo.domainName = buf.readStr(constants.CSFRM_IMPLICIT);
243
+ }
244
+ }
245
+ if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1_EXT_3) {
246
+ if (buf.readUB4() > 0) {
247
+ fetchInfo.annotations = {};
248
+ buf.skipUB1();
249
+ const numAnnotations = buf.readUB4();
250
+ buf.skipUB1();
251
+ let key, value;
252
+ for (let i = 0; i < numAnnotations; i++) {
253
+ buf.skipUB4();
254
+ value = "";
255
+ key = buf.readStr(constants.CSFRM_IMPLICIT);
256
+ numBytes = buf.readUB4();
257
+ if (numBytes > 0) {
258
+ value = buf.readStr(constants.CSFRM_IMPLICIT);
259
+ }
260
+ fetchInfo.annotations[key] = value;
261
+ buf.skipUB4(); // flags
262
+ }
263
+ buf.skipUB4(); // flags
264
+ }
265
+ }
266
+ if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_4) {
267
+ const dimensions = buf.readUB4();
268
+ const vectorFormat = buf.readUInt8();
269
+ const vectorFlags = buf.readUInt8();
270
+ if (fetchInfo.dbType === types.DB_TYPE_VECTOR) {
271
+ if (!(vectorFlags & constants.VECTOR_META_FLAG_FLEXIBLE_DIM)) {
272
+ fetchInfo.vectorDimensions = dimensions;
273
+ }
274
+ if (vectorFormat !== constants.VECTOR_FORMAT_FLEX) {
275
+ fetchInfo.vectorFormat = vectorFormat;
276
+ }
277
+ }
278
+ }
279
+
234
280
  switch (fetchInfo.dbType) {
235
281
  case types.DB_TYPE_VARCHAR:
236
282
  case types.DB_TYPE_NVARCHAR:
@@ -253,6 +299,9 @@ class MessageWithData extends Message {
253
299
  if (fetchInfo.dbTypeClass.partial) {
254
300
  this.connection._partialDbObjectTypes.push(fetchInfo.dbTypeClass);
255
301
  }
302
+ if (fetchInfo.dbTypeClass.isXmlType) {
303
+ fetchInfo.dbType = types.DB_TYPE_XMLTYPE;
304
+ }
256
305
  break;
257
306
  default:
258
307
  break;
@@ -454,14 +503,21 @@ class MessageWithData extends Message {
454
503
  }
455
504
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) {
456
505
  colValue = buf.readOson();
506
+ } else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) {
507
+ colValue = buf.readVector();
457
508
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_INT_NAMED) {
458
509
  const obj = buf.readDbObject();
459
510
  if (obj.packedData) {
460
511
  const objType = (variable.fetchInfo) ? variable.fetchInfo.dbTypeClass :
461
512
  variable.typeClass;
462
- colValue = new ThinDbObjectImpl(objType, obj.packedData);
463
- colValue.toid = obj.toid;
464
- colValue.oid = obj.oid;
513
+
514
+ if (variable.type === types.DB_TYPE_XMLTYPE) {
515
+ colValue = readXML(this.connection, obj.packedData);
516
+ } else {
517
+ colValue = new ThinDbObjectImpl(objType, obj.packedData);
518
+ colValue.toid = obj.toid;
519
+ colValue.oid = obj.oid;
520
+ }
465
521
  }
466
522
  } else {
467
523
  errors.throwErr(errors.ERR_UNSUPPORTED_DATA_TYPE, dbType.num,
@@ -472,7 +528,10 @@ class MessageWithData extends Message {
472
528
  const actualNumBytes = buf.readSB4();
473
529
  if (actualNumBytes < 0 && oraTypeNum === constants.TNS_DATA_TYPE_BOOLEAN) {
474
530
  colValue = null;
475
- } else if (actualNumBytes !== 0 && colValue !== null) {
531
+
532
+ // For objects, maxsize validation is skipped
533
+ } else if (actualNumBytes !== 0 && colValue !== null &&
534
+ oraTypeNum !== constants.TNS_DATA_TYPE_INT_NAMED) {
476
535
  this.saveDeferredErr(errors.ERR_INSUFFICIENT_BUFFER_FOR_BINDS);
477
536
  }
478
537
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_LONG || oraTypeNum === constants.TNS_DATA_TYPE_LONG_RAW || variable.maxSize > buf.caps.maxStringSize) {
@@ -554,7 +613,8 @@ class MessageWithData extends Message {
554
613
  if (variable.type === types.DB_TYPE_CLOB ||
555
614
  variable.type === types.DB_TYPE_NCLOB ||
556
615
  variable.type === types.DB_TYPE_BLOB ||
557
- variable.type === types.DB_TYPE_JSON) {
616
+ variable.type === types.DB_TYPE_JSON ||
617
+ variable.type === types.DB_TYPE_VECTOR) {
558
618
  if (variable.type !== variable.fetchInfo.fetchType) {
559
619
  variable.type = variable.fetchInfo.fetchType;
560
620
  variable.maxSize = constants.TNS_MAX_LONG_LENGTH;
@@ -639,6 +699,9 @@ class MessageWithData extends Message {
639
699
  } else if (variable.type === types.DB_TYPE_JSON) {
640
700
  contFlag = constants.TNS_LOB_PREFETCH_FLAG;
641
701
  maxSize = lobPrefetchLength = constants.TNS_JSON_MAX_LENGTH;
702
+ } else if (variable.type === types.DB_TYPE_VECTOR) {
703
+ contFlag = constants.TNS_LOB_PREFETCH_FLAG;
704
+ maxSize = lobPrefetchLength = constants.TNS_VECTOR_MAX_LENGTH;
642
705
  }
643
706
  buf.writeUInt8(oraTypeNum);
644
707
  buf.writeUInt8(flag);
@@ -694,7 +757,7 @@ class MessageWithData extends Message {
694
757
  this.writeBindParamsColumn(buf, variable, variable.values[i]);
695
758
  }
696
759
  } else {
697
- if (variable.maxSize > buf.caps.maxStringSize) {
760
+ if ((!this.statement.isPlSql) && variable.maxSize > buf.caps.maxStringSize) {
698
761
  foundLong = true;
699
762
  } else {
700
763
  this.writeBindParamsColumn(buf, variable,
@@ -759,8 +822,10 @@ class MessageWithData extends Message {
759
822
  ) {
760
823
  buf.writeOracleDate(value, variable.type);
761
824
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_BINARY_DOUBLE) {
825
+ buf.writeUInt8(8);
762
826
  buf.writeBinaryDouble(value);
763
827
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_BINARY_FLOAT) {
828
+ buf.writeUInt8(4);
764
829
  buf.writeBinaryFloat(value);
765
830
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_CURSOR) {
766
831
  let cursor = value;
@@ -788,6 +853,8 @@ class MessageWithData extends Message {
788
853
  buf.writeBytesWithLength(Buffer.from(value));
789
854
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) {
790
855
  buf.writeOson(value);
856
+ } else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) {
857
+ buf.writeVector(value);
791
858
  } else if (oraTypeNum === constants.TNS_DATA_TYPE_INT_NAMED) {
792
859
  buf.writeDbObject(value);
793
860
  } 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,11 +26,12 @@
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');
@@ -395,6 +396,22 @@ class ReadPacket extends BaseBuffer {
395
396
  return {rba, partitionID, blockNum, slotNum};
396
397
  }
397
398
 
399
+ /**
400
+ * Reads VECTOR data (QLocator followed by data) and decodes it into a
401
+ * JavaScript object.
402
+ */
403
+ readVector() {
404
+ const numBytes = this.readUB4();
405
+ if (numBytes === 0) {
406
+ return null;
407
+ }
408
+ this.skipUB8(); // size (unused)
409
+ this.skipUB4(); // chunk size (unused)
410
+ const decoder = new vector.VectorDecoder(this.readBytesWithLength());
411
+ this.skipBytesChunked(); // locator (unused)
412
+ return decoder.decode();
413
+ }
414
+
398
415
  skipBytesChunked() {
399
416
  const numBytes = this.readUInt8();
400
417
  if (numBytes === 0 || numBytes === constants.TNS_NULL_LENGTH_INDICATOR) {
@@ -479,6 +496,9 @@ class WritePacket extends BaseBuffer {
479
496
  buf = Buffer.from(buf);
480
497
  this.startPacket();
481
498
  }
499
+ if (!this.nsi.ntAdapter) {
500
+ errors.throwErr(errors.ERR_INVALID_CONNECTION);
501
+ }
482
502
  this.nsi.ntAdapter.send(buf);
483
503
  }
484
504
 
@@ -537,6 +557,40 @@ class WritePacket extends BaseBuffer {
537
557
  this.protocol.sequenceId = (this.protocol.sequenceId + 1) % 256;
538
558
  }
539
559
 
560
+ /**
561
+ * Encodes a JavaScript object into VECTOR data and then writes it (QLocator
562
+ * followed by data) to the buffer.
563
+ */
564
+ writeVector(value) {
565
+ const encoder = new vector.VectorEncoder();
566
+ const buf = encoder.encode(value);
567
+ this.writeQLocator(buf.length);
568
+ this.writeBytesWithLength(buf);
569
+ }
570
+
571
+ //---------------------------------------------------------------------------
572
+ // writeQLocator()
573
+ //
574
+ // Writes a QLocator. QLocators are always 40 bytes in length.
575
+ //---------------------------------------------------------------------------
576
+ writeQLocator(numBytes) {
577
+ this.writeUB4(40); // QLocator length
578
+ this.writeUInt8(40); // repeated length
579
+ this.writeUInt16BE(38); // internal length
580
+ this.writeUInt16BE(constants.TNS_LOB_QLOCATOR_VERSION);
581
+ this.writeUInt8(constants.TNS_LOB_LOC_FLAGS_VALUE_BASED |
582
+ constants.TNS_LOB_LOC_FLAGS_BLOB | constants.TNS_LOB_LOC_FLAGS_ABSTRACT);
583
+ this.writeUInt8(constants.TNS_LOB_LOC_FLAGS_INIT);
584
+ this.writeUInt16BE(0); // additional flags
585
+ this.writeUInt16BE(1); // byt1
586
+ this.writeUInt64BE(numBytes);
587
+ this.writeUInt16BE(0); // unused
588
+ this.writeUInt16BE(0); // csid
589
+ this.writeUInt16BE(0); // unused
590
+ this.writeUInt64BE(0); // unused
591
+ this.writeUInt64BE(0); // unused
592
+ }
593
+
540
594
  }
541
595
 
542
596
  module.exports = {
@@ -64,7 +64,7 @@ function setObfuscatedValue(value) {
64
64
  arr.push(buf[i] ^ bytes[i]);
65
65
  }
66
66
  bytes.fill(0);
67
- return {obfuscatedValue : buf, value : arr};
67
+ return {obfuscatedValue: buf, value: arr};
68
68
  }
69
69
 
70
70
  // returns the Deobfuscated value, after removing the obfuscation
@@ -53,16 +53,20 @@ class ConnectDescription {
53
53
  */
54
54
  class ConnStrategy {
55
55
  constructor() {
56
- this.nextOptToTry = 0;
57
- this.reorderDescriptionList = 0;
56
+ this.reset();
58
57
  this.retryCount = 0;
59
- this.lastRetryCounter = 0;
60
- this.lastRetryConnectDescription = 0;
61
58
  this.currentDescription = null;
62
59
  this.descriptionList = new Array();
63
60
  this.sBuf = new Array();
64
61
  }
65
62
 
63
+ reset() {
64
+ this.nextOptToTry = 0;
65
+ this.lastRetryCounter = 0;
66
+ this.lastRetryConnectDescription = 0;
67
+ this.reorderDescriptionList = 0;
68
+ }
69
+
66
70
  hasMoreOptions() {
67
71
  let cOptsSize = 0;
68
72