oracledb 6.5.1 → 6.7.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 (73) hide show
  1. package/README.md +2 -2
  2. package/build/Release/oracledb-6.7.0-darwin-arm64.node +0 -0
  3. package/build/Release/oracledb-6.7.0-darwin-arm64.node-buildinfo.txt +1 -0
  4. package/build/Release/oracledb-6.7.0-darwin-x64.node +0 -0
  5. package/build/Release/oracledb-6.7.0-darwin-x64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-6.7.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-6.7.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-6.7.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.7.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-6.7.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.7.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-6.7.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/examples/README.md +4 -0
  14. package/lib/configProviders/azure.js +178 -0
  15. package/lib/configProviders/base.js +85 -0
  16. package/lib/configProviders/ociobject.js +211 -0
  17. package/lib/connection.js +97 -14
  18. package/lib/constants.js +1 -0
  19. package/lib/errors.js +68 -6
  20. package/lib/impl/aqQueue.js +2 -1
  21. package/lib/impl/base.js +45 -0
  22. package/lib/impl/connection.js +53 -0
  23. package/lib/impl/datahandlers/constants.js +3 -1
  24. package/lib/impl/datahandlers/vector.js +24 -9
  25. package/lib/impl/lob.js +29 -1
  26. package/lib/impl/pool.js +15 -0
  27. package/lib/impl/resultset.js +28 -2
  28. package/lib/impl/sodaCollection.js +2 -1
  29. package/lib/impl/sodaDatabase.js +2 -1
  30. package/lib/impl/sodaDocCursor.js +2 -1
  31. package/lib/impl/sodaOperation.js +2 -1
  32. package/lib/lob.js +55 -3
  33. package/lib/oracledb.js +246 -7
  34. package/lib/pool.js +14 -5
  35. package/lib/settings.js +1 -0
  36. package/lib/thin/connection.js +304 -29
  37. package/lib/thin/dbObject.js +4 -0
  38. package/lib/thin/lob.js +193 -1
  39. package/lib/thin/pool.js +18 -0
  40. package/lib/thin/protocol/capabilities.js +2 -0
  41. package/lib/thin/protocol/constants.js +29 -1
  42. package/lib/thin/protocol/messages/auth.js +12 -6
  43. package/lib/thin/protocol/messages/base.js +3 -0
  44. package/lib/thin/protocol/messages/index.js +5 -1
  45. package/lib/thin/protocol/messages/lobOp.js +17 -5
  46. package/lib/thin/protocol/messages/sessionRelease.js +1 -0
  47. package/lib/thin/protocol/messages/transactionChangeState.js +99 -0
  48. package/lib/thin/protocol/messages/transactionSwitch.js +139 -0
  49. package/lib/thin/protocol/messages/withData.js +21 -6
  50. package/lib/thin/protocol/protocol.js +23 -0
  51. package/lib/thin/sqlnet/connStrategy.js +9 -1
  52. package/lib/thin/sqlnet/constants.js +2 -0
  53. package/lib/thin/sqlnet/navNodes.js +14 -2
  54. package/lib/thin/sqlnet/networkSession.js +11 -10
  55. package/lib/thin/sqlnet/ntTcp.js +1 -1
  56. package/lib/thin/sqlnet/paramParser.js +87 -50
  57. package/lib/thin/sqlnet/sessionAtts.js +14 -2
  58. package/lib/thin/util.js +4 -3
  59. package/lib/traceHandler.js +133 -0
  60. package/lib/transformer.js +1 -2
  61. package/lib/types.js +1 -1
  62. package/lib/util.js +213 -35
  63. package/lib/version.js +2 -2
  64. package/package.json +1 -1
  65. package/build/Release/oracledb-6.5.1-darwin-x64.node +0 -0
  66. package/build/Release/oracledb-6.5.1-darwin-x64.node-buildinfo.txt +0 -1
  67. package/build/Release/oracledb-6.5.1-js-buildinfo.txt +0 -1
  68. package/build/Release/oracledb-6.5.1-linux-arm64.node +0 -0
  69. package/build/Release/oracledb-6.5.1-linux-arm64.node-buildinfo.txt +0 -1
  70. package/build/Release/oracledb-6.5.1-linux-x64.node +0 -0
  71. package/build/Release/oracledb-6.5.1-linux-x64.node-buildinfo.txt +0 -1
  72. package/build/Release/oracledb-6.5.1-win32-x64.node +0 -0
  73. package/build/Release/oracledb-6.5.1-win32-x64.node-buildinfo.txt +0 -1
