oracledb 6.3.0 → 6.4.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 +3 -3
- package/build/Release/oracledb-6.4.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.4.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.4.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.4.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.4.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.4.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/README.md +3 -0
- package/lib/aqQueue.js +8 -8
- package/lib/connection.js +55 -9
- package/lib/constants.js +7 -1
- package/lib/dbObject.js +72 -1
- package/lib/errors.js +27 -8
- package/lib/{thin/protocol → impl/datahandlers}/buffer.js +36 -32
- package/lib/impl/datahandlers/constants.js +105 -0
- package/lib/{thin/protocol → impl/datahandlers}/oson.js +19 -1
- package/lib/impl/datahandlers/vector.js +156 -0
- package/lib/impl/pool.js +9 -0
- package/lib/impl/resultset.js +34 -17
- package/lib/lob.js +22 -6
- package/lib/oracledb.js +24 -0
- package/lib/pool.js +10 -1
- package/lib/poolStatistics.js +3 -1
- package/lib/settings.js +30 -6
- package/lib/sodaDocCursor.js +14 -1
- package/lib/thin/connection.js +100 -144
- package/lib/thin/dbObject.js +4 -2
- package/lib/thin/lob.js +6 -6
- package/lib/thin/pool.js +22 -4
- package/lib/thin/protocol/capabilities.js +3 -1
- package/lib/thin/protocol/constants.js +20 -52
- package/lib/thin/protocol/messages/auth.js +1 -1
- package/lib/thin/protocol/messages/base.js +21 -18
- package/lib/thin/protocol/messages/dataType.js +3 -2
- package/lib/thin/protocol/messages/withData.js +38 -6
- package/lib/thin/protocol/packet.js +58 -4
- package/lib/thin/sqlnet/networkSession.js +13 -1
- package/lib/thin/statement.js +7 -7
- package/lib/thin/statementCache.js +167 -0
- package/lib/transformer.js +13 -4
- package/lib/types.js +12 -2
- package/lib/util.js +29 -0
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/build/Release/oracledb-6.3.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.3.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.3.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.3.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.3.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.3.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.3.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.3.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.3.0-win32-x64.node-buildinfo.txt +0 -1
|
@@ -322,7 +322,7 @@ class AuthMessage extends Message {
|
|
|
322
322
|
|
|
323
323
|
this.conn.dbDomain = this.sessionData['AUTH_SC_DB_DOMAIN'];
|
|
324
324
|
this.conn.dbName = this.sessionData['AUTH_SC_DBUNIQUE_NAME'];
|
|
325
|
-
this.conn.maxOpenCursors = Number(this.sessionData['AUTH_MAX_OPEN_CURSORS']);
|
|
325
|
+
this.conn.maxOpenCursors = Number(this.sessionData['AUTH_MAX_OPEN_CURSORS'] || 0);
|
|
326
326
|
this.conn.serviceName = this.sessionData['AUTH_SC_SERVICE_NAME'];
|
|
327
327
|
this.conn.instanceName = this.sessionData['AUTH_INSTANCENAME'];
|
|
328
328
|
const fullVersionNum = Number(this.sessionData['AUTH_VERSION_NO']);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -90,11 +90,11 @@ class Message {
|
|
|
90
90
|
buf.skipBytesChunked();
|
|
91
91
|
}
|
|
92
92
|
// batch error codes
|
|
93
|
-
|
|
94
|
-
if (
|
|
93
|
+
const numErrors = buf.readUB2(); // batch error codes array
|
|
94
|
+
if (numErrors > 0) {
|
|
95
95
|
this.errorInfo.batchErrors = [];
|
|
96
96
|
const firstByte = buf.readUInt8();
|
|
97
|
-
for (let i = 0; i <
|
|
97
|
+
for (let i = 0; i < numErrors; i++) {
|
|
98
98
|
if (firstByte === constants.TNS_LONG_LENGTH_INDICATOR) {
|
|
99
99
|
buf.skipUB4(); // chunk length ignored
|
|
100
100
|
}
|
|
@@ -107,14 +107,21 @@ class Message {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// batch error offset
|
|
110
|
-
|
|
111
|
-
if (
|
|
110
|
+
const numOffsets = buf.readUB4(); // batch error row offset array
|
|
111
|
+
if (numOffsets > 0) {
|
|
112
|
+
if (numOffsets > 65535) {
|
|
113
|
+
errors.throwErr(errors.ERR_TOO_MANY_BATCH_ERRORS);
|
|
114
|
+
}
|
|
112
115
|
const firstByte = buf.readUInt8();
|
|
113
|
-
|
|
116
|
+
let offset;
|
|
117
|
+
for (let i = 0; i < numOffsets; i++) {
|
|
114
118
|
if (firstByte === constants.TNS_LONG_LENGTH_INDICATOR) {
|
|
115
119
|
buf.skipUB4(); // chunk length ignored
|
|
116
120
|
}
|
|
117
|
-
|
|
121
|
+
offset = buf.readUB4();
|
|
122
|
+
if (i < numErrors) {
|
|
123
|
+
this.errorInfo.batchErrors[i].offset = offset;
|
|
124
|
+
}
|
|
118
125
|
}
|
|
119
126
|
if (firstByte === constants.TNS_LONG_LENGTH_INDICATOR) {
|
|
120
127
|
buf.skipBytes(1); // ignore end marker
|
|
@@ -122,10 +129,10 @@ class Message {
|
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
// batch error messages
|
|
125
|
-
|
|
126
|
-
if (
|
|
132
|
+
const errMsgArr = buf.readUB2(); // batch error messages array
|
|
133
|
+
if (errMsgArr > 0) {
|
|
127
134
|
buf.skipBytes(1); // ignore packed size
|
|
128
|
-
for (let i = 0; i <
|
|
135
|
+
for (let i = 0; i < errMsgArr; i++) {
|
|
129
136
|
buf.skipUB2(); // skip chunk length
|
|
130
137
|
|
|
131
138
|
this.errorInfo.batchErrors[i].message = buf.readStr(constants.CSFRM_IMPLICIT);
|
|
@@ -275,7 +282,7 @@ class Message {
|
|
|
275
282
|
const flags = buf.readUB4(); // session flags
|
|
276
283
|
if (flags & constants.TNS_SESSGET_SESSION_CHANGED) {
|
|
277
284
|
if (this.connection._drcpEstablishSession) {
|
|
278
|
-
this.connection.
|
|
285
|
+
this.connection.statementCache.clearOpenCursors();
|
|
279
286
|
}
|
|
280
287
|
}
|
|
281
288
|
this.connection._drcpEstablishSession = false;
|
|
@@ -290,7 +297,7 @@ class Message {
|
|
|
290
297
|
if (this.connection._currentSchemaModified) {
|
|
291
298
|
this._writeCurrentSchemaPiggyback(buf);
|
|
292
299
|
}
|
|
293
|
-
if (this.connection._cursorsToClose.size > 0 && !this.connection._drcpEstablishSession) {
|
|
300
|
+
if (this.connection.statementCache._cursorsToClose.size > 0 && !this.connection._drcpEstablishSession) {
|
|
294
301
|
this.writeCloseCursorsPiggyBack(buf);
|
|
295
302
|
}
|
|
296
303
|
if (
|
|
@@ -319,11 +326,7 @@ class Message {
|
|
|
319
326
|
writeCloseCursorsPiggyBack(buf) {
|
|
320
327
|
this.writePiggybackHeader(buf, constants.TNS_FUNC_CLOSE_CURSORS);
|
|
321
328
|
buf.writeUInt8(1);
|
|
322
|
-
|
|
323
|
-
for (const cursorNum of this.connection._cursorsToClose.keys()) {
|
|
324
|
-
buf.writeUB4(cursorNum);
|
|
325
|
-
}
|
|
326
|
-
this.connection._cursorsToClose.clear();
|
|
329
|
+
this.connection.statementCache.writeCursorsToClose(buf);
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
writeCloseTempLobsPiggyback(buf) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -392,7 +392,8 @@ const dataTypes = [
|
|
|
392
392
|
[constants.TNS_DATA_TYPE_UDS, constants.TNS_DATA_TYPE_UDS, constants.TNS_TYPE_REP_UNIVERSAL],
|
|
393
393
|
[constants.TNS_DATA_TYPE_TNP, constants.TNS_DATA_TYPE_TNP, constants.TNS_TYPE_REP_UNIVERSAL],
|
|
394
394
|
[constants.TNS_DATA_TYPE_OER, constants.TNS_DATA_TYPE_OER, constants.TNS_TYPE_REP_UNIVERSAL],
|
|
395
|
-
[constants.TNS_DATA_TYPE_OAC, constants.TNS_DATA_TYPE_OAC, constants.TNS_TYPE_REP_UNIVERSAL]
|
|
395
|
+
[constants.TNS_DATA_TYPE_OAC, constants.TNS_DATA_TYPE_OAC, constants.TNS_TYPE_REP_UNIVERSAL],
|
|
396
|
+
[constants.TNS_DATA_TYPE_VECTOR, constants.TNS_DATA_TYPE_VECTOR, constants.TNS_TYPE_REP_UNIVERSAL]
|
|
396
397
|
];
|
|
397
398
|
|
|
398
399
|
module.exports = DataTypeMessage;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -117,7 +117,7 @@ class MessageWithData extends Message {
|
|
|
117
117
|
this.errorOccurred = false;
|
|
118
118
|
this.statement.moreRowsToFetch = false;
|
|
119
119
|
} else if (this.errorInfo.num !== 0 && this.errorInfo.cursorId !== 0) {
|
|
120
|
-
this.connection.statementCache.delete(this.statement.sql);
|
|
120
|
+
this.connection.statementCache._cachedStatements.delete(this.statement.sql);
|
|
121
121
|
this.statement.returnToCache = false;
|
|
122
122
|
}
|
|
123
123
|
if (this.errorInfo.batchErrors) {
|
|
@@ -148,15 +148,16 @@ class MessageWithData extends Message {
|
|
|
148
148
|
buf.skipUB1();
|
|
149
149
|
}
|
|
150
150
|
resultSet.metadata = [];
|
|
151
|
+
const metadata = [];
|
|
152
|
+
const queryVars = [];
|
|
151
153
|
for (let i = 0; i < statement.numQueryVars; i++) {
|
|
152
154
|
const variable = this.processColumnInfo(buf, i + 1);
|
|
153
155
|
if (prevQueryVars && i < prevQueryVars.length) {
|
|
154
156
|
this._adjustFetchType(prevQueryVars[i], variable);
|
|
155
157
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
queryVars.push(variable);
|
|
159
|
+
metadata.push(variable.fetchInfo);
|
|
158
160
|
}
|
|
159
|
-
|
|
160
161
|
let numBytes = buf.readUB4();
|
|
161
162
|
if (numBytes > 0) {
|
|
162
163
|
buf.skipBytesChunked(); // current date
|
|
@@ -170,6 +171,13 @@ class MessageWithData extends Message {
|
|
|
170
171
|
buf.skipBytesChunked();
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
/*
|
|
175
|
+
* The message state(resultSet) and statement state(queryVars) is modified
|
|
176
|
+
* at end of the DescribeInfo function so that an OutOfPacketsError
|
|
177
|
+
* won't cause partial information state to be stored.
|
|
178
|
+
*/
|
|
179
|
+
resultSet.metadata = metadata;
|
|
180
|
+
statement.queryVars = queryVars;
|
|
173
181
|
this.resultSetsToSetup.push(resultSet);
|
|
174
182
|
}
|
|
175
183
|
|
|
@@ -223,6 +231,7 @@ class MessageWithData extends Message {
|
|
|
223
231
|
nullable: nullable
|
|
224
232
|
};
|
|
225
233
|
fetchInfo.isJson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_JSON);
|
|
234
|
+
fetchInfo.isOson = Boolean(udsFlags & constants.TNS_UDS_FLAGS_IS_OSON);
|
|
226
235
|
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) {
|
|
227
236
|
numBytes = buf.readUB4();
|
|
228
237
|
if (numBytes > 0) {
|
|
@@ -254,6 +263,19 @@ class MessageWithData extends Message {
|
|
|
254
263
|
buf.skipUB4(); // flags
|
|
255
264
|
}
|
|
256
265
|
}
|
|
266
|
+
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_4) {
|
|
267
|
+
const dimensions = buf.readUB4();
|
|
268
|
+
const vectorFormat = buf.readUInt8();
|
|
269
|
+
const vectorFlags = buf.readUInt8();
|
|
270
|
+
if (fetchInfo.dbType === types.DB_TYPE_VECTOR) {
|
|
271
|
+
if (!(vectorFlags & constants.VECTOR_META_FLAG_FLEXIBLE_DIM)) {
|
|
272
|
+
fetchInfo.vectorDimensions = dimensions;
|
|
273
|
+
}
|
|
274
|
+
if (vectorFormat !== constants.VECTOR_FORMAT_FLEX) {
|
|
275
|
+
fetchInfo.vectorFormat = vectorFormat;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
257
279
|
|
|
258
280
|
switch (fetchInfo.dbType) {
|
|
259
281
|
case types.DB_TYPE_VARCHAR:
|
|
@@ -481,6 +503,8 @@ class MessageWithData extends Message {
|
|
|
481
503
|
}
|
|
482
504
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) {
|
|
483
505
|
colValue = buf.readOson();
|
|
506
|
+
} else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) {
|
|
507
|
+
colValue = buf.readVector();
|
|
484
508
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_INT_NAMED) {
|
|
485
509
|
const obj = buf.readDbObject();
|
|
486
510
|
if (obj.packedData) {
|
|
@@ -589,7 +613,8 @@ class MessageWithData extends Message {
|
|
|
589
613
|
if (variable.type === types.DB_TYPE_CLOB ||
|
|
590
614
|
variable.type === types.DB_TYPE_NCLOB ||
|
|
591
615
|
variable.type === types.DB_TYPE_BLOB ||
|
|
592
|
-
variable.type === types.DB_TYPE_JSON
|
|
616
|
+
variable.type === types.DB_TYPE_JSON ||
|
|
617
|
+
variable.type === types.DB_TYPE_VECTOR) {
|
|
593
618
|
if (variable.type !== variable.fetchInfo.fetchType) {
|
|
594
619
|
variable.type = variable.fetchInfo.fetchType;
|
|
595
620
|
variable.maxSize = constants.TNS_MAX_LONG_LENGTH;
|
|
@@ -674,6 +699,9 @@ class MessageWithData extends Message {
|
|
|
674
699
|
} else if (variable.type === types.DB_TYPE_JSON) {
|
|
675
700
|
contFlag = constants.TNS_LOB_PREFETCH_FLAG;
|
|
676
701
|
maxSize = lobPrefetchLength = constants.TNS_JSON_MAX_LENGTH;
|
|
702
|
+
} else if (variable.type === types.DB_TYPE_VECTOR) {
|
|
703
|
+
contFlag = constants.TNS_LOB_PREFETCH_FLAG;
|
|
704
|
+
maxSize = lobPrefetchLength = constants.TNS_VECTOR_MAX_LENGTH;
|
|
677
705
|
}
|
|
678
706
|
buf.writeUInt8(oraTypeNum);
|
|
679
707
|
buf.writeUInt8(flag);
|
|
@@ -794,8 +822,10 @@ class MessageWithData extends Message {
|
|
|
794
822
|
) {
|
|
795
823
|
buf.writeOracleDate(value, variable.type);
|
|
796
824
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_BINARY_DOUBLE) {
|
|
825
|
+
buf.writeUInt8(8);
|
|
797
826
|
buf.writeBinaryDouble(value);
|
|
798
827
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_BINARY_FLOAT) {
|
|
828
|
+
buf.writeUInt8(4);
|
|
799
829
|
buf.writeBinaryFloat(value);
|
|
800
830
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_CURSOR) {
|
|
801
831
|
let cursor = value;
|
|
@@ -823,6 +853,8 @@ class MessageWithData extends Message {
|
|
|
823
853
|
buf.writeBytesWithLength(Buffer.from(value));
|
|
824
854
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) {
|
|
825
855
|
buf.writeOson(value);
|
|
856
|
+
} else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) {
|
|
857
|
+
buf.writeVector(value);
|
|
826
858
|
} else if (oraTypeNum === constants.TNS_DATA_TYPE_INT_NAMED) {
|
|
827
859
|
buf.writeDbObject(value);
|
|
828
860
|
} else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -26,11 +26,12 @@
|
|
|
26
26
|
|
|
27
27
|
'use strict';
|
|
28
28
|
|
|
29
|
-
const { BaseBuffer } = require('
|
|
29
|
+
const { BaseBuffer } = require('../../impl/datahandlers/buffer.js');
|
|
30
30
|
const { Buffer } = require('buffer');
|
|
31
|
-
const constants = require(
|
|
32
|
-
const oson = require('
|
|
31
|
+
const constants = require('./constants.js');
|
|
32
|
+
const oson = require('../../impl/datahandlers/oson.js');
|
|
33
33
|
const utils = require('./utils.js');
|
|
34
|
+
const vector = require('../../impl/datahandlers/vector.js');
|
|
34
35
|
const errors = require("../../errors.js");
|
|
35
36
|
|
|
36
37
|
const TNS_BASE64_ALPHABET_ARRAY = Buffer.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 'utf8');
|
|
@@ -395,6 +396,22 @@ class ReadPacket extends BaseBuffer {
|
|
|
395
396
|
return {rba, partitionID, blockNum, slotNum};
|
|
396
397
|
}
|
|
397
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Reads VECTOR data (QLocator followed by data) and decodes it into a
|
|
401
|
+
* JavaScript object.
|
|
402
|
+
*/
|
|
403
|
+
readVector() {
|
|
404
|
+
const numBytes = this.readUB4();
|
|
405
|
+
if (numBytes === 0) {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
this.skipUB8(); // size (unused)
|
|
409
|
+
this.skipUB4(); // chunk size (unused)
|
|
410
|
+
const decoder = new vector.VectorDecoder(this.readBytesWithLength());
|
|
411
|
+
this.skipBytesChunked(); // locator (unused)
|
|
412
|
+
return decoder.decode();
|
|
413
|
+
}
|
|
414
|
+
|
|
398
415
|
skipBytesChunked() {
|
|
399
416
|
const numBytes = this.readUInt8();
|
|
400
417
|
if (numBytes === 0 || numBytes === constants.TNS_NULL_LENGTH_INDICATOR) {
|
|
@@ -479,6 +496,9 @@ class WritePacket extends BaseBuffer {
|
|
|
479
496
|
buf = Buffer.from(buf);
|
|
480
497
|
this.startPacket();
|
|
481
498
|
}
|
|
499
|
+
if (!this.nsi.ntAdapter) {
|
|
500
|
+
errors.throwErr(errors.ERR_INVALID_CONNECTION);
|
|
501
|
+
}
|
|
482
502
|
this.nsi.ntAdapter.send(buf);
|
|
483
503
|
}
|
|
484
504
|
|
|
@@ -537,6 +557,40 @@ class WritePacket extends BaseBuffer {
|
|
|
537
557
|
this.protocol.sequenceId = (this.protocol.sequenceId + 1) % 256;
|
|
538
558
|
}
|
|
539
559
|
|
|
560
|
+
/**
|
|
561
|
+
* Encodes a JavaScript object into VECTOR data and then writes it (QLocator
|
|
562
|
+
* followed by data) to the buffer.
|
|
563
|
+
*/
|
|
564
|
+
writeVector(value) {
|
|
565
|
+
const encoder = new vector.VectorEncoder();
|
|
566
|
+
const buf = encoder.encode(value);
|
|
567
|
+
this.writeQLocator(buf.length);
|
|
568
|
+
this.writeBytesWithLength(buf);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
//---------------------------------------------------------------------------
|
|
572
|
+
// writeQLocator()
|
|
573
|
+
//
|
|
574
|
+
// Writes a QLocator. QLocators are always 40 bytes in length.
|
|
575
|
+
//---------------------------------------------------------------------------
|
|
576
|
+
writeQLocator(numBytes) {
|
|
577
|
+
this.writeUB4(40); // QLocator length
|
|
578
|
+
this.writeUInt8(40); // repeated length
|
|
579
|
+
this.writeUInt16BE(38); // internal length
|
|
580
|
+
this.writeUInt16BE(constants.TNS_LOB_QLOCATOR_VERSION);
|
|
581
|
+
this.writeUInt8(constants.TNS_LOB_LOC_FLAGS_VALUE_BASED |
|
|
582
|
+
constants.TNS_LOB_LOC_FLAGS_BLOB | constants.TNS_LOB_LOC_FLAGS_ABSTRACT);
|
|
583
|
+
this.writeUInt8(constants.TNS_LOB_LOC_FLAGS_INIT);
|
|
584
|
+
this.writeUInt16BE(0); // additional flags
|
|
585
|
+
this.writeUInt16BE(1); // byt1
|
|
586
|
+
this.writeUInt64BE(numBytes);
|
|
587
|
+
this.writeUInt16BE(0); // unused
|
|
588
|
+
this.writeUInt16BE(0); // csid
|
|
589
|
+
this.writeUInt16BE(0); // unused
|
|
590
|
+
this.writeUInt64BE(0); // unused
|
|
591
|
+
this.writeUInt64BE(0); // unused
|
|
592
|
+
}
|
|
593
|
+
|
|
540
594
|
}
|
|
541
595
|
|
|
542
596
|
module.exports = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -530,6 +530,18 @@ class NetworkSession {
|
|
|
530
530
|
await this.connect1(address, addressNode, userConfig);
|
|
531
531
|
}
|
|
532
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Force Disconnect the stream, primarily used
|
|
535
|
+
* to disconnect dead/hung connections.
|
|
536
|
+
*/
|
|
537
|
+
forceDisconnect(err) {
|
|
538
|
+
if (!this.connected) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
this.ntAdapter.stream.destroy(err);
|
|
542
|
+
this.connected = false;
|
|
543
|
+
}
|
|
544
|
+
|
|
533
545
|
/**
|
|
534
546
|
* Disconnect
|
|
535
547
|
* @param {int} type of disconnect
|
package/lib/thin/statement.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -219,10 +219,10 @@ class Parser {
|
|
|
219
219
|
|
|
220
220
|
/**
|
|
221
221
|
* Single line comments consist of two dashes and all characters up to the
|
|
222
|
-
* next line break. This method is called when
|
|
223
|
-
* and checks for the subsequent dash. If found,
|
|
224
|
-
* is traversed and the current position is updated;
|
|
225
|
-
* current position is left untouched.
|
|
222
|
+
* next line break (or the end of the data). This method is called when
|
|
223
|
+
* the first dash is detected and checks for the subsequent dash. If found,
|
|
224
|
+
* the single line comment is traversed and the current position is updated;
|
|
225
|
+
* otherwise, the current position is left untouched.
|
|
226
226
|
*/
|
|
227
227
|
_parseSingleLineComment() {
|
|
228
228
|
let inComment = false;
|
|
@@ -233,15 +233,15 @@ class Parser {
|
|
|
233
233
|
ch = this.sqlData[pos];
|
|
234
234
|
if (!inComment) {
|
|
235
235
|
if (ch !== '-') {
|
|
236
|
-
|
|
236
|
+
return;
|
|
237
237
|
}
|
|
238
238
|
inComment = true;
|
|
239
239
|
} else if (ch === '\n') {
|
|
240
|
-
this.pos = pos;
|
|
241
240
|
break;
|
|
242
241
|
}
|
|
243
242
|
pos += 1;
|
|
244
243
|
}
|
|
244
|
+
this.pos = pos;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
/**
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Copyright (c) 2024, 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
|
+
// Node file defining the StatementCache class used to manage cached statements
|
|
26
|
+
//-----------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
const errors = require("../errors.js");
|
|
29
|
+
const { Statement } = require("./statement");
|
|
30
|
+
|
|
31
|
+
class StatementCache {
|
|
32
|
+
constructor(maxSize) {
|
|
33
|
+
this._cachedStatements = new Map();
|
|
34
|
+
this._maxSize = maxSize;
|
|
35
|
+
this._cursorsToClose = new Set();
|
|
36
|
+
this._openCursors = new Set();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//---------------------------------------------------------------------------
|
|
40
|
+
// _addCursorToClose()
|
|
41
|
+
//
|
|
42
|
+
// Add the statement's cursor to the list of cursors that need to be closed.
|
|
43
|
+
//---------------------------------------------------------------------------
|
|
44
|
+
_addCursorToClose(statement) {
|
|
45
|
+
if (this._cursorsToClose.has(statement.cursorId)) {
|
|
46
|
+
const reason = `attempt to close cursor ${statement.cursorId} twice`;
|
|
47
|
+
errors.throwErr(errors.ERR_INTERNAL, reason);
|
|
48
|
+
}
|
|
49
|
+
if (statement.cursorId != 0) {
|
|
50
|
+
this._cursorsToClose.add(statement.cursorId);
|
|
51
|
+
}
|
|
52
|
+
this._openCursors.delete(statement);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//---------------------------------------------------------------------------
|
|
56
|
+
// _adjustCache()
|
|
57
|
+
// Adjust the cache so that no more than the maximum number of statements
|
|
58
|
+
// are cached by removing least recently used statements
|
|
59
|
+
//---------------------------------------------------------------------------
|
|
60
|
+
_adjustCache() {
|
|
61
|
+
while (this._cachedStatements.size > this._maxSize) {
|
|
62
|
+
const sql = this._cachedStatements.keys().next().value;
|
|
63
|
+
const stmt = this._cachedStatements.get(sql);
|
|
64
|
+
this._cachedStatements.delete(sql);
|
|
65
|
+
if (stmt.inUse) {
|
|
66
|
+
stmt.returnToCache = false;
|
|
67
|
+
} else if (stmt.cursorId !== 0) {
|
|
68
|
+
this._addCursorToClose(stmt);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//---------------------------------------------------------------------------
|
|
74
|
+
//clearOpenCursors() {
|
|
75
|
+
// Clears the list of open cursors and removes the list of cursors that
|
|
76
|
+
// need to be closed. This is required when a DRCP session change has
|
|
77
|
+
// taken place as the cursor ID values are invalidated.
|
|
78
|
+
//---------------------------------------------------------------------------
|
|
79
|
+
clearOpenCursors() {
|
|
80
|
+
const newOpenCursors = new Set();
|
|
81
|
+
for (const stmt of this._openCursors) {
|
|
82
|
+
stmt.cursorId = 0;
|
|
83
|
+
if (stmt.inUse) {
|
|
84
|
+
newOpenCursors.add(stmt);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this._openCursors = newOpenCursors;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//---------------------------------------------------------------------------
|
|
91
|
+
// get_statement()
|
|
92
|
+
// Get a statement from the statement cache, or prepare a new statement
|
|
93
|
+
// for use. If a statement is already in use or the statement is not
|
|
94
|
+
// supposed to be cached, a copy will be made (and not returned to the
|
|
95
|
+
// cache).
|
|
96
|
+
//---------------------------------------------------------------------------
|
|
97
|
+
getStatement(sql, cacheStatement = false) {
|
|
98
|
+
let stmt = null;
|
|
99
|
+
if (sql) {
|
|
100
|
+
stmt = this._cachedStatements.get(sql);
|
|
101
|
+
if (!cacheStatement) {
|
|
102
|
+
this._openCursors.add(stmt);
|
|
103
|
+
this._cachedStatements.delete(sql);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!stmt) {
|
|
107
|
+
stmt = new Statement();
|
|
108
|
+
if (sql) {
|
|
109
|
+
stmt._prepare(sql);
|
|
110
|
+
}
|
|
111
|
+
if (cacheStatement && !stmt.isDdl && this._maxSize > 0) {
|
|
112
|
+
stmt.returnToCache = true;
|
|
113
|
+
this._cachedStatements.set(sql, stmt);
|
|
114
|
+
this._adjustCache();
|
|
115
|
+
}
|
|
116
|
+
this._openCursors.add(stmt);
|
|
117
|
+
} else if (stmt.inUse || !cacheStatement) {
|
|
118
|
+
stmt = stmt._copy();
|
|
119
|
+
this._openCursors.add(stmt);
|
|
120
|
+
} else {
|
|
121
|
+
this._cachedStatements.delete(sql);
|
|
122
|
+
this._cachedStatements.set(sql, stmt);
|
|
123
|
+
}
|
|
124
|
+
stmt.inUse = true;
|
|
125
|
+
return stmt;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//---------------------------------------------------------------------------
|
|
129
|
+
// returnStatement()
|
|
130
|
+
// Return the statement to the statement cache, if applicable. If the
|
|
131
|
+
// statement must not be returned to the statement cache, add the cursor
|
|
132
|
+
// id to the list of cursor ids to close on the next round trip to the
|
|
133
|
+
// database. Clear all bind variables and fetch variables in order to
|
|
134
|
+
// ensure that unnecessary references are not retained.
|
|
135
|
+
//---------------------------------------------------------------------------
|
|
136
|
+
returnStatement(statement) {
|
|
137
|
+
if (statement.bindInfoList) {
|
|
138
|
+
statement.bindInfoList.forEach(bindInfo => {
|
|
139
|
+
bindInfo.bindVar = null;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (statement.queryVars) {
|
|
143
|
+
statement.queryVars.forEach(queryVar => {
|
|
144
|
+
queryVar.values.fill(null);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (statement.returnToCache) {
|
|
148
|
+
statement.inUse = false;
|
|
149
|
+
} else if (statement.cursorId !== 0) {
|
|
150
|
+
this._addCursorToClose(statement);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
//---------------------------------------------------------------------------
|
|
155
|
+
// writeCursorsToClose()
|
|
156
|
+
// Write the list of cursors to close to the buffer.
|
|
157
|
+
//---------------------------------------------------------------------------
|
|
158
|
+
writeCursorsToClose(buf) {
|
|
159
|
+
buf.writeUB4(this._cursorsToClose.size);
|
|
160
|
+
for (const cursorNum of this._cursorsToClose.keys()) {
|
|
161
|
+
buf.writeUB4(cursorNum);
|
|
162
|
+
}
|
|
163
|
+
this._cursorsToClose.clear();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = StatementCache;
|
package/lib/transformer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2023, Oracle and/or its affiliates.
|
|
1
|
+
// Copyright (c) 2023, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -34,6 +34,7 @@ const constants = require('./constants.js');
|
|
|
34
34
|
const errors = require('./errors.js');
|
|
35
35
|
const util = require('util');
|
|
36
36
|
const types = require('./types.js');
|
|
37
|
+
const nodbUtil = require('./util.js');
|
|
37
38
|
|
|
38
39
|
//-----------------------------------------------------------------------------
|
|
39
40
|
// checkType()
|
|
@@ -86,9 +87,9 @@ function transformJsonValue(value) {
|
|
|
86
87
|
|
|
87
88
|
// handle simple scalars
|
|
88
89
|
if (value === undefined || value === null ||
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
typeof value === 'number' || typeof value === 'string' ||
|
|
91
|
+
typeof value === 'boolean' || Buffer.isBuffer(value) ||
|
|
92
|
+
util.isDate(value) || nodbUtil.isVectorValue(value))
|
|
92
93
|
return value;
|
|
93
94
|
|
|
94
95
|
// arrays are transformed to a new array with processed values
|
|
@@ -220,6 +221,14 @@ function transformValueIn(info, value, options) {
|
|
|
220
221
|
checkType(info, options, types.DB_TYPE_OBJECT);
|
|
221
222
|
return value._impl;
|
|
222
223
|
|
|
224
|
+
// handle vectors
|
|
225
|
+
} else if (value instanceof Float32Array || value instanceof Float64Array ||
|
|
226
|
+
value instanceof Int8Array) {
|
|
227
|
+
checkType(info, options, types.DB_TYPE_VECTOR);
|
|
228
|
+
return value;
|
|
229
|
+
} else if (info.type === types.DB_TYPE_VECTOR && Array.isArray(value)) {
|
|
230
|
+
return new Float64Array(value);
|
|
231
|
+
|
|
223
232
|
// handle arrays
|
|
224
233
|
} else if (options.allowArray && Array.isArray(value)) {
|
|
225
234
|
info.isArray = true;
|
package/lib/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2024, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -199,6 +199,9 @@ const DB_TYPE_VARCHAR = new DbType(2001,
|
|
|
199
199
|
const DB_TYPE_XMLTYPE = new DbType(2032,
|
|
200
200
|
"DB_TYPE_XMLTYPE", "XMLTYPE",
|
|
201
201
|
{ oraTypeNum: 109, csfrm: constants.CSFRM_IMPLICIT, bufferSizeFactor: 2147483647 });
|
|
202
|
+
const DB_TYPE_VECTOR = new DbType(2033,
|
|
203
|
+
"DB_TYPE_VECTOR", "VECTOR",
|
|
204
|
+
{ oraTypeNum: 127 });
|
|
202
205
|
|
|
203
206
|
// database type conversion map: the top level key refers to the database
|
|
204
207
|
// type being fetched and the value is another map; this map's key is the
|
|
@@ -276,6 +279,11 @@ const DB_TYPE_CONVERSION_MAP = new Map([
|
|
|
276
279
|
[DB_TYPE_UROWID, new Map([
|
|
277
280
|
[DB_TYPE_VARCHAR, DB_TYPE_ROWID]
|
|
278
281
|
])],
|
|
282
|
+
[DB_TYPE_VECTOR, new Map([
|
|
283
|
+
[DB_TYPE_VARCHAR, DB_TYPE_LONG],
|
|
284
|
+
[DB_TYPE_LONG, DB_TYPE_LONG],
|
|
285
|
+
[DB_TYPE_CLOB, DB_TYPE_CLOB]
|
|
286
|
+
])],
|
|
279
287
|
]);
|
|
280
288
|
|
|
281
289
|
// default fetch type map
|
|
@@ -308,7 +316,8 @@ const DB_TYPE_FETCH_TYPE_MAP = new Map([
|
|
|
308
316
|
[DB_TYPE_TIMESTAMP_TZ, DB_TYPE_TIMESTAMP_TZ],
|
|
309
317
|
[DB_TYPE_UROWID, DB_TYPE_UROWID],
|
|
310
318
|
[DB_TYPE_VARCHAR, DB_TYPE_VARCHAR],
|
|
311
|
-
[DB_TYPE_XMLTYPE, DB_TYPE_XMLTYPE]
|
|
319
|
+
[DB_TYPE_XMLTYPE, DB_TYPE_XMLTYPE],
|
|
320
|
+
[DB_TYPE_VECTOR, DB_TYPE_VECTOR]
|
|
312
321
|
]);
|
|
313
322
|
|
|
314
323
|
// additional aliases for types by column type name
|
|
@@ -353,6 +362,7 @@ module.exports = {
|
|
|
353
362
|
DB_TYPE_TIMESTAMP_TZ,
|
|
354
363
|
DB_TYPE_UROWID,
|
|
355
364
|
DB_TYPE_VARCHAR,
|
|
365
|
+
DB_TYPE_VECTOR,
|
|
356
366
|
DB_TYPE_CONVERSION_MAP,
|
|
357
367
|
DB_TYPE_FETCH_TYPE_MAP,
|
|
358
368
|
DB_TYPE_XMLTYPE,
|