oracledb 6.0.2 → 6.1.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 +15 -17
- package/SECURITY.md +1 -1
- package/build/Release/oracledb-6.1.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/example.js +0 -1
- package/lib/aqQueue.js +40 -26
- package/lib/connection.js +15 -3
- package/lib/errors.js +15 -10
- package/lib/impl/connection.js +9 -0
- package/lib/impl/resultset.js +7 -4
- package/lib/oracledb.js +15 -12
- package/lib/pool.js +11 -2
- package/lib/settings.js +1 -1
- package/lib/sodaCollection.js +1 -1
- package/lib/thin/connection.js +92 -30
- package/lib/thin/dbObject.js +2 -2
- package/lib/thin/lob.js +2 -2
- package/lib/thin/pool.js +153 -71
- package/lib/thin/protocol/buffer.js +24 -6
- package/lib/thin/protocol/constants.js +8 -18
- package/lib/thin/protocol/encryptDecrypt.js +17 -17
- package/lib/thin/protocol/messages/auth.js +27 -31
- package/lib/thin/protocol/messages/base.js +30 -53
- package/lib/thin/protocol/messages/connectionCookie.js +76 -0
- package/lib/thin/protocol/messages/dataType.js +13 -9
- package/lib/thin/protocol/messages/execute.js +11 -11
- package/lib/thin/protocol/messages/index.js +2 -0
- package/lib/thin/protocol/messages/lobOp.js +3 -3
- package/lib/thin/protocol/messages/protocol.js +31 -20
- package/lib/thin/protocol/messages/withData.js +60 -53
- package/lib/thin/protocol/oson.js +4 -4
- package/lib/thin/protocol/packet.js +51 -28
- package/lib/thin/protocol/protocol.js +12 -7
- package/lib/thin/protocol/utils.js +2 -2
- package/lib/thin/resultSet.js +6 -6
- package/lib/thin/sqlnet/connStrategy.js +134 -7
- package/lib/thin/sqlnet/constants.js +2 -0
- package/lib/thin/sqlnet/ezConnectResolver.js +29 -24
- package/lib/thin/sqlnet/navNodes.js +35 -28
- package/lib/thin/sqlnet/networkSession.js +45 -40
- package/lib/thin/sqlnet/ntTcp.js +70 -35
- package/lib/thin/sqlnet/nvStrToNvPair.js +16 -16
- package/lib/thin/sqlnet/packet.js +17 -10
- package/lib/thin/sqlnet/paramParser.js +9 -9
- package/lib/thin/sqlnet/sessionAtts.js +4 -0
- package/lib/thin/statement.js +4 -3
- package/lib/thin/util.js +28 -8
- package/lib/transformer.js +3 -1
- package/lib/util.js +0 -13
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/build/Release/oracledb-6.0.2-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.0.2-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.0.2-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-linux-x64.node +0 -0
- package/build/Release/oracledb-6.0.2-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-win32-x64.node +0 -0
- package/build/Release/oracledb-6.0.2-win32-x64.node-buildinfo.txt +0 -1
package/lib/thin/connection.js
CHANGED
|
@@ -32,7 +32,7 @@ const ThinResultSetImpl = require('./resultSet.js');
|
|
|
32
32
|
const ThinLobImpl = require("./lob.js");
|
|
33
33
|
const Protocol = require("./protocol/protocol.js");
|
|
34
34
|
const { BaseBuffer } = require('./protocol/buffer.js');
|
|
35
|
-
const {NetworkSession:nsi
|
|
35
|
+
const {NetworkSession:nsi} = require("./sqlnet/networkSession.js");
|
|
36
36
|
const { Statement } = require("./statement");
|
|
37
37
|
const thinUtil = require('./util');
|
|
38
38
|
const sqlNetConstants = require('./sqlnet/constants.js');
|
|
@@ -49,6 +49,8 @@ const finalizationRegistry = new global.FinalizationRegistry((heldValue) => {
|
|
|
49
49
|
class TDSBuffer extends BaseBuffer {
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
const connectionCookies = new Map();
|
|
53
|
+
|
|
52
54
|
class ThinConnectionImpl extends ConnectionImpl {
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -443,10 +445,6 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
443
445
|
await this._protocol.breakMessage();
|
|
444
446
|
}
|
|
445
447
|
|
|
446
|
-
_healthStatus() {
|
|
447
|
-
return this.nscon.recvInbandNotif();
|
|
448
|
-
}
|
|
449
|
-
|
|
450
448
|
isHealthy() {
|
|
451
449
|
try {
|
|
452
450
|
if (this.nscon.recvInbandNotif() === 0)
|
|
@@ -461,6 +459,26 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
461
459
|
return (this._pool) ? true : false;
|
|
462
460
|
}
|
|
463
461
|
|
|
462
|
+
//---------------------------------------------------------------------------
|
|
463
|
+
// getConnectionCookieByUUID()
|
|
464
|
+
//
|
|
465
|
+
// It fetches from map which keeps keyname as UUID+ServiceName.
|
|
466
|
+
// UUID identifies the CDB instance and ServiceName identifies the
|
|
467
|
+
// entity within a PDB which uniquely identifies a pdb instance.
|
|
468
|
+
//---------------------------------------------------------------------------
|
|
469
|
+
getConnectionCookieByUUID(uuid) {
|
|
470
|
+
let cookie;
|
|
471
|
+
if (uuid) {
|
|
472
|
+
const key = uuid + ((this.serviceName) ? this.serviceName : this.sid);
|
|
473
|
+
cookie = connectionCookies.get(key);
|
|
474
|
+
if (!cookie) {
|
|
475
|
+
cookie = {};
|
|
476
|
+
connectionCookies.set(key, cookie);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return cookie;
|
|
480
|
+
}
|
|
481
|
+
|
|
464
482
|
/**
|
|
465
483
|
*
|
|
466
484
|
* @param {object} params Configuration of the connection
|
|
@@ -499,22 +517,32 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
499
517
|
this._clientInfoModified = false;
|
|
500
518
|
this._module = "";
|
|
501
519
|
this._moduleModified = false;
|
|
520
|
+
this._drcpEnabled = false;
|
|
502
521
|
this.serviceName = '';
|
|
503
522
|
this.remoteAddress = '';
|
|
504
|
-
this.privilege = params.privilege;
|
|
505
523
|
this.comboKey = null; // used in changePassword API
|
|
506
524
|
|
|
507
525
|
this.nscon = new nsi();
|
|
508
526
|
finalizationRegistry.register(this, this.nscon);
|
|
509
527
|
await this.nscon.connect(params);
|
|
510
528
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
529
|
+
let serverType;
|
|
530
|
+
if (this.isPooled()) {
|
|
531
|
+
serverType = params._connInfo[0];
|
|
532
|
+
this.serviceName = params._connInfo[2];
|
|
533
|
+
this.purity = params._connInfo[3] | constants.PURITY_DEFAULT;
|
|
534
|
+
this.sid = params._connInfo[4];
|
|
535
|
+
} else {
|
|
536
|
+
serverType = this.nscon.getOption(sqlNetConstants.SERVERTYPE);
|
|
537
|
+
this.serviceName = this.nscon.getOption(sqlNetConstants.SVCNAME);
|
|
538
|
+
this.sid = this.nscon.getOption(sqlNetConstants.SID);
|
|
539
|
+
this.purity = this.nscon.getOption(sqlNetConstants.PURITY) | constants.PURITY_DEFAULT;
|
|
540
|
+
}
|
|
541
|
+
if (serverType) {
|
|
542
|
+
this._drcpEnabled = serverType.toLowerCase() === 'pooled';
|
|
543
|
+
}
|
|
516
544
|
this.remoteAddress = this.nscon.getOption(sqlNetConstants.REMOTEADDR);
|
|
517
|
-
this.
|
|
545
|
+
this.connectionClass = params.connectionClass;
|
|
518
546
|
|
|
519
547
|
/*
|
|
520
548
|
* if drcp is used, use purity = NEW as the default purity for
|
|
@@ -538,13 +566,41 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
538
566
|
}
|
|
539
567
|
|
|
540
568
|
try {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
569
|
+
const cookie = this.getConnectionCookieByUUID(this.nscon.dbUUID);
|
|
570
|
+
this.nscon.dbUUID = null;
|
|
571
|
+
const protocolMessage = new messages.ProtocolMessage(this);
|
|
572
|
+
const dataTypeMessage = new messages.DataTypeMessage(this);
|
|
573
|
+
const authMessage = new messages.AuthMessage(this, params);
|
|
574
|
+
let sentCookie = false;
|
|
575
|
+
if (cookie && cookie.populated) {
|
|
576
|
+
const cookieMessage = new messages.ConnectionCookieMessage(this);
|
|
577
|
+
cookieMessage.cookie = cookie;
|
|
578
|
+
cookieMessage.protocolMessage = protocolMessage;
|
|
579
|
+
cookieMessage.dataTypeMessage = dataTypeMessage;
|
|
580
|
+
cookieMessage.authMessage = authMessage;
|
|
581
|
+
await this._protocol._processMessage(cookieMessage);
|
|
582
|
+
sentCookie = true;
|
|
583
|
+
} else {
|
|
584
|
+
await this._protocol._processMessage(protocolMessage);
|
|
585
|
+
}
|
|
586
|
+
if (!sentCookie || !cookie.populated) {
|
|
587
|
+
await this._protocol._processMessage(dataTypeMessage);
|
|
588
|
+
// Does OSESSKEY for non-token Authentication else OAUTH
|
|
589
|
+
await this._protocol._processMessage(authMessage);
|
|
590
|
+
if (cookie && !cookie.populated) {
|
|
591
|
+
cookie.protocolVersion = protocolMessage.serverVersion;
|
|
592
|
+
cookie.serverBanner = protocolMessage.serverBanner;
|
|
593
|
+
cookie.charsetID = this._protocol.caps.charSetID;
|
|
594
|
+
cookie.ncharsetID = this._protocol.caps.nCharsetId;
|
|
595
|
+
cookie.flags = protocolMessage.serverFlags;
|
|
596
|
+
cookie.compileCaps = Buffer.from(protocolMessage.serverCompileCaps);
|
|
597
|
+
cookie.runtimeCaps = Buffer.from(protocolMessage.serverRunTimeCaps);
|
|
598
|
+
cookie.populated = true;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (!params.token) { // non-token Authentication
|
|
602
|
+
await this._protocol._processMessage(authMessage); // OAUTH
|
|
603
|
+
}
|
|
548
604
|
} catch (err) {
|
|
549
605
|
this.nscon.disconnect();
|
|
550
606
|
throw err;
|
|
@@ -614,7 +670,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
614
670
|
// option is true
|
|
615
671
|
//---------------------------------------------------------------------------
|
|
616
672
|
_prepare(sql, options) {
|
|
617
|
-
|
|
673
|
+
const statement = this._getStatement(sql, options.keepInStmtCache);
|
|
618
674
|
statement.bufferRowIndex = 0;
|
|
619
675
|
statement.bufferRowCount = 0;
|
|
620
676
|
statement.lastRowIndex = 0;
|
|
@@ -626,8 +682,8 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
626
682
|
// Binds the values by user to the statement object
|
|
627
683
|
//---------------------------------------------------------------------------
|
|
628
684
|
async _bind(stmt, variable, pos = 0) {
|
|
629
|
-
|
|
630
|
-
|
|
685
|
+
const bindInfoDict = stmt.bindInfoDict;
|
|
686
|
+
const bindInfoList = stmt.bindInfoList;
|
|
631
687
|
|
|
632
688
|
/*
|
|
633
689
|
* For PL/SQL blocks, if the size of a string or bytes object exceeds
|
|
@@ -650,8 +706,8 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
650
706
|
if (val === null) {
|
|
651
707
|
return null;
|
|
652
708
|
}
|
|
653
|
-
|
|
654
|
-
|
|
709
|
+
const data = await val.getData();
|
|
710
|
+
const len = val._length;
|
|
655
711
|
if (data && len > maxSize) {
|
|
656
712
|
errors.throwErr(errors.ERR_INSUFFICIENT_BUFFER_FOR_BINDS);
|
|
657
713
|
}
|
|
@@ -662,7 +718,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
662
718
|
if (variable.type === types.DB_TYPE_CLOB ||
|
|
663
719
|
variable.type === types.DB_TYPE_NCLOB ||
|
|
664
720
|
variable.type === types.DB_TYPE_BLOB) {
|
|
665
|
-
for (
|
|
721
|
+
for (const [index, val] of variable.values.entries()) {
|
|
666
722
|
if (!(val instanceof ThinLobImpl)) {
|
|
667
723
|
if (val && val.length > 0) {
|
|
668
724
|
const lobImpl = new ThinLobImpl();
|
|
@@ -693,7 +749,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
693
749
|
stmt._setVariable(bindInfo, variable);
|
|
694
750
|
});
|
|
695
751
|
} else {
|
|
696
|
-
|
|
752
|
+
const bindInfo = bindInfoList[pos - 1];
|
|
697
753
|
stmt._setVariable(bindInfo, variable);
|
|
698
754
|
}
|
|
699
755
|
}
|
|
@@ -739,7 +795,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
739
795
|
//---------------------------------------------------------------------------
|
|
740
796
|
// Clears the statement cache for the connection
|
|
741
797
|
//---------------------------------------------------------------------------
|
|
742
|
-
|
|
798
|
+
resetStatementCache() {
|
|
743
799
|
this.statementCache.clear();
|
|
744
800
|
this._cursorsToClose.clear();
|
|
745
801
|
}
|
|
@@ -761,9 +817,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
761
817
|
// information for a statment.
|
|
762
818
|
//---------------------------------------------------------------------------
|
|
763
819
|
async getStatementInfo(sql) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
820
|
+
const options = {};
|
|
821
|
+
const result = {};
|
|
822
|
+
const statement = await this._prepareAndBind(sql, null, options, true);
|
|
767
823
|
options.connection = this;
|
|
768
824
|
// parse the statement (but not for DDL which doesn't support it)
|
|
769
825
|
if (!statement.isDdl) {
|
|
@@ -1038,6 +1094,12 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1038
1094
|
return '';
|
|
1039
1095
|
}
|
|
1040
1096
|
|
|
1097
|
+
//---------------------------------------------------------------------------
|
|
1098
|
+
// Returns the Oracle Database instance name associated with the connection.
|
|
1099
|
+
//---------------------------------------------------------------------------
|
|
1100
|
+
getInstanceName() {
|
|
1101
|
+
return this.instanceName;
|
|
1102
|
+
}
|
|
1041
1103
|
}
|
|
1042
1104
|
|
|
1043
1105
|
module.exports = ThinConnectionImpl;
|
package/lib/thin/dbObject.js
CHANGED
|
@@ -362,10 +362,10 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
362
362
|
return buf.readBinaryInteger();
|
|
363
363
|
case types.DB_TYPE_VARCHAR:
|
|
364
364
|
case types.DB_TYPE_CHAR:
|
|
365
|
-
return buf.readStr(constants.
|
|
365
|
+
return buf.readStr(constants.CSFRM_IMPLICIT);
|
|
366
366
|
case types.DB_TYPE_NVARCHAR:
|
|
367
367
|
case types.DB_TYPE_NCHAR:
|
|
368
|
-
return buf.readStr(constants.
|
|
368
|
+
return buf.readStr(constants.CSFRM_NCHAR);
|
|
369
369
|
case types.DB_TYPE_RAW:
|
|
370
370
|
return Buffer.from(buf.readBytesWithLength());
|
|
371
371
|
case types.DB_TYPE_BINARY_DOUBLE:
|
package/lib/thin/lob.js
CHANGED
|
@@ -121,10 +121,10 @@ class ThinLobImpl extends LobImpl {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
getCsfrm() {
|
|
124
|
-
if (this.dbType._csfrm !== constants.
|
|
124
|
+
if (this.dbType._csfrm !== constants.CSFRM_NCHAR) {
|
|
125
125
|
if (this._locator[constants.TNS_LOB_LOC_OFFSET_FLAG_3] &
|
|
126
126
|
constants.TNS_LOB_LOC_FLAGS_VAR_LENGTH_CHARSET) {
|
|
127
|
-
return constants.
|
|
127
|
+
return constants.CSFRM_NCHAR;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
return this.dbType._csfrm;
|
package/lib/thin/pool.js
CHANGED
|
@@ -36,6 +36,7 @@ const thinUtil = require('./util.js');
|
|
|
36
36
|
const {getConnectionInfo} = require('./sqlnet/networkSession.js');
|
|
37
37
|
const crypto = require('crypto');
|
|
38
38
|
const EventEmitter = require('events');
|
|
39
|
+
const Timers = require('timers');
|
|
39
40
|
|
|
40
41
|
class ThinPoolImpl extends PoolImpl {
|
|
41
42
|
|
|
@@ -69,30 +70,33 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
69
70
|
this._privateKey = params.privateKey;
|
|
70
71
|
this._obfuscatedPrivateKey = [];
|
|
71
72
|
this._schedulerJob = null;
|
|
73
|
+
this._poolCloseWaiter = null;
|
|
74
|
+
this._pendingRequests = [];
|
|
75
|
+
|
|
72
76
|
// password obfuscation
|
|
73
77
|
if (this._password !== undefined) {
|
|
74
|
-
|
|
78
|
+
const obj = protocolUtil.setObfuscatedValue(this._password);
|
|
75
79
|
this._password = obj.value;
|
|
76
80
|
this._obfuscatedPassword = obj.obfuscatedValue;
|
|
77
81
|
this._userConfig.password = null;
|
|
78
82
|
}
|
|
79
83
|
// wallet password obfuscation
|
|
80
84
|
if (this._walletPassword !== undefined) {
|
|
81
|
-
|
|
85
|
+
const obj = protocolUtil.setObfuscatedValue(this._walletPassword);
|
|
82
86
|
this._walletPassword = obj.value;
|
|
83
87
|
this._obfuscatedWalletPassword = obj.obfuscatedValue;
|
|
84
88
|
this._userConfig.walletPassword = null;
|
|
85
89
|
}
|
|
86
90
|
// token obfuscation
|
|
87
91
|
if (this._token !== undefined) {
|
|
88
|
-
|
|
92
|
+
const obj = protocolUtil.setObfuscatedValue(this._token);
|
|
89
93
|
this._token = obj.value;
|
|
90
94
|
this._obfuscatedToken = obj.obfuscatedValue;
|
|
91
95
|
this._userConfig.token = null;
|
|
92
96
|
}
|
|
93
97
|
// privateKey obfuscation
|
|
94
98
|
if (this._privateKey !== undefined) {
|
|
95
|
-
|
|
99
|
+
const obj = protocolUtil.setObfuscatedValue(this._privateKey);
|
|
96
100
|
this._privateKey = obj.value;
|
|
97
101
|
this._obfuscatedPrivateKey = obj.obfuscatedValue;
|
|
98
102
|
this._userConfig.privateKey = null;
|
|
@@ -121,8 +125,9 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
121
125
|
this._generateConnectionClass();
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
// create minimum connections
|
|
125
|
-
|
|
128
|
+
// create a background task. It will create minimum connections in the pool
|
|
129
|
+
// and expand the pool as required.
|
|
130
|
+
this.bgThreadFunc();
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
//---------------------------------------------------------------------------
|
|
@@ -131,13 +136,13 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
131
136
|
setAccessToken(params) {
|
|
132
137
|
if (params.token) {
|
|
133
138
|
this._token = params.token;
|
|
134
|
-
|
|
139
|
+
const objToken = protocolUtil.setObfuscatedValue(this._token);
|
|
135
140
|
this._token = objToken.value;
|
|
136
141
|
this._obfuscatedToken = objToken.obfuscatedValue;
|
|
137
142
|
}
|
|
138
143
|
if (params.privateKey) {
|
|
139
144
|
this._privateKey = params.privateKey;
|
|
140
|
-
|
|
145
|
+
const objKey = protocolUtil.setObfuscatedValue(this._privateKey);
|
|
141
146
|
this._privateKey = objKey.value;
|
|
142
147
|
this._obfuscatedPrivateKey = objKey.obfuscatedValue;
|
|
143
148
|
}
|
|
@@ -151,15 +156,21 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
151
156
|
async _getConnAttrs() {
|
|
152
157
|
let accessToken;
|
|
153
158
|
const clonedAttrs = Object.assign({}, this._userConfig);
|
|
159
|
+
// deobfuscate password
|
|
154
160
|
if (clonedAttrs.password === null) {
|
|
155
161
|
clonedAttrs.password = protocolUtil.getDeobfuscatedValue(this._password,
|
|
156
162
|
this._obfuscatedPassword);
|
|
157
163
|
}
|
|
164
|
+
|
|
165
|
+
// deobfuscate wallet password
|
|
158
166
|
if (clonedAttrs.walletPassword === null) {
|
|
159
167
|
clonedAttrs.walletPassword =
|
|
160
168
|
protocolUtil.getDeobfuscatedValue(this._walletPassword,
|
|
161
169
|
this._obfuscatedWalletPassword);
|
|
162
170
|
}
|
|
171
|
+
|
|
172
|
+
// deobfuscate token and private key
|
|
173
|
+
// check for token expiry
|
|
163
174
|
if (clonedAttrs.token === null) {
|
|
164
175
|
clonedAttrs.token =
|
|
165
176
|
protocolUtil.getDeobfuscatedValue(this._token, this._obfuscatedToken);
|
|
@@ -173,7 +184,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
173
184
|
errors.throwErr(errors.ERR_TOKEN_HAS_EXPIRED);
|
|
174
185
|
} else {
|
|
175
186
|
// update pool with OAuth2 token
|
|
176
|
-
|
|
187
|
+
const obj = protocolUtil.setObfuscatedValue(clonedAttrs.token);
|
|
177
188
|
this._token = obj.value;
|
|
178
189
|
this._obfuscatedToken = obj.obfuscatedValue;
|
|
179
190
|
}
|
|
@@ -185,11 +196,11 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
185
196
|
errors.throwErr(errors.ERR_TOKEN_HAS_EXPIRED);
|
|
186
197
|
} else {
|
|
187
198
|
// update pool with IAM token and private key
|
|
188
|
-
|
|
199
|
+
const objToken = protocolUtil.setObfuscatedValue(clonedAttrs.token);
|
|
189
200
|
this._token = objToken.value;
|
|
190
201
|
this._obfuscatedToken = objToken.obfuscatedValue;
|
|
191
202
|
|
|
192
|
-
|
|
203
|
+
const objKey = protocolUtil.setObfuscatedValue(clonedAttrs.privateKey);
|
|
193
204
|
this._privateKey = objKey.value;
|
|
194
205
|
this._obfuscatedPrivateKey = objKey.obfuscatedValue;
|
|
195
206
|
}
|
|
@@ -212,9 +223,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
212
223
|
// create new connection and return it
|
|
213
224
|
//---------------------------------------------------------------------------
|
|
214
225
|
async getConnection() {
|
|
215
|
-
if (settings.connectionClass !== '') {
|
|
216
|
-
this._userConfig.connectionClass = settings.connectionClass;
|
|
217
|
-
}
|
|
218
226
|
return await this.acquire();
|
|
219
227
|
}
|
|
220
228
|
|
|
@@ -231,13 +239,34 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
231
239
|
//---------------------------------------------------------------------------
|
|
232
240
|
// close pool by destroying available connections
|
|
233
241
|
//---------------------------------------------------------------------------
|
|
234
|
-
async close(
|
|
242
|
+
async close() {
|
|
243
|
+
|
|
244
|
+
// wait till background task for pool expansion is finished; if it is not
|
|
245
|
+
// currently running, wake it up!
|
|
246
|
+
await new Promise((resolve) => {
|
|
247
|
+
this._poolCloseWaiter = resolve;
|
|
248
|
+
if (this.bgWaiter) {
|
|
249
|
+
this.bgWaiter();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
235
253
|
// clear scheduled job
|
|
236
254
|
if (this._schedulerJob) {
|
|
237
255
|
clearTimeout(this._schedulerJob);
|
|
238
256
|
this._schedulerJob = null;
|
|
239
257
|
}
|
|
240
|
-
|
|
258
|
+
|
|
259
|
+
// destroy all free connections
|
|
260
|
+
for (const conn of this._freeConnectionList) {
|
|
261
|
+
await this._destroy(conn);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// destroy all used connections
|
|
265
|
+
for (const conn of this._usedConnectionList) {
|
|
266
|
+
await this._destroy(conn);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.eventEmitter.removeAllListeners();
|
|
241
270
|
}
|
|
242
271
|
|
|
243
272
|
//---------------------------------------------------------------------------
|
|
@@ -310,25 +339,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
310
339
|
return this._stmtCacheSize;
|
|
311
340
|
}
|
|
312
341
|
|
|
313
|
-
//---------------------------------------------------------------------------
|
|
314
|
-
// _growPool()
|
|
315
|
-
//
|
|
316
|
-
// Grows the pool to include the specified number of connections.
|
|
317
|
-
//---------------------------------------------------------------------------
|
|
318
|
-
async _growPool(numConns) {
|
|
319
|
-
const clonedAttrs = await this._getConnAttrs();
|
|
320
|
-
while (numConns > 0) {
|
|
321
|
-
const conn = new ThinConnectionImpl();
|
|
322
|
-
conn._pool = this;
|
|
323
|
-
await conn.connect(clonedAttrs);
|
|
324
|
-
conn._newSession = true;
|
|
325
|
-
conn._dropSess = false;
|
|
326
|
-
conn._lastTimeUsed = Date.now();
|
|
327
|
-
this._freeConnectionList.push(conn);
|
|
328
|
-
numConns--;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
342
|
//---------------------------------------------------------------------------
|
|
333
343
|
// _setScheduler()
|
|
334
344
|
//
|
|
@@ -366,6 +376,94 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
366
376
|
this._setScheduler();
|
|
367
377
|
}
|
|
368
378
|
|
|
379
|
+
//---------------------------------------------------------------------------
|
|
380
|
+
// _getNumConns()
|
|
381
|
+
//
|
|
382
|
+
// get number of connections need to be created
|
|
383
|
+
//---------------------------------------------------------------------------
|
|
384
|
+
_getNumConns() {
|
|
385
|
+
const usedConns = this._freeConnectionList.length + this._usedConnectionList.size;
|
|
386
|
+
// less connections in the pool than poolMin? restore to poolMin
|
|
387
|
+
if (usedConns < this._poolMin) {
|
|
388
|
+
return this._poolMin - usedConns;
|
|
389
|
+
// connections need to be created? create up to poolIncrement without exceeding poolMax
|
|
390
|
+
} else if (this._pendingRequests.length > 0) {
|
|
391
|
+
return Math.min(this._poolIncrement, this._poolMax - usedConns);
|
|
392
|
+
// no pending requests and we are already at poolMin so nothing to do!
|
|
393
|
+
} else {
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
//---------------------------------------------------------------------------
|
|
399
|
+
// bgThreadFunc()
|
|
400
|
+
//
|
|
401
|
+
// method which runs in a background thread and is used to create connections.
|
|
402
|
+
// When first started, it creates poolMin connections. After that, it creates
|
|
403
|
+
// poolIncrement connections up to the value of poolMax when needed.
|
|
404
|
+
// The thread terminates automatically when the pool is closed.
|
|
405
|
+
//---------------------------------------------------------------------------
|
|
406
|
+
async bgThreadFunc() {
|
|
407
|
+
|
|
408
|
+
// continue until a close request is received
|
|
409
|
+
while (!this._poolCloseWaiter) {
|
|
410
|
+
// get count for connections to be created
|
|
411
|
+
const numConns = this._getNumConns();
|
|
412
|
+
|
|
413
|
+
// connection creation is going on serially and not concurrently
|
|
414
|
+
for (let i = 0; i < numConns; i++) {
|
|
415
|
+
try {
|
|
416
|
+
// get deobfuscated value
|
|
417
|
+
const config = await this._getConnAttrs();
|
|
418
|
+
const conn = new ThinConnectionImpl();
|
|
419
|
+
conn._pool = this;
|
|
420
|
+
await conn.connect(config);
|
|
421
|
+
conn._newSession = true;
|
|
422
|
+
conn._dropSess = false;
|
|
423
|
+
conn._lastTimeUsed = Date.now();
|
|
424
|
+
this._freeConnectionList.push(conn);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
this._bgErr = err;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (this._poolIncrement > 1 && (this._poolMax - this._usedConnectionList.size
|
|
430
|
+
- this._freeConnectionList.length) > 1) {
|
|
431
|
+
this._setScheduler();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// resolve pending request
|
|
435
|
+
if (this._pendingRequests.length > 0) {
|
|
436
|
+
const payload = this._pendingRequests.shift();
|
|
437
|
+
payload.resolve();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// give an opportunity for other "threads" to do their work.
|
|
441
|
+
await new Promise((resolve) => Timers.setImmediate(resolve));
|
|
442
|
+
|
|
443
|
+
// break loop when pool is closing
|
|
444
|
+
if (this._poolCloseWaiter) {
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// when pool is closing, break from while loop
|
|
450
|
+
if (this._poolCloseWaiter) {
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// if no pending requests, wait for pending requests to appear!
|
|
455
|
+
if (this._pendingRequests.length == 0 || this._bgErr) {
|
|
456
|
+
await new Promise((resolve) => {
|
|
457
|
+
this.bgWaiter = resolve;
|
|
458
|
+
});
|
|
459
|
+
this.bgWaiter = null;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// notify the closer that the close can actually take place
|
|
464
|
+
this._poolCloseWaiter();
|
|
465
|
+
}
|
|
466
|
+
|
|
369
467
|
//---------------------------------------------------------------------------
|
|
370
468
|
// acquire()
|
|
371
469
|
//
|
|
@@ -413,17 +511,28 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
413
511
|
|
|
414
512
|
// no free connections exist at this point; if less than poolMin
|
|
415
513
|
// connections exist, grow the pool to poolMin again; otherwise, increase
|
|
416
|
-
// the pool by poolIncrement up to poolMax
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
this._setScheduler();
|
|
514
|
+
// the pool by poolIncrement up to poolMax. We are deferring this
|
|
515
|
+
// to the background thread function!
|
|
516
|
+
await new Promise((resolve) => {
|
|
517
|
+
this._pendingRequests.push({resolve: resolve});
|
|
518
|
+
if (this.bgWaiter) {
|
|
519
|
+
// this wakes up the function to do some more work
|
|
520
|
+
this.bgWaiter();
|
|
424
521
|
}
|
|
425
|
-
}
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
if (this._bgErr) {
|
|
525
|
+
const err = this._bgErr;
|
|
526
|
+
this._bgErr = null;
|
|
426
527
|
|
|
528
|
+
// if an error has occurred in the background thread we clear it and then,
|
|
529
|
+
// if there are more pending requests we request the background thread
|
|
530
|
+
// function to try again.
|
|
531
|
+
if (this._pendingRequests.length > 0 && this.bgWaiter) {
|
|
532
|
+
this.bgWaiter();
|
|
533
|
+
}
|
|
534
|
+
throw err;
|
|
535
|
+
}
|
|
427
536
|
// return a connection from the ones that were just built
|
|
428
537
|
const conn = this._freeConnectionList.pop();
|
|
429
538
|
this._usedConnectionList.add(conn);
|
|
@@ -441,33 +550,6 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
441
550
|
this._setScheduler();
|
|
442
551
|
}
|
|
443
552
|
|
|
444
|
-
//---------------------------------------------------------------------------
|
|
445
|
-
// destroyAllNow()
|
|
446
|
-
//
|
|
447
|
-
// called during pool close operation and close any available connection
|
|
448
|
-
// available in connection pool
|
|
449
|
-
//---------------------------------------------------------------------------
|
|
450
|
-
async destroyAllNow(obj) {
|
|
451
|
-
let conn;
|
|
452
|
-
while (this._freeConnectionList.length !== 0) {
|
|
453
|
-
conn = this._freeConnectionList.pop();
|
|
454
|
-
await this._destroy(conn);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (obj.forceClose) {
|
|
458
|
-
for (const item of this._usedConnectionList) {
|
|
459
|
-
await this._destroy(item);
|
|
460
|
-
this._usedConnectionList.delete(item);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (this._usedConnectionList.size !== 0) {
|
|
465
|
-
errors.throwErr(errors.ERR_POOL_HAS_BUSY_CONNECTIONS);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
this.eventEmitter.removeAllListeners();
|
|
469
|
-
}
|
|
470
|
-
|
|
471
553
|
//---------------------------------------------------------------------------
|
|
472
554
|
// _generateConnectionClass()
|
|
473
555
|
//
|
|
@@ -92,13 +92,13 @@ class BaseBuffer {
|
|
|
92
92
|
return 0;
|
|
93
93
|
} else if (size & 0x80) {
|
|
94
94
|
if (!signed) {
|
|
95
|
-
errors.throwErr(errors.ERR_UNEXPECTED_NEGATIVE_INTEGER);
|
|
95
|
+
errors.throwErr(errors.ERR_UNEXPECTED_NEGATIVE_INTEGER, this.pos, this.packetNum);
|
|
96
96
|
}
|
|
97
97
|
isNegative = true;
|
|
98
98
|
size = size & 0x7f;
|
|
99
99
|
}
|
|
100
100
|
if (size > maxSize) {
|
|
101
|
-
errors.throwErr(errors.ERR_INTEGER_TOO_LARGE, size, maxSize);
|
|
101
|
+
errors.throwErr(errors.ERR_INTEGER_TOO_LARGE, size, maxSize, this.pos, this.packetNum);
|
|
102
102
|
}
|
|
103
103
|
if (skip) {
|
|
104
104
|
this.skipBytes(size);
|
|
@@ -465,7 +465,7 @@ class BaseBuffer {
|
|
|
465
465
|
if (!buf) {
|
|
466
466
|
return null;
|
|
467
467
|
}
|
|
468
|
-
if (csfrm === constants.
|
|
468
|
+
if (csfrm === constants.CSFRM_IMPLICIT)
|
|
469
469
|
return buf.toString();
|
|
470
470
|
|
|
471
471
|
// need a copy of the buffer since swap16() changes the buffer in place and
|
|
@@ -748,7 +748,7 @@ class BaseBuffer {
|
|
|
748
748
|
const ptr = this.reserveBytes(length);
|
|
749
749
|
if (type === types.DB_TYPE_DATE || type == types.DB_TYPE_TIMESTAMP) {
|
|
750
750
|
const year = date.getFullYear();
|
|
751
|
-
ptr[0] = Math.
|
|
751
|
+
ptr[0] = Math.trunc(year / 100) + 100;
|
|
752
752
|
ptr[1] = year % 100 + 100;
|
|
753
753
|
ptr[2] = date.getMonth() + 1;
|
|
754
754
|
ptr[3] = date.getDate();
|
|
@@ -757,7 +757,7 @@ class BaseBuffer {
|
|
|
757
757
|
ptr[6] = date.getSeconds() + 1;
|
|
758
758
|
} else {
|
|
759
759
|
const year = date.getUTCFullYear();
|
|
760
|
-
ptr[0] = Math.
|
|
760
|
+
ptr[0] = Math.trunc(year / 100) + 100;
|
|
761
761
|
ptr[1] = year % 100 + 100;
|
|
762
762
|
ptr[2] = date.getUTCMonth() + 1;
|
|
763
763
|
ptr[3] = date.getUTCDate();
|
|
@@ -847,7 +847,7 @@ class BaseBuffer {
|
|
|
847
847
|
buf[0] = numPairs + 1 + appendSentinel;
|
|
848
848
|
buf[1] = exponentOnWire;
|
|
849
849
|
for (let i = 0, pos = 2; i < value.length; i += 2, pos++) {
|
|
850
|
-
|
|
850
|
+
const base100Digit = Number(value.substring(i, i + 2));
|
|
851
851
|
if (isNegative) {
|
|
852
852
|
buf[pos] = 101 - base100Digit;
|
|
853
853
|
} else {
|
|
@@ -923,6 +923,24 @@ class BaseBuffer {
|
|
|
923
923
|
}
|
|
924
924
|
}
|
|
925
925
|
|
|
926
|
+
//---------------------------------------------------------------------------
|
|
927
|
+
// writeUB2()
|
|
928
|
+
//
|
|
929
|
+
// Writes an unsigned integer (up to 2 bytes in length) in variable length
|
|
930
|
+
// format to the buffer.
|
|
931
|
+
//---------------------------------------------------------------------------
|
|
932
|
+
writeUB2(value) {
|
|
933
|
+
if (value === 0) {
|
|
934
|
+
this.writeUInt8(0);
|
|
935
|
+
} else if (value <= 0xff) {
|
|
936
|
+
this.writeUInt8(1);
|
|
937
|
+
this.writeUInt8(value);
|
|
938
|
+
} else {
|
|
939
|
+
this.writeUInt8(2);
|
|
940
|
+
this.writeUInt16BE(value);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
926
944
|
//---------------------------------------------------------------------------
|
|
927
945
|
// writeUB8()
|
|
928
946
|
//
|