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.
- package/LICENSE.txt +1 -1
- package/NOTICE.txt +1 -1
- package/README.md +9 -9
- package/build/Release/oracledb-7.0.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-7.0.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-7.0.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-linux-x64.node +0 -0
- package/build/Release/oracledb-7.0.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-win32-x64.node +0 -0
- package/build/Release/oracledb-7.0.0-win32-x64.node-buildinfo.txt +1 -0
- package/eslint.config.js +39 -0
- package/lib/aqDeqOptions.js +18 -1
- package/lib/aqQueue.js +10 -6
- package/lib/connection.js +418 -39
- package/lib/dbObject.js +25 -4
- package/lib/endUserSecurityContext.js +176 -0
- package/lib/errors.js +99 -8
- package/lib/impl/aqDeqOptions.js +10 -1
- package/lib/impl/connection.js +76 -2
- package/lib/impl/datahandlers/buffer.js +68 -5
- package/lib/impl/datahandlers/oson.js +7 -2
- package/lib/impl/datahandlers/vector.js +25 -5
- package/lib/impl/lob.js +9 -0
- package/lib/impl/parserHelpers.js +443 -0
- package/lib/impl/resultset.js +1 -1
- package/lib/impl/sodaDocument.js +5 -14
- package/lib/lob.js +27 -14
- package/lib/obfuscation.js +97 -0
- package/lib/oracledb.js +163 -49
- package/lib/parser.js +204 -0
- package/lib/pipeline.js +113 -0
- package/lib/pool.js +203 -147
- package/lib/poolStatistics.js +1 -1
- package/lib/resultset.js +42 -21
- package/lib/settings.js +1 -0
- package/lib/sodaCollection.js +12 -8
- package/lib/sodaDatabase.js +35 -8
- package/lib/sodaDocument.js +24 -6
- package/lib/sodaOperation.js +7 -6
- package/lib/thin/aq.js +475 -0
- package/lib/thin/connection.js +518 -54
- package/lib/thin/dbObject.js +7 -1
- package/lib/thin/lob.js +20 -1
- package/lib/thin/pool.js +42 -62
- package/lib/thin/protocol/capabilities.js +21 -4
- package/lib/thin/protocol/constants.js +143 -2
- package/lib/thin/protocol/encryptDecrypt.js +45 -10
- package/lib/thin/protocol/messages/aqArray.js +238 -0
- package/lib/thin/protocol/messages/aqBase.js +305 -0
- package/lib/thin/protocol/messages/aqDeq.js +164 -0
- package/lib/thin/protocol/messages/aqEnq.js +135 -0
- package/lib/thin/protocol/messages/auth.js +18 -28
- package/lib/thin/protocol/messages/base.js +245 -4
- package/lib/thin/protocol/messages/dataType.js +8 -3
- package/lib/thin/protocol/messages/directPathLoadStream.js +377 -0
- package/lib/thin/protocol/messages/directPathOp.js +65 -0
- package/lib/thin/protocol/messages/directPathPrepare.js +158 -0
- package/lib/thin/protocol/messages/endPipeline.js +56 -0
- package/lib/thin/protocol/messages/execute.js +9 -7
- package/lib/thin/protocol/messages/index.js +9 -1
- package/lib/thin/protocol/messages/protocol.js +2 -2
- package/lib/thin/protocol/messages/withData.js +10 -142
- package/lib/thin/protocol/packet.js +120 -28
- package/lib/thin/protocol/protocol.js +110 -25
- package/lib/thin/protocol/utils.js +1 -26
- package/lib/thin/resultSet.js +13 -19
- package/lib/thin/sqlnet/ezConnectResolver.js +2 -2
- package/lib/thin/sqlnet/networkSession.js +63 -41
- package/lib/thin/sqlnet/ntTcp.js +24 -0
- package/lib/thin/sqlnet/nvStrToNvPair.js +50 -25
- package/lib/thin/sqlnet/packet.js +25 -4
- package/lib/thin/sqlnet/paramParser.js +10 -7
- package/lib/thin/statementCache.js +2 -4
- package/lib/traceHandler.js +59 -2
- package/lib/transformer.js +8 -3
- package/lib/types.js +36 -22
- package/lib/util.js +6 -19
- package/lib/version.js +3 -3
- package/package/install.js +5 -5
- package/package/prunebinaries.js +1 -1
- package/package.json +1 -1
- package/plugins/configProviders/awsCommon.js +125 -0
- package/plugins/configProviders/awss3/index.js +138 -0
- package/plugins/configProviders/awssecretsmanager/index.js +147 -0
- package/plugins/configProviders/azure/index.js +7 -5
- package/plugins/token/extensionAzure/index.js +0 -1
- package/plugins/token/extensionOci/index.js +0 -1
- package/build/Release/oracledb-6.9.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-win32-x64.node-buildinfo.txt +0 -1
package/lib/pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2016,
|
|
1
|
+
// Copyright (c) 2016, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -34,7 +34,7 @@ const settings = require('./settings.js');
|
|
|
34
34
|
const nodbUtil = require('./util.js');
|
|
35
35
|
const impl = require('./impl');
|
|
36
36
|
const PoolStatistics = require('./poolStatistics.js');
|
|
37
|
-
|
|
37
|
+
const traceHandler = require('./traceHandler.js');
|
|
38
38
|
|
|
39
39
|
class Pool extends EventEmitter {
|
|
40
40
|
|
|
@@ -46,8 +46,12 @@ class Pool extends EventEmitter {
|
|
|
46
46
|
this._enableStatistics = false;
|
|
47
47
|
this._timeOfReset = this._createdDate = Date.now();
|
|
48
48
|
this._sessionCallback = undefined;
|
|
49
|
-
this.
|
|
49
|
+
this._pendingRequestQueue = new Set();
|
|
50
50
|
this._connectionClass = settings.connectionClass;
|
|
51
|
+
this._bgRequestWaiter = null;
|
|
52
|
+
this._bgRequestId = 0;
|
|
53
|
+
this._processing = 0;
|
|
54
|
+
this._ensureNoPendingRequests = null;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
//---------------------------------------------------------------------------
|
|
@@ -68,36 +72,6 @@ class Pool extends EventEmitter {
|
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
//---------------------------------------------------------------------------
|
|
72
|
-
// _checkRequestQueue()
|
|
73
|
-
//
|
|
74
|
-
// When a connection is returned to the pool, this method is called (via an
|
|
75
|
-
// event handler) to determine when requests for connections should be
|
|
76
|
-
// resumed and cancels any timeout that may have been associated with the
|
|
77
|
-
// request. This method is also called from reconfigure() so that waiting
|
|
78
|
-
// connection requests can be processed. Note the use of a local variable for
|
|
79
|
-
// the number of connections out. This is because the connection requests will
|
|
80
|
-
// not resume until after the loop is finished, and therefore the number of
|
|
81
|
-
// connections the pool thinks is out will not be incremented.
|
|
82
|
-
//---------------------------------------------------------------------------
|
|
83
|
-
_checkRequestQueue() {
|
|
84
|
-
let connectionsOut = this._connectionsOut;
|
|
85
|
-
while (this._connRequestQueue.length > 0 && connectionsOut < this.poolMax) {
|
|
86
|
-
connectionsOut += 1;
|
|
87
|
-
const payload = this._connRequestQueue.shift();
|
|
88
|
-
if (this._enableStatistics) {
|
|
89
|
-
this._totalRequestsDequeued += 1;
|
|
90
|
-
this._updateWaitStatistics(payload);
|
|
91
|
-
}
|
|
92
|
-
if (payload.timeoutHandle) {
|
|
93
|
-
clearTimeout(payload.timeoutHandle);
|
|
94
|
-
}
|
|
95
|
-
// inform the waiter that processing can continue
|
|
96
|
-
payload.resolve();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
//---------------------------------------------------------------------------
|
|
101
75
|
// _enableStats (DEPRECATED)
|
|
102
76
|
//
|
|
103
77
|
// Property for whether statistics are enabled on the pool.
|
|
@@ -118,7 +92,7 @@ class Pool extends EventEmitter {
|
|
|
118
92
|
this._totalFailedRequests = 0;
|
|
119
93
|
this._totalRequestsRejected = 0;
|
|
120
94
|
this._totalRequestTimeouts = 0;
|
|
121
|
-
this._maximumQueueLength = this.
|
|
95
|
+
this._maximumQueueLength = this._pendingRequestQueue.size;
|
|
122
96
|
this._totalTimeInQueue = 0;
|
|
123
97
|
this._minTimeInQueue = 0;
|
|
124
98
|
this._maxTimeInQueue = 0;
|
|
@@ -143,9 +117,7 @@ class Pool extends EventEmitter {
|
|
|
143
117
|
this._status = constants.POOL_STATUS_OPEN;
|
|
144
118
|
this._connectionsOut = 0;
|
|
145
119
|
this._poolAlias = poolAlias;
|
|
146
|
-
|
|
147
|
-
// register event handler for when request queue should be checked
|
|
148
|
-
this.on('_checkRequestQueue', this._checkRequestQueue);
|
|
120
|
+
this._bgRequestHandler();
|
|
149
121
|
|
|
150
122
|
this._resetStatistics();
|
|
151
123
|
|
|
@@ -157,8 +129,8 @@ class Pool extends EventEmitter {
|
|
|
157
129
|
// Update pool wait statistics after a connect request has spent some time in
|
|
158
130
|
// the queue.
|
|
159
131
|
//---------------------------------------------------------------------------
|
|
160
|
-
_updateWaitStatistics(
|
|
161
|
-
const waitTime = Date.now() -
|
|
132
|
+
_updateWaitStatistics(request) {
|
|
133
|
+
const waitTime = Date.now() - request.enqueuedTime;
|
|
162
134
|
this._totalTimeInQueue += waitTime;
|
|
163
135
|
if (this._minTimeInQueue === 0) {
|
|
164
136
|
this._minTimeInQueue = waitTime;
|
|
@@ -280,10 +252,12 @@ class Pool extends EventEmitter {
|
|
|
280
252
|
// if the pool is draining/reconfiguring/closed, throw an appropriate error
|
|
281
253
|
this._checkPoolOpen(false);
|
|
282
254
|
|
|
255
|
+
if (forceClose)
|
|
256
|
+
this._status = constants.POOL_STATUS_DRAINING;
|
|
257
|
+
|
|
283
258
|
// wait for the pool to become empty or for the drain timeout to expire
|
|
284
259
|
// (whichever comes first)
|
|
285
260
|
if (drainTime > 0) {
|
|
286
|
-
this._status = constants.POOL_STATUS_DRAINING;
|
|
287
261
|
await new Promise(resolve => {
|
|
288
262
|
const timeout = setTimeout(() => {
|
|
289
263
|
this.removeAllListeners('_allCheckedIn');
|
|
@@ -302,10 +276,21 @@ class Pool extends EventEmitter {
|
|
|
302
276
|
errors.throwErr(errors.ERR_POOL_HAS_BUSY_CONNECTIONS);
|
|
303
277
|
}
|
|
304
278
|
|
|
279
|
+
// ensure no connection requests are being processed before proceeding to
|
|
280
|
+
// close the pool (required for thick mode)
|
|
281
|
+
if (this._processing != 0)
|
|
282
|
+
await new Promise(resolve => this._ensureNoPendingRequests = resolve);
|
|
283
|
+
|
|
305
284
|
// close the pool
|
|
306
285
|
await this._impl.close();
|
|
307
286
|
this._status = constants.POOL_STATUS_CLOSED;
|
|
287
|
+
|
|
288
|
+
// stop the _bgRequestWaiter waiting in background
|
|
289
|
+
if (this._bgRequestWaiter)
|
|
290
|
+
this._bgRequestWaiter();
|
|
291
|
+
|
|
308
292
|
this.emit('_afterPoolClose');
|
|
293
|
+
traceHandler.getTraceInstance()?.onPoolClose(this);
|
|
309
294
|
|
|
310
295
|
}
|
|
311
296
|
|
|
@@ -391,7 +376,6 @@ class Pool extends EventEmitter {
|
|
|
391
376
|
// queueTimeout milliseconds.
|
|
392
377
|
//---------------------------------------------------------------------------
|
|
393
378
|
async getConnection(a1) {
|
|
394
|
-
let poolMax;
|
|
395
379
|
let options = {};
|
|
396
380
|
|
|
397
381
|
// check arguments
|
|
@@ -412,131 +396,195 @@ class Pool extends EventEmitter {
|
|
|
412
396
|
this._totalConnectionRequests += 1;
|
|
413
397
|
}
|
|
414
398
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
399
|
+
if (this._bgRequestId == Number.MAX_SAFE_INTEGER)
|
|
400
|
+
this._bgRequestId = 0;
|
|
401
|
+
|
|
402
|
+
const request = {
|
|
403
|
+
id: this._bgRequestId++,
|
|
404
|
+
options: options,
|
|
405
|
+
conn: null,
|
|
406
|
+
isWaiting: true,
|
|
407
|
+
error: null,
|
|
408
|
+
timeoutHandle: null,
|
|
409
|
+
enqueuedTime: Date.now(),
|
|
410
|
+
wasQueued: false
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// This promise acquires a connection from pool
|
|
414
|
+
const promiseToAcquire = new Promise((resolve, reject) => {
|
|
415
|
+
request.resolve = resolve;
|
|
416
|
+
request.reject = reject;
|
|
417
|
+
|
|
418
|
+
// If we haven't reached poolMax we shouldn't add to queue(honor queueMax)
|
|
419
|
+
if (this._connectionsOut < this.poolMax) {
|
|
420
|
+
this._processRequest(request);
|
|
421
|
+
} else {
|
|
422
|
+
// Ensure queueMax is not exceeded
|
|
423
|
+
if (this._pendingRequestQueue.size == this._queueMax) {
|
|
424
|
+
if (this._enableStatistics)
|
|
425
|
+
this._totalRequestsRejected += 1;
|
|
426
|
+
return reject(errors.getErr(errors.ERR_QUEUE_MAX_EXCEEDED,
|
|
427
|
+
this._queueMax));
|
|
435
428
|
}
|
|
436
|
-
errors.throwErr(errors.ERR_QUEUE_MAX_EXCEEDED, this._queueMax);
|
|
437
|
-
}
|
|
438
429
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
// set up a payload which will be added to the queue for processing
|
|
444
|
-
const payload = { resolve: resolve, reject: reject };
|
|
445
|
-
|
|
446
|
-
// if using a queue timeout, establish the timeout so that when it
|
|
447
|
-
// expires the payload will be removed from the queue and an exception
|
|
448
|
-
// thrown
|
|
449
|
-
if (this._queueTimeout !== 0) {
|
|
450
|
-
payload.timeoutHandle = setTimeout(() => {
|
|
451
|
-
const ix = this._connRequestQueue.indexOf(payload);
|
|
452
|
-
if (ix >= 0) {
|
|
453
|
-
this._connRequestQueue.splice(ix, 1);
|
|
454
|
-
}
|
|
455
|
-
if (this._enableStatistics) {
|
|
456
|
-
this._totalRequestTimeouts += 1;
|
|
457
|
-
this._updateWaitStatistics(payload);
|
|
458
|
-
}
|
|
459
|
-
try {
|
|
460
|
-
errors.throwErr(errors.ERR_CONN_REQUEST_TIMEOUT,
|
|
461
|
-
this._queueTimeout);
|
|
462
|
-
} catch (err) {
|
|
463
|
-
reject(err);
|
|
464
|
-
}
|
|
465
|
-
}, this._queueTimeout);
|
|
466
|
-
}
|
|
430
|
+
// Queueing our request
|
|
431
|
+
request.wasQueued = true;
|
|
432
|
+
this._pendingRequestQueue.add(request);
|
|
433
|
+
traceHandler.getTraceInstance()?.onPoolWait(this);
|
|
467
434
|
|
|
468
|
-
// add payload to the queue
|
|
469
|
-
this._connRequestQueue.push(payload);
|
|
470
435
|
if (this._enableStatistics) {
|
|
471
|
-
payload.enqueuedTime = Date.now();
|
|
472
436
|
this._totalRequestsEnqueued += 1;
|
|
473
437
|
this._maximumQueueLength = Math.max(this._maximumQueueLength,
|
|
474
|
-
this.
|
|
438
|
+
this._pendingRequestQueue.size);
|
|
475
439
|
}
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// This promise will timeout after queueTimeout seconds
|
|
444
|
+
const promiseToTimeout = new Promise ((_, reject) => {
|
|
445
|
+
if (this._queueTimeout > 0)
|
|
446
|
+
request.timeoutHandle = setTimeout(() => {
|
|
447
|
+
request.isWaiting = false;
|
|
448
|
+
this._pendingRequestQueue.delete(request);
|
|
449
|
+
if (this.enableStatistics)
|
|
450
|
+
this._totalRequestTimeouts += 1;
|
|
451
|
+
traceHandler.getTraceInstance()?.onPoolRequestTimeout(this);
|
|
452
|
+
reject(errors.getErr(errors.ERR_CONN_REQUEST_TIMEOUT,
|
|
453
|
+
this._queueTimeout));
|
|
454
|
+
}, this._queueTimeout);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// Earliest promise to resolve/reject gets fulfilled
|
|
458
|
+
try {
|
|
459
|
+
await Promise.race([promiseToAcquire, promiseToTimeout]);
|
|
460
|
+
} catch (err) {
|
|
461
|
+
request.error = err;
|
|
462
|
+
}
|
|
476
463
|
|
|
477
|
-
|
|
464
|
+
clearTimeout(request.timeoutHandle);
|
|
465
|
+
// Update time waited by request
|
|
466
|
+
if (this._enableStatistics && request.wasQueued)
|
|
467
|
+
this._updateWaitStatistics(request);
|
|
478
468
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
469
|
+
// Request failed to be fulfilled (errored/timeout)
|
|
470
|
+
if (request.error)
|
|
471
|
+
throw request.error;
|
|
482
472
|
|
|
483
|
-
|
|
473
|
+
traceHandler.getTraceInstance()?.onPoolAcquire(this);
|
|
484
474
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
// another attempt doesn't proceed while this one is underway
|
|
488
|
-
this._connectionsOut += 1;
|
|
489
|
-
try {
|
|
475
|
+
return request.conn;
|
|
476
|
+
}
|
|
490
477
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
478
|
+
//---------------------------------------------------------------------------
|
|
479
|
+
// _bgRequestHandler()
|
|
480
|
+
//
|
|
481
|
+
// This method handles the queuing of all pending requests and processes them
|
|
482
|
+
// depending on the open connections and if the request is still waiting.
|
|
483
|
+
//---------------------------------------------------------------------------
|
|
484
|
+
async _bgRequestHandler() {
|
|
485
|
+
while (this.status != constants.POOL_STATUS_DRAINING ||
|
|
486
|
+
this.status != constants.POOL_STATUS_CLOSED) {
|
|
495
487
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
await new Promise((resolve, reject) => {
|
|
505
|
-
this.sessionCallback(conn, requestedTag, function(err) {
|
|
506
|
-
if (err) {
|
|
507
|
-
reject(err);
|
|
508
|
-
} else {
|
|
509
|
-
resolve();
|
|
510
|
-
}
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
} catch (err) {
|
|
514
|
-
await conn.close({ drop: true });
|
|
515
|
-
throw err;
|
|
516
|
-
}
|
|
488
|
+
const request = this._pendingRequestQueue.values().next().value;
|
|
489
|
+
if (request && (this._connectionsOut < this.poolMax)) {
|
|
490
|
+
this._processRequest(request);
|
|
491
|
+
} else {
|
|
492
|
+
await new Promise((resolve) => {
|
|
493
|
+
this._bgRequestWaiter = resolve;
|
|
494
|
+
});
|
|
495
|
+
this._bgRequestWaiter = null;
|
|
517
496
|
}
|
|
497
|
+
}
|
|
518
498
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
this.emit('_checkRequestQueue');
|
|
524
|
-
if (this._connectionsOut == 0) {
|
|
525
|
-
this.emit('_allCheckedIn');
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
return (conn);
|
|
499
|
+
// reject _pendingRequests waiting to be processed
|
|
500
|
+
for (const request of this._pendingRequestQueue)
|
|
501
|
+
request.reject(errors.throwErr(errors.ERR_POOL_CLOSED));
|
|
502
|
+
}
|
|
530
503
|
|
|
504
|
+
//---------------------------------------------------------------------------
|
|
505
|
+
// _processRequest()
|
|
506
|
+
//
|
|
507
|
+
// Method called to process a connection request and return the required
|
|
508
|
+
// 'connection'/'error returned by DB' if the client is still waiting.
|
|
509
|
+
//---------------------------------------------------------------------------
|
|
510
|
+
async _processRequest(request) {
|
|
511
|
+
const conn = new Connection();
|
|
512
|
+
try {
|
|
513
|
+
this._processing += 1;
|
|
514
|
+
this._connectionsOut += 1;
|
|
515
|
+
this._pendingRequestQueue.delete(request);
|
|
516
|
+
conn._impl = await this._impl.getConnection(request.options);
|
|
517
|
+
conn._pool = this;
|
|
518
|
+
await this._tagFixup(conn, request.options.tag);
|
|
519
|
+
if (request.isWaiting)
|
|
520
|
+
request.conn = conn;
|
|
521
|
+
else
|
|
522
|
+
await conn.close({});
|
|
523
|
+
request.resolve();
|
|
531
524
|
} catch (err) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
525
|
+
if (request.isWaiting) {
|
|
526
|
+
if (this._enableStatistics)
|
|
527
|
+
this._totalFailedRequests += 1;
|
|
528
|
+
request.reject(err);
|
|
529
|
+
}
|
|
530
|
+
// Request errored, so we have some space in pool
|
|
531
|
+
this._release(conn._impl, request.options);
|
|
532
|
+
} finally {
|
|
533
|
+
this._processing -= 1;
|
|
534
|
+
if (this.status == constants.POOL_STATUS_DRAINING &&
|
|
535
|
+
this._processing == 0 && this._ensureNoPendingRequests)
|
|
536
|
+
this._ensureNoPendingRequests();
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
//---------------------------------------------------------------------------
|
|
541
|
+
// _tagFixup()
|
|
542
|
+
//
|
|
543
|
+
// Method to check if requested tag matches the connection's tag.
|
|
544
|
+
// If it does not match the callback function is invoked.
|
|
545
|
+
//---------------------------------------------------------------------------
|
|
546
|
+
async _tagFixup(conn, tag) {
|
|
547
|
+
const requestedTag = tag || "";
|
|
548
|
+
if (typeof this.sessionCallback === 'function' &&
|
|
549
|
+
(conn._impl._newSession ||
|
|
550
|
+
conn.tag != requestedTag)) {
|
|
551
|
+
try {
|
|
552
|
+
await new Promise((resolve, reject) => {
|
|
553
|
+
this.sessionCallback(conn, requestedTag, function(err) {
|
|
554
|
+
if (err) {
|
|
555
|
+
reject(err);
|
|
556
|
+
} else {
|
|
557
|
+
resolve();
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
} catch (err) {
|
|
562
|
+
await conn.close({ drop: true });
|
|
563
|
+
throw err;
|
|
535
564
|
}
|
|
536
|
-
this.emit('_checkRequestQueue');
|
|
537
|
-
throw err;
|
|
538
565
|
}
|
|
566
|
+
}
|
|
539
567
|
|
|
568
|
+
//---------------------------------------------------------------------------
|
|
569
|
+
// _release()
|
|
570
|
+
//
|
|
571
|
+
// Method called by 'close() in connection.js after a release'/'error in
|
|
572
|
+
// _processRequest' to decrease connectionsOut & wake up _bgRequestWaiter
|
|
573
|
+
//---------------------------------------------------------------------------
|
|
574
|
+
async _release(impl, options) {
|
|
575
|
+
this._connectionsOut -= 1;
|
|
576
|
+
try {
|
|
577
|
+
// Directly close the connection using the underlying connection impl
|
|
578
|
+
if (impl)
|
|
579
|
+
await impl.close(options);
|
|
580
|
+
} finally {
|
|
581
|
+
if (this._connectionsOut == 0)
|
|
582
|
+
this.emit('_allCheckedIn');
|
|
583
|
+
setImmediate(() => {
|
|
584
|
+
if (this._pendingRequestQueue.size > 0 && this._bgRequestWaiter)
|
|
585
|
+
this._bgRequestWaiter();
|
|
586
|
+
});
|
|
587
|
+
}
|
|
540
588
|
}
|
|
541
589
|
|
|
542
590
|
//---------------------------------------------------------------------------
|
|
@@ -747,7 +795,6 @@ class Pool extends EventEmitter {
|
|
|
747
795
|
} finally {
|
|
748
796
|
this._status = constants.POOL_STATUS_OPEN;
|
|
749
797
|
}
|
|
750
|
-
this.emit('_checkRequestQueue');
|
|
751
798
|
}
|
|
752
799
|
|
|
753
800
|
//---------------------------------------------------------------------------
|
|
@@ -817,6 +864,15 @@ class Pool extends EventEmitter {
|
|
|
817
864
|
get connectTraceConfig() {
|
|
818
865
|
return this._impl && this._impl._getConnectTraceConfig();
|
|
819
866
|
}
|
|
867
|
+
|
|
868
|
+
//---------------------------------------------------------------------------
|
|
869
|
+
// Symbol.asyncDispose
|
|
870
|
+
//
|
|
871
|
+
// Implement explicit resource management.
|
|
872
|
+
//---------------------------------------------------------------------------
|
|
873
|
+
async [Symbol.asyncDispose]() {
|
|
874
|
+
await this.close();
|
|
875
|
+
}
|
|
820
876
|
}
|
|
821
877
|
|
|
822
878
|
nodbUtil.wrapFns(Pool.prototype, false,
|
package/lib/poolStatistics.js
CHANGED
|
@@ -54,7 +54,7 @@ class PoolStatistics {
|
|
|
54
54
|
this.rejectedRequests = pool._totalRequestsRejected;
|
|
55
55
|
this.requestTimeouts = pool._totalRequestTimeouts;
|
|
56
56
|
this.maximumQueueLength = pool._maximumQueueLength;
|
|
57
|
-
this.currentQueueLength = pool.
|
|
57
|
+
this.currentQueueLength = pool._pendingRequestQueue.size;
|
|
58
58
|
this.timeInQueue = pool._totalTimeInQueue;
|
|
59
59
|
this.minimumTimeInQueue = pool._minTimeInQueue;
|
|
60
60
|
this.maximumTimeInQueue = pool._maxTimeInQueue;
|
package/lib/resultset.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2016,
|
|
1
|
+
// Copyright (c) 2016, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -59,7 +59,7 @@ class ResultSet {
|
|
|
59
59
|
|
|
60
60
|
// fetch all rows
|
|
61
61
|
let rowsFetched = [];
|
|
62
|
-
while (true) {
|
|
62
|
+
while (true) {
|
|
63
63
|
if (maxRows > 0 && fetchArraySize >= maxRows) {
|
|
64
64
|
fetchArraySize = maxRows;
|
|
65
65
|
}
|
|
@@ -206,12 +206,7 @@ class ResultSet {
|
|
|
206
206
|
this._impl = resultSetImpl;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
|
|
210
|
-
// close()
|
|
211
|
-
//
|
|
212
|
-
// Close the result set and make it unusable for further operations.
|
|
213
|
-
//---------------------------------------------------------------------------
|
|
214
|
-
async close() {
|
|
209
|
+
async _close() {
|
|
215
210
|
errors.assertArgCount(arguments, 0, 0);
|
|
216
211
|
errors.assert(this._impl && this._connection._impl, errors.ERR_INVALID_RS);
|
|
217
212
|
|
|
@@ -226,13 +221,15 @@ class ResultSet {
|
|
|
226
221
|
}
|
|
227
222
|
|
|
228
223
|
//---------------------------------------------------------------------------
|
|
229
|
-
//
|
|
224
|
+
// close()
|
|
230
225
|
//
|
|
231
|
-
//
|
|
232
|
-
// available. Rows are buffered in a JavaScript array in order to avoid trips
|
|
233
|
-
// through the thread pool that would be required if implemented in C.
|
|
226
|
+
// Close the result set and make it unusable for further operations.
|
|
234
227
|
//---------------------------------------------------------------------------
|
|
235
|
-
async
|
|
228
|
+
async close() {
|
|
229
|
+
await this._close.apply(this, arguments);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async _getRow() {
|
|
236
233
|
errors.assertArgCount(arguments, 0, 0);
|
|
237
234
|
errors.assert(this._impl && this._connection._impl, errors.ERR_INVALID_RS);
|
|
238
235
|
|
|
@@ -252,15 +249,17 @@ class ResultSet {
|
|
|
252
249
|
}
|
|
253
250
|
|
|
254
251
|
//---------------------------------------------------------------------------
|
|
255
|
-
//
|
|
252
|
+
// getRow()
|
|
256
253
|
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
// rows are pulled from the buffer and potentially concatenated with rows
|
|
261
|
-
// from calls to the implementation's getRows().
|
|
254
|
+
// Returns a single row to the caller from the result set, if one is
|
|
255
|
+
// available. Rows are buffered in a JavaScript array in order to avoid trips
|
|
256
|
+
// through the thread pool that would be required if implemented in C.
|
|
262
257
|
//---------------------------------------------------------------------------
|
|
263
|
-
async
|
|
258
|
+
async getRow() {
|
|
259
|
+
return await this._getRow.apply(this, arguments);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async _doGetRows(numRows) {
|
|
264
263
|
let rowsNeeded;
|
|
265
264
|
|
|
266
265
|
errors.assertArgCount(arguments, 0, 1);
|
|
@@ -282,7 +281,7 @@ class ResultSet {
|
|
|
282
281
|
if (numRows == 0) {
|
|
283
282
|
requestedRows = this._rowCache;
|
|
284
283
|
const fetchArraySize = this._impl.fetchArraySize;
|
|
285
|
-
while (true) {
|
|
284
|
+
while (true) {
|
|
286
285
|
const rows = await this._getRows(fetchArraySize);
|
|
287
286
|
if (rows) {
|
|
288
287
|
await this._processRows(rows, false);
|
|
@@ -312,6 +311,19 @@ class ResultSet {
|
|
|
312
311
|
return requestedRows;
|
|
313
312
|
}
|
|
314
313
|
|
|
314
|
+
//---------------------------------------------------------------------------
|
|
315
|
+
// getRows()
|
|
316
|
+
//
|
|
317
|
+
// Check to see if any rows are in the JS buffer (which could result from
|
|
318
|
+
// interspersed calls to getRow() and getRows()). If no rows are in the
|
|
319
|
+
// buffer, the call is just proxied to the implementation layer. Otherwise,
|
|
320
|
+
// rows are pulled from the buffer and potentially concatenated with rows
|
|
321
|
+
// from calls to the implementation's getRows().
|
|
322
|
+
//---------------------------------------------------------------------------
|
|
323
|
+
async getRows() {
|
|
324
|
+
return await this._doGetRows.apply(this, arguments);
|
|
325
|
+
}
|
|
326
|
+
|
|
315
327
|
//---------------------------------------------------------------------------
|
|
316
328
|
// metaData()
|
|
317
329
|
//
|
|
@@ -358,6 +370,15 @@ class ResultSet {
|
|
|
358
370
|
};
|
|
359
371
|
}
|
|
360
372
|
|
|
373
|
+
//---------------------------------------------------------------------------
|
|
374
|
+
// Symbol.asyncDispose
|
|
375
|
+
//
|
|
376
|
+
// Implement explicit resource management.
|
|
377
|
+
//---------------------------------------------------------------------------
|
|
378
|
+
async [Symbol.asyncDispose]() {
|
|
379
|
+
await this.close();
|
|
380
|
+
}
|
|
381
|
+
|
|
361
382
|
}
|
|
362
383
|
|
|
363
384
|
nodbUtil.wrapFns(ResultSet.prototype, errors.ERR_BUSY_RS,
|
package/lib/settings.js
CHANGED
|
@@ -62,6 +62,7 @@ class Settings {
|
|
|
62
62
|
this.configProviderCacheTimeout = 86400;
|
|
63
63
|
this.thin = true;
|
|
64
64
|
this.thinDriverInitialized = false;
|
|
65
|
+
this.thickModeDSNPassthrough = true;
|
|
65
66
|
this.createFetchTypeMap(this.fetchAsString, this.fetchAsBuffer);
|
|
66
67
|
this.fetchTypeHandler = undefined;
|
|
67
68
|
this.dbObjectTypeHandler = undefined;
|
package/lib/sodaCollection.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2018,
|
|
1
|
+
// Copyright (c) 2018, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -34,6 +34,10 @@ const settings = require('./settings.js');
|
|
|
34
34
|
|
|
35
35
|
class SodaCollection {
|
|
36
36
|
|
|
37
|
+
constructor(sodaDb) {
|
|
38
|
+
this._sodaDb = sodaDb;
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
//---------------------------------------------------------------------------
|
|
38
42
|
// createIndex()
|
|
39
43
|
//
|
|
@@ -84,7 +88,7 @@ class SodaCollection {
|
|
|
84
88
|
//---------------------------------------------------------------------------
|
|
85
89
|
find() {
|
|
86
90
|
errors.assertArgCount(arguments, 0, 0);
|
|
87
|
-
const op = new SodaOperation();
|
|
91
|
+
const op = new SodaOperation(this._sodaDb);
|
|
88
92
|
op._impl = this._impl.find();
|
|
89
93
|
return op;
|
|
90
94
|
}
|
|
@@ -111,7 +115,7 @@ class SodaCollection {
|
|
|
111
115
|
|
|
112
116
|
const actualDocs = Array(docs.length);
|
|
113
117
|
for (let i = 0; i < docs.length; i++) {
|
|
114
|
-
actualDocs[i] =
|
|
118
|
+
actualDocs[i] = this._sodaDb._verifySodaDoc(docs[i]);
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
const options = {autoCommit: settings.autoCommit};
|
|
@@ -140,7 +144,7 @@ class SodaCollection {
|
|
|
140
144
|
|
|
141
145
|
const actualDocs = Array(docs.length);
|
|
142
146
|
for (let i = 0; i < docs.length; i++) {
|
|
143
|
-
actualDocs[i] =
|
|
147
|
+
actualDocs[i] = this._sodaDb._verifySodaDoc(docs[i]);
|
|
144
148
|
}
|
|
145
149
|
|
|
146
150
|
const docImpls = await this._impl.insertManyAndGet(actualDocs, options);
|
|
@@ -159,7 +163,7 @@ class SodaCollection {
|
|
|
159
163
|
//---------------------------------------------------------------------------
|
|
160
164
|
async insertOne(content) {
|
|
161
165
|
errors.assertArgCount(arguments, 1, 1);
|
|
162
|
-
content =
|
|
166
|
+
content = this._sodaDb._verifySodaDoc(content);
|
|
163
167
|
const options = {autoCommit: settings.autoCommit};
|
|
164
168
|
await this._impl.insertOne(content, options);
|
|
165
169
|
}
|
|
@@ -174,7 +178,7 @@ class SodaCollection {
|
|
|
174
178
|
const options = {autoCommit: settings.autoCommit};
|
|
175
179
|
|
|
176
180
|
errors.assertArgCount(arguments, 1, 2);
|
|
177
|
-
content =
|
|
181
|
+
content = this._sodaDb._verifySodaDoc(content);
|
|
178
182
|
if (arguments.length == 2) {
|
|
179
183
|
errors.assertParamValue(nodbUtil.isObject(a2), 2);
|
|
180
184
|
if (a2.hint !== undefined) {
|
|
@@ -223,7 +227,7 @@ class SodaCollection {
|
|
|
223
227
|
//---------------------------------------------------------------------------
|
|
224
228
|
async save(content) {
|
|
225
229
|
errors.assertArgCount(arguments, 1, 1);
|
|
226
|
-
content =
|
|
230
|
+
content = this._sodaDb._verifySodaDoc(content);
|
|
227
231
|
const options = {autoCommit: settings.autoCommit};
|
|
228
232
|
await this._impl.save(content, options);
|
|
229
233
|
}
|
|
@@ -236,7 +240,7 @@ class SodaCollection {
|
|
|
236
240
|
//---------------------------------------------------------------------------
|
|
237
241
|
async saveAndGet(content, a2) {
|
|
238
242
|
errors.assertArgCount(arguments, 1, 2);
|
|
239
|
-
content =
|
|
243
|
+
content = this._sodaDb._verifySodaDoc(content);
|
|
240
244
|
const options = {autoCommit: settings.autoCommit};
|
|
241
245
|
if (arguments.length == 2) {
|
|
242
246
|
errors.assertParamValue(nodbUtil.isObject(a2), 2);
|