oracledb 6.9.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/LICENSE.txt +1 -1
  2. package/NOTICE.txt +1 -1
  3. package/README.md +9 -9
  4. package/build/Release/oracledb-7.0.0-darwin-arm64.node +0 -0
  5. package/build/Release/oracledb-7.0.0-darwin-arm64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-7.0.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-7.0.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-7.0.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-7.0.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-7.0.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-7.0.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-7.0.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/eslint.config.js +39 -0
  14. package/lib/aqDeqOptions.js +18 -1
  15. package/lib/aqQueue.js +10 -6
  16. package/lib/connection.js +418 -39
  17. package/lib/dbObject.js +25 -4
  18. package/lib/endUserSecurityContext.js +176 -0
  19. package/lib/errors.js +99 -8
  20. package/lib/impl/aqDeqOptions.js +10 -1
  21. package/lib/impl/connection.js +76 -2
  22. package/lib/impl/datahandlers/buffer.js +68 -5
  23. package/lib/impl/datahandlers/oson.js +7 -2
  24. package/lib/impl/datahandlers/vector.js +25 -5
  25. package/lib/impl/lob.js +9 -0
  26. package/lib/impl/parserHelpers.js +443 -0
  27. package/lib/impl/resultset.js +1 -1
  28. package/lib/impl/sodaDocument.js +5 -14
  29. package/lib/lob.js +27 -14
  30. package/lib/obfuscation.js +97 -0
  31. package/lib/oracledb.js +163 -49
  32. package/lib/parser.js +204 -0
  33. package/lib/pipeline.js +113 -0
  34. package/lib/pool.js +203 -147
  35. package/lib/poolStatistics.js +1 -1
  36. package/lib/resultset.js +42 -21
  37. package/lib/settings.js +1 -0
  38. package/lib/sodaCollection.js +12 -8
  39. package/lib/sodaDatabase.js +35 -8
  40. package/lib/sodaDocument.js +24 -6
  41. package/lib/sodaOperation.js +7 -6
  42. package/lib/thin/aq.js +475 -0
  43. package/lib/thin/connection.js +518 -54
  44. package/lib/thin/dbObject.js +7 -1
  45. package/lib/thin/lob.js +20 -1
  46. package/lib/thin/pool.js +42 -62
  47. package/lib/thin/protocol/capabilities.js +21 -4
  48. package/lib/thin/protocol/constants.js +143 -2
  49. package/lib/thin/protocol/encryptDecrypt.js +45 -10
  50. package/lib/thin/protocol/messages/aqArray.js +238 -0
  51. package/lib/thin/protocol/messages/aqBase.js +305 -0
  52. package/lib/thin/protocol/messages/aqDeq.js +164 -0
  53. package/lib/thin/protocol/messages/aqEnq.js +135 -0
  54. package/lib/thin/protocol/messages/auth.js +18 -28
  55. package/lib/thin/protocol/messages/base.js +245 -4
  56. package/lib/thin/protocol/messages/dataType.js +8 -3
  57. package/lib/thin/protocol/messages/directPathLoadStream.js +377 -0
  58. package/lib/thin/protocol/messages/directPathOp.js +65 -0
  59. package/lib/thin/protocol/messages/directPathPrepare.js +158 -0
  60. package/lib/thin/protocol/messages/endPipeline.js +56 -0
  61. package/lib/thin/protocol/messages/execute.js +9 -7
  62. package/lib/thin/protocol/messages/index.js +9 -1
  63. package/lib/thin/protocol/messages/protocol.js +2 -2
  64. package/lib/thin/protocol/messages/withData.js +10 -142
  65. package/lib/thin/protocol/packet.js +120 -28
  66. package/lib/thin/protocol/protocol.js +110 -25
  67. package/lib/thin/protocol/utils.js +1 -26
  68. package/lib/thin/resultSet.js +13 -19
  69. package/lib/thin/sqlnet/ezConnectResolver.js +2 -2
  70. package/lib/thin/sqlnet/networkSession.js +63 -41
  71. package/lib/thin/sqlnet/ntTcp.js +24 -0
  72. package/lib/thin/sqlnet/nvStrToNvPair.js +50 -25
  73. package/lib/thin/sqlnet/packet.js +25 -4
  74. package/lib/thin/sqlnet/paramParser.js +10 -7
  75. package/lib/thin/statementCache.js +2 -4
  76. package/lib/traceHandler.js +59 -2
  77. package/lib/transformer.js +8 -3
  78. package/lib/types.js +36 -22
  79. package/lib/util.js +6 -19
  80. package/lib/version.js +3 -3
  81. package/package/install.js +5 -5
  82. package/package/prunebinaries.js +1 -1
  83. package/package.json +1 -1
  84. package/plugins/configProviders/awsCommon.js +125 -0
  85. package/plugins/configProviders/awss3/index.js +138 -0
  86. package/plugins/configProviders/awssecretsmanager/index.js +147 -0
  87. package/plugins/configProviders/azure/index.js +7 -5
  88. package/plugins/token/extensionAzure/index.js +0 -1
  89. package/plugins/token/extensionOci/index.js +0 -1
  90. package/build/Release/oracledb-6.9.0-darwin-arm64.node +0 -0
  91. package/build/Release/oracledb-6.9.0-darwin-arm64.node-buildinfo.txt +0 -1
  92. package/build/Release/oracledb-6.9.0-darwin-x64.node +0 -0
  93. package/build/Release/oracledb-6.9.0-darwin-x64.node-buildinfo.txt +0 -1
  94. package/build/Release/oracledb-6.9.0-js-buildinfo.txt +0 -1
  95. package/build/Release/oracledb-6.9.0-linux-arm64.node +0 -0
  96. package/build/Release/oracledb-6.9.0-linux-arm64.node-buildinfo.txt +0 -1
  97. package/build/Release/oracledb-6.9.0-linux-x64.node +0 -0
  98. package/build/Release/oracledb-6.9.0-linux-x64.node-buildinfo.txt +0 -1
  99. package/build/Release/oracledb-6.9.0-win32-x64.node +0 -0
  100. package/build/Release/oracledb-6.9.0-win32-x64.node-buildinfo.txt +0 -1
