oracledb 5.5.0 → 6.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/CHANGELOG.md +1 -1875
- package/LICENSE.txt +8 -222
- package/NOTICE.txt +1 -1
- package/README.md +38 -30
- package/SECURITY.md +38 -0
- package/build/Release/oracledb-6.0.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.0.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.0.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.0.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.0.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.0.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/README.md +113 -0
- package/examples/dbconfig.js +100 -0
- package/examples/example.js +156 -0
- package/index.js +26 -0
- package/lib/aqDeqOptions.js +146 -7
- package/lib/aqEnqOptions.js +59 -7
- package/lib/aqMessage.js +118 -7
- package/lib/aqQueue.js +242 -53
- package/lib/connection.js +1324 -465
- package/lib/constants.js +203 -0
- package/lib/dbObject.js +346 -32
- package/lib/errors.js +781 -0
- package/lib/impl/aqDeqOptions.js +197 -0
- package/lib/impl/aqEnqOptions.js +89 -0
- package/lib/impl/aqMessage.js +134 -0
- package/lib/impl/aqQueue.js +81 -0
- package/lib/impl/connection.js +529 -0
- package/lib/impl/dbObject.js +159 -0
- package/lib/impl/index.js +59 -0
- package/lib/impl/lob.js +85 -0
- package/lib/impl/pool.js +195 -0
- package/lib/impl/resultset.js +223 -0
- package/lib/impl/sodaCollection.js +174 -0
- package/lib/impl/sodaDatabase.js +81 -0
- package/lib/impl/sodaDocCursor.js +63 -0
- package/lib/impl/sodaDocument.js +98 -0
- package/lib/impl/sodaOperation.js +109 -0
- package/lib/lob.js +156 -68
- package/lib/oracledb.js +1047 -345
- package/lib/pool.js +654 -465
- package/lib/poolStatistics.js +23 -9
- package/lib/queryStream.js +14 -7
- package/lib/resultset.js +291 -183
- package/lib/settings.js +191 -0
- package/lib/sodaCollection.js +214 -201
- package/lib/sodaDatabase.js +107 -71
- package/lib/sodaDocCursor.js +44 -32
- package/lib/sodaDocument.js +76 -14
- package/lib/sodaOperation.js +131 -118
- package/lib/thin/connection.js +1038 -0
- package/lib/thin/dbObject.js +629 -0
- package/lib/thin/index.js +40 -0
- package/lib/thin/lob.js +188 -0
- package/lib/thin/pool.js +481 -0
- package/lib/thin/protocol/buffer.js +1040 -0
- package/lib/thin/protocol/capabilities.js +116 -0
- package/lib/thin/protocol/constants.js +764 -0
- package/lib/thin/protocol/encryptDecrypt.js +185 -0
- package/lib/thin/protocol/messages/auth.js +348 -0
- package/lib/thin/protocol/messages/base.js +475 -0
- package/lib/thin/protocol/messages/commit.js +56 -0
- package/lib/thin/protocol/messages/dataType.js +382 -0
- package/lib/thin/protocol/messages/execute.js +312 -0
- package/lib/thin/protocol/messages/fetch.js +60 -0
- package/lib/thin/protocol/messages/index.js +53 -0
- package/lib/thin/protocol/messages/lobOp.js +200 -0
- package/lib/thin/protocol/messages/logOff.js +53 -0
- package/lib/thin/protocol/messages/ping.js +56 -0
- package/lib/thin/protocol/messages/protocol.js +78 -0
- package/lib/thin/protocol/messages/rollback.js +56 -0
- package/lib/thin/protocol/messages/sessionRelease.js +60 -0
- package/lib/thin/protocol/messages/withData.js +811 -0
- package/lib/thin/protocol/oson.js +660 -0
- package/lib/thin/protocol/packet.js +520 -0
- package/lib/thin/protocol/protocol.js +202 -0
- package/lib/thin/protocol/utils.js +88 -0
- package/lib/thin/resultSet.js +122 -0
- package/lib/thin/sqlnet/connStrategy.js +175 -0
- package/lib/thin/sqlnet/constants.js +199 -0
- package/lib/thin/sqlnet/ezConnectResolver.js +488 -0
- package/lib/thin/sqlnet/navNodes.js +870 -0
- package/lib/thin/sqlnet/networkSession.js +620 -0
- package/lib/thin/sqlnet/ntTcp.js +525 -0
- package/lib/thin/sqlnet/nvStrToNvPair.js +783 -0
- package/lib/thin/sqlnet/packet.js +405 -0
- package/lib/thin/sqlnet/paramParser.js +205 -0
- package/lib/thin/sqlnet/sessionAtts.js +160 -0
- package/lib/thin/statement.js +301 -0
- package/lib/thin/util.js +289 -0
- package/lib/transformer.js +250 -0
- package/lib/types.js +357 -0
- package/lib/util.js +194 -110
- package/lib/version.js +36 -0
- package/package/README.md +33 -30
- package/package/install.js +89 -64
- package/package/prunebinaries.js +60 -12
- package/package.json +3 -3
- package/build/Release/oracledb-5.5.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-5.5.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-5.5.0-linux-x64.node +0 -0
- package/build/Release/oracledb-5.5.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-5.5.0-win32-x64.node +0 -0
- package/build/Release/oracledb-5.5.0-win32-x64.node-buildinfo.txt +0 -1
package/lib/thin/lob.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
|
2
|
+
|
|
3
|
+
//-----------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// This software is dual-licensed to you under the Universal Permissive License
|
|
6
|
+
// (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
7
|
+
// 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
8
|
+
// either license.
|
|
9
|
+
//
|
|
10
|
+
// If you elect to accept the software under the Apache License, Version 2.0,
|
|
11
|
+
// the following applies:
|
|
12
|
+
//
|
|
13
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
// you may not use this file except in compliance with the License.
|
|
15
|
+
// You may obtain a copy of the License at
|
|
16
|
+
//
|
|
17
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
//
|
|
19
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
// See the License for the specific language governing permissions and
|
|
23
|
+
// limitations under the License.
|
|
24
|
+
//
|
|
25
|
+
//-----------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const LobImpl = require('../impl/lob.js');
|
|
30
|
+
const constants = require('./protocol/constants.js');
|
|
31
|
+
const LobOpMessage = require('./protocol/messages/lobOp.js');
|
|
32
|
+
const errors = require('../errors.js');
|
|
33
|
+
|
|
34
|
+
class ThinLobImpl extends LobImpl {
|
|
35
|
+
|
|
36
|
+
//---------------------------------------------------------------------------
|
|
37
|
+
// _getConnImpl()
|
|
38
|
+
//
|
|
39
|
+
// Common method on all classes that make use of a connection -- used to
|
|
40
|
+
// ensure serialization of all use of the connection.
|
|
41
|
+
//---------------------------------------------------------------------------
|
|
42
|
+
_getConnImpl() {
|
|
43
|
+
return this.conn;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//---------------------------------------------------------------------------
|
|
47
|
+
// _sendMessage()
|
|
48
|
+
//
|
|
49
|
+
// Sends a LOB operation message to the server and processes the response.
|
|
50
|
+
//---------------------------------------------------------------------------
|
|
51
|
+
async _sendMessage(options) {
|
|
52
|
+
const message = new LobOpMessage(this.conn, options);
|
|
53
|
+
await this.conn._protocol._processMessage(message);
|
|
54
|
+
if (options.operation === constants.TNS_LOB_OP_READ) {
|
|
55
|
+
return (message.data) ? message.data : null;
|
|
56
|
+
} else {
|
|
57
|
+
return message.amount;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getChunkSize() {
|
|
62
|
+
return this._chunkSize;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async _getChunkSizeAsync() {
|
|
66
|
+
this.checkConn();
|
|
67
|
+
const options = {
|
|
68
|
+
operation: constants.TNS_LOB_OP_GET_CHUNK_SIZE,
|
|
69
|
+
sourceLobImpl: this,
|
|
70
|
+
sendAmount: true
|
|
71
|
+
};
|
|
72
|
+
this._chunkSize = this._pieceSize = await this._sendMessage(options);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getLength() {
|
|
76
|
+
return this._length;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getPieceSize() {
|
|
80
|
+
return this._pieceSize;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
setPieceSize(value) {
|
|
84
|
+
this._pieceSize = value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getType() {
|
|
88
|
+
return this.dbType;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async getData() {
|
|
92
|
+
if (this._length < 0) {
|
|
93
|
+
errors.throwErr(errors.ERR_INVALID_LOB);
|
|
94
|
+
}
|
|
95
|
+
return await this.read(1, this._length);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async read(offset, length) {
|
|
99
|
+
this.checkConn();
|
|
100
|
+
const options = {
|
|
101
|
+
operation: constants.TNS_LOB_OP_READ,
|
|
102
|
+
sourceLobImpl: this,
|
|
103
|
+
sourceOffset: offset,
|
|
104
|
+
sendAmount: true,
|
|
105
|
+
amount: length || this._pieceSize
|
|
106
|
+
};
|
|
107
|
+
return await this._sendMessage(options);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async write(offset, data) {
|
|
111
|
+
this.checkConn();
|
|
112
|
+
const options = {
|
|
113
|
+
operation: constants.TNS_LOB_OP_WRITE,
|
|
114
|
+
sourceLobImpl: this,
|
|
115
|
+
sourceOffset: offset,
|
|
116
|
+
data: data
|
|
117
|
+
};
|
|
118
|
+
await this._sendMessage(options);
|
|
119
|
+
this._length += data.length;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getCsfrm() {
|
|
123
|
+
if (this.dbType._csfrm !== constants.TNS_CS_NCHAR) {
|
|
124
|
+
if (this._locator[constants.TNS_LOB_LOC_OFFSET_FLAG_3] &
|
|
125
|
+
constants.TNS_LOB_LOC_FLAGS_VAR_LENGTH_CHARSET) {
|
|
126
|
+
return constants.TNS_CS_NCHAR;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return this.dbType._csfrm;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Creates a temporary LOB.
|
|
134
|
+
*
|
|
135
|
+
* @param {object} conn Connection Impl object
|
|
136
|
+
* @param {number} dbType indicates BLOB/CLOB DB type
|
|
137
|
+
*/
|
|
138
|
+
async create(conn, dbType) {
|
|
139
|
+
this.dirtyLength = false;
|
|
140
|
+
this.conn = conn;
|
|
141
|
+
this.dbType = dbType;
|
|
142
|
+
this._locator = Buffer.alloc(40);
|
|
143
|
+
this._isTempLob = true;
|
|
144
|
+
this._length = 0;
|
|
145
|
+
const options = {
|
|
146
|
+
operation: constants.TNS_LOB_OP_CREATE_TEMP,
|
|
147
|
+
sourceLobImpl: this,
|
|
148
|
+
amount: constants.TNS_DURATION_SESSION,
|
|
149
|
+
destOffset: dbType._oraTypeNum,
|
|
150
|
+
sourceOffset: dbType._csfrm,
|
|
151
|
+
sendAmount: true
|
|
152
|
+
};
|
|
153
|
+
await this._sendMessage(options);
|
|
154
|
+
await this._getChunkSizeAsync();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
checkConn() {
|
|
158
|
+
if (!this.conn.nscon.connected)
|
|
159
|
+
errors.throwErr(errors.ERR_LOB_CLOSED);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
close() {
|
|
163
|
+
this.checkConn();
|
|
164
|
+
if (this._isTempLob) {
|
|
165
|
+
// Add to freelist which will be sent in piggyback fashion
|
|
166
|
+
this.conn._tempLobsToClose.push(this._locator);
|
|
167
|
+
this.conn._tempLobsTotalSize += this._locator.length;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
init(conn, locator, dbType, len, chunkSize) {
|
|
172
|
+
this.dirtyLength = false;
|
|
173
|
+
this.conn = conn;
|
|
174
|
+
this._locator = locator;
|
|
175
|
+
this._isTempLob = false;
|
|
176
|
+
if (this._locator[constants.TNS_LOB_LOC_OFFSET_FLAG_4] & constants.TNS_LOB_LOC_FLAGS_TEMP === constants.TNS_LOB_LOC_FLAGS_TEMP
|
|
177
|
+
|| this._locator[constants.TNS_LOB_LOC_OFFSET_FLAG_1] & constants.TNS_LOB_LOC_FLAGS_ABSTRACT === constants.TNS_LOB_LOC_FLAGS_ABSTRACT) {
|
|
178
|
+
this._isTempLob = true;
|
|
179
|
+
}
|
|
180
|
+
this.dbType = dbType;
|
|
181
|
+
this._length = len;
|
|
182
|
+
this._chunkSize = chunkSize;
|
|
183
|
+
this._pieceSize = chunkSize;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = ThinLobImpl;
|
package/lib/thin/pool.js
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
// Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
|
2
|
+
|
|
3
|
+
//-----------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// This software is dual-licensed to you under the Universal Permissive License
|
|
6
|
+
// (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
7
|
+
// 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
8
|
+
// either license.
|
|
9
|
+
//
|
|
10
|
+
// If you elect to accept the software under the Apache License, Version 2.0,
|
|
11
|
+
// the following applies:
|
|
12
|
+
//
|
|
13
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
// you may not use this file except in compliance with the License.
|
|
15
|
+
// You may obtain a copy of the License at
|
|
16
|
+
//
|
|
17
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
//
|
|
19
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
// See the License for the specific language governing permissions and
|
|
23
|
+
// limitations under the License.
|
|
24
|
+
//
|
|
25
|
+
//-----------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const PoolImpl = require('../impl/pool.js');
|
|
30
|
+
const ThinConnectionImpl = require('./connection.js');
|
|
31
|
+
const protocolUtil = require('./protocol/utils.js');
|
|
32
|
+
const errors = require('../errors.js');
|
|
33
|
+
const settings = require('../settings.js');
|
|
34
|
+
const util = require('../util.js');
|
|
35
|
+
const thinUtil = require('./util.js');
|
|
36
|
+
const {getConnectionInfo} = require('./sqlnet/networkSession.js');
|
|
37
|
+
const crypto = require('crypto');
|
|
38
|
+
const EventEmitter = require('events');
|
|
39
|
+
|
|
40
|
+
class ThinPoolImpl extends PoolImpl {
|
|
41
|
+
|
|
42
|
+
_init(params) {
|
|
43
|
+
if (!params.homogeneous) {
|
|
44
|
+
errors.throwErr(errors.ERR_NOT_IMPLEMENTED, 'Heterogeneous Pooling');
|
|
45
|
+
}
|
|
46
|
+
thinUtil.checkCredentials(params);
|
|
47
|
+
|
|
48
|
+
this._availableObjects = [];
|
|
49
|
+
this._name = 'node-thin';
|
|
50
|
+
this._poolMin = params.poolMin;
|
|
51
|
+
this._poolMax = params.poolMax;
|
|
52
|
+
this._poolIncrement = params.poolIncrement;
|
|
53
|
+
this._poolTimeout = params.poolTimeout;
|
|
54
|
+
this._poolPingInterval = params.poolPingInterval;
|
|
55
|
+
this._stmtCacheSize = params.stmtCacheSize;
|
|
56
|
+
|
|
57
|
+
// The user Config filterd from common layer is cached except
|
|
58
|
+
// sensitive data as sensitive data is obfuscated in the pool
|
|
59
|
+
// and de-obfuscated as necessary.
|
|
60
|
+
this._userConfig = params;
|
|
61
|
+
this._freeConnectionList = [];
|
|
62
|
+
this._usedConnectionList = new Set();
|
|
63
|
+
this._password = params.password;
|
|
64
|
+
this._walletPassword = params.walletPassword;
|
|
65
|
+
this._obfuscatedPassword = [];
|
|
66
|
+
this._obfuscatedWalletPassword = [];
|
|
67
|
+
this._token = params.token;
|
|
68
|
+
this._obfuscatedToken = [];
|
|
69
|
+
this._privateKey = params.privateKey;
|
|
70
|
+
this._obfuscatedPrivateKey = [];
|
|
71
|
+
this._schedulerJob = null;
|
|
72
|
+
// password obfuscation
|
|
73
|
+
if (this._password !== undefined) {
|
|
74
|
+
let obj = protocolUtil.setObfuscatedValue(this._password);
|
|
75
|
+
this._password = obj.value;
|
|
76
|
+
this._obfuscatedPassword = obj.obfuscatedValue;
|
|
77
|
+
this._userConfig.password = null;
|
|
78
|
+
}
|
|
79
|
+
// wallet password obfuscation
|
|
80
|
+
if (this._walletPassword !== undefined) {
|
|
81
|
+
let obj = protocolUtil.setObfuscatedValue(this._walletPassword);
|
|
82
|
+
this._walletPassword = obj.value;
|
|
83
|
+
this._obfuscatedWalletPassword = obj.obfuscatedValue;
|
|
84
|
+
this._userConfig.walletPassword = null;
|
|
85
|
+
}
|
|
86
|
+
// token obfuscation
|
|
87
|
+
if (this._token !== undefined) {
|
|
88
|
+
let obj = protocolUtil.setObfuscatedValue(this._token);
|
|
89
|
+
this._token = obj.value;
|
|
90
|
+
this._obfuscatedToken = obj.obfuscatedValue;
|
|
91
|
+
this._userConfig.token = null;
|
|
92
|
+
}
|
|
93
|
+
// privateKey obfuscation
|
|
94
|
+
if (this._privateKey !== undefined) {
|
|
95
|
+
let obj = protocolUtil.setObfuscatedValue(this._privateKey);
|
|
96
|
+
this._privateKey = obj.value;
|
|
97
|
+
this._obfuscatedPrivateKey = obj.obfuscatedValue;
|
|
98
|
+
this._userConfig.privateKey = null;
|
|
99
|
+
}
|
|
100
|
+
this._accessTokenFn = params.accessTokenFn;
|
|
101
|
+
this._isDRCPEnabled = false;
|
|
102
|
+
this.eventEmitter = new EventEmitter();
|
|
103
|
+
// listener to remove dead or idle connections
|
|
104
|
+
this.eventEmitter.on('_removePoolConnection', async (connImpl) => {
|
|
105
|
+
await this._destroy(connImpl);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
//---------------------------------------------------------------------------
|
|
110
|
+
// create pool with specified parameters and miminum number of connections as
|
|
111
|
+
// specified by poolMin
|
|
112
|
+
//---------------------------------------------------------------------------
|
|
113
|
+
async create(params) {
|
|
114
|
+
this._init(params);
|
|
115
|
+
this._userConfig._connInfo =
|
|
116
|
+
await getConnectionInfo(params);
|
|
117
|
+
this._isDRCPEnabled =
|
|
118
|
+
String(this._userConfig._connInfo[0]).toLowerCase() === 'pooled';
|
|
119
|
+
// generate connection class when none is provided by user
|
|
120
|
+
if (this._isDRCPEnabled && settings.connectionClass === '') {
|
|
121
|
+
this._generateConnectionClass();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// create minimum connections
|
|
125
|
+
await this._growPool(this._poolMin);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//---------------------------------------------------------------------------
|
|
129
|
+
// set new token and private key in pool
|
|
130
|
+
//---------------------------------------------------------------------------
|
|
131
|
+
setAccessToken(params) {
|
|
132
|
+
if (params.token) {
|
|
133
|
+
this._token = params.token;
|
|
134
|
+
let objToken = protocolUtil.setObfuscatedValue(this._token);
|
|
135
|
+
this._token = objToken.value;
|
|
136
|
+
this._obfuscatedToken = objToken.obfuscatedValue;
|
|
137
|
+
}
|
|
138
|
+
if (params.privateKey) {
|
|
139
|
+
this._privateKey = params.privateKey;
|
|
140
|
+
let objKey = protocolUtil.setObfuscatedValue(this._privateKey);
|
|
141
|
+
this._privateKey = objKey.value;
|
|
142
|
+
this._obfuscatedPrivateKey = objKey.obfuscatedValue;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//---------------------------------------------------------------------------
|
|
147
|
+
// get connection from pool
|
|
148
|
+
//---------------------------------------------------------------------------
|
|
149
|
+
async _connect(connAttrs) {
|
|
150
|
+
let accessToken;
|
|
151
|
+
const conn = new ThinConnectionImpl();
|
|
152
|
+
conn._pool = this;
|
|
153
|
+
let clonedAttrs = Object.assign({}, connAttrs);
|
|
154
|
+
if (clonedAttrs.password === null) {
|
|
155
|
+
clonedAttrs.password = protocolUtil.getDeobfuscatedValue(this._password,
|
|
156
|
+
this._obfuscatedPassword);
|
|
157
|
+
}
|
|
158
|
+
if (clonedAttrs.walletPassword === null) {
|
|
159
|
+
clonedAttrs.walletPassword =
|
|
160
|
+
protocolUtil.getDeobfuscatedValue(this._walletPassword,
|
|
161
|
+
this._obfuscatedWalletPassword);
|
|
162
|
+
}
|
|
163
|
+
if (clonedAttrs.token === null) {
|
|
164
|
+
clonedAttrs.token =
|
|
165
|
+
protocolUtil.getDeobfuscatedValue(this._token, this._obfuscatedToken);
|
|
166
|
+
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
167
|
+
if (typeof this._accessTokenFn === 'function') {
|
|
168
|
+
accessToken = await this._accessTokenFn(true);
|
|
169
|
+
if (typeof accessToken === 'string') {
|
|
170
|
+
clonedAttrs.token = accessToken;
|
|
171
|
+
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
172
|
+
// OAuth2 token is expired
|
|
173
|
+
errors.throwErr(errors.ERR_TOKEN_HAS_EXPIRED);
|
|
174
|
+
} else {
|
|
175
|
+
// update pool with OAuth2 token
|
|
176
|
+
let obj = protocolUtil.setObfuscatedValue(clonedAttrs.token);
|
|
177
|
+
this._token = obj.value;
|
|
178
|
+
this._obfuscatedToken = obj.obfuscatedValue;
|
|
179
|
+
}
|
|
180
|
+
} else if (typeof accessToken === 'object') {
|
|
181
|
+
clonedAttrs.token = accessToken.token;
|
|
182
|
+
clonedAttrs.privateKey = accessToken.privateKey;
|
|
183
|
+
if (util.isTokenExpired(clonedAttrs.token)) {
|
|
184
|
+
// IAM token is expired
|
|
185
|
+
errors.throwErr(errors.ERR_TOKEN_HAS_EXPIRED);
|
|
186
|
+
} else {
|
|
187
|
+
// update pool with IAM token and private key
|
|
188
|
+
let objToken = protocolUtil.setObfuscatedValue(clonedAttrs.token);
|
|
189
|
+
this._token = objToken.value;
|
|
190
|
+
this._obfuscatedToken = objToken.obfuscatedValue;
|
|
191
|
+
|
|
192
|
+
let objKey = protocolUtil.setObfuscatedValue(clonedAttrs.privateKey);
|
|
193
|
+
this._privateKey = objKey.value;
|
|
194
|
+
this._obfuscatedPrivateKey = objKey.obfuscatedValue;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
errors.throwErr(errors.ERR_TOKEN_HAS_EXPIRED);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (clonedAttrs.privateKey === null) {
|
|
203
|
+
clonedAttrs.privateKey =
|
|
204
|
+
protocolUtil.getDeobfuscatedValue(this._privateKey,
|
|
205
|
+
this._obfuscatedPrivateKey);
|
|
206
|
+
}
|
|
207
|
+
await conn.connect(clonedAttrs);
|
|
208
|
+
clonedAttrs = null;
|
|
209
|
+
return conn;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
//---------------------------------------------------------------------------
|
|
213
|
+
// return available connection if present in pool else
|
|
214
|
+
// create new connection and return it
|
|
215
|
+
//---------------------------------------------------------------------------
|
|
216
|
+
async getConnection() {
|
|
217
|
+
if (settings.connectionClass !== '') {
|
|
218
|
+
this._userConfig.connectionClass = settings.connectionClass;
|
|
219
|
+
}
|
|
220
|
+
return await this.acquire();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
//---------------------------------------------------------------------------
|
|
224
|
+
// destroy connection when pool close operation is called
|
|
225
|
+
//---------------------------------------------------------------------------
|
|
226
|
+
async _destroy(connection) {
|
|
227
|
+
if (connection.nscon.ntAdapter.connected) {
|
|
228
|
+
connection._dropSess = true;
|
|
229
|
+
await connection.close();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
//---------------------------------------------------------------------------
|
|
234
|
+
// close pool by destroying available connections
|
|
235
|
+
//---------------------------------------------------------------------------
|
|
236
|
+
async close(obj) {
|
|
237
|
+
// clear scheduled job
|
|
238
|
+
if (this._schedulerJob) {
|
|
239
|
+
clearTimeout(this._schedulerJob);
|
|
240
|
+
this._schedulerJob = null;
|
|
241
|
+
}
|
|
242
|
+
return await this.destroyAllNow(obj);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
//---------------------------------------------------------------------------
|
|
246
|
+
// returns poolMax from configuration
|
|
247
|
+
//---------------------------------------------------------------------------
|
|
248
|
+
getPoolMax() {
|
|
249
|
+
return this._poolMax;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
//---------------------------------------------------------------------------
|
|
253
|
+
// returns poolMin from configuration
|
|
254
|
+
//---------------------------------------------------------------------------
|
|
255
|
+
getPoolMin() {
|
|
256
|
+
return this._poolMin;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
//---------------------------------------------------------------------------
|
|
260
|
+
// get number of used connection
|
|
261
|
+
//---------------------------------------------------------------------------
|
|
262
|
+
getConnectionsInUse() {
|
|
263
|
+
return this._usedConnectionList.size;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
//---------------------------------------------------------------------------
|
|
267
|
+
// get number of free connection
|
|
268
|
+
//---------------------------------------------------------------------------
|
|
269
|
+
getConnectionsOpen() {
|
|
270
|
+
return this._freeConnectionList.length + this._usedConnectionList.size;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
//---------------------------------------------------------------------------
|
|
274
|
+
// returns poolIncrement from configuration
|
|
275
|
+
//---------------------------------------------------------------------------
|
|
276
|
+
getPoolIncrement() {
|
|
277
|
+
return this._poolIncrement;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//---------------------------------------------------------------------------
|
|
281
|
+
// returns maximum number of connections allowed per shard in the pool
|
|
282
|
+
//---------------------------------------------------------------------------
|
|
283
|
+
getPoolMaxPerShard() {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
//---------------------------------------------------------------------------
|
|
288
|
+
// returns the pool ping interval (seconds)
|
|
289
|
+
//---------------------------------------------------------------------------
|
|
290
|
+
getPoolPingInterval() {
|
|
291
|
+
return this._poolPingInterval;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
//---------------------------------------------------------------------------
|
|
295
|
+
// returns the pool timeout
|
|
296
|
+
//---------------------------------------------------------------------------
|
|
297
|
+
getPoolTimeout() {
|
|
298
|
+
return this._poolTimeout;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
//---------------------------------------------------------------------------
|
|
302
|
+
// returns whether the SODA metadata cache is enabled or not
|
|
303
|
+
//---------------------------------------------------------------------------
|
|
304
|
+
getSodaMetaDataCache() {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
//---------------------------------------------------------------------------
|
|
309
|
+
// returns the statement cache size associate with the pool
|
|
310
|
+
//---------------------------------------------------------------------------
|
|
311
|
+
getStmtCacheSize() {
|
|
312
|
+
return this._stmtCacheSize;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
//---------------------------------------------------------------------------
|
|
316
|
+
// _growPool()
|
|
317
|
+
//
|
|
318
|
+
// Grows the pool to include the specified number of connections.
|
|
319
|
+
//---------------------------------------------------------------------------
|
|
320
|
+
async _growPool(numConns) {
|
|
321
|
+
while (numConns > 0) {
|
|
322
|
+
let conn = await this._connect(this._userConfig);
|
|
323
|
+
conn._newSession = true;
|
|
324
|
+
conn._dropSess = false;
|
|
325
|
+
conn._lastTimeUsed = Date.now();
|
|
326
|
+
this._freeConnectionList.push(conn);
|
|
327
|
+
numConns--;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
//---------------------------------------------------------------------------
|
|
332
|
+
// _setScheduler()
|
|
333
|
+
//
|
|
334
|
+
// set scheduler to scan and remove idle connections
|
|
335
|
+
//---------------------------------------------------------------------------
|
|
336
|
+
_setScheduler() {
|
|
337
|
+
if (!this._schedulerJob && this._poolTimeout > 0 &&
|
|
338
|
+
this._freeConnectionList.length > 0 &&
|
|
339
|
+
(this._freeConnectionList.length + this._usedConnectionList.size >
|
|
340
|
+
this._poolMin)) {
|
|
341
|
+
this._schedulerJob = setTimeout(() => {
|
|
342
|
+
this._scanIdleConnection();
|
|
343
|
+
}, this._poolTimeout * 1000);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
//---------------------------------------------------------------------------
|
|
348
|
+
// scanIdleConnection()
|
|
349
|
+
//
|
|
350
|
+
// scan connection list and removes idle connections from pool
|
|
351
|
+
//---------------------------------------------------------------------------
|
|
352
|
+
_scanIdleConnection() {
|
|
353
|
+
while ((this._usedConnectionList.size + this._freeConnectionList.length) >
|
|
354
|
+
this._poolMin && this._freeConnectionList.length > 0) {
|
|
355
|
+
const conn = this._freeConnectionList[this._freeConnectionList.length - 1];
|
|
356
|
+
if (Date.now() - conn._lastTimeUsed < this._poolTimeout * 1000) {
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
this.eventEmitter.emit('_removePoolConnection', conn);
|
|
361
|
+
this._freeConnectionList.pop();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
this._schedulerJob = null;
|
|
365
|
+
this._setScheduler();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
//---------------------------------------------------------------------------
|
|
369
|
+
// acquire()
|
|
370
|
+
//
|
|
371
|
+
// acquire a connection from connection pool
|
|
372
|
+
//---------------------------------------------------------------------------
|
|
373
|
+
async acquire() {
|
|
374
|
+
|
|
375
|
+
// return first connection from the free list that passes health checks
|
|
376
|
+
while (this._freeConnectionList.length > 0) {
|
|
377
|
+
const conn = this._freeConnectionList.pop();
|
|
378
|
+
|
|
379
|
+
// if connection is unhealthy, drop it from the pool
|
|
380
|
+
if (!conn.isHealthy()) {
|
|
381
|
+
this.eventEmitter.emit('_removePoolConnection', conn);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// perform a ping, if necessary; a ping interval less than 0 disables
|
|
386
|
+
// pings; a ping interval of 0 forces a ping for each use of the
|
|
387
|
+
// connection and a value greater than 0 will be performed if the
|
|
388
|
+
// connection has not been used for that period of time; if the ping is
|
|
389
|
+
// unsuccessful, drop the connection from the pool
|
|
390
|
+
let requiresPing = false;
|
|
391
|
+
if (this._poolPingInterval === 0) {
|
|
392
|
+
requiresPing = true;
|
|
393
|
+
} else if (this._poolPingInterval > 0) {
|
|
394
|
+
const elapsed = Date.now() - conn._lastTimeUsed;
|
|
395
|
+
if (elapsed > this._poolPingInterval * 1000)
|
|
396
|
+
requiresPing = true;
|
|
397
|
+
}
|
|
398
|
+
if (requiresPing) {
|
|
399
|
+
try {
|
|
400
|
+
await conn.ping();
|
|
401
|
+
} catch {
|
|
402
|
+
this.eventEmitter.emit('_removePoolConnection', conn);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// connection has passed health checks, return it immediately
|
|
408
|
+
this._usedConnectionList.add(conn);
|
|
409
|
+
return conn;
|
|
410
|
+
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// no free connections exist at this point; if less than poolMin
|
|
414
|
+
// connections exist, grow the pool to poolMin again; otherwise, increase
|
|
415
|
+
// the pool by poolIncrement up to poolMax
|
|
416
|
+
if (this._usedConnectionList.size < this._poolMin) {
|
|
417
|
+
await this._growPool(this._poolMin - this._usedConnectionList.size);
|
|
418
|
+
} else {
|
|
419
|
+
const sizeAvailable = this._poolMax - this._usedConnectionList.size;
|
|
420
|
+
await this._growPool(Math.min(this._poolIncrement, sizeAvailable));
|
|
421
|
+
if (this._poolIncrement > 1 && sizeAvailable > 1) {
|
|
422
|
+
this._setScheduler();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// return a connection from the ones that were just built
|
|
427
|
+
const conn = this._freeConnectionList.pop();
|
|
428
|
+
this._usedConnectionList.add(conn);
|
|
429
|
+
return conn;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// release connection to connection pool
|
|
433
|
+
release(conn) {
|
|
434
|
+
this._usedConnectionList.delete(conn);
|
|
435
|
+
if (conn.nscon.connected) {
|
|
436
|
+
conn._lastTimeUsed = Date.now();
|
|
437
|
+
conn._newSession = false;
|
|
438
|
+
this._freeConnectionList.push(conn);
|
|
439
|
+
}
|
|
440
|
+
this._setScheduler();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
//---------------------------------------------------------------------------
|
|
444
|
+
// destroyAllNow()
|
|
445
|
+
//
|
|
446
|
+
// called during pool close operation and close any available connection
|
|
447
|
+
// available in connection pool
|
|
448
|
+
//---------------------------------------------------------------------------
|
|
449
|
+
async destroyAllNow(obj) {
|
|
450
|
+
let conn;
|
|
451
|
+
while (this._freeConnectionList.length !== 0) {
|
|
452
|
+
conn = this._freeConnectionList.pop();
|
|
453
|
+
await this._destroy(conn);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (obj.forceClose) {
|
|
457
|
+
for (const item of this._usedConnectionList) {
|
|
458
|
+
await this._destroy(item);
|
|
459
|
+
this._usedConnectionList.delete(item);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (this._usedConnectionList.size !== 0) {
|
|
464
|
+
errors.throwErr(errors.ERR_POOL_HAS_BUSY_CONNECTIONS);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
this.eventEmitter.removeAllListeners();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
//---------------------------------------------------------------------------
|
|
471
|
+
// _generateConnectionClass()
|
|
472
|
+
//
|
|
473
|
+
// generate connection class for drcp if none is provided by user
|
|
474
|
+
//---------------------------------------------------------------------------
|
|
475
|
+
_generateConnectionClass() {
|
|
476
|
+
this._userConfig.connectionClass = crypto.randomBytes(16).toString('base64');
|
|
477
|
+
this._userConfig.connectionClass = "NJS:" + this._userConfig.connectionClass;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
module.exports = ThinPoolImpl;
|