@@ -60,7 +60,13 @@ class ThinConnectionImpl extends ConnectionImpl {
60
60
  async close() {
61
61
  try {
62
62
  if (this._protocol.txnInProgress) {
63
- await this.rollback();
63
+ if (this.tpcContext) {
64
+ const message = this.createTpcRollbackMessage();
65
+ await this._protocol._processMessage(message);
66
+ } else {
67
+ await this.rollback();
68
+ }
69
+ this.tpcContext = null;
64
70
  }
65
71
  if (this._drcpEnabled) {
66
72
  await this._sessRelease();
@@ -163,12 +169,27 @@ class ThinConnectionImpl extends ConnectionImpl {
163
169
  //---------------------------------------------------------------------------
164
170
  async _execute(statement, numIters, binds, options, executeManyFlag) {
165
171
 
172
+ // Throw error if executeMany is not called on a DML statement or PL/SQL
173
+ if (executeManyFlag && statement.isQuery) {
174
+ errors.throwErr(errors.ERR_EXECMANY_NOT_ALLOWED_ON_QUERIES);
175
+ }
166
176
  // perform binds
167
- const numBinds = statement.bindInfoList.length;
168
- const numVars = binds.length;
169
- if (numBinds !== numVars && (numVars === 0 || !binds[0].name)) {
170
- errors.throwErr(errors.ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS, numBinds, numVars);
177
+ const numStmtBinds = statement.bindInfoList.length;
178
+ const numUserBinds = binds.length;
179
+ if (numStmtBinds !== numUserBinds) {
180
+ if (!binds[0]?.name) {
181
+ // positional bind mismatch or zero binds
182
+ errors.throwErr(errors.ERR_WRONG_NUMBER_OF_BINDS, numStmtBinds, numUserBinds);
183
+ }
184
+
185
+ // named bind mismatch
186
+ // Find the number of distinct named bind placeholders and see
187
+ // if they match the bind values
188
+ const numDistinctStmtBinds = statement.bindInfoDict.size;
189
+ if (numDistinctStmtBinds !== numUserBinds)
190
+ errors.throwErr(errors.ERR_WRONG_NUMBER_OF_BINDS, numStmtBinds, numUserBinds);
171
191
  }
192
+
172
193
  for (let i = 0; i < binds.length; i++) {
173
194
  await this._bind(statement, binds[i], i + 1);
174
195
  }
@@ -385,6 +406,9 @@ class ThinConnectionImpl extends ConnectionImpl {
385
406
  info.elementType = this._parseTDSAttr(buf, info.elementTypeInfo);
386
407
  if (info.elementType === types.DB_TYPE_OBJECT) {
387
408
  await this._getElementTypeObj(info);
409
+ if (info.elementTypeClass.isXmlType) {
410
+ info.elementType = types.DB_TYPE_XMLTYPE;
411
+ }
388
412
  }
389
413
  } else {
390
414
  if (info.attributes) { // skip for XML type as it has no attributes.
@@ -395,6 +419,79 @@ class ThinConnectionImpl extends ConnectionImpl {
395
419
  }
396
420
  }
397
421
 
422
+ //---------------------------------------------------------------------------
423
+ // _populateRowTypeInfo()
424
+ //
425
+ // Get column and datatype information in case of %ROWTYPE handling.
426
+ //---------------------------------------------------------------------------
427
+ async _populateRowTypeInfo(info, options, result) {
428
+ const getColumnsSQL = `
429
+ SELECT
430
+ column_name,
431
+ data_type,
432
+ data_type_owner,
433
+ case
434
+ when data_type in
435
+ ('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2', 'RAW')
436
+ then data_length
437
+ else 0
438
+ end,
439
+ nvl(data_precision, 0),
440
+ nvl(data_scale, 0)
441
+ from all_tab_cols
442
+ where owner = :owner
443
+ and table_name = :name
444
+ and hidden_column != 'YES'
445
+ order by column_id`;
446
+
447
+ const bindVal = [
448
+ {
449
+ name: "owner",
450
+ type: types.DB_TYPE_VARCHAR,
451
+ maxSize: 128,
452
+ dir: constants.BIND_IN,
453
+ values: [result.outBinds.schema],
454
+ },
455
+ {
456
+ name: "name",
457
+ type: types.DB_TYPE_VARCHAR,
458
+ maxSize: 128,
459
+ dir: constants.BIND_IN,
460
+ values: [info.name.substring(0, info.name.length - 8)]
461
+ }
462
+ ];
463
+ const val = await this.execute(
464
+ getColumnsSQL, 1, bindVal, options, false
465
+ );
466
+ try {
467
+ const attrRows = await val.resultSet._getAllRows();
468
+ info.attributes = [];
469
+ for (const row of attrRows) {
470
+ const metaData = {
471
+ name: row[0],
472
+ dataType: row[1],
473
+ dataTypeOwner: row[2],
474
+ maxSize: row[3],
475
+ dataPrecision: row[4],
476
+ dataScale: row[5],
477
+ };
478
+ if (!metaData.dataTypeOwner) {
479
+ const startPos = row[1].indexOf('(');
480
+ const endPos = row[1].indexOf(')');
481
+ if (endPos > startPos) {
482
+ metaData.dataType = metaData.dataType.substring(0, startPos) +
483
+ metaData.dataType.substring(
484
+ endPos + 1, metaData.dataType.length
485
+ );
486
+ }
487
+ }
488
+ this._addAttr(info.attributes, metaData);
489
+ }
490
+ } finally {
491
+ val.resultSet.close();
492
+ }
493
+ }
494
+
398
495
  //---------------------------------------------------------------------------
399
496
  // _populateDbObjectTypeInfo()
400
497
  //
@@ -439,6 +536,7 @@ class ThinConnectionImpl extends ConnectionImpl {
439
536
  end;
440
537
  end if;
441
538
  end;`;
539
+
442
540
  const binds = [
443
541
  {
444
542
  name: "full_name",
@@ -510,37 +608,74 @@ class ThinConnectionImpl extends ConnectionImpl {
510
608
  errors.throwErr(errors.ERR_INVALID_OBJECT_TYPE_NAME, name);
511
609
  }
512
610
 
513
- // check cache; if already present, nothing more to do!
514
- const info = this._getDbObjectType(result.outBinds.schema,
515
- result.outBinds.name, result.outBinds.package_name, result.outBinds.oid);
516
- if (!info.partial)
517
- return info;
611
+ try {
612
+ // check cache; if already present, nothing more to do!
613
+ const info = this._getDbObjectType(result.outBinds.schema,
614
+ result.outBinds.name, result.outBinds.package_name, result.outBinds.oid);
615
+ if (!info.partial) {
616
+ return info;
617
+ }
518
618
 
519
- // process TDS and attributes cursor
520
- info.version = result.outBinds.version;
521
- const attrRows = await result.outBinds.attrs_rc.getRows(1000, {});
522
- if (attrRows.length > 0) {
523
- // Its an object not a collection.
524
- info.attributes = [];
525
- for (const row of attrRows) {
526
- const attr = { name: row[1] };
527
- if (row[4]) {
528
- attr.type = types.DB_TYPE_OBJECT;
529
- attr.typeClass = this._getDbObjectType(row[4], row[3], row[5], row[6]);
530
- if (attr.typeClass.partial) {
531
- this._partialDbObjectTypes.push(attr.typeClass);
619
+ // process TDS and attributes cursor
620
+ if (info.name.endsWith('%ROWTYPE')) {
621
+ await this._populateRowTypeInfo(info, options, result);
622
+ } else {
623
+ info.version = result.outBinds.version;
624
+ const attrRows = await result.outBinds.attrs_rc._getAllRows();
625
+ if (attrRows.length > 0) {
626
+ // Its an object not a collection.
627
+ info.attributes = [];
628
+ for (const row of attrRows) {
629
+ const metaData = {
630
+ name: row[1],
631
+ dataType: row[3],
632
+ dataTypeOwner: row[4],
633
+ packageName: row[5],
634
+ oid: row[6]
635
+ };
636
+ this._addAttr(info.attributes, metaData);
532
637
  }
533
- } else {
534
- attr.type = types.getTypeByColumnTypeName(row[3]);
638
+
535
639
  }
536
- info.attributes.push(attr);
640
+ await this._parseTDS(result.outBinds.tds, info);
537
641
  }
642
+ info.partial = false;
643
+ return info;
644
+ } finally {
645
+ result.outBinds.attrs_rc.close();
538
646
  }
539
647
 
540
- await this._parseTDS(result.outBinds.tds, info);
541
- info.partial = false;
542
- return info;
648
+ }
543
649
 
650
+ //---------------------------------------------------------------------------
651
+ // _addAttr()
652
+ //
653
+ // Populates "attributes" object present in "attrList".
654
+ //---------------------------------------------------------------------------
655
+ _addAttr(attributes, attrInfo) {
656
+ const attr = { name: attrInfo.name };
657
+ if (attrInfo.dataTypeOwner) {
658
+ attr.type = types.DB_TYPE_OBJECT;
659
+ attr.typeClass = this._getDbObjectType(
660
+ attrInfo.dataTypeOwner,
661
+ attrInfo.dataType,
662
+ attrInfo.packageName,
663
+ attrInfo.oid
664
+ );
665
+
666
+ if (attr.typeClass.isXmlType) {
667
+ attr.type = types.DB_TYPE_XMLTYPE;
668
+ }
669
+ if (attr.typeClass.partial) {
670
+ this._partialDbObjectTypes.push(attr.typeClass);
671
+ }
672
+ } else {
673
+ attr.type = types.getTypeByColumnTypeName(attrInfo.dataType);
674
+ attr.maxSize = attrInfo.maxSize;
675
+ attr.precision = attrInfo.dataPrecision;
676
+ attr.scale = attrInfo.dataScale;
677
+ }
678
+ attributes.push(attr);
544
679
  }
545
680
 
546
681
  //---------------------------------------------------------------------------
@@ -633,6 +768,7 @@ class ThinConnectionImpl extends ConnectionImpl {
633
768
  this.serviceName = '';
634
769
  this.remoteAddress = '';
635
770
  this.comboKey = null; // used in changePassword API
771
+ this.tpcContext = null;
636
772
 
637
773
  this.nscon = new nsi();
638
774
  finalizationRegistry.register(this, this.nscon);
@@ -693,8 +829,14 @@ class ThinConnectionImpl extends ConnectionImpl {
693
829
  await this._protocol._processMessage(authMessage);
694
830
  }
695
831
  } else {
832
+ // When Fast Auth is explicitly disabled on servers > 23ai,
833
+ // we dont rely on message type TNS_MSG_TYPE_END_OF_REQUEST too
834
+ // for protocolMessage and dataTypeMessage.
835
+ const endOfRequestSupport = this.nscon.endOfRequestSupport;
836
+ this.nscon.endOfRequestSupport = false;
696
837
  await this._protocol._processMessage(protocolMessage);
697
838
  await this._protocol._processMessage(dataTypeMessage);
839
+ this.nscon.endOfRequestSupport = endOfRequestSupport;
698
840
  await this._protocol._processMessage(authMessage);
699
841
  }
700
842
  if (!params.token) { // non-token Authentication
@@ -948,6 +1090,14 @@ class ThinConnectionImpl extends ConnectionImpl {
948
1090
  this._dbOp = dbOp;
949
1091
  }
950
1092
 
1093
+ setExternalName(value) {
1094
+ this.externalName = value;
1095
+ }
1096
+
1097
+ setInternalName(value) {
1098
+ this.internalName = value;
1099
+ }
1100
+
951
1101
  setClientInfo(clientInfo) {
952
1102
  this._clientInfoModified = true;
953
1103
  this._clientInfo = clientInfo;
@@ -986,6 +1136,102 @@ class ThinConnectionImpl extends ConnectionImpl {
986
1136
  return lobImpl;
987
1137
  }
988
1138
 
1139
+ // Check the state returned by the tpcCommit() call.
1140
+ checkTpcCommitState(state, onePhase) {
1141
+ if ((onePhase && state !== constants.TNS_TPC_TXN_STATE_READ_ONLY
1142
+ && state !== constants.TNS_TPC_TXN_STATE_COMMITTED) ||
1143
+ (!onePhase && state !== constants.TNS_TPC_TXN_STATE_FORGOTTEN)) {
1144
+ errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, state);
1145
+ }
1146
+ }
1147
+
1148
+ // Creates a two-phase commit message suitable for committing a transaction.
1149
+ createTpcCommitMessage(xid, onePhase) {
1150
+ const message = new messages.TransactionChangeStateMessage(this);
1151
+ message.operation = constants.TNS_TPC_TXN_COMMIT;
1152
+ message.state = (onePhase == 0) ? constants.TNS_TPC_TXN_STATE_COMMITTED :
1153
+ constants.TNS_TPC_TXN_STATE_READ_ONLY;
1154
+ message.xid = xid;
1155
+ message.context = this.tpcContext;
1156
+ return message;
1157
+ }
1158
+
1159
+ // Creates a two-phase commit rollback message suitable for use in both
1160
+ // the close() method and explicitly by the user.
1161
+ createTpcRollbackMessage(xid = null) {
1162
+ const message = new messages.TransactionChangeStateMessage(this);
1163
+ message.operation = constants.TNS_TPC_TXN_ABORT;
1164
+ message.state = constants.TNS_TPC_TXN_STATE_ABORTED;
1165
+ message.xid = xid;
1166
+ message.context = this.tpcContext;
1167
+ return message;
1168
+ }
1169
+
1170
+ //---------------------------------------------------------------------------
1171
+ // tpcBegin()
1172
+ //---------------------------------------------------------------------------
1173
+ async tpcBegin(xid, flags, timeout) {
1174
+ const message = new messages.TransactionSwitchMessage(this);
1175
+ message.operation = constants.TNS_TPC_TXN_START;
1176
+ message.xid = xid;
1177
+ message.flags = flags;
1178
+ message.timeout = timeout;
1179
+ await this._protocol._processMessage(message);
1180
+ this.tpcContext = message.context;
1181
+ }
1182
+
1183
+ //---------------------------------------------------------------------------
1184
+ // tpcCommit()
1185
+ //---------------------------------------------------------------------------
1186
+ async tpcCommit(xid, onePhase) {
1187
+ const message = this.createTpcCommitMessage(xid, onePhase);
1188
+ await this._protocol._processMessage(message);
1189
+ this.checkTpcCommitState(message.state, onePhase);
1190
+ }
1191
+
1192
+ //---------------------------------------------------------------------------
1193
+ // tpcEnd()
1194
+ //---------------------------------------------------------------------------
1195
+ async tpcEnd(xid, flags) {
1196
+ const message = new messages.TransactionSwitchMessage(this);
1197
+ message.operation = constants.TNS_TPC_TXN_DETACH;
1198
+ message.xid = xid;
1199
+ message.context = this.tpcContext;
1200
+ message.flags = flags;
1201
+ await this._protocol._processMessage(message);
1202
+ this.tpcContext = null;
1203
+ }
1204
+
1205
+ //---------------------------------------------------------------------------
1206
+ // tpcPrepare()
1207
+ //---------------------------------------------------------------------------
1208
+ async tpcPrepare(xid) {
1209
+ const message = new messages.TransactionChangeStateMessage(this);
1210
+ message.operation = constants.TNS_TPC_TXN_PREPARE;
1211
+ message.xid = xid;
1212
+ message.context = this.tpcContext;
1213
+ await this._protocol._processMessage(message);
1214
+ if (message.state === constants.TNS_TPC_TXN_STATE_REQUIRES_COMMIT) {
1215
+ return true;
1216
+ } else if (message.state === constants.TNS_TPC_TXN_STATE_READ_ONLY) {
1217
+ return false;
1218
+ }
1219
+
1220
+ errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state);
1221
+ }
1222
+
1223
+ //---------------------------------------------------------------------------
1224
+ // tpcRollback()
1225
+ //---------------------------------------------------------------------------
1226
+ async tpcRollback(xid) {
1227
+ const message = this.createTpcRollbackMessage(xid);
1228
+ await this._protocol._processMessage(message);
1229
+ if (message.state !== constants.TNS_TPC_TXN_STATE_ABORTED) {
1230
+ errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state);
1231
+ }
1232
+ }
1233
+
1234
+
989
1235
  //---------------------------------------------------------------------------
990
1236
  // Returns the statement cache size for the statement cache maintained by
991
1237
  // the connection object
@@ -1009,6 +1255,10 @@ class ThinConnectionImpl extends ConnectionImpl {
1009
1255
  return '';
1010
1256
  }
1011
1257
 
1258
+ getExternalName() {
1259
+ return this.externalName;
1260
+ }
1261
+
1012
1262
  //---------------------------------------------------------------------------
1013
1263
  // Returns the Oracle Database instance name associated with the connection.
1014
1264
  //---------------------------------------------------------------------------
@@ -1016,6 +1266,10 @@ class ThinConnectionImpl extends ConnectionImpl {
1016
1266
  return this.instanceName;
1017
1267
  }
1018
1268
 
1269
+ getInternalName() {
1270
+ return this.internalName;
1271
+ }
1272
+
1019
1273
  //---------------------------------------------------------------------------
1020
1274
  // Returns the Oracle Database domain name associated with the connection.
1021
1275
  //---------------------------------------------------------------------------
@@ -1023,6 +1277,27 @@ class ThinConnectionImpl extends ConnectionImpl {
1023
1277
  return this.dbDomain;
1024
1278
  }
1025
1279
 
1280
+ //---------------------------------------------------------------------------
1281
+ // Returns the Oracle Database host name associated with the connection.
1282
+ //---------------------------------------------------------------------------
1283
+ getHostName() {
1284
+ return this.nscon.ntAdapter.hostName;
1285
+ }
1286
+
1287
+ //---------------------------------------------------------------------------
1288
+ // Returns the Oracle Database port number associated with the connection.
1289
+ //---------------------------------------------------------------------------
1290
+ getPort() {
1291
+ return this.nscon.ntAdapter.port;
1292
+ }
1293
+
1294
+ //---------------------------------------------------------------------------
1295
+ // Returns the protocol associated with the connection.
1296
+ //---------------------------------------------------------------------------
1297
+ getProtocol() {
1298
+ return (this.nscon.ntAdapter.secure) ? 'TCPS' : 'TCP';
1299
+ }
1300
+
1026
1301
  //---------------------------------------------------------------------------
1027
1302
  // Returns the Oracle Database name associated with the connection.
1028
1303
  //---------------------------------------------------------------------------
@@ -397,10 +397,14 @@ class ThinDbObjectImpl extends DbObjectImpl {
397
397
  case types.DB_TYPE_BOOLEAN:
398
398
  return buf.readBool();
399
399
  case types.DB_TYPE_OBJECT:
400
+ case types.DB_TYPE_XMLTYPE:
400
401
  isNull = buf.getIsAtomicNull();
401
402
  if (isNull)
402
403
  return null;
403
404
  obj = new ThinDbObjectImpl(typeClass);
405
+ if (obj._objType.isXmlType) {
406
+ return readXML(obj._objType._connection, buf.readBytesWithLength());
407
+ }
404
408
  if (obj._objType.isCollection || this._objType.isCollection) {
405
409
  obj.packedData = Buffer.from(buf.readBytesWithLength());
406
410
  } else {