@@ -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
  //
@@ -42,6 +42,7 @@ const types = require('../types.js');
42
42
  const errors = require("../errors.js");
43
43
  const messages = require('./protocol/messages');
44
44
  const StatementCache = require('./statementCache.js');
45
+ const { ThinQueueImpl } = require('./aq.js');
45
46
 
46
47
  const finalizationRegistry = new global.FinalizationRegistry((heldValue) => {
47
48
  heldValue.disconnect();
@@ -52,6 +53,29 @@ class TDSBuffer extends BaseBuffer {
52
53
 
53
54
  class ThinConnectionImpl extends ConnectionImpl {
54
55
 
56
+ static _createNamespace(nameSpaceName) {
57
+ return {
58
+ nameSpaceName,
59
+ keyValues: [],
60
+ pendingClear: false
61
+ };
62
+ }
63
+
64
+ static _mergeKeyValues(namespace, keyValues) {
65
+ const mergedKeyValues = namespace.keyValues.slice();
66
+ for (const entry of keyValues) {
67
+ const entryKey = Object.keys(entry)[0];
68
+ const existingIndex = mergedKeyValues.findIndex((existingEntry) =>
69
+ Object.prototype.hasOwnProperty.call(existingEntry, entryKey));
70
+ if (existingIndex !== -1) {
71
+ mergedKeyValues.splice(existingIndex, 1);
72
+ }
73
+ mergedKeyValues.push(entry);
74
+ }
75
+ namespace.keyValues = mergedKeyValues;
76
+ namespace.pendingClear = false;
77
+ }
78
+
55
79
  /**
56
80
  * Terminates the connection
57
81
  *
@@ -59,6 +83,7 @@ class ThinConnectionImpl extends ConnectionImpl {
59
83
  */
60
84
  async close() {
61
85
  try {
86
+ this.clearEndUserSecurityContext();
62
87
  if (this._protocol.txnInProgress) {
63
88
  if (this.tpcContext) {
64
89
  const message = this.createTpcRollbackMessage();
@@ -81,7 +106,7 @@ class ThinConnectionImpl extends ConnectionImpl {
81
106
  }
82
107
  this.nscon.disconnect();
83
108
  }
84
- } catch (err) {
109
+ } catch {
85
110
  // immediate close of open socket on failure
86
111
  // exception won't be thrown to user
87
112
  this.nscon.disconnect(sqlNetConstants.NSFIMM);
@@ -165,12 +190,8 @@ class ThinConnectionImpl extends ConnectionImpl {
165
190
  }
166
191
  }
167
192
 
168
- //---------------------------------------------------------------------------
169
- // _execute()
170
- //
171
- // Calls the RPC that executes a SQL statement and returns the results.
172
- //---------------------------------------------------------------------------
173
- async _execute(statement, numIters, binds, options, executeManyFlag) {
193
+ async _getExecuteMessage(statement, numIters, binds, options,
194
+ executeManyFlag, internalTempLobs = []) {
174
195
 
175
196
  // Throw error if executeMany is not called on a DML statement or PL/SQL
176
197
  if (executeManyFlag && statement.isQuery) {
@@ -194,7 +215,7 @@ class ThinConnectionImpl extends ConnectionImpl {
194
215
  }
195
216
 
196
217
  for (let i = 0; i < binds.length; i++) {
197
- await this._bind(statement, binds[i], i + 1);
218
+ await this._bind(statement, binds[i], i + 1, internalTempLobs);
198
219
  }
199
220
  if (statement.isPlSql && (options.batchErrors || options.dmlRowCounts)) {
200
221
  errors.throwErr(errors.ERR_EXEC_MODE_ONLY_FOR_DML);
@@ -205,6 +226,18 @@ class ThinConnectionImpl extends ConnectionImpl {
205
226
  message.numExecs = numIters;
206
227
  message.arrayDmlRowCounts = options.dmlRowCounts;
207
228
  message.batchErrors = options.batchErrors;
229
+ return message;
230
+ }
231
+
232
+ //---------------------------------------------------------------------------
233
+ // _execute()
234
+ //
235
+ // Calls the RPC that executes a SQL statement and returns the results.
236
+ //---------------------------------------------------------------------------
237
+ async _execute(statement, numIters, binds, options, executeManyFlag, internalTempLobs = []) {
238
+
239
+ const message = await this._getExecuteMessage(statement, numIters, binds,
240
+ options, executeManyFlag, internalTempLobs);
208
241
 
209
242
  // if a PL/SQL statement requires a full execute, perform only a single
210
243
  // iteration in order to allow the determination of input/output binds
@@ -226,14 +259,124 @@ class ThinConnectionImpl extends ConnectionImpl {
226
259
  }
227
260
 
228
261
  // if a define is required, send an additional request to the database
229
- if (statement.requiresDefine && statement.sql) {
230
- statement.requiresFullExecute = true;
231
- await this._protocol._processMessage(message);
232
- statement.requiresFullExecute = false;
233
- statement.requiresDefine = false;
234
- }
262
+ await this._handleDefines(statement, message);
235
263
 
236
264
  // process results
265
+ return this._processExecuteResult(statement, numIters, options,
266
+ executeManyFlag, message);
267
+ }
268
+
269
+ //---------------------------------------------------------------------------
270
+ // _sendMessagesForPipeline()
271
+ //
272
+ // Sends the messages for the pipeline to the database for processing.
273
+ // This is async function only because of await adapter.pauseWrite()
274
+ // which is used to slow down writing to network socket.
275
+ //---------------------------------------------------------------------------
276
+ async _sendMessagesForPipeline(messages, continueOnError) {
277
+ for (const messageObj of messages) {
278
+ if (messageObj.pipelineResultImpl.error)
279
+ continue;
280
+ const message = messageObj.message;
281
+ const opType = messageObj.pipelineResultImpl.op.opType;
282
+ try {
283
+ if (['execute', 'executeMany', 'fetchOne', 'fetchMany',
284
+ 'fetchAll'].includes(opType)) {
285
+ const statement = messageObj.statement;
286
+ if (statement.isPlSql && (statement.cursorId === 0 ||
287
+ statement.requiresFullExecute)) {
288
+ message.numExecs = 1;
289
+ message.noImplicitRelease = true;
290
+ await this._protocol._encodeMessage(message);
291
+ message.requiresSingleExecute = true;
292
+ } else if (message.numExecs > 0) {
293
+ await this._protocol._encodeMessage(message);
294
+ }
295
+ } else if (opType === 'commit')
296
+ await this._protocol._encodeMessage(message);
297
+ } catch (err) {
298
+ this._returnStatement(messageObj.statement);
299
+ if (!continueOnError) {
300
+ throw (err);
301
+ }
302
+ messageObj.pipelineResultImpl.error = err;
303
+ }
304
+ }
305
+ }
306
+
307
+ //---------------------------------------------------------------------------
308
+ // _createMessagesForPipelineOp()
309
+ //
310
+ // Creates a single message for a pipeline operation.
311
+ //---------------------------------------------------------------------------
312
+ async _createMessagesForPipelineOp(conn, operation) {
313
+ const opType = operation.opType;
314
+ if (opType === 'commit') {
315
+ errors.assert(conn._impl, errors.ERR_INVALID_CONNECTION);
316
+ return { message: new messages.CommitMessage(this) };
317
+ }
318
+
319
+ let processedArgs;
320
+ switch (opType) {
321
+ case 'execute':
322
+ processedArgs = await conn._processExecuteArgs(operation.statement,
323
+ operation.parameters, operation.options);
324
+ break;
325
+ case 'executeMany':
326
+ processedArgs = await conn._processExecuteManyArgs(operation.statement,
327
+ operation.parameters, operation.options);
328
+ break;
329
+ case 'fetchOne':
330
+ case 'fetchMany':
331
+ case 'fetchAll': {
332
+ const options = {
333
+ ...operation.options,
334
+ fetchTypeHandler: conn._createFetchTypeHandler(operation.fetchLobs)
335
+ };
336
+ processedArgs = await conn._processExecuteArgs(operation.statement,
337
+ operation.parameters, options);
338
+ break;
339
+ }
340
+ default:
341
+ errors.throwErr(errors.ERR_PIPELINE_OPERATION_NOT_SUPPORTED, opType);
342
+ }
343
+
344
+ const {sql, numIters, binds, options, executeManyFlag} = processedArgs;
345
+ return await this._prepareForExecute(sql, numIters, binds, options,
346
+ executeManyFlag);
347
+ }
348
+
349
+ //---------------------------------------------------------------------------
350
+ // _createMessagesForPipeline()
351
+ //
352
+ // Creates a list of messages for the pipeline and returns them after they
353
+ // have been submitted to the database for processing.
354
+ //---------------------------------------------------------------------------
355
+ async _createMessagesForPipeline(conn, resultsImpl, continueOnError) {
356
+ const messagesForPipeline = [];
357
+ let tokenNum = 1;
358
+ for (const resultImpl of resultsImpl) {
359
+ let messageObj;
360
+ try {
361
+ messageObj = await this._createMessagesForPipelineOp(conn,
362
+ resultImpl.op);
363
+ } catch (err) {
364
+ if (!continueOnError)
365
+ throw (err);
366
+ resultImpl.error = err;
367
+ continue;
368
+ }
369
+ messageObj.message.pipelineMessage = true;
370
+ messageObj.pipelineResultImpl = resultImpl;
371
+ messageObj.message.tokenNum = tokenNum;
372
+ tokenNum++;
373
+ messagesForPipeline.push(messageObj);
374
+ }
375
+ return messagesForPipeline;
376
+ }
377
+
378
+ _processExecuteResult(statement, numIters, options, executeManyFlag,
379
+ message) {
237
380
  const result = {};
238
381
  if (message.warning) {
239
382
  result.warning = message.warning;
@@ -283,6 +426,164 @@ class ThinConnectionImpl extends ConnectionImpl {
283
426
  return result;
284
427
  }
285
428
 
429
+ //---------------------------------------------------------------------------
430
+ // _completePipelineOp()
431
+ //
432
+ // Completes a particular pipeline operation.
433
+ //---------------------------------------------------------------------------
434
+ async _completePipelineOp(messageObj, conn) {
435
+ const message = messageObj.message;
436
+ const opType = messageObj.pipelineResultImpl.op.opType;
437
+
438
+ // Post-processing of pipeline message happen once after reading response
439
+ // of all the operations is completed in the first phase.
440
+ await message.postProcess();
441
+ await this._protocol._processCallStatus(message);
442
+
443
+ if (opType === 'commit')
444
+ return;
445
+
446
+ if (['execute', 'executeMany', 'fetchOne', 'fetchMany',
447
+ 'fetchAll'].includes(opType)) {
448
+ const statement = messageObj.statement;
449
+ const numIters = messageObj.numIters;
450
+ const options = messageObj.options;
451
+ const executeManyFlag = messageObj.executeManyFlag;
452
+ try {
453
+
454
+ // for PL/SQL blocks that required a single execute, perform any
455
+ // remaining executes now
456
+ if (message.requiresSingleExecute) {
457
+ statement.requiresFullExecute = false;
458
+ message.numExecs = numIters - 1;
459
+ message.offset = 1;
460
+ message.noImplicitRelease = false;
461
+ if (message.numExecs > 0) {
462
+ await this._protocol._processMessage(message);
463
+ statement.requiresFullExecute = false;
464
+ }
465
+ message.requiresSingleExecute = false;
466
+ } else {
467
+ statement.requiresFullExecute = false;
468
+ }
469
+
470
+ // resend the message if that is required (for operations that fetch
471
+ // LOBS, for example)
472
+ await this._handleDefines(statement, message);
473
+
474
+ // process results
475
+ messageObj.resultTemp = this._processExecuteResult(statement, numIters,
476
+ options, executeManyFlag, message);
477
+ } catch (err) {
478
+ this._returnStatement(messageObj.statement);
479
+ throw (err);
480
+ } finally {
481
+ for (const lob of messageObj.internalTempLobs) {
482
+ this._tempLobsToClose.push(lob._locator);
483
+ this._tempLobsTotalSize += lob._locator.length;
484
+ }
485
+ }
486
+ if (opType === 'executeMany')
487
+ await conn._transformExecuteManyResult(messageObj.resultTemp,
488
+ messageObj.options);
489
+ else if (opType === 'execute') {
490
+ await conn._handleFetchForExecuteInPipeline(messageObj.resultTemp, messageObj.options);
491
+ }
492
+
493
+ if (['fetchOne', 'fetchMany', 'fetchAll'].includes(opType)) {
494
+ // fetch rows
495
+ await conn._transformExecuteResult(messageObj.resultTemp,
496
+ messageObj.options, messageObj.pipelineResultImpl.op);
497
+ }
498
+ }
499
+ }
500
+
501
+ //---------------------------------------------------------------------------
502
+ // _completePipelineOps()
503
+ //
504
+ // Completes any pipeline operations that have not actually completed.
505
+ // This could be due to the fact that LOBs were fetched or a fetch all
506
+ // operation has more rows to fetch.
507
+ //---------------------------------------------------------------------------
508
+ async _completePipelineOps(messagesForPipeline, conn, continueOnError) {
509
+ for (const messageObj of messagesForPipeline) {
510
+ const resultImpl = messageObj.pipelineResultImpl;
511
+ if (resultImpl.error)
512
+ continue;
513
+ try {
514
+ await this._completePipelineOp(messageObj, conn);
515
+ if (!messageObj.pipelineResultImpl.error) {
516
+ messageObj.pipelineResultImpl.result = messageObj.resultTemp;
517
+ }
518
+ } catch (err) {
519
+ this._returnStatement(messageObj.statement);
520
+ if (!continueOnError) {
521
+ throw (err);
522
+ }
523
+ messageObj.pipelineResultImpl.error = err;
524
+ }
525
+ }
526
+ }
527
+
528
+ // Returns whether the connection supports pipelining. Currently this is
529
+ // only supported with Oracle Database 23ai and later.
530
+ supportsPipelining() {
531
+ return this.nscon.pipeliningSupport;
532
+ }
533
+
534
+ //---------------------------------------------------------------------------
535
+ // runPipelineWithPipelining()
536
+ //
537
+ // Run the pipeline with pipelining when the database supports it.
538
+ //---------------------------------------------------------------------------
539
+ async runPipelineWithPipelining(conn, resultsImpl, continueOnError) {
540
+ this.pipelineMode = continueOnError ?
541
+ constants.TNS_PIPELINE_MODE_CONTINUE_ON_ERROR :
542
+ constants.TNS_PIPELINE_MODE_ABORT_ON_ERROR;
543
+ this.nscon.pipelineEnabled = true;
544
+
545
+ // Create all pipeline messages
546
+ const messagesForPipeline = await this._createMessagesForPipeline(conn,
547
+ resultsImpl, continueOnError);
548
+ try {
549
+ this._protocol.readBuf.resetPackets();
550
+
551
+ // Encode all messages
552
+ await this._sendMessagesForPipeline(messagesForPipeline,
553
+ continueOnError);
554
+
555
+ // endPipeline message
556
+ const endMessage = new messages.EndPipelineMessage(this);
557
+
558
+ // Decode responses for all operation messages, then process the final
559
+ // end-pipeline response and cleanup any remaining response packets.
560
+ await this._protocol.endPipeline(messagesForPipeline,
561
+ endMessage, this, continueOnError);
562
+
563
+ // Complete post processing of results (and deferred operations in
564
+ // non-pipeline mode)
565
+ await this._completePipelineOps(messagesForPipeline, conn,
566
+ continueOnError);
567
+
568
+ return conn._buildPipelineResults(resultsImpl);
569
+ } finally {
570
+ this.pipelineMode = 0;
571
+ this.nscon.pipelineEnabled = false;
572
+ }
573
+ }
574
+
575
+ //---------------------------------------------------------------------------
576
+ // runPipelineWithoutPipelining()
577
+ //
578
+ // Run the pipeline without pipelining when the database doesn't support
579
+ // pipelining. Call timeouts are disabled for consistency with when
580
+ // run with pipelining.
581
+ //---------------------------------------------------------------------------
582
+ async runPipelineWithoutPipelining(conn, resultsImpl, continueOnError) {
583
+ return await conn._runPipelineWithoutPipelining(resultsImpl,
584
+ continueOnError);
585
+ }
586
+
286
587
  //---------------------------------------------------------------------------
287
588
  // _parseTDSAttr()
288
589
  //
@@ -781,6 +1082,42 @@ class ThinConnectionImpl extends ConnectionImpl {
781
1082
  return (this._pool) ? true : false;
782
1083
  }
783
1084
 
1085
+ _postConnect(authMessage) {
1086
+ let releaseNum;
1087
+ let updateNum;
1088
+ let portReleaseNum;
1089
+ let portUpdateNum;
1090
+
1091
+ this.dbDomain = authMessage.sessionData['AUTH_SC_DB_DOMAIN'];
1092
+ this.dbName = authMessage.sessionData['AUTH_SC_DBUNIQUE_NAME'];
1093
+ this.dbUniqueName = authMessage.sessionData['AUTH_SC_REAL_DBUNIQUE_NAME'];
1094
+ this.maxOpenCursors = Number(authMessage.sessionData['AUTH_MAX_OPEN_CURSORS'] || 0);
1095
+ this.serviceName = authMessage.sessionData['AUTH_SC_SERVICE_NAME'];
1096
+ this.instanceName = authMessage.sessionData['AUTH_INSTANCENAME'];
1097
+ this.maxIdentifierLength = Number(authMessage.sessionData['AUTH_MAX_IDEN_LENGTH'] || 30);
1098
+ const fullVersionNum = Number(authMessage.sessionData['AUTH_VERSION_NO']);
1099
+ const versionNum = (fullVersionNum >> 24) & 0xFF;
1100
+ this.warning = authMessage.warning;
1101
+ if (this._protocol.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_18_1_EXT_1) {
1102
+ releaseNum = (fullVersionNum >> 16) & 0xFF;
1103
+ updateNum = (fullVersionNum >> 12) & 0x0F;
1104
+ portReleaseNum = (fullVersionNum >> 4) & 0xFF;
1105
+ portUpdateNum = fullVersionNum & 0x0F;
1106
+ } else {
1107
+ releaseNum = (fullVersionNum >> 20) & 0x0F;
1108
+ updateNum = (fullVersionNum >> 12) & 0xFF;
1109
+ portReleaseNum = (fullVersionNum >> 8) & 0x0F;
1110
+ portUpdateNum = fullVersionNum & 0xFF;
1111
+ }
1112
+ this.serverVersionString = versionNum + '.' + releaseNum + '.' + updateNum + '.' + portReleaseNum + '.' + portUpdateNum;
1113
+ this.serverVersion = versionNum * 100000000 + releaseNum * 1000000 + updateNum * 10000 + portReleaseNum * 100 + portUpdateNum * 1;
1114
+
1115
+ // Set pdbName only from Oracle Database version 12.2 onwards.
1116
+ if (this.serverVersion >= 1202000000) {
1117
+ this.pdbName = authMessage.sessionData.AUTH_DBNAME;
1118
+ }
1119
+ }
1120
+
784
1121
  /**
785
1122
  *
786
1123
  * @param {object} params Configuration of the connection
@@ -822,51 +1159,52 @@ class ThinConnectionImpl extends ConnectionImpl {
822
1159
  this.comboKey = null; // used in changePassword API
823
1160
  this.tpcContext = null;
824
1161
  this._sessionlessData = null;
1162
+ this._nameSpaceMap = new Map();
825
1163
 
826
1164
  this.nscon = new nsi();
827
1165
  finalizationRegistry.register(this, this.nscon);
828
1166
  await this.nscon.connect(params);
829
1167
 
830
- let serverType;
831
- if (this.isPooled()) {
832
- serverType = params._connInfo[0];
833
- this.serviceName = params._connInfo[2];
834
- this.purity = params._connInfo[3] | constants.PURITY_DEFAULT;
835
- this.sid = params._connInfo[4];
836
- } else {
837
- serverType = this.nscon.getOption(sqlNetConstants.SERVERTYPE);
838
- this.serviceName = this.nscon.getOption(sqlNetConstants.SVCNAME);
839
- this.sid = this.nscon.getOption(sqlNetConstants.SID);
840
- this.purity = this.nscon.getOption(sqlNetConstants.PURITY) | constants.PURITY_DEFAULT;
841
- }
842
- if (serverType) {
843
- this._drcpEnabled = serverType.toLowerCase() === 'pooled';
844
- }
845
- this.remoteAddress = this.nscon.getOption(sqlNetConstants.REMOTEADDR);
846
- this.connectionClass = params.connectionClass;
847
-
848
- /*
849
- * if drcp is used, use purity = NEW as the default purity for
850
- * standalone connections and purity = SELF for connections that belong
851
- * to a pool
852
- */
853
- if (this.purity === constants.PURITY_DEFAULT && this._drcpEnabled) {
1168
+ try {
1169
+ let serverType;
854
1170
  if (this.isPooled()) {
855
- this.purity = constants.PURITY_SELF;
1171
+ serverType = params._connInfo[0];
1172
+ this.serviceName = params._connInfo[2];
1173
+ this.purity = params._connInfo[3] | constants.PURITY_DEFAULT;
1174
+ this.sid = params._connInfo[4];
856
1175
  } else {
857
- this.purity = constants.PURITY_NEW;
1176
+ serverType = this.nscon.getOption(sqlNetConstants.SERVERTYPE);
1177
+ this.serviceName = this.nscon.getOption(sqlNetConstants.SVCNAME);
1178
+ this.sid = this.nscon.getOption(sqlNetConstants.SID);
1179
+ this.purity = this.nscon.getOption(sqlNetConstants.PURITY) | constants.PURITY_DEFAULT;
1180
+ }
1181
+ if (serverType) {
1182
+ this._drcpEnabled = serverType.toLowerCase() === 'pooled';
1183
+ }
1184
+ this.remoteAddress = this.nscon.getOption(sqlNetConstants.REMOTEADDR);
1185
+ this.connectionClass = params.connectionClass;
1186
+
1187
+ /*
1188
+ * if drcp is used, use purity = NEW as the default purity for
1189
+ * standalone connections and purity = SELF for connections that belong
1190
+ * to a pool
1191
+ */
1192
+ if (this.purity === constants.PURITY_DEFAULT && this._drcpEnabled) {
1193
+ if (this.isPooled()) {
1194
+ this.purity = constants.PURITY_SELF;
1195
+ } else {
1196
+ this.purity = constants.PURITY_NEW;
1197
+ }
858
1198
  }
859
- }
860
1199
 
861
- this._protocol = new Protocol(this);
1200
+ this._protocol = new Protocol(this);
862
1201
 
863
- // check if the protocol version supported by the database is high
864
- // enough; if not, reject the connection immediately
865
- if (this._protocol.caps.protocolVersion < constants.TNS_VERSION_MIN_ACCEPTED) {
866
- errors.throwErr(errors.ERR_SERVER_VERSION_NOT_SUPPORTED);
867
- }
1202
+ // check if the protocol version supported by the database is high
1203
+ // enough; if not, reject the connection immediately
1204
+ if (this._protocol.caps.protocolVersion < constants.TNS_VERSION_MIN_ACCEPTED) {
1205
+ errors.throwErr(errors.ERR_SERVER_VERSION_NOT_SUPPORTED);
1206
+ }
868
1207
 
869
- try {
870
1208
  const protocolMessage = new messages.ProtocolMessage(this);
871
1209
  const dataTypeMessage = new messages.DataTypeMessage(this);
872
1210
  const authMessage = new messages.AuthMessage(this, params);
@@ -895,6 +1233,7 @@ class ThinConnectionImpl extends ConnectionImpl {
895
1233
  if (!params.externalAuth) { // non-token Authentication
896
1234
  await this._protocol._processMessage(authMessage); // OAUTH
897
1235
  }
1236
+ this._postConnect(authMessage);
898
1237
  } catch (err) {
899
1238
  this.nscon.disconnect();
900
1239
  throw err;
@@ -924,7 +1263,8 @@ class ThinConnectionImpl extends ConnectionImpl {
924
1263
  // option is true
925
1264
  //---------------------------------------------------------------------------
926
1265
  _prepare(sql, options) {
927
- const statement = this._getStatement(sql, options.keepInStmtCache);
1266
+ const forceNew = Boolean(options.fetchTypeMap);
1267
+ const statement = this._getStatement(sql, options.keepInStmtCache, forceNew);
928
1268
  statement.bufferRowIndex = 0;
929
1269
  statement.bufferRowCount = 0;
930
1270
  statement.lastRowIndex = 0;
@@ -935,7 +1275,7 @@ class ThinConnectionImpl extends ConnectionImpl {
935
1275
  //---------------------------------------------------------------------------
936
1276
  // Binds the values by user to the statement object
937
1277
  //---------------------------------------------------------------------------
938
- async _bind(stmt, variable, pos = 0) {
1278
+ async _bind(stmt, variable, pos = 0, internalTempLobs = []) {
939
1279
  const bindInfoDict = stmt.bindInfoDict;
940
1280
  const bindInfoList = stmt.bindInfoList;
941
1281
 
@@ -946,6 +1286,8 @@ class ThinConnectionImpl extends ConnectionImpl {
946
1286
  * the user expects to get it
947
1287
  */
948
1288
  if (stmt.isPlSql && variable.maxSize > 32767) {
1289
+ if (this.pipelineMode)
1290
+ errors.throwErr(errors.ERR_PIPELINE_LARGE_BUFFERS_NOT_SUPPORTED);
949
1291
  if (variable.type === types.DB_TYPE_RAW ||
950
1292
  variable.type === types.DB_TYPE_LONG_RAW) {
951
1293
  variable.type = types.DB_TYPE_BLOB;
@@ -977,6 +1319,7 @@ class ThinConnectionImpl extends ConnectionImpl {
977
1319
  if (val && val.length > 0) {
978
1320
  const lobImpl = new ThinLobImpl();
979
1321
  await lobImpl.create(this, variable.type);
1322
+ internalTempLobs.push(lobImpl);
980
1323
  await lobImpl.write(1, val);
981
1324
  variable.values[index] = lobImpl;
982
1325
  } else {
@@ -1064,6 +1407,15 @@ class ThinConnectionImpl extends ConnectionImpl {
1064
1407
  }
1065
1408
  }
1066
1409
 
1410
+ async _handleDefines(statement, message) {
1411
+ if (statement.requiresDefine && statement.sql) {
1412
+ statement.requiresFullExecute = true;
1413
+ await this._protocol._processMessage(message);
1414
+ statement.requiresDefine = false;
1415
+ statement.requiresFullExecute = false;
1416
+ }
1417
+ }
1418
+
1067
1419
  //---------------------------------------------------------------------------
1068
1420
  // execute()
1069
1421
  //
@@ -1071,15 +1423,31 @@ class ThinConnectionImpl extends ConnectionImpl {
1071
1423
  //---------------------------------------------------------------------------
1072
1424
  async execute(sql, numIters, binds, options, executeManyFlag) {
1073
1425
  const statement = this._prepare(sql, options);
1426
+ const internalTempLobs = [];
1074
1427
  try {
1075
1428
  return await this._execute(statement, numIters, binds, options,
1076
- executeManyFlag);
1429
+ executeManyFlag, internalTempLobs);
1077
1430
  } catch (err) {
1078
1431
  this._returnStatement(statement);
1079
1432
  throw err;
1433
+ } finally {
1434
+ // Add to freelist which will be sent in piggyback fashion
1435
+ for (const lob of internalTempLobs) {
1436
+ this._tempLobsToClose.push(lob._locator);
1437
+ this._tempLobsTotalSize += lob._locator.length;
1438
+ }
1080
1439
  }
1081
1440
  }
1082
1441
 
1442
+ async _prepareForExecute(sql, numIters, binds, options, executeManyFlag) {
1443
+ const statement = this._prepare(sql, options);
1444
+ const internalTempLobs = [];
1445
+ const message = await this._getExecuteMessage(statement, numIters, binds,
1446
+ options, executeManyFlag, internalTempLobs);
1447
+ return {statement, numIters, options, executeManyFlag, internalTempLobs,
1448
+ message};
1449
+ }
1450
+
1083
1451
  //---------------------------------------------------------------------------
1084
1452
  // Get the statement object from the statement cache for the SQL if it exists
1085
1453
  // else prepare a new statement object for the SQL. If a statement is already
@@ -1089,9 +1457,9 @@ class ThinConnectionImpl extends ConnectionImpl {
1089
1457
  // cache) since it is unknown at this point whether the original session or a
1090
1458
  // new session is going to be used.
1091
1459
  //---------------------------------------------------------------------------
1092
- _getStatement(sql, cacheStatement = false) {
1460
+ _getStatement(sql, cacheStatement = false, forceNew = false) {
1093
1461
  return this.statementCache.getStatement(sql, cacheStatement,
1094
- this._drcpEstablishSession);
1462
+ forceNew || this._drcpEstablishSession);
1095
1463
  }
1096
1464
 
1097
1465
  //---------------------------------------------------------------------------
@@ -1415,6 +1783,20 @@ class ThinConnectionImpl extends ConnectionImpl {
1415
1783
  return this.dbName;
1416
1784
  }
1417
1785
 
1786
+ //---------------------------------------------------------------------------
1787
+ // Returns the name of a container associated with the connection.
1788
+ //---------------------------------------------------------------------------
1789
+ getPdbName() {
1790
+ return this.pdbName;
1791
+ }
1792
+
1793
+ //---------------------------------------------------------------------------
1794
+ // Returns the Oracle Database unique name associated with the connection.
1795
+ //---------------------------------------------------------------------------
1796
+ getDbUniqueName() {
1797
+ return this.dbUniqueName;
1798
+ }
1799
+
1418
1800
  //---------------------------------------------------------------------------
1419
1801
  // Returns maximum number of cursors that can be opened in one session.
1420
1802
  //---------------------------------------------------------------------------
@@ -1450,5 +1832,87 @@ class ThinConnectionImpl extends ConnectionImpl {
1450
1832
  getWarning() {
1451
1833
  return this.warning;
1452
1834
  }
1835
+
1836
+ //---------------------------------------------------------------------------
1837
+ // getQueue()
1838
+ //
1839
+ // Returns a queue for use with advanced queuing.
1840
+ //---------------------------------------------------------------------------
1841
+ getQueue(name, payloadTypeClass, payloadType) {
1842
+ return new ThinQueueImpl(this, name, payloadTypeClass, payloadType);
1843
+ }
1844
+
1845
+ // Queue key/value pairs to be sent to the server.
1846
+ // If the namespace already has pending entries, merge and replace by key.
1847
+ appContext(namespaceName, keyValues) {
1848
+ const existingNamespace = this._nameSpaceMap.get(namespaceName);
1849
+
1850
+ // If namespace doesn't exist or was cleared, just initialize it
1851
+ if (!existingNamespace || existingNamespace.pendingClear) {
1852
+ const ns = existingNamespace || ThinConnectionImpl._createNamespace(namespaceName);
1853
+ ns.pendingClear = false;
1854
+ ns.keyValues = keyValues;
1855
+ this._nameSpaceMap.set(namespaceName, ns);
1856
+ return;
1857
+ }
1858
+
1859
+ ThinConnectionImpl._mergeKeyValues(existingNamespace, keyValues);
1860
+ }
1861
+
1862
+ // This will clear all context on the server.
1863
+ // If the nameSpaceName exists , it updates else creates a new entry with clear flag set.
1864
+ clearAppContext(namespaceName) {
1865
+ const ns = ThinConnectionImpl._createNamespace(namespaceName);
1866
+ ns.pendingClear = true;
1867
+ this._nameSpaceMap.set(namespaceName, ns);
1868
+ }
1869
+
1870
+ //---------------------------------------------------------------------------
1871
+ // directPathLoad()
1872
+ // Implements direct path loading into a table.
1873
+ //---------------------------------------------------------------------------
1874
+ async directPathLoad(schemaName, tableName, columnNames, data) {
1875
+ const prepareMessage = new messages.DirectPathPrepareMessage(this);
1876
+ prepareMessage.schemaName = schemaName;
1877
+ prepareMessage.tableName = tableName;
1878
+ prepareMessage.columnNames = columnNames;
1879
+ await this._protocol._processMessage(prepareMessage);
1880
+
1881
+ const opMessage = new messages.DirectPathOpMessage(this);
1882
+ opMessage.prepare(prepareMessage.cursorId, constants.TNS_DP_OP_ABORT);
1883
+
1884
+ try {
1885
+ const loadMessage = new messages.DirectPathLoadStreamMessage(this);
1886
+ loadMessage.prepare(prepareMessage.cursorId, data, prepareMessage.columnMetadata);
1887
+ await this._protocol._processMessage(loadMessage);
1888
+ opMessage.opCode = constants.TNS_DP_OP_FINISH;
1889
+ } finally {
1890
+ await this._protocol._processMessage(opMessage);
1891
+ }
1892
+ }
1893
+
1894
+ //---------------------------------------------------------------------------
1895
+ // setEndUserSecurityContext()
1896
+ //
1897
+ // Set the End Security Context.
1898
+ //---------------------------------------------------------------------------
1899
+ setEndUserSecurityContext(context) {
1900
+ if (!this._protocol.caps.supportsEndUserSecurityContext) {
1901
+ errors.throwErr(errors.ERR_UNSUPPORTED_DEEP_DATA_SECURITY_FEATURE);
1902
+ }
1903
+
1904
+ if (this.securityContext && this.securityContext !== context) {
1905
+ this.securityContext.clearEncodedPayload();
1906
+ }
1907
+ this.securityContext = context;
1908
+ }
1909
+
1910
+ clearEndUserSecurityContext() {
1911
+ if (this.securityContext) {
1912
+ this.securityContext.clearEncodedPayload();
1913
+ }
1914
+ this.securityContext = null;
1915
+ }
1916
+
1453
1917
  }
1454
1918
  module.exports = ThinConnectionImpl;