oracledb 6.10.0 → 7.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/LICENSE.txt +1 -1
- package/NOTICE.txt +1 -1
- package/README.md +9 -9
- package/build/Release/oracledb-7.0.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-7.0.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-7.0.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-linux-x64.node +0 -0
- package/build/Release/oracledb-7.0.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-win32-x64.node +0 -0
- package/build/Release/oracledb-7.0.0-win32-x64.node-buildinfo.txt +1 -0
- package/eslint.config.js +39 -0
- package/lib/connection.js +412 -37
- package/lib/endUserSecurityContext.js +176 -0
- package/lib/errors.js +86 -5
- package/lib/impl/connection.js +76 -2
- package/lib/impl/datahandlers/buffer.js +19 -5
- package/lib/impl/datahandlers/vector.js +25 -5
- package/lib/impl/lob.js +9 -0
- package/lib/impl/parserHelpers.js +443 -0
- package/lib/impl/resultset.js +1 -1
- package/lib/lob.js +27 -14
- package/lib/obfuscation.js +97 -0
- package/lib/oracledb.js +148 -43
- package/lib/parser.js +204 -0
- package/lib/pipeline.js +113 -0
- package/lib/pool.js +16 -1
- package/lib/resultset.js +42 -21
- package/lib/settings.js +1 -0
- package/lib/thin/connection.js +467 -53
- package/lib/thin/dbObject.js +7 -1
- package/lib/thin/lob.js +20 -1
- package/lib/thin/pool.js +42 -62
- package/lib/thin/protocol/capabilities.js +18 -3
- package/lib/thin/protocol/constants.js +82 -2
- package/lib/thin/protocol/encryptDecrypt.js +43 -8
- package/lib/thin/protocol/messages/auth.js +6 -1
- package/lib/thin/protocol/messages/base.js +245 -4
- package/lib/thin/protocol/messages/dataType.js +8 -3
- package/lib/thin/protocol/messages/directPathLoadStream.js +377 -0
- package/lib/thin/protocol/messages/directPathOp.js +65 -0
- package/lib/thin/protocol/messages/directPathPrepare.js +158 -0
- package/lib/thin/protocol/messages/endPipeline.js +56 -0
- package/lib/thin/protocol/messages/execute.js +9 -7
- package/lib/thin/protocol/messages/index.js +9 -1
- package/lib/thin/protocol/messages/protocol.js +2 -2
- package/lib/thin/protocol/messages/withData.js +8 -140
- package/lib/thin/protocol/packet.js +115 -24
- package/lib/thin/protocol/protocol.js +110 -25
- package/lib/thin/protocol/utils.js +1 -26
- package/lib/thin/resultSet.js +13 -19
- package/lib/thin/sqlnet/ezConnectResolver.js +2 -2
- package/lib/thin/sqlnet/networkSession.js +62 -40
- package/lib/thin/sqlnet/ntTcp.js +24 -0
- package/lib/thin/sqlnet/nvStrToNvPair.js +50 -25
- package/lib/thin/sqlnet/packet.js +25 -4
- package/lib/thin/sqlnet/paramParser.js +10 -7
- package/lib/thin/statementCache.js +2 -4
- package/lib/traceHandler.js +59 -2
- package/lib/transformer.js +8 -3
- package/lib/types.js +35 -21
- package/lib/util.js +6 -6
- package/lib/version.js +3 -3
- package/package/install.js +5 -5
- package/package/prunebinaries.js +1 -1
- package/package.json +1 -1
- package/plugins/configProviders/awsCommon.js +125 -0
- package/plugins/configProviders/awss3/index.js +138 -0
- package/plugins/configProviders/awssecretsmanager/index.js +147 -0
- package/plugins/configProviders/azure/index.js +4 -5
- package/plugins/token/extensionAzure/index.js +0 -1
- package/plugins/token/extensionOci/index.js +0 -1
- package/build/Release/oracledb-6.10.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.10.0-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.10.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.10.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.10.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.10.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.10.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.10.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.10.0-win32-x64.node-buildinfo.txt +0 -1
|
@@ -56,13 +56,13 @@ class ExecuteMessage extends MessageWithData {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
//-------------------------------------------------------------------------
|
|
59
|
-
//
|
|
59
|
+
// writeExecuteMessage()
|
|
60
60
|
//
|
|
61
61
|
// Write the message for a full execute.
|
|
62
62
|
//-------------------------------------------------------------------------
|
|
63
63
|
writeExecuteMessage(buf) {
|
|
64
64
|
let options = 0x0;
|
|
65
|
-
let
|
|
65
|
+
let execFlags = 0;
|
|
66
66
|
let numParams = 0;
|
|
67
67
|
let numIters = 1;
|
|
68
68
|
// Configuring the options field thats send to the server
|
|
@@ -70,7 +70,7 @@ class ExecuteMessage extends MessageWithData {
|
|
|
70
70
|
const params = stmt.bindInfoList;
|
|
71
71
|
|
|
72
72
|
if (this.noImplicitRelease) {
|
|
73
|
-
|
|
73
|
+
execFlags |= constants.TNS_EXEC_OPTION_NO_IMPL_REL;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
if (!stmt.requiresDefine && !this.parseOnly && params) {
|
|
@@ -79,7 +79,7 @@ class ExecuteMessage extends MessageWithData {
|
|
|
79
79
|
if (stmt.requiresDefine) {
|
|
80
80
|
options |= constants.TNS_EXEC_OPTION_DEFINE;
|
|
81
81
|
} else if (!this.parseOnly && stmt.sql) {
|
|
82
|
-
|
|
82
|
+
execFlags |= constants.TNS_EXEC_OPTION_IMPLICIT_RESULTSET;
|
|
83
83
|
options |= constants.TNS_EXEC_OPTION_EXECUTE;
|
|
84
84
|
}
|
|
85
85
|
if (stmt.cursorId === 0 || stmt.isDdl) {
|
|
@@ -111,7 +111,7 @@ class ExecuteMessage extends MessageWithData {
|
|
|
111
111
|
options |= constants.TNS_EXEC_OPTION_BATCH_ERRORS;
|
|
112
112
|
}
|
|
113
113
|
if (this.arrayDmlRowCounts) {
|
|
114
|
-
|
|
114
|
+
execFlags |= constants.TNS_EXEC_OPTION_DML_ROWCOUNTS;
|
|
115
115
|
}
|
|
116
116
|
if (this.options.autoCommit) {
|
|
117
117
|
options |= constants.TNS_EXEC_OPTION_COMMIT;
|
|
@@ -213,7 +213,7 @@ class ExecuteMessage extends MessageWithData {
|
|
|
213
213
|
buf.writeUB4(0); // al8i4[6] SCN (part 2)
|
|
214
214
|
buf.writeUB4((stmt.isQuery) ? 1 : 0); // al8i4[7] is query
|
|
215
215
|
buf.writeUB4(0); // al8i4[8]
|
|
216
|
-
buf.writeUB4(
|
|
216
|
+
buf.writeUB4(execFlags); // al8i4[9] DML row counts/implicit
|
|
217
217
|
buf.writeUB4(0); // al8i4[10]
|
|
218
218
|
buf.writeUB4(0); // al8i4[11]
|
|
219
219
|
buf.writeUB4(0); // al8i4[12]
|
|
@@ -321,7 +321,9 @@ class ExecuteMessage extends MessageWithData {
|
|
|
321
321
|
// no rows have yet been sent so the header information needs to be sent
|
|
322
322
|
if (this.currentRow === 0) {
|
|
323
323
|
const stmt = this.statement;
|
|
324
|
-
if (stmt.cursorId !== 0 && !stmt.requiresFullExecute && !this.parseOnly
|
|
324
|
+
if (stmt.cursorId !== 0 && !stmt.requiresFullExecute && !this.parseOnly
|
|
325
|
+
&& !stmt.requiresDefine && !stmt.noPrefetch && !stmt.isDdl
|
|
326
|
+
&& !this.batchErrors) {
|
|
325
327
|
if (stmt.isQuery && this.options.prefetchRows > 0) {
|
|
326
328
|
this.functionCode = constants.TNS_FUNC_REEXECUTE_AND_FETCH;
|
|
327
329
|
} else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2023, Oracle and/or its affiliates.
|
|
1
|
+
// Copyright (c) 2023, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -29,7 +29,11 @@
|
|
|
29
29
|
const AuthMessage = require('./auth.js');
|
|
30
30
|
const CommitMessage = require('./commit.js');
|
|
31
31
|
const DataTypeMessage = require('./dataType.js');
|
|
32
|
+
const DirectPathPrepareMessage = require('./directPathPrepare.js');
|
|
33
|
+
const DirectPathLoadStreamMessage = require('./directPathLoadStream.js');
|
|
34
|
+
const DirectPathOpMessage = require('./directPathOp.js');
|
|
32
35
|
const ExecuteMessage = require('./execute.js');
|
|
36
|
+
const EndPipelineMessage = require('./endPipeline.js');
|
|
33
37
|
const FetchMessage = require('./fetch.js');
|
|
34
38
|
const LobOpMessage = require('./lobOp.js');
|
|
35
39
|
const LogOffMessage = require('./logOff.js');
|
|
@@ -46,7 +50,11 @@ module.exports = {
|
|
|
46
50
|
CommitMessage,
|
|
47
51
|
FastAuthMessage,
|
|
48
52
|
DataTypeMessage,
|
|
53
|
+
DirectPathPrepareMessage,
|
|
54
|
+
DirectPathLoadStreamMessage,
|
|
55
|
+
DirectPathOpMessage,
|
|
49
56
|
ExecuteMessage,
|
|
57
|
+
EndPipelineMessage,
|
|
50
58
|
FetchMessage,
|
|
51
59
|
LobOpMessage,
|
|
52
60
|
LogOffMessage,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -63,7 +63,7 @@ class ProtocolMessage extends Message {
|
|
|
63
63
|
this.serverVersion = buf.readUInt8();
|
|
64
64
|
buf.skipUB1();
|
|
65
65
|
this.serverBanner = buf.readNullTerminatedBytes(48);
|
|
66
|
-
buf.caps.
|
|
66
|
+
buf.caps.charsetId = buf.readUInt16LE();
|
|
67
67
|
this.serverFlags = buf.readUInt8();
|
|
68
68
|
const num_elem = buf.readUInt16LE();
|
|
69
69
|
if (num_elem > 0) { // skip elements
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -58,6 +58,7 @@ class MessageWithData extends Message {
|
|
|
58
58
|
this.parseOnly = false;
|
|
59
59
|
this.resultSetsToSetup = [];
|
|
60
60
|
this.deferredErr = null;
|
|
61
|
+
this.postProcessDone = false;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/**
|
|
@@ -189,145 +190,6 @@ class MessageWithData extends Message {
|
|
|
189
190
|
this.resultSetsToSetup.push(resultSet);
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
processColumnInfo(buf, columnNum) {
|
|
193
|
-
const dataType = buf.readUInt8();
|
|
194
|
-
buf.skipUB1(); // flags
|
|
195
|
-
const precision = buf.readInt8();
|
|
196
|
-
const scale = buf.readInt8();
|
|
197
|
-
const maxSize = buf.readUB4();
|
|
198
|
-
buf.skipUB4(); // max number of array elements
|
|
199
|
-
buf.skipUB8(); // cont flags
|
|
200
|
-
let oid;
|
|
201
|
-
let numBytes = buf.readUB4(); // OID
|
|
202
|
-
if (numBytes > 0) {
|
|
203
|
-
oid = Buffer.from(buf.readBytesWithLength());
|
|
204
|
-
}
|
|
205
|
-
buf.skipUB2(); // version
|
|
206
|
-
buf.skipUB2(); // character set id
|
|
207
|
-
const csfrm = buf.readUInt8(); // character set form
|
|
208
|
-
let size = buf.readUB4();
|
|
209
|
-
if (dataType === constants.TNS_DATA_TYPE_RAW) {
|
|
210
|
-
size = maxSize;
|
|
211
|
-
}
|
|
212
|
-
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_12_2) {
|
|
213
|
-
buf.skipUB4(); // oaccolid
|
|
214
|
-
}
|
|
215
|
-
const nullable = Boolean(buf.readUInt8());
|
|
216
|
-
buf.skipUB1(); // v7 length of name
|
|
217
|
-
let name;
|
|
218
|
-
numBytes = buf.readUB4();
|
|
219
|
-
if (numBytes > 0) {
|
|
220
|
-
name = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
221
|
-
}
|
|
222
|
-
let schema;
|
|
223
|
-
numBytes = buf.readUB4();
|
|
224
|
-
if (numBytes > 0) {
|
|
225
|
-
schema = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
226
|
-
}
|
|
227
|
-
numBytes = buf.readUB4();
|
|
228
|
-
let typeName;
|
|
229
|
-
if (numBytes > 0) {
|
|
230
|
-
typeName = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
231
|
-
}
|
|
232
|
-
buf.skipUB2(); // column position
|
|
233
|
-
const udsFlags = buf.readUB4(); // uds flag
|
|
234
|
-
|
|
235
|
-
// build metadata
|
|
236
|
-
const fetchInfo = {
|
|
237
|
-
name: name,
|
|
238
|
-
dbColumnName: name,
|
|
239
|
-
dbType: types.getTypeByOraTypeNum(dataType, csfrm),
|
|
240
|
-
nullable: nullable
|
|
241
|
-
};
|
|
242
|
-
fetchInfo.isJson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_JSON);
|
|
243
|
-
fetchInfo.isOson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_OSON);
|
|
244
|
-
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) {
|
|
245
|
-
numBytes = buf.readUB4();
|
|
246
|
-
if (numBytes > 0) {
|
|
247
|
-
fetchInfo.domainSchema = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
248
|
-
}
|
|
249
|
-
numBytes = buf.readUB4();
|
|
250
|
-
if (numBytes > 0) {
|
|
251
|
-
fetchInfo.domainName = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1_EXT_3) {
|
|
255
|
-
if (buf.readUB4() > 0) {
|
|
256
|
-
fetchInfo.annotations = {};
|
|
257
|
-
buf.skipUB1();
|
|
258
|
-
const numAnnotations = buf.readUB4();
|
|
259
|
-
buf.skipUB1();
|
|
260
|
-
let key, value;
|
|
261
|
-
for (let i = 0; i < numAnnotations; i++) {
|
|
262
|
-
buf.skipUB4();
|
|
263
|
-
value = "";
|
|
264
|
-
key = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
265
|
-
numBytes = buf.readUB4();
|
|
266
|
-
if (numBytes > 0) {
|
|
267
|
-
value = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
268
|
-
}
|
|
269
|
-
fetchInfo.annotations[key] = value;
|
|
270
|
-
buf.skipUB4(); // flags
|
|
271
|
-
}
|
|
272
|
-
buf.skipUB4(); // flags
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_4) {
|
|
276
|
-
const dimensions = buf.readUB4();
|
|
277
|
-
const vectorFormat = buf.readUInt8();
|
|
278
|
-
const vectorFlags = buf.readUInt8();
|
|
279
|
-
if (fetchInfo.dbType === types.DB_TYPE_VECTOR) {
|
|
280
|
-
if (!(vectorFlags & constants.VECTOR_META_FLAG_FLEXIBLE_DIM)) {
|
|
281
|
-
fetchInfo.vectorDimensions = dimensions;
|
|
282
|
-
}
|
|
283
|
-
fetchInfo.isSparseVector = Boolean(vectorFlags & constants.VECTOR_META_FLAG_SPARSE);
|
|
284
|
-
if (vectorFormat !== constants.VECTOR_FORMAT_FLEX) {
|
|
285
|
-
fetchInfo.vectorFormat = vectorFormat;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
switch (fetchInfo.dbType) {
|
|
291
|
-
case types.DB_TYPE_VARCHAR:
|
|
292
|
-
case types.DB_TYPE_NVARCHAR:
|
|
293
|
-
case types.DB_TYPE_CHAR:
|
|
294
|
-
case types.DB_TYPE_NCHAR:
|
|
295
|
-
case types.DB_TYPE_RAW:
|
|
296
|
-
fetchInfo.byteSize = size;
|
|
297
|
-
break;
|
|
298
|
-
case types.DB_TYPE_NUMBER:
|
|
299
|
-
fetchInfo.precision = precision;
|
|
300
|
-
break;
|
|
301
|
-
case types.DB_TYPE_TIMESTAMP:
|
|
302
|
-
case types.DB_TYPE_TIMESTAMP_TZ:
|
|
303
|
-
case types.DB_TYPE_TIMESTAMP_LTZ:
|
|
304
|
-
fetchInfo.precision = scale;
|
|
305
|
-
break;
|
|
306
|
-
case types.DB_TYPE_OBJECT:
|
|
307
|
-
fetchInfo.dbTypeClass = this.connection._getDbObjectType(schema,
|
|
308
|
-
typeName, undefined, oid);
|
|
309
|
-
if (fetchInfo.dbTypeClass.partial) {
|
|
310
|
-
this.connection._partialDbObjectTypes.push(fetchInfo.dbTypeClass);
|
|
311
|
-
}
|
|
312
|
-
if (fetchInfo.dbTypeClass.isXmlType) {
|
|
313
|
-
fetchInfo.dbType = types.DB_TYPE_XMLTYPE;
|
|
314
|
-
}
|
|
315
|
-
break;
|
|
316
|
-
default:
|
|
317
|
-
break;
|
|
318
|
-
}
|
|
319
|
-
if (fetchInfo.dbType === types.DB_TYPE_NUMBER) {
|
|
320
|
-
fetchInfo.scale = scale;
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
fetchInfo: fetchInfo,
|
|
324
|
-
type: fetchInfo.dbType,
|
|
325
|
-
maxSize: maxSize,
|
|
326
|
-
columnNum: columnNum,
|
|
327
|
-
values: new Array(this.options.fetchArraySize)
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
193
|
processRowHeader(buf) {
|
|
332
194
|
buf.skipUB1(); // flags
|
|
333
195
|
buf.skipUB2(); // num requests
|
|
@@ -607,10 +469,16 @@ class MessageWithData extends Message {
|
|
|
607
469
|
}
|
|
608
470
|
|
|
609
471
|
async postProcess() {
|
|
472
|
+
if (this.postProcessDone) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
610
476
|
if (this.deferredErr) {
|
|
611
477
|
throw this.deferredErr;
|
|
612
478
|
}
|
|
613
479
|
|
|
480
|
+
this.postProcessDone = true;
|
|
481
|
+
|
|
614
482
|
if (this.outVariables) {
|
|
615
483
|
for (const variable of this.outVariables) {
|
|
616
484
|
if (variable.isArray) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -35,8 +35,6 @@ const vector = require('../../impl/datahandlers/vector.js');
|
|
|
35
35
|
const errors = require("../../errors.js");
|
|
36
36
|
|
|
37
37
|
const TNS_BASE64_ALPHABET_ARRAY = Buffer.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 'utf8');
|
|
38
|
-
const FAST_AUTH_END_OF_RPC_VALUE = 0x800;
|
|
39
|
-
const FAST_AUTH_END_OF_RPC_OFFSET = 0x8;
|
|
40
38
|
const MSG_TYPE_OFFSET = 11;
|
|
41
39
|
|
|
42
40
|
/**
|
|
@@ -161,7 +159,7 @@ class ReadPacket extends BaseBuffer {
|
|
|
161
159
|
return this.readBytes(numBytes);
|
|
162
160
|
}
|
|
163
161
|
this.chunkedBytesBuf.startChunkedRead();
|
|
164
|
-
while (true) {
|
|
162
|
+
while (true) {
|
|
165
163
|
const numBytesInChunk = this.readUB4();
|
|
166
164
|
if (numBytesInChunk === 0) {
|
|
167
165
|
break;
|
|
@@ -293,6 +291,51 @@ class ReadPacket extends BaseBuffer {
|
|
|
293
291
|
this.packetNum = packet.num;
|
|
294
292
|
}
|
|
295
293
|
|
|
294
|
+
/**
|
|
295
|
+
* It is used in pipeline mode to ignore reading packets
|
|
296
|
+
* if client detects a protocol error.
|
|
297
|
+
*/
|
|
298
|
+
resetPackets() {
|
|
299
|
+
this.savedPackets = [];
|
|
300
|
+
this.savedPacketPos = 0;
|
|
301
|
+
this.savedPos = 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Discards the remaining responses after the pipeline has
|
|
306
|
+
* encountered an exception in ABORT_ON_ERROR mode
|
|
307
|
+
*/
|
|
308
|
+
async discardPipelineResponses(num) {
|
|
309
|
+
while (num > 0) {
|
|
310
|
+
await this.waitForPackets(true);
|
|
311
|
+
num--;
|
|
312
|
+
}
|
|
313
|
+
this.resetPackets();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
_isEndOfResponse(packet) {
|
|
317
|
+
// In pipeline mode, when a DML operation fails due to invalid RETURNING
|
|
318
|
+
// binds, we may receive a partial response followed by a break packet
|
|
319
|
+
// before the full response arrives. Such break packets are ignored.
|
|
320
|
+
//
|
|
321
|
+
// In non-pipeline mode, return true if the packet is not a data packet.
|
|
322
|
+
if (packet.type !== constants.TNS_PACKET_TYPE_DATA) {
|
|
323
|
+
return !this.nsi.pipelineEnabled;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// End-of-response marker
|
|
327
|
+
if (packet.buf.readUInt16BE(8) &
|
|
328
|
+
constants.TNS_DATA_FLAGS_END_OF_RESPONSE) {
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Single-byte 1D packet
|
|
333
|
+
return (
|
|
334
|
+
packet.buf.length === MSG_TYPE_OFFSET &&
|
|
335
|
+
packet.buf[MSG_TYPE_OFFSET - 1] === constants.TNS_MSG_TYPE_END_OF_REQUEST
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
296
339
|
/**
|
|
297
340
|
* Read packets from network.
|
|
298
341
|
* If checkRequestBoundary is passed as true, it
|
|
@@ -308,21 +351,24 @@ class ReadPacket extends BaseBuffer {
|
|
|
308
351
|
this.savedPackets.push(packet);
|
|
309
352
|
}
|
|
310
353
|
if (checkRequestBoundary && this.nsi.endOfRequestSupport) {
|
|
311
|
-
while (packet
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
354
|
+
while (!this._isEndOfResponse(packet)) {
|
|
355
|
+
if (
|
|
356
|
+
packet.type !== constants.TNS_PACKET_TYPE_DATA &&
|
|
357
|
+
this.nsi.isBreak
|
|
358
|
+
) {
|
|
359
|
+
// For pipeline Mode only, we issue a dummy reset to the sqlnet layer
|
|
360
|
+
// to set state, `this.isBreak = this.isReset = false;`
|
|
361
|
+
await this.nsi.reset();
|
|
362
|
+
|
|
363
|
+
this.resetPackets();
|
|
316
364
|
}
|
|
317
365
|
|
|
318
|
-
//
|
|
319
|
-
if (packet.buf.length === MSG_TYPE_OFFSET &&
|
|
320
|
-
packet.buf[MSG_TYPE_OFFSET - 1] ===
|
|
321
|
-
constants.TNS_MSG_TYPE_END_OF_REQUEST) {
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
366
|
+
// Read new packet.
|
|
324
367
|
packet = await this.nsi.recvPacket();
|
|
325
|
-
|
|
368
|
+
|
|
369
|
+
if (!this.nsi.isBreak) {
|
|
370
|
+
this.savedPackets.push(packet);
|
|
371
|
+
}
|
|
326
372
|
}
|
|
327
373
|
}
|
|
328
374
|
this.startPacket(this.savedPackets[this.savedPacketPos++]);
|
|
@@ -447,7 +493,7 @@ class ReadPacket extends BaseBuffer {
|
|
|
447
493
|
if (numBytes !== constants.TNS_LONG_LENGTH_INDICATOR) {
|
|
448
494
|
this.skipBytes(numBytes);
|
|
449
495
|
} else {
|
|
450
|
-
while (true) {
|
|
496
|
+
while (true) {
|
|
451
497
|
const tempNumBytes = this.readUB4();
|
|
452
498
|
if (tempNumBytes === 0)
|
|
453
499
|
break;
|
|
@@ -491,6 +537,33 @@ class WritePacket extends BaseBuffer {
|
|
|
491
537
|
this.packetType = constants.TNS_PACKET_TYPE_DATA;
|
|
492
538
|
this.caps = caps;
|
|
493
539
|
this.nsi = nsi;
|
|
540
|
+
this._dataFlags = 0;
|
|
541
|
+
this.tokenNum = 0;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
_asBuffer(input) {
|
|
545
|
+
if (Buffer.isBuffer(input)) {
|
|
546
|
+
return input;
|
|
547
|
+
}
|
|
548
|
+
if (typeof input === 'string') {
|
|
549
|
+
return Buffer.from(input);
|
|
550
|
+
}
|
|
551
|
+
errors.throwErr(errors.ERR_INTERNAL, 'Expected Buffer or string');
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Writes a 32-bit length, writeUB4 followed by the field if present.
|
|
555
|
+
// For Null input, We just write length as 0.
|
|
556
|
+
_writeBytesWithTwoLengths(input) {
|
|
557
|
+
if (input == null) {
|
|
558
|
+
this.writeUB4(0);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const buf = this._asBuffer(input);
|
|
562
|
+
const length = buf.length;
|
|
563
|
+
this.writeUB4(length);
|
|
564
|
+
if (length > 0) {
|
|
565
|
+
this.writeBytesWithLength(buf);
|
|
566
|
+
}
|
|
494
567
|
}
|
|
495
568
|
|
|
496
569
|
/**
|
|
@@ -518,37 +591,48 @@ class WritePacket extends BaseBuffer {
|
|
|
518
591
|
this.writeUInt8(this.packetType);
|
|
519
592
|
this.writeUInt8(0);
|
|
520
593
|
this.writeUInt16BE(0);
|
|
594
|
+
let flags = this._dataFlags;
|
|
521
595
|
let buf = this.buf.subarray(0, size);
|
|
522
596
|
if (!finalPacket) {
|
|
523
597
|
buf = Buffer.from(buf);
|
|
524
598
|
this.startPacket();
|
|
525
599
|
} else {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
600
|
+
if (this.nsi.pipelineEnabled) {
|
|
601
|
+
// For pipeline mode, next operation would start writing
|
|
602
|
+
// into this.buf. Hence create a copy so that it wont
|
|
603
|
+
// overwrite the contents given to stream.write().
|
|
604
|
+
buf = Buffer.from(buf);
|
|
605
|
+
}
|
|
606
|
+
// Write End of RPC bit in last packet used only for fastAuth Message
|
|
607
|
+
// and in pipeline mode.
|
|
608
|
+
flags |= constants.TNS_DATA_FLAGS_END_OF_REQUEST;
|
|
529
609
|
}
|
|
530
610
|
if (!this.nsi.ntAdapter) {
|
|
531
611
|
errors.throwErr(errors.ERR_INVALID_CONNECTION);
|
|
532
612
|
}
|
|
613
|
+
if (this.packetType === constants.TNS_PACKET_TYPE_DATA) {
|
|
614
|
+
buf.writeUInt16BE(flags, constants.TNS_DATA_FLAGS_OFFSET);
|
|
615
|
+
}
|
|
533
616
|
this.nsi.sendPacket(buf);
|
|
534
617
|
}
|
|
535
618
|
|
|
536
619
|
/**
|
|
537
620
|
* Starts a packet.
|
|
538
621
|
*/
|
|
539
|
-
startPacket(
|
|
622
|
+
startPacket() {
|
|
540
623
|
this.pos = constants.PACKET_HEADER_SIZE;
|
|
541
624
|
if (this.packetType === constants.TNS_PACKET_TYPE_DATA) {
|
|
542
|
-
this.writeUInt16BE(
|
|
625
|
+
this.writeUInt16BE(this._dataFlags);
|
|
543
626
|
}
|
|
544
627
|
}
|
|
545
628
|
|
|
546
629
|
/**
|
|
547
630
|
* Starts a database request.
|
|
548
631
|
*/
|
|
549
|
-
startRequest(packetType
|
|
632
|
+
startRequest(packetType) {
|
|
550
633
|
this.packetType = packetType;
|
|
551
|
-
this.
|
|
634
|
+
this._dataFlags = 0;
|
|
635
|
+
this.startPacket();
|
|
552
636
|
}
|
|
553
637
|
|
|
554
638
|
/**
|
|
@@ -572,6 +656,13 @@ class WritePacket extends BaseBuffer {
|
|
|
572
656
|
this.writeUB4(flags);
|
|
573
657
|
}
|
|
574
658
|
|
|
659
|
+
writeStrKeywordValuePair(key, valueBytes, flags = 0, text) {
|
|
660
|
+
this.writeUB4(flags);
|
|
661
|
+
this._writeBytesWithTwoLengths(key);
|
|
662
|
+
this._writeBytesWithTwoLengths(text);
|
|
663
|
+
this._writeBytesWithTwoLengths(valueBytes);
|
|
664
|
+
}
|
|
665
|
+
|
|
575
666
|
/**
|
|
576
667
|
* Encodes a JavaScript object into OSON and then writes it (QLocator
|
|
577
668
|
* followed by data) to the buffer.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -69,7 +69,7 @@ class Protocol {
|
|
|
69
69
|
async _decodeMessage(message) {
|
|
70
70
|
message.preProcess();
|
|
71
71
|
await this.readBuf.waitForPackets(true);
|
|
72
|
-
while (true) {
|
|
72
|
+
while (true) {
|
|
73
73
|
if (this.nsi.isBreak) {
|
|
74
74
|
await this.resetMessage();
|
|
75
75
|
delete this.readBuf.savedPackets;
|
|
@@ -89,7 +89,31 @@ class Protocol {
|
|
|
89
89
|
throw (err);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async _processPipelineMessage(messageObj, connImpl, continueOnError) {
|
|
95
|
+
let opProcessed = false;
|
|
96
|
+
const { message } = messageObj;
|
|
97
|
+
await this.readBuf.waitForPackets(true);
|
|
98
|
+
try {
|
|
99
|
+
message.preProcess();
|
|
100
|
+
message.decode(this.readBuf);
|
|
101
|
+
opProcessed = true;
|
|
102
|
+
this._checkAndRaiseException(message);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (!opProcessed && !this.connInProgress &&
|
|
105
|
+
err.code !== errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
106
|
+
this.readBuf.resetPackets();
|
|
107
|
+
}
|
|
108
|
+
if (messageObj.statement)
|
|
109
|
+
connImpl._returnStatement(messageObj.statement);
|
|
110
|
+
if (!continueOnError) {
|
|
111
|
+
err.opProcessed = opProcessed;
|
|
112
|
+
throw (err);
|
|
113
|
+
}
|
|
114
|
+
messageObj.pipelineResultImpl.error = err;
|
|
115
|
+
}
|
|
116
|
+
return opProcessed;
|
|
93
117
|
}
|
|
94
118
|
|
|
95
119
|
/**
|
|
@@ -112,6 +136,59 @@ class Protocol {
|
|
|
112
136
|
this.writeBuf.endRequest();
|
|
113
137
|
}
|
|
114
138
|
|
|
139
|
+
_raiseException(message) {
|
|
140
|
+
let err = new Error(message.errorInfo.message);
|
|
141
|
+
err.offset = message.errorInfo.pos;
|
|
142
|
+
err.errorNum = message.errorInfo.num;
|
|
143
|
+
err.isRecoverable = message.errorInfo.isRecoverable;
|
|
144
|
+
err = errors.transformErr(err);
|
|
145
|
+
if (err.code === errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
146
|
+
this.nsi.disconnect();
|
|
147
|
+
}
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_checkAndRaiseException(message) {
|
|
152
|
+
if (message.errorOccurred) {
|
|
153
|
+
this._raiseException(message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Called when all messages for the pipeline have been sent to the
|
|
158
|
+
* database. An end pipeline message is sent to the database and then
|
|
159
|
+
* the responses to all of the messages are processed.
|
|
160
|
+
*/
|
|
161
|
+
async endPipeline(messagesForPipeline, endMessage, connImpl,
|
|
162
|
+
continueOnError) {
|
|
163
|
+
await this._encodeMessage(endMessage);
|
|
164
|
+
|
|
165
|
+
// required for cleanup of response packets
|
|
166
|
+
let numResponsesToDiscard = messagesForPipeline.length + 1;
|
|
167
|
+
try {
|
|
168
|
+
for (const messageObj of messagesForPipeline) {
|
|
169
|
+
const opProcessed = await this._processPipelineMessage(
|
|
170
|
+
messageObj, connImpl, continueOnError);
|
|
171
|
+
if (opProcessed)
|
|
172
|
+
numResponsesToDiscard--;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Process the final message
|
|
176
|
+
await this.readBuf.waitForPackets(true);
|
|
177
|
+
endMessage.process(this.readBuf);
|
|
178
|
+
this._checkAndRaiseException(endMessage);
|
|
179
|
+
numResponsesToDiscard = 0;
|
|
180
|
+
|
|
181
|
+
} catch (err) {
|
|
182
|
+
|
|
183
|
+
// If an operation response was already consumed before failure, account
|
|
184
|
+
// for it before discarding the remaining pipeline responses.
|
|
185
|
+
if (err.opProcessed)
|
|
186
|
+
numResponsesToDiscard--;
|
|
187
|
+
await this.readBuf.discardPipelineResponses(numResponsesToDiscard);
|
|
188
|
+
throw (err);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
115
192
|
async _recoverFromError(caughtErr, message) {
|
|
116
193
|
/*
|
|
117
194
|
* We have NJS error(protocol related) detected during packet write/read
|
|
@@ -119,11 +196,16 @@ class Protocol {
|
|
|
119
196
|
* response as ORA-1013 from the server.
|
|
120
197
|
*/
|
|
121
198
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
199
|
+
if (message.isPipeline) {
|
|
200
|
+
// We just cleanup all pending response packets
|
|
201
|
+
this.readBuf.resetPackets();
|
|
202
|
+
} else {
|
|
203
|
+
this.breakMessage();
|
|
204
|
+
this._breakInProgress = false;
|
|
205
|
+
await this.resetMessage();
|
|
206
|
+
await this.readBuf.waitForPackets();
|
|
207
|
+
message.decode(this.readBuf);
|
|
208
|
+
}
|
|
127
209
|
} catch (err) { // Recovery failed
|
|
128
210
|
this.nsi.disconnect();
|
|
129
211
|
const newErr = errors.getErr(errors.ERR_CONNECTION_CLOSED);
|
|
@@ -134,6 +216,18 @@ class Protocol {
|
|
|
134
216
|
}
|
|
135
217
|
}
|
|
136
218
|
|
|
219
|
+
async _processCallStatus(message) {
|
|
220
|
+
if (message.flushOutBinds) {
|
|
221
|
+
await this.flushOutBindMessage(message);
|
|
222
|
+
}
|
|
223
|
+
this.txnInProgress = Boolean(message.callStatus &
|
|
224
|
+
constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
|
|
225
|
+
// processes the call status flags returned by the server.
|
|
226
|
+
if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
|
|
227
|
+
message.connection.statementCache.clearCursors();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
137
231
|
/**
|
|
138
232
|
*
|
|
139
233
|
* @param {object} message The RPC dynamic structure specific to the RPC
|
|
@@ -159,6 +253,11 @@ class Protocol {
|
|
|
159
253
|
if (traceEnabled) {
|
|
160
254
|
traceContext.operation = `oracledb.${message.constructor.name}`;
|
|
161
255
|
traceInstance.onBeginRoundTrip(traceContext);
|
|
256
|
+
if (traceContext.userContext?.traceParent) {
|
|
257
|
+
// The traceParent is set from instrumentation module.
|
|
258
|
+
message.connection.appContext('CLIENTCONTEXT',
|
|
259
|
+
[{ ora$opentelem$tracectx: traceContext.userContext.traceParent }]);
|
|
260
|
+
}
|
|
162
261
|
}
|
|
163
262
|
await this._encodeMessage(message);
|
|
164
263
|
if (message.messageType !== constants.TNS_MSG_TYPE_ONEWAY_FN) {
|
|
@@ -184,14 +283,7 @@ class Protocol {
|
|
|
184
283
|
traceInstance.onEndRoundTrip(traceContext);
|
|
185
284
|
}
|
|
186
285
|
}
|
|
187
|
-
|
|
188
|
-
await this.flushOutBindMessage(message);
|
|
189
|
-
}
|
|
190
|
-
this.txnInProgress = Boolean(message.callStatus & constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
|
|
191
|
-
// processes the call status flags returned by the server.
|
|
192
|
-
if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
|
|
193
|
-
message.connection.statementCache.clearCursors();
|
|
194
|
-
}
|
|
286
|
+
await this._processCallStatus(message);
|
|
195
287
|
|
|
196
288
|
if (message.errorOccurred) {
|
|
197
289
|
if (callTimeoutExpired) {
|
|
@@ -201,16 +293,9 @@ class Protocol {
|
|
|
201
293
|
message.errorOccurred = false;
|
|
202
294
|
return await this._processMessage(message);
|
|
203
295
|
}
|
|
204
|
-
|
|
205
|
-
err.offset = message.errorInfo.pos;
|
|
206
|
-
err.errorNum = message.errorInfo.num;
|
|
207
|
-
err.isRecoverable = message.errorInfo.isRecoverable;
|
|
208
|
-
err = errors.transformErr(err);
|
|
209
|
-
if (err.code === errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
210
|
-
this.nsi.disconnect();
|
|
211
|
-
}
|
|
212
|
-
throw err;
|
|
296
|
+
this._raiseException(message);
|
|
213
297
|
}
|
|
298
|
+
await message.postProcess();
|
|
214
299
|
}
|
|
215
300
|
|
|
216
301
|
async flushOutBindMessage(message) {
|