oracledb 6.9.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/aqDeqOptions.js +18 -1
- package/lib/aqQueue.js +10 -6
- package/lib/connection.js +418 -39
- package/lib/dbObject.js +25 -4
- package/lib/endUserSecurityContext.js +176 -0
- package/lib/errors.js +99 -8
- package/lib/impl/aqDeqOptions.js +10 -1
- package/lib/impl/connection.js +76 -2
- package/lib/impl/datahandlers/buffer.js +68 -5
- package/lib/impl/datahandlers/oson.js +7 -2
- 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/impl/sodaDocument.js +5 -14
- package/lib/lob.js +27 -14
- package/lib/obfuscation.js +97 -0
- package/lib/oracledb.js +163 -49
- package/lib/parser.js +204 -0
- package/lib/pipeline.js +113 -0
- package/lib/pool.js +203 -147
- package/lib/poolStatistics.js +1 -1
- package/lib/resultset.js +42 -21
- package/lib/settings.js +1 -0
- package/lib/sodaCollection.js +12 -8
- package/lib/sodaDatabase.js +35 -8
- package/lib/sodaDocument.js +24 -6
- package/lib/sodaOperation.js +7 -6
- package/lib/thin/aq.js +475 -0
- package/lib/thin/connection.js +518 -54
- 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 +21 -4
- package/lib/thin/protocol/constants.js +143 -2
- package/lib/thin/protocol/encryptDecrypt.js +45 -10
- package/lib/thin/protocol/messages/aqArray.js +238 -0
- package/lib/thin/protocol/messages/aqBase.js +305 -0
- package/lib/thin/protocol/messages/aqDeq.js +164 -0
- package/lib/thin/protocol/messages/aqEnq.js +135 -0
- package/lib/thin/protocol/messages/auth.js +18 -28
- 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 +10 -142
- package/lib/thin/protocol/packet.js +120 -28
- 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 +63 -41
- 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 +36 -22
- package/lib/util.js +6 -19
- 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 +7 -5
- package/plugins/token/extensionAzure/index.js +0 -1
- package/plugins/token/extensionOci/index.js +0 -1
- package/build/Release/oracledb-6.9.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-win32-x64.node-buildinfo.txt +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -28,8 +28,43 @@
|
|
|
28
28
|
|
|
29
29
|
const { Buffer } = require('buffer');
|
|
30
30
|
const crypto = require('crypto');
|
|
31
|
+
const errors = require('../../errors.js');
|
|
32
|
+
|
|
33
|
+
const MAX_PBKDF2_ITERATIONS = 100_000;
|
|
34
|
+
|
|
35
|
+
function getPBKDF2Iterations(sessionData, key) {
|
|
36
|
+
const iterations = Number(sessionData[key]);
|
|
37
|
+
if (!Number.isInteger(iterations) || iterations < 1 ||
|
|
38
|
+
iterations > MAX_PBKDF2_ITERATIONS) {
|
|
39
|
+
errors.throwErr(errors.ERR_INVALID_SERVER_RESPONSE);
|
|
40
|
+
}
|
|
41
|
+
return iterations;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveCipherKey(key) {
|
|
45
|
+
if (!Buffer.isBuffer(key)) {
|
|
46
|
+
errors.throwErr(errors.ERR_INTERNAL,
|
|
47
|
+
'Encryption key must be a Buffer');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let cipherAlg;
|
|
51
|
+
switch (key.length) {
|
|
52
|
+
case 16:
|
|
53
|
+
cipherAlg = 'aes-128-cbc';
|
|
54
|
+
break;
|
|
55
|
+
case 24:
|
|
56
|
+
cipherAlg = 'aes-192-cbc';
|
|
57
|
+
break;
|
|
58
|
+
case 32:
|
|
59
|
+
cipherAlg = 'aes-256-cbc';
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
errors.throwErr(errors.ERR_UNSUPPORTED_KEY_LENGTH, key.length);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return cipherAlg;
|
|
66
|
+
}
|
|
31
67
|
|
|
32
|
-
let algorithm = 'aes-256-cbc';
|
|
33
68
|
const _appendBuffer = Buffer.from([0x00, 0x01]);
|
|
34
69
|
|
|
35
70
|
/**
|
|
@@ -40,9 +75,10 @@ class EncryptDecrypt {
|
|
|
40
75
|
|
|
41
76
|
// Key length is dependent on the algorithm. In this case for aes192, it is
|
|
42
77
|
// 24 bytes (192 bits).
|
|
43
|
-
|
|
78
|
+
decrypt(key, val) {
|
|
44
79
|
const iv = Buffer.alloc(16, 0); // Initialization vector, same is used in server
|
|
45
|
-
const
|
|
80
|
+
const cipherAlg = resolveCipherKey(key);
|
|
81
|
+
const decipher = crypto.createDecipheriv(cipherAlg, key, iv);
|
|
46
82
|
decipher.setAutoPadding(false);
|
|
47
83
|
let decrypted = decipher.update(val);
|
|
48
84
|
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
@@ -61,7 +97,8 @@ class EncryptDecrypt {
|
|
|
61
97
|
val = Buffer.concat([val, nv]);
|
|
62
98
|
}
|
|
63
99
|
}
|
|
64
|
-
const
|
|
100
|
+
const cipherAlg = resolveCipherKey(key);
|
|
101
|
+
const cipher = crypto.createCipheriv(cipherAlg, key, iv);
|
|
65
102
|
let encrypted = cipher.update(val);
|
|
66
103
|
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
|
67
104
|
if (!padding) {
|
|
@@ -108,13 +145,11 @@ class EncryptDecrypt {
|
|
|
108
145
|
|
|
109
146
|
const verifierData = Buffer.from(sessionData['AUTH_VFR_DATA'], 'hex');
|
|
110
147
|
const encodedServerKey = Buffer.from(sessionData['AUTH_SESSKEY'], 'hex');
|
|
111
|
-
let iterations = Number(sessionData['AUTH_PBKDF2_VGEN_COUNT']);
|
|
112
148
|
const passwordBytes = Buffer.from(password, 'utf8');
|
|
113
149
|
let passwordHash;
|
|
114
150
|
let passwordKey;
|
|
115
151
|
|
|
116
152
|
if (verifier11G) {
|
|
117
|
-
algorithm = 'aes-192-cbc';
|
|
118
153
|
keyLen = 24;
|
|
119
154
|
hashAlg = 'sha1';
|
|
120
155
|
const h = crypto.createHash(hashAlg);
|
|
@@ -124,9 +159,9 @@ class EncryptDecrypt {
|
|
|
124
159
|
passwordHash = Buffer.alloc(ph.length + 4);
|
|
125
160
|
ph.copy(passwordHash, 0, 0, ph.length);
|
|
126
161
|
} else {
|
|
127
|
-
algorithm = 'aes-256-cbc';
|
|
128
162
|
const temp = Buffer.from('AUTH_PBKDF2_SPEEDY_KEY', 'utf8');
|
|
129
163
|
const salt = Buffer.concat([verifierData, temp]);
|
|
164
|
+
const iterations = getPBKDF2Iterations(sessionData, 'AUTH_PBKDF2_VGEN_COUNT');
|
|
130
165
|
passwordKey = crypto.pbkdf2Sync(passwordBytes, salt, iterations, 64, 'sha512');
|
|
131
166
|
const h = crypto.createHash(hashAlg);
|
|
132
167
|
h.update(passwordKey);
|
|
@@ -138,7 +173,7 @@ class EncryptDecrypt {
|
|
|
138
173
|
if (newPassword) {
|
|
139
174
|
newPasswordBytes = Buffer.from(newPassword, 'utf8');
|
|
140
175
|
}
|
|
141
|
-
const sessionKeyParta = this.
|
|
176
|
+
const sessionKeyParta = this.decrypt(passwordHash, encodedServerKey);
|
|
142
177
|
const sessionKeyPartb = Buffer.alloc(sessionKeyParta.length);
|
|
143
178
|
crypto.randomFillSync(sessionKeyPartb);
|
|
144
179
|
const encodedClientKey = this._encrypt(passwordHash, sessionKeyPartb);
|
|
@@ -155,7 +190,7 @@ class EncryptDecrypt {
|
|
|
155
190
|
} else {
|
|
156
191
|
authObj.sessionKey = encodedClientKey.slice().toString('hex').toUpperCase().slice(0, 64);
|
|
157
192
|
const mixingSalt = Buffer.from(sessionData['AUTH_PBKDF2_CSK_SALT'], 'hex');
|
|
158
|
-
iterations =
|
|
193
|
+
const iterations = getPBKDF2Iterations(sessionData, 'AUTH_PBKDF2_SDER_COUNT');
|
|
159
194
|
const partABKey = Buffer.concat([sessionKeyPartb.slice(0, keyLen), sessionKeyParta.slice(0, keyLen)]);
|
|
160
195
|
const partABKeyStr = partABKey.toString('hex').toUpperCase();
|
|
161
196
|
const partABKeyBuffer = Buffer.from(partABKeyStr, 'utf8');
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Copyright (c) 2025, 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
|
+
//-----------------------------------------------------------------------------
|
|
28
|
+
// aqArray.js
|
|
29
|
+
//
|
|
30
|
+
// This file defines the messages that are sent to the database and the
|
|
31
|
+
// responses that are received by the client for enqueuing and dequeuing
|
|
32
|
+
// an array of AQ messages.
|
|
33
|
+
//-----------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
'use strict';
|
|
36
|
+
|
|
37
|
+
const AqBaseMessage = require("./aqBase.js");
|
|
38
|
+
const constants = require("../constants.js");
|
|
39
|
+
const errors = require("../../../errors.js");
|
|
40
|
+
|
|
41
|
+
class AqArrayMessage extends AqBaseMessage {
|
|
42
|
+
|
|
43
|
+
constructor(connImpl) {
|
|
44
|
+
super(connImpl);
|
|
45
|
+
this.functionCode = constants.TNS_FUNC_ARRAY_AQ;
|
|
46
|
+
this.numIters = 0;
|
|
47
|
+
this.propsImpls = [];
|
|
48
|
+
this.noMsgFound = false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//--------------------------------------------------------------------------
|
|
52
|
+
// processReturnParameter()
|
|
53
|
+
//
|
|
54
|
+
// Process the return parameters of the AQ array enqueue/dequeue request.
|
|
55
|
+
// We recieve all the msg details in deq and in case of enq the msgIds.
|
|
56
|
+
//--------------------------------------------------------------------------
|
|
57
|
+
processReturnParameter(buf) {
|
|
58
|
+
const numIters = buf.readUB4();
|
|
59
|
+
for (let i = 0; i < numIters; i++) {
|
|
60
|
+
const propsImpl = this.propsImpls[i];
|
|
61
|
+
let temp16 = buf.readUB2();
|
|
62
|
+
if (temp16 > 0) {
|
|
63
|
+
buf.skipUB1();
|
|
64
|
+
this._processMsgProps(buf, propsImpl);
|
|
65
|
+
}
|
|
66
|
+
propsImpl.recipients = this._processRecipients(buf);
|
|
67
|
+
temp16 = buf.readUB2();
|
|
68
|
+
if (temp16 > 0) {
|
|
69
|
+
propsImpl.payload = this._processPayload(buf);
|
|
70
|
+
}
|
|
71
|
+
const msgId = buf.readBytesAndLength();// msgIds array
|
|
72
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
73
|
+
for (let j = 0; j < this.propsImpls.length; j++) {
|
|
74
|
+
this.propsImpls[j].msgId = Buffer.from(msgId.slice(j * 16, (j + 1) * 16));
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
propsImpl.msgId = Buffer.from(msgId);
|
|
78
|
+
}
|
|
79
|
+
temp16 = buf.readUB2(); // extensions len
|
|
80
|
+
if (temp16 > 0) {
|
|
81
|
+
errors.throwErr(errors.ERR_NOT_IMPLEMENTED);
|
|
82
|
+
}
|
|
83
|
+
buf.skipUB2(); // output ack
|
|
84
|
+
}
|
|
85
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
86
|
+
this.numIters = buf.readUB4();
|
|
87
|
+
} else {
|
|
88
|
+
this.numIters = numIters;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//--------------------------------------------------------------------------
|
|
93
|
+
// _writeArrayDeq()
|
|
94
|
+
//
|
|
95
|
+
// Writes to the buffer the fields specific to the array dequeue of AQ
|
|
96
|
+
// messages.
|
|
97
|
+
//--------------------------------------------------------------------------
|
|
98
|
+
_writeArrayDeq(buf) {
|
|
99
|
+
let consumerNameBytes = null;
|
|
100
|
+
let correlationBytes = null;
|
|
101
|
+
let conditionBytes = null;
|
|
102
|
+
const queueNameBytes = Buffer.from(this.queueImpl.name);
|
|
103
|
+
const deliveryMode = this.deqOptionsImpl.deliveryMode;
|
|
104
|
+
let flags = 0;
|
|
105
|
+
|
|
106
|
+
if (deliveryMode === constants.TNS_AQ_MSG_BUFFERED) {
|
|
107
|
+
flags |= constants.TNS_KPD_AQ_BUFMSG;
|
|
108
|
+
} else if (deliveryMode === constants.TNS_AQ_MSG_PERSISTENT_OR_BUFFERED) {
|
|
109
|
+
flags |= constants.TNS_KPD_AQ_EITHER;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (this.deqOptionsImpl.consumerName) {
|
|
113
|
+
consumerNameBytes = Buffer.from(this.deqOptionsImpl.consumerName, 'utf-8');
|
|
114
|
+
}
|
|
115
|
+
if (this.deqOptionsImpl.condition) {
|
|
116
|
+
conditionBytes = Buffer.from(this.deqOptionsImpl.condition, 'utf-8');
|
|
117
|
+
}
|
|
118
|
+
if (this.deqOptionsImpl.correlation) {
|
|
119
|
+
correlationBytes = Buffer.from(this.deqOptionsImpl.correlation, 'utf-8');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const propsImpl of this.propsImpls) {
|
|
123
|
+
buf.writeUB4(queueNameBytes.length);
|
|
124
|
+
buf.writeBytesWithLength(queueNameBytes);
|
|
125
|
+
this._writeMsgProps(buf, propsImpl);
|
|
126
|
+
buf.writeUB4(0); // num recipients
|
|
127
|
+
this._writeValueWithLength(buf, consumerNameBytes);
|
|
128
|
+
buf.writeSB4(this.deqOptionsImpl.mode);
|
|
129
|
+
buf.writeSB4(this.deqOptionsImpl.navigation);
|
|
130
|
+
buf.writeSB4(this.deqOptionsImpl.visibility);
|
|
131
|
+
buf.writeSB4(this.deqOptionsImpl.wait);
|
|
132
|
+
this._writeValueWithLength(buf, this.deqOptionsImpl.msgid);
|
|
133
|
+
this._writeValueWithLength(buf, correlationBytes);
|
|
134
|
+
this._writeValueWithLength(buf, conditionBytes);
|
|
135
|
+
buf.writeUB4(0); // extensions
|
|
136
|
+
buf.writeUB4(0); // rel msg id
|
|
137
|
+
buf.writeSB4(0); // seq deviation
|
|
138
|
+
buf.writeUB4(16); // toid length
|
|
139
|
+
buf.writeBytesWithLength(this.queueImpl.payloadToid);
|
|
140
|
+
buf.writeUB2(constants.TNS_AQ_MESSAGE_VERSION);
|
|
141
|
+
buf.writeUB4(0); // payload length
|
|
142
|
+
buf.writeUB4(0); // raw pay length
|
|
143
|
+
buf.writeUB4(0);
|
|
144
|
+
buf.writeUB4(flags); // deliveryMode flag
|
|
145
|
+
buf.writeUB4(0); // extensions len
|
|
146
|
+
buf.writeUB4(0); // source seq len
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//--------------------------------------------------------------------------
|
|
151
|
+
// _writeArrayEnq()
|
|
152
|
+
//
|
|
153
|
+
// Writes input parameters in case of array enqueue.
|
|
154
|
+
//--------------------------------------------------------------------------
|
|
155
|
+
_writeArrayEnq(buf) {
|
|
156
|
+
const queueNameBytes = Buffer.from(this.queueImpl.name);
|
|
157
|
+
const deliveryMode = this.enqOptionsImpl.deliveryMode;
|
|
158
|
+
let flags = 0;
|
|
159
|
+
|
|
160
|
+
if (deliveryMode === constants.TNS_AQ_MSG_BUFFERED) {
|
|
161
|
+
flags |= constants.TNS_KPD_AQ_BUFMSG;
|
|
162
|
+
} else if (deliveryMode === constants.TNS_AQ_MSG_PERSISTENT_OR_BUFFERED) {
|
|
163
|
+
flags |= constants.TNS_KPD_AQ_EITHER;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
buf.writeUB4(0); // rel msgid len
|
|
167
|
+
buf.writeUInt8(constants.TNS_MSG_TYPE_ROW_HEADER);
|
|
168
|
+
buf.writeUB4(queueNameBytes.length);
|
|
169
|
+
buf.writeBytesWithLength(queueNameBytes);
|
|
170
|
+
buf.writeBytes(this.queueImpl.payloadToid);
|
|
171
|
+
buf.writeUB2(constants.TNS_AQ_MESSAGE_VERSION);
|
|
172
|
+
buf.writeUB4(flags);
|
|
173
|
+
|
|
174
|
+
for (const propsImpl of this.propsImpls) {
|
|
175
|
+
buf.writeUInt8(constants.TNS_MSG_TYPE_ROW_DATA);
|
|
176
|
+
buf.writeUB4(flags); // aqi flags
|
|
177
|
+
this._writeMsgProps(buf, propsImpl);
|
|
178
|
+
if (propsImpl.recipients === null || propsImpl.recipients.length === 0) {
|
|
179
|
+
buf.writeUB4(0); // num recipients
|
|
180
|
+
} else {
|
|
181
|
+
buf.writeUB4(3 * propsImpl.recipients.length);
|
|
182
|
+
this._writeRecipients(buf, propsImpl);
|
|
183
|
+
}
|
|
184
|
+
buf.writeSB4(this.enqOptionsImpl.visibility);
|
|
185
|
+
buf.writeUB4(0); // relative msg id
|
|
186
|
+
buf.writeSB4(0); // seq deviation
|
|
187
|
+
if (!this.queueImpl.payloadTypeClass && !this.queueImpl.isJson) {
|
|
188
|
+
buf.writeUB4(propsImpl.payload.length);
|
|
189
|
+
}
|
|
190
|
+
this._writePayload(buf, propsImpl);
|
|
191
|
+
}
|
|
192
|
+
buf.writeUInt8(constants.TNS_MSG_TYPE_STATUS);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//--------------------------------------------------------------------------
|
|
196
|
+
// _writeMessageBody()
|
|
197
|
+
//
|
|
198
|
+
// Writes the body of the message to the buffer.
|
|
199
|
+
//--------------------------------------------------------------------------
|
|
200
|
+
encode(buf) {
|
|
201
|
+
this.writeFunctionHeader(buf);
|
|
202
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
203
|
+
buf.writeUInt8(0); // input params
|
|
204
|
+
buf.writeUB4(0); // length
|
|
205
|
+
} else {
|
|
206
|
+
buf.writeUInt8(1);
|
|
207
|
+
buf.writeUB4(this.numIters);
|
|
208
|
+
}
|
|
209
|
+
buf.writeUB4(constants.TNS_AQ_ARRAY_FLAGS_RETURN_MESSAGE_ID);
|
|
210
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
211
|
+
buf.writeUInt8(1); // output params
|
|
212
|
+
buf.writeUInt8(0); // length
|
|
213
|
+
} else {
|
|
214
|
+
buf.writeUInt8(1);
|
|
215
|
+
buf.writeUInt8(1);
|
|
216
|
+
}
|
|
217
|
+
buf.writeSB4(this.operation);
|
|
218
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
219
|
+
buf.writeUInt8(1); // num iters (pointer)
|
|
220
|
+
} else {
|
|
221
|
+
buf.writeUInt8(0);
|
|
222
|
+
}
|
|
223
|
+
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_21_1) {
|
|
224
|
+
buf.writeUB4(0xffff); // shard id
|
|
225
|
+
}
|
|
226
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
227
|
+
buf.writeUB4(this.numIters);
|
|
228
|
+
}
|
|
229
|
+
if (this.operation === constants.TNS_AQ_ARRAY_ENQ) {
|
|
230
|
+
this._writeArrayEnq(buf);
|
|
231
|
+
} else {
|
|
232
|
+
this._writeArrayDeq(buf);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = AqArrayMessage;
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// Copyright (c) 2025, 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
|
+
//-----------------------------------------------------------------------------
|
|
28
|
+
// aqBase.js
|
|
29
|
+
//
|
|
30
|
+
// This file defines the base class for messages that are sent to the
|
|
31
|
+
// database and the responses that are received by the client for enqueuing and
|
|
32
|
+
// dequeuing AQ messages.
|
|
33
|
+
//-----------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
'use strict';
|
|
36
|
+
|
|
37
|
+
const constants = require("../constants.js");
|
|
38
|
+
const errors = require("../../../errors.js");
|
|
39
|
+
const BaseMessage = require("./base.js");
|
|
40
|
+
const { ThinDbObjectImpl } = require("../../dbObject.js");
|
|
41
|
+
const oson = require('../../../impl/datahandlers/oson.js');
|
|
42
|
+
|
|
43
|
+
class AqBaseMessage extends BaseMessage {
|
|
44
|
+
|
|
45
|
+
constructor(connImpl) {
|
|
46
|
+
super(connImpl);
|
|
47
|
+
this.queueImpl = null;
|
|
48
|
+
this.deqOptionsImpl = null;
|
|
49
|
+
this.enqOptionsImpl = null;
|
|
50
|
+
this.noMsgFound = false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//--------------------------------------------------------------------------
|
|
54
|
+
// _processDate()
|
|
55
|
+
//
|
|
56
|
+
// Processes a date found in the buffer.
|
|
57
|
+
//--------------------------------------------------------------------------
|
|
58
|
+
_processDate(buf) {
|
|
59
|
+
const numBytes = buf.readUB4();
|
|
60
|
+
if (numBytes > 0)
|
|
61
|
+
return buf.readOracleDate(true);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//--------------------------------------------------------------------------
|
|
65
|
+
// _processErrorInfo()
|
|
66
|
+
//
|
|
67
|
+
// Process error information from the buffer. If the error that indicates
|
|
68
|
+
// that no messages were received is detected, the error is cleared and
|
|
69
|
+
// the flag set so that the dequeue can handle that case.
|
|
70
|
+
//--------------------------------------------------------------------------
|
|
71
|
+
processErrorInfo(buf) {
|
|
72
|
+
super.processErrorInfo(buf);
|
|
73
|
+
if (this.errorInfo.num === constants.TNS_ERR_NO_MESSAGES_FOUND) {
|
|
74
|
+
this.errorInfo.num = 0;
|
|
75
|
+
this.errorOccurred = false;
|
|
76
|
+
this.noMsgFound = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//--------------------------------------------------------------------------
|
|
81
|
+
// _processExtensions()
|
|
82
|
+
//
|
|
83
|
+
// Processes extensions to the message property object returned by the
|
|
84
|
+
// database.
|
|
85
|
+
//--------------------------------------------------------------------------
|
|
86
|
+
_processExtensions(buf, propsImpl) {
|
|
87
|
+
const numExtensions = buf.readUB4();
|
|
88
|
+
if (numExtensions > 0) {
|
|
89
|
+
buf.skipUB1();
|
|
90
|
+
for (let i = 0; i < numExtensions; i++) {
|
|
91
|
+
const textValue = buf.readBytesAndLength();
|
|
92
|
+
const binaryValue = buf.readBytesAndLength();
|
|
93
|
+
const value = textValue || binaryValue;
|
|
94
|
+
const keyword = buf.readUB2();
|
|
95
|
+
if (value) {
|
|
96
|
+
if (keyword === constants.TNS_AQ_EXT_KEYWORD_AGENT_NAME) {
|
|
97
|
+
propsImpl.senderAgentName = value;
|
|
98
|
+
} else if (keyword === constants.TNS_AQ_EXT_KEYWORD_AGENT_ADDRESS) {
|
|
99
|
+
propsImpl.senderAgentAddress = value;
|
|
100
|
+
} else if (keyword === constants.TNS_AQ_EXT_KEYWORD_AGENT_PROTOCOL) {
|
|
101
|
+
propsImpl.senderAgentProtocol = value[0];
|
|
102
|
+
} else if (keyword === constants.TNS_AQ_EXT_KEYWORD_ORIGINAL_MSGID) {
|
|
103
|
+
propsImpl.originalMsgId = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//--------------------------------------------------------------------------
|
|
111
|
+
// _processMsgId()
|
|
112
|
+
//
|
|
113
|
+
// Reads a message id from the buffer and returns it.
|
|
114
|
+
//--------------------------------------------------------------------------
|
|
115
|
+
_processMsgId(buf) {
|
|
116
|
+
return Buffer.from(buf.readBytes(constants.TNS_AQ_MESSAGE_ID_LENGTH));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//--------------------------------------------------------------------------
|
|
120
|
+
// _processMsgProps()
|
|
121
|
+
//
|
|
122
|
+
// Processes a message property object returned by the database.
|
|
123
|
+
//--------------------------------------------------------------------------
|
|
124
|
+
_processMsgProps(buf, propsImpl) {
|
|
125
|
+
propsImpl.priority = buf.readSB4();
|
|
126
|
+
propsImpl.delay = buf.readSB4();
|
|
127
|
+
propsImpl.expiration = buf.readSB4();
|
|
128
|
+
propsImpl.correlation = buf.readStrAndLength();
|
|
129
|
+
propsImpl.numAttempts = buf.readSB4();
|
|
130
|
+
propsImpl.exceptionQueue = buf.readStrAndLength();
|
|
131
|
+
propsImpl.state = buf.readSB4();
|
|
132
|
+
propsImpl.enqTime = this._processDate(buf);
|
|
133
|
+
propsImpl.enqTxnId = buf.readBytesAndLength();
|
|
134
|
+
this._processExtensions(buf, propsImpl);
|
|
135
|
+
const temp32 = buf.readUB4(); // user properties
|
|
136
|
+
if (temp32 > 0) {
|
|
137
|
+
errors.throwErr(errors.ERR_NOT_IMPLEMENTED);
|
|
138
|
+
}
|
|
139
|
+
buf.skipUB4(); // csn
|
|
140
|
+
buf.skipUB4(); // dsn
|
|
141
|
+
const flags = buf.readUB4();
|
|
142
|
+
if (flags === constants.TNS_KPD_AQ_BUFMSG) {
|
|
143
|
+
propsImpl.deliveryMode = constants.TNS_AQ_MSG_BUFFERED;
|
|
144
|
+
} else {
|
|
145
|
+
propsImpl.deliveryMode = constants.TNS_AQ_MSG_PERSISTENT;
|
|
146
|
+
}
|
|
147
|
+
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_21_1) {
|
|
148
|
+
buf.skipUB4(); // shard number
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//--------------------------------------------------------------------------
|
|
153
|
+
// _processPayload()
|
|
154
|
+
//
|
|
155
|
+
// Processes the payload for an enqueued message returned by the database.
|
|
156
|
+
//--------------------------------------------------------------------------
|
|
157
|
+
_processPayload(buf) {
|
|
158
|
+
const payloadData = buf.readDbObject();
|
|
159
|
+
if (this.queueImpl.payloadTypeClass) {
|
|
160
|
+
const obj = new this.queueImpl.payloadTypeClass();
|
|
161
|
+
const objImpl = new ThinDbObjectImpl(this.queueImpl.payloadTypeClass,
|
|
162
|
+
payloadData.packedData);
|
|
163
|
+
if (payloadData) {
|
|
164
|
+
objImpl.toid = payloadData.toid;
|
|
165
|
+
objImpl.oid = payloadData.oid;
|
|
166
|
+
}
|
|
167
|
+
obj._impl = objImpl;
|
|
168
|
+
return obj;
|
|
169
|
+
} else {
|
|
170
|
+
if (payloadData.packedData) {
|
|
171
|
+
const payload = Buffer.from(payloadData.packedData.slice(4));
|
|
172
|
+
if (this.queueImpl.isJson) {
|
|
173
|
+
const decoder = new oson.OsonDecoder(payload);
|
|
174
|
+
return decoder.decode();
|
|
175
|
+
}
|
|
176
|
+
return payload;
|
|
177
|
+
} else if (!this.queueImpl.isJson) {
|
|
178
|
+
return Buffer.alloc(0);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//--------------------------------------------------------------------------
|
|
184
|
+
// _processRecipients()
|
|
185
|
+
//
|
|
186
|
+
// Process recipients for a message.
|
|
187
|
+
//--------------------------------------------------------------------------
|
|
188
|
+
_processRecipients(buf) {
|
|
189
|
+
const numRecipients = buf.readUB4();
|
|
190
|
+
if (numRecipients > 0)
|
|
191
|
+
errors.throwNotImplemented('aq recipients');
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//--------------------------------------------------------------------------
|
|
196
|
+
// _writeMsgProps()
|
|
197
|
+
//
|
|
198
|
+
// Write a message property object to the buffer.
|
|
199
|
+
//--------------------------------------------------------------------------
|
|
200
|
+
_writeMsgProps(buf, propsImpl) {
|
|
201
|
+
buf.writeSB4(propsImpl.priority);
|
|
202
|
+
buf.writeSB4(propsImpl.delay);
|
|
203
|
+
buf.writeSB4(propsImpl.expiration);
|
|
204
|
+
this._writeValueWithLength(buf, propsImpl.correlation);
|
|
205
|
+
buf.writeUB4(0); // number of attempts
|
|
206
|
+
this._writeValueWithLength(buf, propsImpl.exceptionQueue);
|
|
207
|
+
buf.writeUB4(propsImpl.state);
|
|
208
|
+
buf.writeUB4(0); // enqueue time length
|
|
209
|
+
this._writeValueWithLength(buf, propsImpl.enqTxnId);
|
|
210
|
+
buf.writeUB4(4); // number of extensions
|
|
211
|
+
buf.writeUInt8(0x0e); // unknown extra byte
|
|
212
|
+
|
|
213
|
+
this._writeKeywordValuePair(buf, null, null,
|
|
214
|
+
constants.TNS_AQ_EXT_KEYWORD_AGENT_NAME);
|
|
215
|
+
this._writeKeywordValuePair(buf, null, null,
|
|
216
|
+
constants.TNS_AQ_EXT_KEYWORD_AGENT_ADDRESS);
|
|
217
|
+
this._writeKeywordValuePair(buf, null, Buffer.from([0x00]),
|
|
218
|
+
constants.TNS_AQ_EXT_KEYWORD_AGENT_PROTOCOL);
|
|
219
|
+
this._writeKeywordValuePair(buf, null, null,
|
|
220
|
+
constants.TNS_AQ_EXT_KEYWORD_ORIGINAL_MSGID);
|
|
221
|
+
|
|
222
|
+
buf.writeUB4(0); // user property
|
|
223
|
+
buf.writeUB4(0); // cscn
|
|
224
|
+
buf.writeUB4(0); // dscn
|
|
225
|
+
buf.writeUB4(0); // flags
|
|
226
|
+
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_21_1) {
|
|
227
|
+
buf.writeUB4(0xffffffff); // shard id
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
//--------------------------------------------------------------------------
|
|
232
|
+
// _writePayload()
|
|
233
|
+
//
|
|
234
|
+
// Writes the payload of the message property object to the buffer.
|
|
235
|
+
//--------------------------------------------------------------------------
|
|
236
|
+
_writePayload(buf, propsImpl) {
|
|
237
|
+
if (this.queueImpl.isJson) {
|
|
238
|
+
buf.writeOson(propsImpl.payload, this.connection._osonMaxFieldNameSize,
|
|
239
|
+
false);
|
|
240
|
+
} else if (this.queueImpl.payloadTypeClass) {
|
|
241
|
+
buf.writeDbObject(propsImpl.payload);
|
|
242
|
+
} else {
|
|
243
|
+
buf.writeBytes(propsImpl.payload);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
//--------------------------------------------------------------------------
|
|
248
|
+
// _writeRecipients()
|
|
249
|
+
//
|
|
250
|
+
// Write the recipient list of the message property object to the buffer.
|
|
251
|
+
//--------------------------------------------------------------------------
|
|
252
|
+
_writeRecipients(buf, propsImpl) {
|
|
253
|
+
let index = 0;
|
|
254
|
+
for (const recipient of propsImpl.recipients) {
|
|
255
|
+
this._writeKeywordValuePair(buf, recipient, null, index);
|
|
256
|
+
this._writeKeywordValuePair(buf, null, null, index + 1);
|
|
257
|
+
this._writeKeywordValuePair(buf, null, Buffer.from([0x00]), index + 2);
|
|
258
|
+
index += 3;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
//--------------------------------------------------------------------------
|
|
263
|
+
// _writeValueWithLength()
|
|
264
|
+
//
|
|
265
|
+
// Write a string to the buffer, prefixed by a length.
|
|
266
|
+
//--------------------------------------------------------------------------
|
|
267
|
+
_writeValueWithLength(buf, value) {
|
|
268
|
+
if (!value) {
|
|
269
|
+
buf.writeUB4(0);
|
|
270
|
+
} else {
|
|
271
|
+
const valueBytes = Buffer.isBuffer(value) ?
|
|
272
|
+
value : Buffer.from(value, 'utf-8');
|
|
273
|
+
buf.writeUB4(valueBytes.length);
|
|
274
|
+
buf.writeBytesWithLength(valueBytes);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//--------------------------------------------------------------------------
|
|
279
|
+
// _writeKeywordValuePair()
|
|
280
|
+
//
|
|
281
|
+
// Writes a keyword value pair to the buffer.
|
|
282
|
+
//--------------------------------------------------------------------------
|
|
283
|
+
_writeKeywordValuePair(buf, textValue, binaryValue, keyword) {
|
|
284
|
+
let textValueBytes;
|
|
285
|
+
if (!textValue) {
|
|
286
|
+
buf.writeUB4(0);
|
|
287
|
+
} else {
|
|
288
|
+
textValueBytes = Buffer.from(textValue);
|
|
289
|
+
buf.writeUB4(textValueBytes.length);
|
|
290
|
+
buf.writeBytesWithLength(textValueBytes);
|
|
291
|
+
}
|
|
292
|
+
if (!binaryValue) {
|
|
293
|
+
buf.writeUB4(0);
|
|
294
|
+
} else {
|
|
295
|
+
buf.writeUB4(binaryValue.length);
|
|
296
|
+
buf.writeBytesWithLength(binaryValue);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
buf.writeUB2(keyword);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
module.exports = AqBaseMessage;
|