oracledb 7.0.1 → 26.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/README.md +16 -6
- package/build/Release/oracledb-26.0.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-26.0.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-26.0.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-26.0.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-26.0.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-26.0.0-linux-x64.node +0 -0
- package/build/Release/oracledb-26.0.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-26.0.0-win32-x64.node +0 -0
- package/build/Release/oracledb-26.0.0-win32-x64.node-buildinfo.txt +1 -0
- package/lib/connection.js +71 -8
- package/lib/constants.js +4 -0
- package/lib/endUserSecurityContext.js +20 -8
- package/lib/errors.js +70 -5
- package/lib/impl/connection.js +36 -0
- package/lib/impl/datahandlers/buffer.js +91 -18
- package/lib/impl/datahandlers/oson.js +3 -2
- package/lib/impl/resultset.js +32 -11
- package/lib/oracledb.js +34 -0
- package/lib/pool.js +6 -2
- package/lib/queryStream.js +13 -5
- package/lib/resultset.js +10 -3
- package/lib/securityContextProvider.js +206 -0
- package/lib/thin/aq.js +2 -3
- package/lib/thin/connection.js +381 -19
- package/lib/thin/dbObject.js +17 -8
- package/lib/thin/pool.js +3 -2
- package/lib/thin/protocol/capabilities.js +37 -4
- package/lib/thin/protocol/constants.js +49 -1
- package/lib/thin/protocol/messages/auth.js +17 -6
- package/lib/thin/protocol/messages/base.js +74 -16
- package/lib/thin/protocol/messages/dataType.js +46 -0
- package/lib/thin/protocol/messages/directPathLoadStream.js +3 -2
- package/lib/thin/protocol/messages/execute.js +10 -4
- package/lib/thin/protocol/messages/index.js +4 -0
- package/lib/thin/protocol/messages/notification.js +281 -0
- package/lib/thin/protocol/messages/subscribe.js +181 -0
- package/lib/thin/protocol/messages/withData.js +21 -7
- package/lib/thin/protocol/packet.js +2 -4
- package/lib/thin/protocol/protocol.js +7 -4
- package/lib/thin/resultSet.js +40 -20
- package/lib/thin/sqlnet/ezConnectResolver.js +7 -0
- package/lib/thin/sqlnet/navNodes.js +3 -3
- package/lib/thin/sqlnet/ntTcp.js +24 -8
- package/lib/thin/statement.js +6 -1
- package/lib/thin/statementCache.js +34 -6
- package/lib/thin/subscr.js +363 -0
- package/lib/transformer.js +60 -17
- package/lib/util.js +46 -8
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/plugins/configProviders/gcpstorage/index.js +121 -0
- package/plugins/configProviders/ociobject/index.js +1 -1
- package/plugins/token/cache.js +154 -0
- package/plugins/token/endUserSecurityProvider/index.js +377 -0
- package/plugins/token/extensionAzure/index.js +160 -28
- package/plugins/token/extensionOci/index.js +221 -16
- package/plugins/vectorsdk/OracleVecDB.js +346 -0
- package/plugins/vectorsdk/index.js +49 -0
- package/plugins/vectorsdk/utils.js +370 -0
- package/plugins/vectorsdk/vectorEmbedding.js +223 -0
- package/plugins/vectorsdk/vectorIndex.js +177 -0
- package/plugins/vectorsdk/vectorRecords.js +406 -0
- package/plugins/vectorsdk/vectorSchema.js +408 -0
- package/plugins/vectorsdk/vectorSearch.js +538 -0
- package/build/Release/oracledb-7.0.1-darwin-arm64.node +0 -0
- package/build/Release/oracledb-7.0.1-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-7.0.1-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-7.0.1-linux-arm64.node +0 -0
- package/build/Release/oracledb-7.0.1-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-7.0.1-linux-x64.node +0 -0
- package/build/Release/oracledb-7.0.1-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-7.0.1-win32-x64.node +0 -0
- package/build/Release/oracledb-7.0.1-win32-x64.node-buildinfo.txt +0 -1
package/lib/thin/connection.js
CHANGED
|
@@ -39,10 +39,20 @@ const sqlNetConstants = require('./sqlnet/constants.js');
|
|
|
39
39
|
const constants = require('./protocol/constants.js');
|
|
40
40
|
const process = require('process');
|
|
41
41
|
const types = require('../types.js');
|
|
42
|
+
const pubConstants = require('../constants.js');
|
|
42
43
|
const errors = require("../errors.js");
|
|
43
44
|
const messages = require('./protocol/messages');
|
|
44
45
|
const StatementCache = require('./statementCache.js');
|
|
46
|
+
const ThinSubscrImpl = require('./subscr.js');
|
|
45
47
|
const { ThinQueueImpl } = require('./aq.js');
|
|
48
|
+
const parserHelpers = require('../impl/parserHelpers.js');
|
|
49
|
+
const { createNVPair, findNVPair } = require('./sqlnet/nvStrToNvPair.js');
|
|
50
|
+
const { ObfuscatedValue } = require('../obfuscation.js');
|
|
51
|
+
|
|
52
|
+
// Oracle can return a named UTC alias instead of the equivalent fixed offset
|
|
53
|
+
// +00:00. These aliases have no offset changes, so Thin can safely treat them
|
|
54
|
+
// as a zero fixed offset after the DBTIMEZONE fallback query identifies one.
|
|
55
|
+
const UTC_DB_TIME_ZONE_NAMES = new Set(['UTC', 'GMT', 'UNIVERSAL', 'ZULU']);
|
|
46
56
|
|
|
47
57
|
const finalizationRegistry = new global.FinalizationRegistry((heldValue) => {
|
|
48
58
|
heldValue.disconnect();
|
|
@@ -84,6 +94,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
84
94
|
async close() {
|
|
85
95
|
try {
|
|
86
96
|
this.clearEndUserSecurityContext();
|
|
97
|
+
this._clearDatabaseOpenTelemetryTracing();
|
|
87
98
|
if (this._protocol.txnInProgress) {
|
|
88
99
|
if (this.tpcContext) {
|
|
89
100
|
const message = this.createTpcRollbackMessage();
|
|
@@ -246,7 +257,9 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
246
257
|
if (statement.isPlSql && (statement.cursorId === 0 ||
|
|
247
258
|
statement.requiresFullExecute)) {
|
|
248
259
|
message.numExecs = 1;
|
|
249
|
-
|
|
260
|
+
// Suppress release only when another iteration follows.
|
|
261
|
+
message.noImplicitRelease = numIters > 1;
|
|
262
|
+
|
|
250
263
|
await this._protocol._processMessage(message);
|
|
251
264
|
statement.requiresFullExecute = false;
|
|
252
265
|
message.numExecs = numIters - 1;
|
|
@@ -286,7 +299,6 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
286
299
|
if (statement.isPlSql && (statement.cursorId === 0 ||
|
|
287
300
|
statement.requiresFullExecute)) {
|
|
288
301
|
message.numExecs = 1;
|
|
289
|
-
message.noImplicitRelease = true;
|
|
290
302
|
await this._protocol._encodeMessage(message);
|
|
291
303
|
message.requiresSingleExecute = true;
|
|
292
304
|
} else if (message.numExecs > 0) {
|
|
@@ -637,13 +649,19 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
637
649
|
case constants.TNS_OBJ_TDS_TYPE_DATE:
|
|
638
650
|
return types.DB_TYPE_DATE;
|
|
639
651
|
case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP:
|
|
640
|
-
buf.
|
|
652
|
+
metaData.scale = buf.readInt8();
|
|
653
|
+
if (metaData.scale !== null && metaData.scale !== undefined)
|
|
654
|
+
metaData.precision = 0;
|
|
641
655
|
return types.DB_TYPE_TIMESTAMP;
|
|
642
656
|
case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP_LTZ:
|
|
643
|
-
buf.
|
|
657
|
+
metaData.scale = buf.readInt8();
|
|
658
|
+
if (metaData.scale !== null && metaData.scale !== undefined)
|
|
659
|
+
metaData.precision = 0;
|
|
644
660
|
return types.DB_TYPE_TIMESTAMP_LTZ;
|
|
645
661
|
case constants.TNS_OBJ_TDS_TYPE_TIMESTAMP_TZ:
|
|
646
|
-
buf.
|
|
662
|
+
metaData.scale = buf.readInt8();
|
|
663
|
+
if (metaData.scale !== null && metaData.scale !== undefined)
|
|
664
|
+
metaData.precision = 0;
|
|
647
665
|
return types.DB_TYPE_TIMESTAMP_TZ;
|
|
648
666
|
case constants.TNS_OBJ_TDS_TYPE_BOOLEAN:
|
|
649
667
|
return types.DB_TYPE_BOOLEAN;
|
|
@@ -750,8 +768,10 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
750
768
|
case
|
|
751
769
|
when data_precision is null and data_scale is null
|
|
752
770
|
then 0
|
|
753
|
-
when data_precision is null
|
|
771
|
+
when data_precision is null and data_type = 'NUMBER'
|
|
754
772
|
then 38
|
|
773
|
+
when data_precision is null and data_type != 'NUMBER'
|
|
774
|
+
then 0
|
|
755
775
|
else data_precision
|
|
756
776
|
end,
|
|
757
777
|
case
|
|
@@ -1019,9 +1039,12 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1019
1039
|
if (tempMaxSize)
|
|
1020
1040
|
attr.maxSize = tempMaxSize;
|
|
1021
1041
|
}
|
|
1022
|
-
if (attr.type === types.DB_TYPE_NUMBER
|
|
1023
|
-
|
|
1024
|
-
|
|
1042
|
+
if (attr.type === types.DB_TYPE_NUMBER ||
|
|
1043
|
+
attr.type === types.DB_TYPE_TIMESTAMP ||
|
|
1044
|
+
attr.type === types.DB_TYPE_TIMESTAMP_TZ ||
|
|
1045
|
+
attr.type === types.DB_TYPE_TIMESTAMP_LTZ) {
|
|
1046
|
+
attr.precision = Number(attrInfo.dataPrecision ?? 0);
|
|
1047
|
+
attr.scale = Number(attrInfo.dataScale ?? 0);
|
|
1025
1048
|
}
|
|
1026
1049
|
}
|
|
1027
1050
|
}
|
|
@@ -1147,12 +1170,16 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1147
1170
|
this._clientIdentifierModified = false;
|
|
1148
1171
|
this._action = "";
|
|
1149
1172
|
this._actionModified = false;
|
|
1173
|
+
this._ecid = "";
|
|
1174
|
+
this._ecidModified = false;
|
|
1150
1175
|
this._dbOp = "";
|
|
1151
1176
|
this._dbOpModified = false;
|
|
1152
1177
|
this._clientInfo = "";
|
|
1153
1178
|
this._clientInfoModified = false;
|
|
1154
1179
|
this._module = "";
|
|
1155
1180
|
this._moduleModified = false;
|
|
1181
|
+
this.databaseOpenTelemetryTracing = false;
|
|
1182
|
+
this._otelModified = false;
|
|
1156
1183
|
this._drcpEnabled = false;
|
|
1157
1184
|
this.serviceName = '';
|
|
1158
1185
|
this.remoteAddress = '';
|
|
@@ -1160,6 +1187,13 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1160
1187
|
this.tpcContext = null;
|
|
1161
1188
|
this._sessionlessData = null;
|
|
1162
1189
|
this._nameSpaceMap = new Map();
|
|
1190
|
+
this._txnPriority = "";
|
|
1191
|
+
this._pendingTxnPriority = undefined;
|
|
1192
|
+
this._txnPriorityModified = false;
|
|
1193
|
+
|
|
1194
|
+
if (!this._isNotificationConnection) {
|
|
1195
|
+
this._setNotificationConnectParams(params);
|
|
1196
|
+
}
|
|
1163
1197
|
|
|
1164
1198
|
this.nscon = new nsi();
|
|
1165
1199
|
finalizationRegistry.register(this, this.nscon);
|
|
@@ -1234,15 +1268,22 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1234
1268
|
await this._protocol._processMessage(authMessage); // OAUTH
|
|
1235
1269
|
}
|
|
1236
1270
|
this._postConnect(authMessage);
|
|
1271
|
+
if (params.txnPriority === "") {
|
|
1272
|
+
this.setTxnPriority("");
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
this.statementCache = new StatementCache(this.statementCacheSize);
|
|
1276
|
+
// maintain a list of partially populated database object types
|
|
1277
|
+
this._partialDbObjectTypes = [];
|
|
1278
|
+
|
|
1279
|
+
if (this._requiresDbTimeZoneInitialization()) {
|
|
1280
|
+
await this._initializeDbTimeZone();
|
|
1281
|
+
}
|
|
1237
1282
|
} catch (err) {
|
|
1238
1283
|
this.nscon.disconnect();
|
|
1239
1284
|
throw err;
|
|
1240
1285
|
}
|
|
1241
1286
|
|
|
1242
|
-
this.statementCache = new StatementCache(this.statementCacheSize);
|
|
1243
|
-
// maintain a list of partially populated database object types
|
|
1244
|
-
this._partialDbObjectTypes = [];
|
|
1245
|
-
|
|
1246
1287
|
if (params.debugJDWP) {
|
|
1247
1288
|
this.jdwpData = Buffer.from(params.debugJDWP);
|
|
1248
1289
|
} else if (process.env.ORA_DEBUG_JDWP) {
|
|
@@ -1251,6 +1292,68 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1251
1292
|
this._protocol.connInProgress = false;
|
|
1252
1293
|
}
|
|
1253
1294
|
|
|
1295
|
+
//---------------------------------------------------------------------------
|
|
1296
|
+
// _requiresDbTimeZoneInitialization()
|
|
1297
|
+
//
|
|
1298
|
+
// The DBTIMEZONE fallback is an ordinary SQL query and must only be sent on
|
|
1299
|
+
// application connections. An EMON notification connection never fetches or
|
|
1300
|
+
// binds TIMESTAMP WITH LOCAL TIME ZONE values, and servers can close it when
|
|
1301
|
+
// sent this query.
|
|
1302
|
+
//---------------------------------------------------------------------------
|
|
1303
|
+
_requiresDbTimeZoneInitialization() {
|
|
1304
|
+
return !this._isNotificationConnection &&
|
|
1305
|
+
this._protocol.caps.dbTzOffset === null;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
//---------------------------------------------------------------------------
|
|
1309
|
+
// _initializeDbTimeZone()
|
|
1310
|
+
//
|
|
1311
|
+
// A TZ_EX response supplies a fixed DBTIMEZONE offset directly. Region
|
|
1312
|
+
// responses supply an Oracle region ID instead, and older servers do not
|
|
1313
|
+
// return a DBTIMEZONE value. In both cases, query DBTIMEZONE once to get
|
|
1314
|
+
// the offset, recognize a named UTC zero-offset alias, or identify a
|
|
1315
|
+
// region configuration unsupported for LTZ.
|
|
1316
|
+
//---------------------------------------------------------------------------
|
|
1317
|
+
async _initializeDbTimeZone() {
|
|
1318
|
+
const options = {
|
|
1319
|
+
connection: { _impl: this },
|
|
1320
|
+
keepInStmtCache: false
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
// Use DBTIMEZONE so named regions are preserved. Using TZ_OFFSET(DBTIMEZONE)
|
|
1324
|
+
// would reduce a DST-aware region to a single offset.
|
|
1325
|
+
const result = await this.execute('SELECT DBTIMEZONE FROM DUAL', 1, [],
|
|
1326
|
+
options, false);
|
|
1327
|
+
let rows;
|
|
1328
|
+
try {
|
|
1329
|
+
rows = await result.resultSet.getRows(1, options);
|
|
1330
|
+
} finally {
|
|
1331
|
+
await result.resultSet.close();
|
|
1332
|
+
}
|
|
1333
|
+
const value = rows[0][0];
|
|
1334
|
+
const match = /^([+-])(\d{2}):(\d{2})$/.exec(value);
|
|
1335
|
+
if (match || UTC_DB_TIME_ZONE_NAMES.has(value.toUpperCase())) {
|
|
1336
|
+
let offset = 0;
|
|
1337
|
+
if (match) {
|
|
1338
|
+
offset = Number(match[2]) * 60 + Number(match[3]);
|
|
1339
|
+
if (match[1] === '-') {
|
|
1340
|
+
offset = -offset;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
this._protocol.caps.dbTzOffset = offset;
|
|
1344
|
+
|
|
1345
|
+
// A fixed DBTIMEZONE, including a UTC alias, does not need a region
|
|
1346
|
+
// name or Oracle timezone-rule processing.
|
|
1347
|
+
this._protocol.caps.dbTzRegion = null;
|
|
1348
|
+
} else {
|
|
1349
|
+
// The TTC response contains only an Oracle internal region ID. Do not
|
|
1350
|
+
// use Node.js ICU rules as a substitute for Oracle's timezone rules.
|
|
1351
|
+
// LTZ fetches and binds reject this configuration in BaseBuffer.
|
|
1352
|
+
this._protocol.caps.dbTzOffset = null;
|
|
1353
|
+
this._protocol.caps.dbTzRegion = value;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1254
1357
|
//---------------------------------------------------------------------------
|
|
1255
1358
|
// Return the statement to the statement cache, if applicable
|
|
1256
1359
|
//---------------------------------------------------------------------------
|
|
@@ -1258,6 +1361,35 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1258
1361
|
this.statementCache.returnStatement(statement);
|
|
1259
1362
|
}
|
|
1260
1363
|
|
|
1364
|
+
//---------------------------------------------------------------------------
|
|
1365
|
+
// Synchronize query variables after result set setup recalculates fetch
|
|
1366
|
+
// types for the current execute. If a LOB-like column's requested define
|
|
1367
|
+
// type has changed, the cached cursor cannot be reused as-is and must be
|
|
1368
|
+
// cleared so that a fresh define round trip is performed.
|
|
1369
|
+
//---------------------------------------------------------------------------
|
|
1370
|
+
_syncQueryVars(statement, previousTypes) {
|
|
1371
|
+
if (!statement.isQuery || statement.queryVars.length === 0) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
const defineTypeChanged = statement.queryVars.some((variable, i) => {
|
|
1376
|
+
const dbType = variable.fetchInfo.dbType;
|
|
1377
|
+
const requiresLobDefine = dbType === types.DB_TYPE_CLOB ||
|
|
1378
|
+
dbType === types.DB_TYPE_NCLOB ||
|
|
1379
|
+
dbType === types.DB_TYPE_BLOB ||
|
|
1380
|
+
dbType === types.DB_TYPE_JSON ||
|
|
1381
|
+
dbType === types.DB_TYPE_VECTOR;
|
|
1382
|
+
return requiresLobDefine &&
|
|
1383
|
+
previousTypes[i] !== variable.fetchInfo.fetchType;
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
if (defineTypeChanged && statement.cursorId !== 0) {
|
|
1387
|
+
// Clearing the cursor forces a full TNS_FUNC_EXECUTE with fresh defines.
|
|
1388
|
+
this.statementCache._addCursorToClose(statement);
|
|
1389
|
+
statement._clearState();
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1261
1393
|
//---------------------------------------------------------------------------
|
|
1262
1394
|
// Parses the sql statement and puts it into cache if keepInStmtCache
|
|
1263
1395
|
// option is true
|
|
@@ -1265,6 +1397,7 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1265
1397
|
_prepare(sql, options) {
|
|
1266
1398
|
const forceNew = Boolean(options.fetchTypeMap);
|
|
1267
1399
|
const statement = this._getStatement(sql, options.keepInStmtCache, forceNew);
|
|
1400
|
+
statement._registrationId = options._subscriptionRegId || 0n;
|
|
1268
1401
|
statement.bufferRowIndex = 0;
|
|
1269
1402
|
statement.bufferRowCount = 0;
|
|
1270
1403
|
statement.lastRowIndex = 0;
|
|
@@ -1272,6 +1405,124 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1272
1405
|
return statement;
|
|
1273
1406
|
}
|
|
1274
1407
|
|
|
1408
|
+
//---------------------------------------------------------------------------
|
|
1409
|
+
// _buildNotificationConnectString()
|
|
1410
|
+
//
|
|
1411
|
+
// Build a connect string that requests an EMON server connection.
|
|
1412
|
+
//---------------------------------------------------------------------------
|
|
1413
|
+
async _buildNotificationConnectString(connectString, configDir) {
|
|
1414
|
+
if (!connectString) {
|
|
1415
|
+
return connectString;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// Resolve aliases before modifying CONNECT_DATA so every connection
|
|
1419
|
+
// string form, including tnsnames.ora aliases, requests EMON.
|
|
1420
|
+
const resolved = await parserHelpers.resolveConnectStr(connectString,
|
|
1421
|
+
configDir);
|
|
1422
|
+
const descriptor = typeof resolved === 'string' ? resolved :
|
|
1423
|
+
resolved.toString();
|
|
1424
|
+
|
|
1425
|
+
let root;
|
|
1426
|
+
try {
|
|
1427
|
+
root = createNVPair(descriptor);
|
|
1428
|
+
} catch {
|
|
1429
|
+
return connectString;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
const stack = [root];
|
|
1433
|
+
while (stack.length > 0) {
|
|
1434
|
+
const node = stack.pop();
|
|
1435
|
+
if (!node) {
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
if (String(node.name).toUpperCase() === "DESCRIPTION") {
|
|
1440
|
+
let connectData = findNVPair(node, "CONNECT_DATA");
|
|
1441
|
+
if (!connectData) {
|
|
1442
|
+
connectData = new node.constructor("CONNECT_DATA");
|
|
1443
|
+
node.addListElement(connectData);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
let serverNode = findNVPair(connectData, "SERVER");
|
|
1447
|
+
if (!serverNode) {
|
|
1448
|
+
serverNode = new connectData.constructor("SERVER");
|
|
1449
|
+
connectData.addListElement(serverNode);
|
|
1450
|
+
}
|
|
1451
|
+
serverNode.setAtom = "EMON";
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
for (let i = 0; i < node.getListSize(); i++) {
|
|
1455
|
+
stack.push(node.getListElement(i));
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
return root.toString();
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
//---------------------------------------------------------------------------
|
|
1463
|
+
// _setNotificationConnectParams()
|
|
1464
|
+
//
|
|
1465
|
+
// Retain only the connection attributes needed to establish the dedicated
|
|
1466
|
+
// notification connection. Sensitive values are obfuscated rather than kept
|
|
1467
|
+
// directly on the connection object.
|
|
1468
|
+
//---------------------------------------------------------------------------
|
|
1469
|
+
_setNotificationConnectParams(params) {
|
|
1470
|
+
this._connectParams = {...params};
|
|
1471
|
+
|
|
1472
|
+
// _connInfo contains pool-specific connection metadata. The EMON
|
|
1473
|
+
// connection must establish its own standalone connection.
|
|
1474
|
+
delete this._connectParams._connInfo;
|
|
1475
|
+
this._password = new ObfuscatedValue();
|
|
1476
|
+
this._walletPassword = new ObfuscatedValue();
|
|
1477
|
+
this._walletContent = new ObfuscatedValue();
|
|
1478
|
+
this._token = new ObfuscatedValue();
|
|
1479
|
+
this._privateKey = new ObfuscatedValue();
|
|
1480
|
+
|
|
1481
|
+
if (params.password !== undefined) {
|
|
1482
|
+
this._password.set(params.password);
|
|
1483
|
+
this._connectParams.password = null;
|
|
1484
|
+
}
|
|
1485
|
+
if (params.walletPassword !== undefined) {
|
|
1486
|
+
this._walletPassword.set(params.walletPassword);
|
|
1487
|
+
this._connectParams.walletPassword = null;
|
|
1488
|
+
}
|
|
1489
|
+
if (params.walletContent !== undefined) {
|
|
1490
|
+
this._walletContent.set(params.walletContent);
|
|
1491
|
+
this._connectParams.walletContent = null;
|
|
1492
|
+
}
|
|
1493
|
+
if (params.token !== undefined) {
|
|
1494
|
+
this._token.set(params.token);
|
|
1495
|
+
this._connectParams.token = null;
|
|
1496
|
+
}
|
|
1497
|
+
if (params.privateKey !== undefined) {
|
|
1498
|
+
this._privateKey.set(params.privateKey);
|
|
1499
|
+
this._connectParams.privateKey = null;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
//---------------------------------------------------------------------------
|
|
1504
|
+
// _getNotificationConnectParams()
|
|
1505
|
+
//
|
|
1506
|
+
// Return connect parameters suitable for the dedicated notification channel.
|
|
1507
|
+
//---------------------------------------------------------------------------
|
|
1508
|
+
async _getNotificationConnectParams() {
|
|
1509
|
+
const params = {...this._connectParams};
|
|
1510
|
+
if (params.password === null)
|
|
1511
|
+
params.password = this._password.get();
|
|
1512
|
+
if (params.walletPassword === null)
|
|
1513
|
+
params.walletPassword = this._walletPassword.get();
|
|
1514
|
+
if (params.walletContent === null)
|
|
1515
|
+
params.walletContent = this._walletContent.get();
|
|
1516
|
+
if (params.token === null)
|
|
1517
|
+
params.token = this._token.get();
|
|
1518
|
+
if (params.privateKey === null)
|
|
1519
|
+
params.privateKey = this._privateKey.get();
|
|
1520
|
+
params.connectString = await this._buildNotificationConnectString(
|
|
1521
|
+
this._connectParams.connectString,
|
|
1522
|
+
this._connectParams.configDir);
|
|
1523
|
+
return params;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1275
1526
|
//---------------------------------------------------------------------------
|
|
1276
1527
|
// Binds the values by user to the statement object
|
|
1277
1528
|
//---------------------------------------------------------------------------
|
|
@@ -1363,8 +1614,10 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1363
1614
|
}
|
|
1364
1615
|
resultSet._resultSetNew(this, statement, options);
|
|
1365
1616
|
if (statement.queryVars.length > 0) {
|
|
1617
|
+
const previousTypes = statement.queryVars.map(variable => variable.type);
|
|
1366
1618
|
const metadata = thinUtil.getMetadataMany(statement.queryVars);
|
|
1367
1619
|
resultSet._setup(options, metadata);
|
|
1620
|
+
this._syncQueryVars(statement, previousTypes);
|
|
1368
1621
|
}
|
|
1369
1622
|
return resultSet;
|
|
1370
1623
|
}
|
|
@@ -1385,19 +1638,17 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1385
1638
|
//
|
|
1386
1639
|
// Parses the SQL statement and returns information about the statement.
|
|
1387
1640
|
//---------------------------------------------------------------------------
|
|
1388
|
-
async getStatementInfo(sql) {
|
|
1389
|
-
const options = {};
|
|
1641
|
+
async getStatementInfo(sql, options) {
|
|
1390
1642
|
const result = {};
|
|
1391
1643
|
const statement = this._prepare(sql, options);
|
|
1392
|
-
options.connection = this;
|
|
1393
1644
|
try {
|
|
1394
1645
|
if (!statement.isDdl) {
|
|
1395
1646
|
const message = new messages.ExecuteMessage(this, statement, options);
|
|
1396
1647
|
message.parseOnly = true;
|
|
1397
1648
|
await this._protocol._processMessage(message);
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1649
|
+
if (message.resultSet) {
|
|
1650
|
+
result.metaData = message.resultSet.metaData;
|
|
1651
|
+
}
|
|
1401
1652
|
}
|
|
1402
1653
|
result.bindNames = Array.from(statement.bindInfoDict.keys());
|
|
1403
1654
|
result.statementType = statement.statementType;
|
|
@@ -1407,6 +1658,66 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1407
1658
|
}
|
|
1408
1659
|
}
|
|
1409
1660
|
|
|
1661
|
+
//---------------------------------------------------------------------------
|
|
1662
|
+
// subscribe()
|
|
1663
|
+
//
|
|
1664
|
+
// Creates or reuses a thin subscription and optionally registers a query for
|
|
1665
|
+
// DBCHANGE subscriptions.
|
|
1666
|
+
//---------------------------------------------------------------------------
|
|
1667
|
+
async subscribe(inSubscr, options) {
|
|
1668
|
+
if (!options.clientInitiated) {
|
|
1669
|
+
errors.throwNotImplemented("server initiated subscription");
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
let subscr = inSubscr;
|
|
1673
|
+
if (subscr?._listenerStopped) {
|
|
1674
|
+
// Same-name subscribe can recover from an unavailable listener. First
|
|
1675
|
+
// deregister the previous server registration, then create a replacement.
|
|
1676
|
+
try {
|
|
1677
|
+
await subscr.unsubscribe(this);
|
|
1678
|
+
} catch (err) {
|
|
1679
|
+
if (err.code !== errors.getErr(errors.ERR_INVALID_SUBSCR).code) {
|
|
1680
|
+
throw err;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
subscr = null;
|
|
1684
|
+
}
|
|
1685
|
+
if (!subscr) {
|
|
1686
|
+
subscr = new ThinSubscrImpl(this, options);
|
|
1687
|
+
await subscr.subscribe(options);
|
|
1688
|
+
} else {
|
|
1689
|
+
if (!(subscr instanceof ThinSubscrImpl)) {
|
|
1690
|
+
errors.throwErr(errors.ERR_INVALID_SUBSCR);
|
|
1691
|
+
}
|
|
1692
|
+
if (subscr.namespace !== options.namespace) {
|
|
1693
|
+
errors.throwErr(errors.ERR_INVALID_SUBSCR);
|
|
1694
|
+
}
|
|
1695
|
+
if (options.namespace === pubConstants.SUBSCR_NAMESPACE_DBCHANGE) {
|
|
1696
|
+
await subscr.registerQuery(options);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
if (options.namespace === pubConstants.SUBSCR_NAMESPACE_DBCHANGE) {
|
|
1701
|
+
return {
|
|
1702
|
+
regId: subscr.regId,
|
|
1703
|
+
subscription: subscr
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
return subscr;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
//---------------------------------------------------------------------------
|
|
1710
|
+
// unsubscribe()
|
|
1711
|
+
//
|
|
1712
|
+
// Unregisters and closes a thin subscription.
|
|
1713
|
+
//---------------------------------------------------------------------------
|
|
1714
|
+
async unsubscribe(subscr) {
|
|
1715
|
+
if (!subscr || !(subscr instanceof ThinSubscrImpl)) {
|
|
1716
|
+
errors.throwErr(errors.ERR_INVALID_SUBSCR);
|
|
1717
|
+
}
|
|
1718
|
+
await subscr.unsubscribe(this);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1410
1721
|
async _handleDefines(statement, message) {
|
|
1411
1722
|
if (statement.requiresDefine && statement.sql) {
|
|
1412
1723
|
statement.requiresFullExecute = true;
|
|
@@ -1501,6 +1812,13 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1501
1812
|
return this.currentSchema;
|
|
1502
1813
|
}
|
|
1503
1814
|
|
|
1815
|
+
getDatabaseOpenTelemetryTracing() {
|
|
1816
|
+
if (!this._protocol.caps.supportsServerOtelTracing) {
|
|
1817
|
+
errors.throwErr(errors.ERR_UNSUPPORTED_DB_OTEL_FEATURE);
|
|
1818
|
+
}
|
|
1819
|
+
return this.databaseOpenTelemetryTracing;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1504
1822
|
setClientId(clientId) {
|
|
1505
1823
|
this._clientIdentifierModified = true;
|
|
1506
1824
|
this._clientIdentifier = clientId;
|
|
@@ -1511,6 +1829,28 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1511
1829
|
this._dbOp = dbOp;
|
|
1512
1830
|
}
|
|
1513
1831
|
|
|
1832
|
+
setDatabaseOpenTelemetryTracing(value) {
|
|
1833
|
+
if (!this._protocol.caps.supportsServerOtelTracing) {
|
|
1834
|
+
errors.throwErr(errors.ERR_UNSUPPORTED_DB_OTEL_FEATURE);
|
|
1835
|
+
}
|
|
1836
|
+
this._otelModified = true;
|
|
1837
|
+
this.databaseOpenTelemetryTracing = value;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
_clearDatabaseOpenTelemetryTracing() {
|
|
1841
|
+
if (this.databaseOpenTelemetryTracing) {
|
|
1842
|
+
this.databaseOpenTelemetryTracing = false;
|
|
1843
|
+
// the new connection acquired would send tracing
|
|
1844
|
+
// as disabled on server unless application explicitly enables it.
|
|
1845
|
+
this._otelModified = true;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
setECID(ecid) {
|
|
1850
|
+
this._ecidModified = true;
|
|
1851
|
+
this._ecid = ecid;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1514
1854
|
setExternalName(value) {
|
|
1515
1855
|
this.externalName = value;
|
|
1516
1856
|
}
|
|
@@ -1540,6 +1880,22 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1540
1880
|
this._action = action;
|
|
1541
1881
|
}
|
|
1542
1882
|
|
|
1883
|
+
// Always queue the requested priority, even if it matches the last known
|
|
1884
|
+
// server value. _txnPriority contains only the last value synchronized from
|
|
1885
|
+
// the server, while _pendingTxnPriority contains only the last value
|
|
1886
|
+
// requested through this method. Neither can reliably account for changes
|
|
1887
|
+
// made through explicit ALTER SESSION.
|
|
1888
|
+
setTxnPriority(priority) {
|
|
1889
|
+
this._protocol.caps.assertTxnPrioritySupported();
|
|
1890
|
+
this._pendingTxnPriority = priority;
|
|
1891
|
+
this._txnPriorityModified = true;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
getTxnPriority() {
|
|
1895
|
+
this._protocol.caps.assertTxnPrioritySupported();
|
|
1896
|
+
return this._txnPriority;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1543
1899
|
async changePassword(user, password, newPassword) {
|
|
1544
1900
|
const config = {
|
|
1545
1901
|
user: user,
|
|
@@ -1905,6 +2261,12 @@ class ThinConnectionImpl extends ConnectionImpl {
|
|
|
1905
2261
|
}
|
|
1906
2262
|
|
|
1907
2263
|
clearEndUserSecurityContext() {
|
|
2264
|
+
// A provider-created context belongs to this borrowed thin connection.
|
|
2265
|
+
// A pool release invokes close(), so reset resolution before this
|
|
2266
|
+
// physical connection is available to its next borrower.
|
|
2267
|
+
if (this._securityContextInitialized) {
|
|
2268
|
+
this._securityContextInitialized = false;
|
|
2269
|
+
}
|
|
1908
2270
|
this.securityContext = null;
|
|
1909
2271
|
}
|
|
1910
2272
|
|
package/lib/thin/dbObject.js
CHANGED
|
@@ -208,7 +208,8 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
208
208
|
_getPackedData() {
|
|
209
209
|
if (this.packedData)
|
|
210
210
|
return this.packedData;
|
|
211
|
-
const
|
|
211
|
+
const caps = this._objType._connection._protocol.caps;
|
|
212
|
+
const buf = new DbObjectPickleBuffer(undefined, caps);
|
|
212
213
|
buf.writeHeader(this);
|
|
213
214
|
this._packData(buf);
|
|
214
215
|
const size = buf.pos;
|
|
@@ -316,7 +317,8 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
316
317
|
// Unpacks the packed data into a map of JavaScript values.
|
|
317
318
|
//---------------------------------------------------------------------------
|
|
318
319
|
_unpackData() {
|
|
319
|
-
const
|
|
320
|
+
const caps = this._objType._connection._protocol.caps;
|
|
321
|
+
const buf = new DbObjectPickleBuffer(this.packedData, caps);
|
|
320
322
|
buf.readHeader(this);
|
|
321
323
|
this._unpackDataFromBuf(buf);
|
|
322
324
|
this.packedData = undefined;
|
|
@@ -368,7 +370,7 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
368
370
|
// Unpacks a single value and returns it.
|
|
369
371
|
//---------------------------------------------------------------------------
|
|
370
372
|
_unpackValue(buf, type, typeClass) {
|
|
371
|
-
let
|
|
373
|
+
let isCollection, obj, value;
|
|
372
374
|
const caps = this._objType._connection._protocol.caps;
|
|
373
375
|
switch (type) {
|
|
374
376
|
case types.DB_TYPE_NUMBER:
|
|
@@ -396,6 +398,7 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
396
398
|
case types.DB_TYPE_TIMESTAMP:
|
|
397
399
|
return buf.readOracleDate(true);
|
|
398
400
|
case types.DB_TYPE_TIMESTAMP_LTZ:
|
|
401
|
+
return buf.readOracleDate(false, true);
|
|
399
402
|
case types.DB_TYPE_TIMESTAMP_TZ:
|
|
400
403
|
return buf.readOracleDate(false);
|
|
401
404
|
case types.DB_TYPE_BOOLEAN:
|
|
@@ -403,14 +406,20 @@ class ThinDbObjectImpl extends DbObjectImpl {
|
|
|
403
406
|
case types.DB_TYPE_OBJECT:
|
|
404
407
|
case types.DB_TYPE_XMLTYPE:
|
|
405
408
|
obj = new ThinDbObjectImpl(typeClass);
|
|
409
|
+
|
|
410
|
+
// check for XMLType
|
|
411
|
+
if (obj._objType.isXmlType) {
|
|
412
|
+
const xmlBytes = buf.readBytesWithLength();
|
|
413
|
+
if (!xmlBytes)
|
|
414
|
+
return null;
|
|
415
|
+
return readXML(obj._objType._connection, xmlBytes);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// check the type of object
|
|
406
419
|
isCollection = obj._objType.isCollection ||
|
|
407
420
|
this._objType.isCollection;
|
|
408
|
-
|
|
409
|
-
if (isNull)
|
|
421
|
+
if (buf.getIsAtomicNull(isCollection))
|
|
410
422
|
return null;
|
|
411
|
-
if (obj._objType.isXmlType) {
|
|
412
|
-
return readXML(obj._objType._connection, buf.readBytesWithLength());
|
|
413
|
-
}
|
|
414
423
|
if (isCollection) {
|
|
415
424
|
obj.packedData = Buffer.from(buf.readBytesWithLength());
|
|
416
425
|
} else {
|
package/lib/thin/pool.js
CHANGED
|
@@ -434,7 +434,7 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
434
434
|
// continue until a close request is received
|
|
435
435
|
while (!this._poolCloseWaiter) {
|
|
436
436
|
|
|
437
|
-
|
|
437
|
+
let numToCreate = this._getNumConnsToCreate();
|
|
438
438
|
// connection creation is going on serially and not concurrently
|
|
439
439
|
for (let i = 0; i < numToCreate; i++) {
|
|
440
440
|
try {
|
|
@@ -480,8 +480,9 @@ class ThinPoolImpl extends PoolImpl {
|
|
|
480
480
|
break;
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
+
numToCreate = this._getNumConnsToCreate();
|
|
483
484
|
// if no pending requests, wait for pending requests to appear!
|
|
484
|
-
if ((
|
|
485
|
+
if ((numToCreate <= 0 || this._bgErr) &&
|
|
485
486
|
this.getConnectionsOpen() >= this._poolMin) {
|
|
486
487
|
await new Promise((resolve) => {
|
|
487
488
|
this.bgWaiter = resolve;
|