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.
Files changed (107) hide show
  1. package/CHANGELOG.md +1 -1875
  2. package/LICENSE.txt +8 -222
  3. package/NOTICE.txt +1 -1
  4. package/README.md +38 -30
  5. package/SECURITY.md +38 -0
  6. package/build/Release/oracledb-6.0.0-darwin-x64.node +0 -0
  7. package/build/Release/oracledb-6.0.0-darwin-x64.node-buildinfo.txt +1 -0
  8. package/build/Release/oracledb-6.0.0-js-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.0.0-linux-arm64.node +0 -0
  10. package/build/Release/oracledb-6.0.0-linux-arm64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.0.0-linux-x64.node +0 -0
  12. package/build/Release/oracledb-6.0.0-linux-x64.node-buildinfo.txt +1 -0
  13. package/build/Release/oracledb-6.0.0-win32-x64.node +0 -0
  14. package/build/Release/oracledb-6.0.0-win32-x64.node-buildinfo.txt +1 -0
  15. package/examples/README.md +113 -0
  16. package/examples/dbconfig.js +100 -0
  17. package/examples/example.js +156 -0
  18. package/index.js +26 -0
  19. package/lib/aqDeqOptions.js +146 -7
  20. package/lib/aqEnqOptions.js +59 -7
  21. package/lib/aqMessage.js +118 -7
  22. package/lib/aqQueue.js +242 -53
  23. package/lib/connection.js +1324 -465
  24. package/lib/constants.js +203 -0
  25. package/lib/dbObject.js +346 -32
  26. package/lib/errors.js +781 -0
  27. package/lib/impl/aqDeqOptions.js +197 -0
  28. package/lib/impl/aqEnqOptions.js +89 -0
  29. package/lib/impl/aqMessage.js +134 -0
  30. package/lib/impl/aqQueue.js +81 -0
  31. package/lib/impl/connection.js +529 -0
  32. package/lib/impl/dbObject.js +159 -0
  33. package/lib/impl/index.js +59 -0
  34. package/lib/impl/lob.js +85 -0
  35. package/lib/impl/pool.js +195 -0
  36. package/lib/impl/resultset.js +223 -0
  37. package/lib/impl/sodaCollection.js +174 -0
  38. package/lib/impl/sodaDatabase.js +81 -0
  39. package/lib/impl/sodaDocCursor.js +63 -0
  40. package/lib/impl/sodaDocument.js +98 -0
  41. package/lib/impl/sodaOperation.js +109 -0
  42. package/lib/lob.js +156 -68
  43. package/lib/oracledb.js +1047 -345
  44. package/lib/pool.js +654 -465
  45. package/lib/poolStatistics.js +23 -9
  46. package/lib/queryStream.js +14 -7
  47. package/lib/resultset.js +291 -183
  48. package/lib/settings.js +191 -0
  49. package/lib/sodaCollection.js +214 -201
  50. package/lib/sodaDatabase.js +107 -71
  51. package/lib/sodaDocCursor.js +44 -32
  52. package/lib/sodaDocument.js +76 -14
  53. package/lib/sodaOperation.js +131 -118
  54. package/lib/thin/connection.js +1038 -0
  55. package/lib/thin/dbObject.js +629 -0
  56. package/lib/thin/index.js +40 -0
  57. package/lib/thin/lob.js +188 -0
  58. package/lib/thin/pool.js +481 -0
  59. package/lib/thin/protocol/buffer.js +1040 -0
  60. package/lib/thin/protocol/capabilities.js +116 -0
  61. package/lib/thin/protocol/constants.js +764 -0
  62. package/lib/thin/protocol/encryptDecrypt.js +185 -0
  63. package/lib/thin/protocol/messages/auth.js +348 -0
  64. package/lib/thin/protocol/messages/base.js +475 -0
  65. package/lib/thin/protocol/messages/commit.js +56 -0
  66. package/lib/thin/protocol/messages/dataType.js +382 -0
  67. package/lib/thin/protocol/messages/execute.js +312 -0
  68. package/lib/thin/protocol/messages/fetch.js +60 -0
  69. package/lib/thin/protocol/messages/index.js +53 -0
  70. package/lib/thin/protocol/messages/lobOp.js +200 -0
  71. package/lib/thin/protocol/messages/logOff.js +53 -0
  72. package/lib/thin/protocol/messages/ping.js +56 -0
  73. package/lib/thin/protocol/messages/protocol.js +78 -0
  74. package/lib/thin/protocol/messages/rollback.js +56 -0
  75. package/lib/thin/protocol/messages/sessionRelease.js +60 -0
  76. package/lib/thin/protocol/messages/withData.js +811 -0
  77. package/lib/thin/protocol/oson.js +660 -0
  78. package/lib/thin/protocol/packet.js +520 -0
  79. package/lib/thin/protocol/protocol.js +202 -0
  80. package/lib/thin/protocol/utils.js +88 -0
  81. package/lib/thin/resultSet.js +122 -0
  82. package/lib/thin/sqlnet/connStrategy.js +175 -0
  83. package/lib/thin/sqlnet/constants.js +199 -0
  84. package/lib/thin/sqlnet/ezConnectResolver.js +488 -0
  85. package/lib/thin/sqlnet/navNodes.js +870 -0
  86. package/lib/thin/sqlnet/networkSession.js +620 -0
  87. package/lib/thin/sqlnet/ntTcp.js +525 -0
  88. package/lib/thin/sqlnet/nvStrToNvPair.js +783 -0
  89. package/lib/thin/sqlnet/packet.js +405 -0
  90. package/lib/thin/sqlnet/paramParser.js +205 -0
  91. package/lib/thin/sqlnet/sessionAtts.js +160 -0
  92. package/lib/thin/statement.js +301 -0
  93. package/lib/thin/util.js +289 -0
  94. package/lib/transformer.js +250 -0
  95. package/lib/types.js +357 -0
  96. package/lib/util.js +194 -110
  97. package/lib/version.js +36 -0
  98. package/package/README.md +33 -30
  99. package/package/install.js +89 -64
  100. package/package/prunebinaries.js +60 -12
  101. package/package.json +3 -3
  102. package/build/Release/oracledb-5.5.0-darwin-x64.node +0 -0
  103. package/build/Release/oracledb-5.5.0-darwin-x64.node-buildinfo.txt +0 -1
  104. package/build/Release/oracledb-5.5.0-linux-x64.node +0 -0
  105. package/build/Release/oracledb-5.5.0-linux-x64.node-buildinfo.txt +0 -1
  106. package/build/Release/oracledb-5.5.0-win32-x64.node +0 -0
  107. package/build/Release/oracledb-5.5.0-win32-x64.node-buildinfo.txt +0 -1
@@ -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;
@@ -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;