oracledb 6.8.0 → 6.10.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/README.md +39 -3
- package/build/Release/oracledb-6.10.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.10.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.10.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.10.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-win32-x64.node-buildinfo.txt +1 -0
- package/lib/aqDeqOptions.js +18 -1
- package/lib/aqMessage.js +10 -1
- package/lib/aqQueue.js +10 -6
- package/lib/configProviders/file.js +72 -0
- package/lib/connection.js +93 -4
- package/lib/dbObject.js +34 -4
- package/lib/errors.js +70 -35
- package/lib/impl/aqDeqOptions.js +10 -1
- package/lib/impl/connection.js +9 -0
- package/lib/impl/datahandlers/buffer.js +49 -0
- package/lib/impl/datahandlers/oson.js +7 -2
- package/lib/impl/pool.js +10 -1
- package/lib/impl/resultset.js +5 -4
- package/lib/impl/sodaDocument.js +5 -14
- package/lib/lob.js +9 -1
- package/lib/oracledb.js +152 -30
- package/lib/pool.js +199 -147
- package/lib/poolStatistics.js +4 -2
- 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 +171 -14
- package/lib/thin/dbObject.js +8 -6
- package/lib/thin/lob.js +2 -3
- package/lib/thin/pool.js +105 -28
- package/lib/thin/protocol/capabilities.js +10 -4
- package/lib/thin/protocol/constants.js +90 -1
- package/lib/thin/protocol/encryptDecrypt.js +2 -2
- 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 +25 -27
- package/lib/thin/protocol/messages/base.js +98 -9
- package/lib/thin/protocol/messages/dataType.js +2 -1
- package/lib/thin/protocol/messages/execute.js +46 -4
- package/lib/thin/protocol/messages/lobOp.js +5 -22
- package/lib/thin/protocol/messages/logOff.js +0 -1
- package/lib/thin/protocol/messages/sessionRelease.js +0 -1
- package/lib/thin/protocol/messages/transactionSwitch.js +12 -4
- package/lib/thin/protocol/messages/withData.js +3 -3
- package/lib/thin/protocol/packet.js +6 -5
- package/lib/thin/protocol/protocol.js +2 -1
- package/lib/thin/sqlnet/connStrategy.js +2 -1
- package/lib/thin/sqlnet/navNodes.js +1 -1
- package/lib/thin/sqlnet/networkSession.js +10 -4
- package/lib/thin/sqlnet/packet.js +2 -1
- package/lib/thin/sqlnet/sessionAtts.js +2 -3
- package/lib/types.js +6 -11
- package/lib/util.js +72 -11
- package/lib/version.js +1 -1
- package/package/install.js +3 -3
- package/package/prunebinaries.js +6 -12
- package/package.json +2 -2
- package/{lib/configProviders/azure.js → plugins/configProviders/azure/index.js} +73 -63
- package/plugins/configProviders/azurevault/index.js +84 -0
- package/{lib → plugins}/configProviders/base.js +13 -3
- package/{lib/configProviders/ociobject.js → plugins/configProviders/ociobject/index.js} +43 -78
- package/plugins/configProviders/ocivault/index.js +100 -0
- package/plugins/token/extensionOci/index.js +71 -35
- package/build/Release/oracledb-6.8.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.8.0-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.8.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.8.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.8.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.8.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.8.0-win32-x64.node-buildinfo.txt +0 -1
package/lib/pool.js
CHANGED
|
@@ -35,7 +35,6 @@ const nodbUtil = require('./util.js');
|
|
|
35
35
|
const impl = require('./impl');
|
|
36
36
|
const PoolStatistics = require('./poolStatistics.js');
|
|
37
37
|
|
|
38
|
-
|
|
39
38
|
class Pool extends EventEmitter {
|
|
40
39
|
|
|
41
40
|
constructor() {
|
|
@@ -46,8 +45,12 @@ class Pool extends EventEmitter {
|
|
|
46
45
|
this._enableStatistics = false;
|
|
47
46
|
this._timeOfReset = this._createdDate = Date.now();
|
|
48
47
|
this._sessionCallback = undefined;
|
|
49
|
-
this.
|
|
48
|
+
this._pendingRequestQueue = new Set();
|
|
50
49
|
this._connectionClass = settings.connectionClass;
|
|
50
|
+
this._bgRequestWaiter = null;
|
|
51
|
+
this._bgRequestId = 0;
|
|
52
|
+
this._processing = 0;
|
|
53
|
+
this._ensureNoPendingRequests = null;
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
//---------------------------------------------------------------------------
|
|
@@ -68,36 +71,6 @@ class Pool extends EventEmitter {
|
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
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
74
|
// _enableStats (DEPRECATED)
|
|
102
75
|
//
|
|
103
76
|
// Property for whether statistics are enabled on the pool.
|
|
@@ -118,7 +91,7 @@ class Pool extends EventEmitter {
|
|
|
118
91
|
this._totalFailedRequests = 0;
|
|
119
92
|
this._totalRequestsRejected = 0;
|
|
120
93
|
this._totalRequestTimeouts = 0;
|
|
121
|
-
this._maximumQueueLength = this.
|
|
94
|
+
this._maximumQueueLength = this._pendingRequestQueue.size;
|
|
122
95
|
this._totalTimeInQueue = 0;
|
|
123
96
|
this._minTimeInQueue = 0;
|
|
124
97
|
this._maxTimeInQueue = 0;
|
|
@@ -143,9 +116,7 @@ class Pool extends EventEmitter {
|
|
|
143
116
|
this._status = constants.POOL_STATUS_OPEN;
|
|
144
117
|
this._connectionsOut = 0;
|
|
145
118
|
this._poolAlias = poolAlias;
|
|
146
|
-
|
|
147
|
-
// register event handler for when request queue should be checked
|
|
148
|
-
this.on('_checkRequestQueue', this._checkRequestQueue);
|
|
119
|
+
this._bgRequestHandler();
|
|
149
120
|
|
|
150
121
|
this._resetStatistics();
|
|
151
122
|
|
|
@@ -157,8 +128,8 @@ class Pool extends EventEmitter {
|
|
|
157
128
|
// Update pool wait statistics after a connect request has spent some time in
|
|
158
129
|
// the queue.
|
|
159
130
|
//---------------------------------------------------------------------------
|
|
160
|
-
_updateWaitStatistics(
|
|
161
|
-
const waitTime = Date.now() -
|
|
131
|
+
_updateWaitStatistics(request) {
|
|
132
|
+
const waitTime = Date.now() - request.enqueuedTime;
|
|
162
133
|
this._totalTimeInQueue += waitTime;
|
|
163
134
|
if (this._minTimeInQueue === 0) {
|
|
164
135
|
this._minTimeInQueue = waitTime;
|
|
@@ -280,10 +251,12 @@ class Pool extends EventEmitter {
|
|
|
280
251
|
// if the pool is draining/reconfiguring/closed, throw an appropriate error
|
|
281
252
|
this._checkPoolOpen(false);
|
|
282
253
|
|
|
254
|
+
if (forceClose)
|
|
255
|
+
this._status = constants.POOL_STATUS_DRAINING;
|
|
256
|
+
|
|
283
257
|
// wait for the pool to become empty or for the drain timeout to expire
|
|
284
258
|
// (whichever comes first)
|
|
285
259
|
if (drainTime > 0) {
|
|
286
|
-
this._status = constants.POOL_STATUS_DRAINING;
|
|
287
260
|
await new Promise(resolve => {
|
|
288
261
|
const timeout = setTimeout(() => {
|
|
289
262
|
this.removeAllListeners('_allCheckedIn');
|
|
@@ -302,9 +275,19 @@ class Pool extends EventEmitter {
|
|
|
302
275
|
errors.throwErr(errors.ERR_POOL_HAS_BUSY_CONNECTIONS);
|
|
303
276
|
}
|
|
304
277
|
|
|
278
|
+
// ensure no connection requests are being processed before proceeding to
|
|
279
|
+
// close the pool (required for thick mode)
|
|
280
|
+
if (this._processing != 0)
|
|
281
|
+
await new Promise(resolve => this._ensureNoPendingRequests = resolve);
|
|
282
|
+
|
|
305
283
|
// close the pool
|
|
306
284
|
await this._impl.close();
|
|
307
285
|
this._status = constants.POOL_STATUS_CLOSED;
|
|
286
|
+
|
|
287
|
+
// stop the _bgRequestWaiter waiting in background
|
|
288
|
+
if (this._bgRequestWaiter)
|
|
289
|
+
this._bgRequestWaiter();
|
|
290
|
+
|
|
308
291
|
this.emit('_afterPoolClose');
|
|
309
292
|
|
|
310
293
|
}
|
|
@@ -391,7 +374,6 @@ class Pool extends EventEmitter {
|
|
|
391
374
|
// queueTimeout milliseconds.
|
|
392
375
|
//---------------------------------------------------------------------------
|
|
393
376
|
async getConnection(a1) {
|
|
394
|
-
let poolMax;
|
|
395
377
|
let options = {};
|
|
396
378
|
|
|
397
379
|
// check arguments
|
|
@@ -412,131 +394,191 @@ class Pool extends EventEmitter {
|
|
|
412
394
|
this._totalConnectionRequests += 1;
|
|
413
395
|
}
|
|
414
396
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
397
|
+
if (this._bgRequestId == Number.MAX_SAFE_INTEGER)
|
|
398
|
+
this._bgRequestId = 0;
|
|
399
|
+
|
|
400
|
+
const request = {
|
|
401
|
+
id: this._bgRequestId++,
|
|
402
|
+
options: options,
|
|
403
|
+
conn: null,
|
|
404
|
+
isWaiting: true,
|
|
405
|
+
error: null,
|
|
406
|
+
timeoutHandle: null,
|
|
407
|
+
enqueuedTime: Date.now(),
|
|
408
|
+
wasQueued: false
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// This promise acquires a connection from pool
|
|
412
|
+
const promiseToAcquire = new Promise((resolve, reject) => {
|
|
413
|
+
request.resolve = resolve;
|
|
414
|
+
request.reject = reject;
|
|
415
|
+
|
|
416
|
+
// If we haven't reached poolMax we shouldn't add to queue(honor queueMax)
|
|
417
|
+
if (this._connectionsOut < this.poolMax) {
|
|
418
|
+
this._processRequest(request);
|
|
419
|
+
} else {
|
|
420
|
+
// Ensure queueMax is not exceeded
|
|
421
|
+
if (this._pendingRequestQueue.size == this._queueMax) {
|
|
422
|
+
if (this._enableStatistics)
|
|
423
|
+
this._totalRequestsRejected += 1;
|
|
424
|
+
return reject(errors.getErr(errors.ERR_QUEUE_MAX_EXCEEDED,
|
|
425
|
+
this._queueMax));
|
|
435
426
|
}
|
|
436
|
-
errors.throwErr(errors.ERR_QUEUE_MAX_EXCEEDED, this._queueMax);
|
|
437
|
-
}
|
|
438
427
|
|
|
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
|
-
}
|
|
428
|
+
// Queueing our request
|
|
429
|
+
request.wasQueued = true;
|
|
430
|
+
this._pendingRequestQueue.add(request);
|
|
467
431
|
|
|
468
|
-
// add payload to the queue
|
|
469
|
-
this._connRequestQueue.push(payload);
|
|
470
432
|
if (this._enableStatistics) {
|
|
471
|
-
payload.enqueuedTime = Date.now();
|
|
472
433
|
this._totalRequestsEnqueued += 1;
|
|
473
434
|
this._maximumQueueLength = Math.max(this._maximumQueueLength,
|
|
474
|
-
this.
|
|
435
|
+
this._pendingRequestQueue.size);
|
|
475
436
|
}
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// This promise will timeout after queueTimeout seconds
|
|
441
|
+
const promiseToTimeout = new Promise ((_, reject) => {
|
|
442
|
+
if (this._queueTimeout > 0)
|
|
443
|
+
request.timeoutHandle = setTimeout(() => {
|
|
444
|
+
request.isWaiting = false;
|
|
445
|
+
this._pendingRequestQueue.delete(request);
|
|
446
|
+
if (this.enableStatistics)
|
|
447
|
+
this._totalRequestTimeouts += 1;
|
|
448
|
+
reject(errors.getErr(errors.ERR_CONN_REQUEST_TIMEOUT,
|
|
449
|
+
this._queueTimeout));
|
|
450
|
+
}, this._queueTimeout);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// Earliest promise to resolve/reject gets fulfilled
|
|
454
|
+
try {
|
|
455
|
+
await Promise.race([promiseToAcquire, promiseToTimeout]);
|
|
456
|
+
} catch (err) {
|
|
457
|
+
request.error = err;
|
|
458
|
+
}
|
|
476
459
|
|
|
477
|
-
|
|
460
|
+
clearTimeout(request.timeoutHandle);
|
|
461
|
+
// Update time waited by request
|
|
462
|
+
if (this._enableStatistics && request.wasQueued)
|
|
463
|
+
this._updateWaitStatistics(request);
|
|
478
464
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
465
|
+
// Request failed to be fulfilled (errored/timeout)
|
|
466
|
+
if (request.error)
|
|
467
|
+
throw request.error;
|
|
482
468
|
|
|
469
|
+
return request.conn;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
//---------------------------------------------------------------------------
|
|
473
|
+
// _bgRequestHandler()
|
|
474
|
+
//
|
|
475
|
+
// This method handles the queuing of all pending requests and processes them
|
|
476
|
+
// depending on the open connections and if the request is still waiting.
|
|
477
|
+
//---------------------------------------------------------------------------
|
|
478
|
+
async _bgRequestHandler() {
|
|
479
|
+
while (this.status != constants.POOL_STATUS_DRAINING ||
|
|
480
|
+
this.status != constants.POOL_STATUS_CLOSED) {
|
|
481
|
+
|
|
482
|
+
const request = this._pendingRequestQueue.values().next().value;
|
|
483
|
+
if (request && (this._connectionsOut < this.poolMax)) {
|
|
484
|
+
this._processRequest(request);
|
|
485
|
+
} else {
|
|
486
|
+
await new Promise((resolve) => {
|
|
487
|
+
this._bgRequestWaiter = resolve;
|
|
488
|
+
});
|
|
489
|
+
this._bgRequestWaiter = null;
|
|
490
|
+
}
|
|
483
491
|
}
|
|
484
492
|
|
|
485
|
-
//
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
try {
|
|
493
|
+
// reject _pendingRequests waiting to be processed
|
|
494
|
+
for (const request of this._pendingRequestQueue)
|
|
495
|
+
request.reject(errors.throwErr(errors.ERR_POOL_CLOSED));
|
|
496
|
+
}
|
|
490
497
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
498
|
+
//---------------------------------------------------------------------------
|
|
499
|
+
// _processRequest()
|
|
500
|
+
//
|
|
501
|
+
// Method called to process a connection request and return the required
|
|
502
|
+
// 'connection'/'error returned by DB' if the client is still waiting.
|
|
503
|
+
//---------------------------------------------------------------------------
|
|
504
|
+
async _processRequest(request) {
|
|
505
|
+
const conn = new Connection();
|
|
506
|
+
try {
|
|
507
|
+
this._processing += 1;
|
|
508
|
+
this._connectionsOut += 1;
|
|
509
|
+
this._pendingRequestQueue.delete(request);
|
|
510
|
+
conn._impl = await this._impl.getConnection(request.options);
|
|
494
511
|
conn._pool = this;
|
|
512
|
+
await this._tagFixup(conn, request.options.tag);
|
|
513
|
+
if (request.isWaiting)
|
|
514
|
+
request.conn = conn;
|
|
515
|
+
else
|
|
516
|
+
await conn.close({});
|
|
517
|
+
request.resolve();
|
|
518
|
+
} catch (err) {
|
|
519
|
+
if (request.isWaiting) {
|
|
520
|
+
if (this._enableStatistics)
|
|
521
|
+
this._totalFailedRequests += 1;
|
|
522
|
+
request.reject(err);
|
|
523
|
+
}
|
|
524
|
+
// Request errored, so we have some space in pool
|
|
525
|
+
this._release(conn._impl, request.options);
|
|
526
|
+
} finally {
|
|
527
|
+
this._processing -= 1;
|
|
528
|
+
if (this.status == constants.POOL_STATUS_DRAINING &&
|
|
529
|
+
this._processing == 0 && this._ensureNoPendingRequests)
|
|
530
|
+
this._ensureNoPendingRequests();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
495
533
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
534
|
+
//---------------------------------------------------------------------------
|
|
535
|
+
// _tagFixup()
|
|
536
|
+
//
|
|
537
|
+
// Method to check if requested tag matches the connection's tag.
|
|
538
|
+
// If it does not match the callback function is invoked.
|
|
539
|
+
//---------------------------------------------------------------------------
|
|
540
|
+
async _tagFixup(conn, tag) {
|
|
541
|
+
const requestedTag = tag || "";
|
|
542
|
+
if (typeof this.sessionCallback === 'function' &&
|
|
543
|
+
(conn._impl._newSession ||
|
|
544
|
+
conn.tag != requestedTag)) {
|
|
545
|
+
try {
|
|
546
|
+
await new Promise((resolve, reject) => {
|
|
547
|
+
this.sessionCallback(conn, requestedTag, function(err) {
|
|
548
|
+
if (err) {
|
|
549
|
+
reject(err);
|
|
550
|
+
} else {
|
|
551
|
+
resolve();
|
|
552
|
+
}
|
|
512
553
|
});
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
554
|
+
});
|
|
555
|
+
} catch (err) {
|
|
556
|
+
await conn.close({ drop: true });
|
|
557
|
+
throw err;
|
|
517
558
|
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
518
561
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
562
|
+
//---------------------------------------------------------------------------
|
|
563
|
+
// _release()
|
|
564
|
+
//
|
|
565
|
+
// Method called by 'close() in connection.js after a release'/'error in
|
|
566
|
+
// _processRequest' to decrease connectionsOut & wake up _bgRequestWaiter
|
|
567
|
+
//---------------------------------------------------------------------------
|
|
568
|
+
async _release(impl, options) {
|
|
569
|
+
this._connectionsOut -= 1;
|
|
570
|
+
try {
|
|
571
|
+
// Directly close the connection using the underlying connection impl
|
|
572
|
+
if (impl)
|
|
573
|
+
await impl.close(options);
|
|
574
|
+
} finally {
|
|
575
|
+
if (this._connectionsOut == 0)
|
|
576
|
+
this.emit('_allCheckedIn');
|
|
577
|
+
setImmediate(() => {
|
|
578
|
+
if (this._pendingRequestQueue.size > 0 && this._bgRequestWaiter)
|
|
579
|
+
this._bgRequestWaiter();
|
|
527
580
|
});
|
|
528
|
-
|
|
529
|
-
return (conn);
|
|
530
|
-
|
|
531
|
-
} catch (err) {
|
|
532
|
-
this._connectionsOut -= 1;
|
|
533
|
-
if (this._enableStatistics) {
|
|
534
|
-
this._totalFailedRequests += 1;
|
|
535
|
-
}
|
|
536
|
-
this.emit('_checkRequestQueue');
|
|
537
|
-
throw err;
|
|
538
581
|
}
|
|
539
|
-
|
|
540
582
|
}
|
|
541
583
|
|
|
542
584
|
//---------------------------------------------------------------------------
|
|
@@ -653,6 +695,15 @@ class Pool extends EventEmitter {
|
|
|
653
695
|
return this._impl.getPoolTimeout();
|
|
654
696
|
}
|
|
655
697
|
|
|
698
|
+
//---------------------------------------------------------------------------
|
|
699
|
+
// maxLifetimeSession
|
|
700
|
+
//
|
|
701
|
+
// Property for the max allowed lifetime of a session in the pool.
|
|
702
|
+
//---------------------------------------------------------------------------
|
|
703
|
+
get maxLifetimeSession() {
|
|
704
|
+
return this._impl.getMaxLifetimeSession();
|
|
705
|
+
}
|
|
706
|
+
|
|
656
707
|
//---------------------------------------------------------------------------
|
|
657
708
|
// queueMax
|
|
658
709
|
//
|
|
@@ -693,6 +744,7 @@ class Pool extends EventEmitter {
|
|
|
693
744
|
errors.assertParamPropUnsignedInt(options, 1, "poolIncrement");
|
|
694
745
|
errors.assertParamPropInt(options, 1, "poolPingInterval");
|
|
695
746
|
errors.assertParamPropUnsignedInt(options, 1, "poolTimeout");
|
|
747
|
+
errors.assertParamPropUnsignedInt(options, 1, "maxLifetimeSession");
|
|
696
748
|
errors.assertParamPropUnsignedInt(options, 1, "stmtCacheSize");
|
|
697
749
|
errors.assertParamPropBool(options, 1, "sodaMetaDataCache");
|
|
698
750
|
|
|
@@ -708,7 +760,8 @@ class Pool extends EventEmitter {
|
|
|
708
760
|
this._status = constants.POOL_STATUS_RECONFIGURING;
|
|
709
761
|
try {
|
|
710
762
|
// poolMin/poolMax/poolIncrement/poolPingInterval/poolTimeout/
|
|
711
|
-
// poolMaxPerShard/stmtCacheSize/sodaMetaDataCache
|
|
763
|
+
// poolMaxPerShard/stmtCacheSize/sodaMetaDataCache/maxLifetimeSession
|
|
764
|
+
// parameters
|
|
712
765
|
await this._impl.reconfigure(options);
|
|
713
766
|
|
|
714
767
|
// pool JS parameters: queueMax, queueTimeout, enableStatistics,
|
|
@@ -736,7 +789,6 @@ class Pool extends EventEmitter {
|
|
|
736
789
|
} finally {
|
|
737
790
|
this._status = constants.POOL_STATUS_OPEN;
|
|
738
791
|
}
|
|
739
|
-
this.emit('_checkRequestQueue');
|
|
740
792
|
}
|
|
741
793
|
|
|
742
794
|
//---------------------------------------------------------------------------
|
package/lib/poolStatistics.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2021,
|
|
1
|
+
// Copyright (c) 2021, 2025, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -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;
|
|
@@ -74,6 +74,7 @@ class PoolStatistics {
|
|
|
74
74
|
this.poolPingInterval = pool.poolPingInterval;
|
|
75
75
|
this.poolPingTimeout = pool.poolPingTimeout;
|
|
76
76
|
this.poolTimeout = pool.poolTimeout;
|
|
77
|
+
this.maxLifetimeSession = pool.maxLifetimeSession;
|
|
77
78
|
this.queueMax = pool.queueMax;
|
|
78
79
|
this.queueTimeout = pool.queueTimeout;
|
|
79
80
|
this.sodaMetaDataCache = pool.sodaMetaDataCache;
|
|
@@ -127,6 +128,7 @@ class PoolStatistics {
|
|
|
127
128
|
console.log('...poolPingInterval (seconds):', this.poolPingInterval);
|
|
128
129
|
console.log('...poolPingTimeout (milliseconds):', this.poolPingTimeout);
|
|
129
130
|
console.log('...poolTimeout (seconds):', this.poolTimeout);
|
|
131
|
+
console.log('...maxLifetimeSession (seconds):', this.maxLifetimeSession);
|
|
130
132
|
console.log('...queueMax:', this.queueMax);
|
|
131
133
|
console.log('...queueTimeout (milliseconds):', this.queueTimeout);
|
|
132
134
|
console.log('...sessionCallback:', this.sessionCallback);
|
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);
|
package/lib/sodaDatabase.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
|
//
|
|
@@ -32,6 +32,7 @@ const SodaDocument = require('./sodaDocument.js');
|
|
|
32
32
|
const errors = require('./errors.js');
|
|
33
33
|
const nodbUtil = require('./util.js');
|
|
34
34
|
const settings = require('./settings.js');
|
|
35
|
+
const transformer = require('./transformer.js');
|
|
35
36
|
|
|
36
37
|
class SodaDatabase {
|
|
37
38
|
|
|
@@ -64,7 +65,7 @@ class SodaDatabase {
|
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
const coll = new SodaCollection();
|
|
68
|
+
const coll = new SodaCollection(this);
|
|
68
69
|
coll._impl = await this._impl.createCollection(name, options);
|
|
69
70
|
return coll;
|
|
70
71
|
}
|
|
@@ -76,6 +77,7 @@ class SodaDatabase {
|
|
|
76
77
|
//---------------------------------------------------------------------------
|
|
77
78
|
createDocument(content, a2) {
|
|
78
79
|
let options = {};
|
|
80
|
+
let inContent;
|
|
79
81
|
|
|
80
82
|
errors.assertArgCount(arguments, 1, 2);
|
|
81
83
|
errors.assertParamValue(Buffer.isBuffer(content) ||
|
|
@@ -87,14 +89,20 @@ class SodaDatabase {
|
|
|
87
89
|
errors.assertParamPropString(options, 2, "mediaType");
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
// native JSON support for SODA is available from Oracle Client 23.4
|
|
93
|
+
if (this._impl.supportsJson &&
|
|
94
|
+
(!options.mediaType || options.mediaType === 'application/json')) {
|
|
95
|
+
inContent = transformer.transformJsonValue(content);
|
|
96
|
+
} else if (Buffer.isBuffer(content)) {
|
|
97
|
+
inContent = content;
|
|
98
|
+
} else if (typeof content === 'string') {
|
|
99
|
+
inContent = Buffer.from(content);
|
|
100
|
+
} else {
|
|
101
|
+
inContent = Buffer.from(JSON.stringify(content));
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
const doc = new SodaDocument();
|
|
97
|
-
doc._impl = this._impl.createDocument(
|
|
105
|
+
doc._impl = this._impl.createDocument(inContent, options);
|
|
98
106
|
return doc;
|
|
99
107
|
}
|
|
100
108
|
|
|
@@ -133,12 +141,31 @@ class SodaDatabase {
|
|
|
133
141
|
const options = {autoCommit: settings.autoCommit};
|
|
134
142
|
const collImpl = await this._impl.openCollection(name, options);
|
|
135
143
|
if (collImpl) {
|
|
136
|
-
const coll = new SodaCollection();
|
|
144
|
+
const coll = new SodaCollection(this);
|
|
137
145
|
coll._impl = collImpl;
|
|
138
146
|
return coll;
|
|
139
147
|
}
|
|
140
148
|
}
|
|
141
149
|
|
|
150
|
+
//---------------------------------------------------------------------------
|
|
151
|
+
// _verifySodaDoc()
|
|
152
|
+
//
|
|
153
|
+
// Verifies the content passed is valid for a SodaDocument object.
|
|
154
|
+
//---------------------------------------------------------------------------
|
|
155
|
+
_verifySodaDoc(content) {
|
|
156
|
+
// check if the content is a sodaDocument object
|
|
157
|
+
if (content != null && content._sodaDocumentMarker)
|
|
158
|
+
return content._impl;
|
|
159
|
+
errors.assertParamValue(nodbUtil.isObject(content), 1);
|
|
160
|
+
|
|
161
|
+
// JSON is assumed, if you pass in the content
|
|
162
|
+
// starting from Oracle Client 23ai onwards, JSON in SODA is supported
|
|
163
|
+
if (this._impl._supportsJson)
|
|
164
|
+
return transformer.transformJsonValue(content);
|
|
165
|
+
|
|
166
|
+
return Buffer.from(JSON.stringify(content));
|
|
167
|
+
}
|
|
168
|
+
|
|
142
169
|
}
|
|
143
170
|
|
|
144
171
|
nodbUtil.wrapFns(SodaDatabase.prototype,
|