oracledb 6.10.0 → 7.0.1
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.1-darwin-arm64.node +0 -0
- package/build/Release/oracledb-7.0.1-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.1-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.1-linux-arm64.node +0 -0
- package/build/Release/oracledb-7.0.1-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.1-linux-x64.node +0 -0
- package/build/Release/oracledb-7.0.1-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.1-win32-x64.node +0 -0
- package/build/Release/oracledb-7.0.1-win32-x64.node-buildinfo.txt +1 -0
- package/lib/aqDeqOptions.js +4 -4
- package/lib/aqEnqOptions.js +2 -2
- package/lib/aqQueue.js +11 -6
- package/lib/connection.js +407 -40
- package/lib/endUserSecurityContext.js +169 -0
- package/lib/errors.js +108 -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 +447 -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 +461 -53
- package/lib/thin/dbObject.js +10 -4
- package/lib/thin/lob.js +20 -1
- package/lib/thin/pool.js +43 -63
- 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/aqArray.js +2 -2
- package/lib/thin/protocol/messages/aqBase.js +2 -2
- package/lib/thin/protocol/messages/auth.js +6 -1
- package/lib/thin/protocol/messages/base.js +246 -5
- 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 -143
- 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 +4 -4
- package/lib/thin/sqlnet/navNodes.js +4 -2
- package/lib/thin/sqlnet/networkSession.js +78 -50
- package/lib/thin/sqlnet/ntTcp.js +24 -0
- package/lib/thin/sqlnet/nvStrToNvPair.js +50 -25
- package/lib/thin/sqlnet/packet.js +49 -8
- package/lib/thin/sqlnet/paramParser.js +10 -7
- package/lib/thin/sqlnet/sessionAtts.js +2 -2
- 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 +4 -4
- 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
package/lib/connection.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2016,
|
|
1
|
+
// Copyright (c) 2016, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -44,6 +44,11 @@ const settings = require('./settings.js');
|
|
|
44
44
|
const transformer = require('./transformer.js');
|
|
45
45
|
const types = require('./types.js');
|
|
46
46
|
const oson = require('./impl/datahandlers/oson.js');
|
|
47
|
+
const traceHandler = require('./traceHandler.js');
|
|
48
|
+
const EndUserSecurityContext = require('./endUserSecurityContext.js');
|
|
49
|
+
|
|
50
|
+
const APP_CONTEXT_KEY_MAX_BYTES = 128;
|
|
51
|
+
const APP_CONTEXT_VALUE_MAX_BYTES = 4 * 1000;
|
|
47
52
|
|
|
48
53
|
// global mapping of subscriptions; these cannot be tied to a particular
|
|
49
54
|
// connection or pool since subscriptions can be created with one connection
|
|
@@ -58,7 +63,7 @@ const defaultNumberConverter = (v) => (v === null) ? null : parseFloat(v);
|
|
|
58
63
|
//
|
|
59
64
|
// Determines the converter associated with each DB type and its metadata.
|
|
60
65
|
// This function is called once during metadata construction and the
|
|
61
|
-
// converters are invoked when
|
|
66
|
+
// converters are invoked when retrieving DBObject values.
|
|
62
67
|
//---------------------------------------------------------------------------
|
|
63
68
|
function _determineDbObjTypeConverter(metadata, options) {
|
|
64
69
|
// clear any previous converter functions that may have been
|
|
@@ -78,9 +83,8 @@ function _determineDbObjTypeConverter(metadata, options) {
|
|
|
78
83
|
}
|
|
79
84
|
if ([types.DB_TYPE_CLOB, types.DB_TYPE_NCLOB, types.DB_TYPE_BLOB,
|
|
80
85
|
types.DB_TYPE_BFILE].includes(metadata.type)) {
|
|
81
|
-
// converters for
|
|
82
|
-
return errors.
|
|
83
|
-
'DbObjConverter for LOBs');
|
|
86
|
+
// converters for LOBs are not supported.
|
|
87
|
+
return errors.throwNotImplemented('DbObjConverter for LOBs');
|
|
84
88
|
}
|
|
85
89
|
metadata.converter = result.converter;
|
|
86
90
|
}
|
|
@@ -290,6 +294,9 @@ class Connection extends EventEmitter {
|
|
|
290
294
|
// function identifying an object type
|
|
291
295
|
if (bindUnit.type !== undefined) {
|
|
292
296
|
if (typeof bindUnit.type === 'string') {
|
|
297
|
+
if (this._impl.pipelineMode) {
|
|
298
|
+
errors.throwErr(errors.ERR_PIPELINE_DBOBJECTS_NOT_SUPPORTED);
|
|
299
|
+
}
|
|
293
300
|
bindInfo.type = types.DB_TYPE_OBJECT;
|
|
294
301
|
bindInfo.typeClass = await this._getDbObjectClassForName(bindUnit.type);
|
|
295
302
|
bindInfo.objType = bindInfo.typeClass._objType;
|
|
@@ -369,6 +376,8 @@ class Connection extends EventEmitter {
|
|
|
369
376
|
}
|
|
370
377
|
if (bindInfo.type === types.DB_TYPE_OBJECT &&
|
|
371
378
|
bindInfo.typeClass === undefined) {
|
|
379
|
+
if (this._impl.pipelineMode)
|
|
380
|
+
errors.throwErr(errors.ERR_PIPELINE_DBOBJECTS_NOT_SUPPORTED);
|
|
372
381
|
bindInfo.typeClass = await this._getDbObjectClass(value._objType);
|
|
373
382
|
bindInfo.objType = bindInfo.typeClass._objType;
|
|
374
383
|
}
|
|
@@ -830,6 +839,7 @@ class Connection extends EventEmitter {
|
|
|
830
839
|
// If connection is part of a pool, notify the pool of its availability
|
|
831
840
|
if (this._pool) {
|
|
832
841
|
await this._pool._release(this._impl, options);
|
|
842
|
+
traceHandler.getTraceInstance()?.onPoolRelease(this._pool);
|
|
833
843
|
} else {
|
|
834
844
|
await this._impl.close(options);
|
|
835
845
|
}
|
|
@@ -846,15 +856,19 @@ class Connection extends EventEmitter {
|
|
|
846
856
|
this._dbObjectClasses.clear();
|
|
847
857
|
}
|
|
848
858
|
|
|
859
|
+
async _commit() {
|
|
860
|
+
errors.assertArgCount(arguments, 0, 0);
|
|
861
|
+
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
862
|
+
await this._impl.commit();
|
|
863
|
+
}
|
|
864
|
+
|
|
849
865
|
//---------------------------------------------------------------------------
|
|
850
866
|
// commit()
|
|
851
867
|
//
|
|
852
868
|
// Commits the current transaction.
|
|
853
869
|
//---------------------------------------------------------------------------
|
|
854
870
|
async commit() {
|
|
855
|
-
|
|
856
|
-
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
857
|
-
await this._impl.commit();
|
|
871
|
+
await this._commit.apply(this, arguments);
|
|
858
872
|
}
|
|
859
873
|
|
|
860
874
|
//---------------------------------------------------------------------------
|
|
@@ -942,6 +956,27 @@ class Connection extends EventEmitter {
|
|
|
942
956
|
return decoder.decode();
|
|
943
957
|
}
|
|
944
958
|
|
|
959
|
+
setEndUserSecurityContext(context) {
|
|
960
|
+
errors.assertArgCount(arguments, 1, 1);
|
|
961
|
+
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
962
|
+
|
|
963
|
+
if (typeof this.protocol !== 'string' || this.protocol !== 'TCPS') {
|
|
964
|
+
errors.throwErr(errors.ERR_END_USER_SECURITY_CONTEXT_REQUIRES_TCPS);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
errors.assertParamValue(
|
|
968
|
+
context instanceof EndUserSecurityContext,
|
|
969
|
+
1
|
|
970
|
+
);
|
|
971
|
+
|
|
972
|
+
this._impl.setEndUserSecurityContext(context);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
clearEndUserSecurityContext() {
|
|
976
|
+
errors.assertArgCount(arguments, 0, 0);
|
|
977
|
+
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
978
|
+
this._impl.clearEndUserSecurityContext();
|
|
979
|
+
}
|
|
945
980
|
|
|
946
981
|
//---------------------------------------------------------------------------
|
|
947
982
|
// encode()
|
|
@@ -953,12 +988,7 @@ class Connection extends EventEmitter {
|
|
|
953
988
|
return encoder.encode(transformer.transformJsonValue(value), this._impl._osonMaxFieldNameSize);
|
|
954
989
|
}
|
|
955
990
|
|
|
956
|
-
|
|
957
|
-
// execute()
|
|
958
|
-
//
|
|
959
|
-
// Executes a SQL statement and returns the results.
|
|
960
|
-
//---------------------------------------------------------------------------
|
|
961
|
-
async execute(sql, a2, a3) {
|
|
991
|
+
async _processExecuteArgs(sql, a2, a3) {
|
|
962
992
|
const numIters = 1;
|
|
963
993
|
let binds = [];
|
|
964
994
|
let options = {};
|
|
@@ -993,50 +1023,100 @@ class Connection extends EventEmitter {
|
|
|
993
1023
|
}
|
|
994
1024
|
this._addDefaultsToExecOpts(options);
|
|
995
1025
|
|
|
1026
|
+
return {sql, numIters, binds, options, executeManyFlag: false};
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
async _execute() {
|
|
1030
|
+
|
|
1031
|
+
// process arguments
|
|
1032
|
+
const { sql, numIters, binds, options, executeManyFlag } =
|
|
1033
|
+
await this._processExecuteArgs.apply(this, arguments);
|
|
1034
|
+
|
|
996
1035
|
// perform actual execute
|
|
997
1036
|
let result;
|
|
998
1037
|
try {
|
|
999
1038
|
if (this._impl._callLevelTraceData) {
|
|
1000
1039
|
this._impl._callLevelTraceData.statement = sql;
|
|
1001
1040
|
}
|
|
1002
|
-
result = await this._impl.execute(sql, numIters, binds, options,
|
|
1041
|
+
result = await this._impl.execute(sql, numIters, binds, options,
|
|
1042
|
+
executeManyFlag);
|
|
1003
1043
|
} catch (err) {
|
|
1004
1044
|
if (err.errorNum === 1406)
|
|
1005
1045
|
errors.throwErr(errors.ERR_INSUFFICIENT_BUFFER_FOR_BINDS);
|
|
1006
1046
|
throw err;
|
|
1007
1047
|
}
|
|
1008
1048
|
|
|
1009
|
-
|
|
1049
|
+
return await this._transformExecuteResult(result, options);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
//---------------------------------------------------------------------------
|
|
1053
|
+
// execute()
|
|
1054
|
+
//
|
|
1055
|
+
// Executes a SQL statement and returns the results.
|
|
1056
|
+
//---------------------------------------------------------------------------
|
|
1057
|
+
async execute() {
|
|
1058
|
+
return await this._execute.apply(this, arguments);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
async _handleFetchForExecuteInPipeline(result, options) {
|
|
1010
1062
|
if (result.warning) {
|
|
1011
1063
|
result.warning = errors.transformErr(result.warning);
|
|
1012
1064
|
}
|
|
1013
1065
|
|
|
1014
|
-
// process queries; if a result set is not desired, fetch all of the rows
|
|
1015
|
-
// from the result set and then destroy the result set
|
|
1016
1066
|
if (result.resultSet !== undefined) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
result.
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1067
|
+
// just close resultSet for pipelineOp.opType 'execute'
|
|
1068
|
+
// To fetch rows, 'fetch*' used instead in pipeline mode
|
|
1069
|
+
await result.resultSet.close();
|
|
1070
|
+
delete result.resultSet;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
this._processOutBinds(result, options);
|
|
1074
|
+
await this._processImplicitResults(result, options);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
async _handleFetchInPipeline(result, resultSet, fetchOpPipeline) {
|
|
1078
|
+
let shouldClose = false;
|
|
1079
|
+
try {
|
|
1080
|
+
if (fetchOpPipeline.opType === 'fetchOne') {
|
|
1081
|
+
const row = await resultSet._getRow();
|
|
1082
|
+
result.rows = row ? [row] : [];
|
|
1083
|
+
shouldClose = true;
|
|
1084
|
+
} else if (fetchOpPipeline.opType === 'fetchMany') {
|
|
1085
|
+
if (fetchOpPipeline.numRows === 0)
|
|
1086
|
+
result.rows = [];
|
|
1087
|
+
else {
|
|
1088
|
+
const maxRows = resultSet._impl.maxRows;
|
|
1089
|
+
const rowsToFetch = (maxRows > 0) ?
|
|
1090
|
+
Math.min(fetchOpPipeline.numRows, maxRows) :
|
|
1091
|
+
fetchOpPipeline.numRows;
|
|
1092
|
+
result.rows = await resultSet._doGetRows(rowsToFetch);
|
|
1093
|
+
}
|
|
1094
|
+
shouldClose = true;
|
|
1095
|
+
} else
|
|
1096
|
+
// fallback to fetchAll
|
|
1023
1097
|
result.rows = await resultSet._getAllRows();
|
|
1024
|
-
|
|
1025
|
-
|
|
1098
|
+
} finally {
|
|
1099
|
+
if (shouldClose)
|
|
1100
|
+
await resultSet._close();
|
|
1101
|
+
delete result.resultSet;
|
|
1026
1102
|
}
|
|
1103
|
+
}
|
|
1027
1104
|
|
|
1028
|
-
|
|
1105
|
+
_processOutBinds(result, options) {
|
|
1029
1106
|
if (result.outBinds !== undefined) {
|
|
1030
1107
|
for (const [key, value] of Object.entries(result.outBinds)) {
|
|
1031
1108
|
const val = this._transformOutBind(value, options);
|
|
1032
1109
|
result.outBinds[key] = val;
|
|
1033
1110
|
}
|
|
1034
1111
|
}
|
|
1112
|
+
}
|
|
1035
1113
|
|
|
1036
|
-
|
|
1037
|
-
// array size fixed, or, if a result set is not requested, that all rows
|
|
1038
|
-
// are fetched
|
|
1114
|
+
async _processImplicitResults(result, options, fetchOpPipeline) {
|
|
1039
1115
|
if (result.implicitResults) {
|
|
1116
|
+
if (fetchOpPipeline) {
|
|
1117
|
+
delete result.implicitResults;
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1040
1120
|
for (const [key, impl] of Object.entries(result.implicitResults)) {
|
|
1041
1121
|
const resultSet = new ResultSet();
|
|
1042
1122
|
resultSet._setup(this, impl);
|
|
@@ -1047,16 +1127,47 @@ class Connection extends EventEmitter {
|
|
|
1047
1127
|
}
|
|
1048
1128
|
}
|
|
1049
1129
|
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
async _transformExecuteResult(result, options, fetchOpPipeline) {
|
|
1133
|
+
// convert ORA errors to NJS
|
|
1134
|
+
if (result.warning) {
|
|
1135
|
+
result.warning = errors.transformErr(result.warning);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// process queries; if a result set is not desired, fetch all of the rows
|
|
1139
|
+
// from the result set and then destroy the result set
|
|
1140
|
+
if (result.resultSet !== undefined) {
|
|
1141
|
+
const resultSet = new ResultSet();
|
|
1142
|
+
resultSet._setup(this, result.resultSet);
|
|
1143
|
+
result.metaData = resultSet._impl.metaData;
|
|
1144
|
+
if (!fetchOpPipeline) {
|
|
1145
|
+
if (options.resultSet) {
|
|
1146
|
+
result.resultSet = resultSet;
|
|
1147
|
+
} else {
|
|
1148
|
+
// for fetchAll, _getAllRows() get rows from buffered rows and
|
|
1149
|
+
// then perform as many round trips as are required to
|
|
1150
|
+
// complete the fetch
|
|
1151
|
+
result.rows = await resultSet._getAllRows();
|
|
1152
|
+
delete result.resultSet;
|
|
1153
|
+
}
|
|
1154
|
+
} else {
|
|
1155
|
+
await this._handleFetchInPipeline(result, resultSet, fetchOpPipeline);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// process output binds
|
|
1160
|
+
this._processOutBinds(result, options);
|
|
1161
|
+
|
|
1162
|
+
// process implicit results; ensure all implicit results have their fetch
|
|
1163
|
+
// array size fixed, or, if a result set is not requested, that all rows
|
|
1164
|
+
// are fetched
|
|
1165
|
+
await this._processImplicitResults(result, options, fetchOpPipeline);
|
|
1050
1166
|
|
|
1051
1167
|
return (result);
|
|
1052
1168
|
}
|
|
1053
1169
|
|
|
1054
|
-
|
|
1055
|
-
// executeMany()
|
|
1056
|
-
//
|
|
1057
|
-
// Executes a SQL statement multiple times and returns the results.
|
|
1058
|
-
//---------------------------------------------------------------------------
|
|
1059
|
-
async executeMany(sql, bindsOrNumIters, a3) {
|
|
1170
|
+
async _processExecuteManyArgs(sql, bindsOrNumIters, userOptions) {
|
|
1060
1171
|
let options = {};
|
|
1061
1172
|
let binds = [];
|
|
1062
1173
|
let numIters;
|
|
@@ -1064,7 +1175,7 @@ class Connection extends EventEmitter {
|
|
|
1064
1175
|
errors.assertArgCount(arguments, 2, 3);
|
|
1065
1176
|
errors.assertParamValue(typeof sql === 'string', 1);
|
|
1066
1177
|
if (arguments.length == 3) {
|
|
1067
|
-
options = this._verifyExecOpts(
|
|
1178
|
+
options = this._verifyExecOpts(userOptions, true);
|
|
1068
1179
|
}
|
|
1069
1180
|
this._addDefaultsToExecOpts(options);
|
|
1070
1181
|
if (typeof bindsOrNumIters === 'number') {
|
|
@@ -1083,9 +1194,24 @@ class Connection extends EventEmitter {
|
|
|
1083
1194
|
}
|
|
1084
1195
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
1085
1196
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1197
|
+
if (this._impl._callLevelTraceData) {
|
|
1198
|
+
this._impl._callLevelTraceData.statement = sql;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
return {sql, numIters, binds, options, executeManyFlag: true};
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
async _executeMany() {
|
|
1205
|
+
const { sql, numIters, binds, options, executeManyFlag }
|
|
1206
|
+
= await this._processExecuteManyArgs.apply(this, arguments);
|
|
1207
|
+
|
|
1208
|
+
const result = await this._impl.execute(sql, numIters, binds,
|
|
1209
|
+
options, executeManyFlag);
|
|
1088
1210
|
|
|
1211
|
+
return this._transformExecuteManyResult(result, options);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
_transformExecuteManyResult(result, options) {
|
|
1089
1215
|
// convert ORA warnings to NJS
|
|
1090
1216
|
if (result.warning) {
|
|
1091
1217
|
result.warning = errors.transformErr(result.warning);
|
|
@@ -1104,6 +1230,15 @@ class Connection extends EventEmitter {
|
|
|
1104
1230
|
return result;
|
|
1105
1231
|
}
|
|
1106
1232
|
|
|
1233
|
+
//---------------------------------------------------------------------------
|
|
1234
|
+
// executeMany()
|
|
1235
|
+
//
|
|
1236
|
+
// Executes a SQL statement multiple times and returns the results.
|
|
1237
|
+
//---------------------------------------------------------------------------
|
|
1238
|
+
async executeMany() {
|
|
1239
|
+
return await this._executeMany.apply(this, arguments);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1107
1242
|
//---------------------------------------------------------------------------
|
|
1108
1243
|
// externalName
|
|
1109
1244
|
//
|
|
@@ -1139,6 +1274,23 @@ class Connection extends EventEmitter {
|
|
|
1139
1274
|
return this._impl && this._impl.getDbName();
|
|
1140
1275
|
}
|
|
1141
1276
|
|
|
1277
|
+
//---------------------------------------------------------------------------
|
|
1278
|
+
// pdbName (READONLY)
|
|
1279
|
+
//
|
|
1280
|
+
// Property for identifying the container associated with connection.
|
|
1281
|
+
//---------------------------------------------------------------------------
|
|
1282
|
+
get pdbName() {
|
|
1283
|
+
return this._impl && this._impl.getPdbName();
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
//---------------------------------------------------------------------------
|
|
1287
|
+
// dbUniqueName (READONLY)
|
|
1288
|
+
//
|
|
1289
|
+
// Property for identifying the DB_UNIQUE_NAME of the Oracle Database.
|
|
1290
|
+
//---------------------------------------------------------------------------
|
|
1291
|
+
get dbUniqueName() {
|
|
1292
|
+
return this._impl && this._impl.getDbUniqueName();
|
|
1293
|
+
}
|
|
1142
1294
|
//---------------------------------------------------------------------------
|
|
1143
1295
|
// hostName (READONLY)
|
|
1144
1296
|
//
|
|
@@ -1461,7 +1613,7 @@ class Connection extends EventEmitter {
|
|
|
1461
1613
|
//---------------------------------------------------------------------------
|
|
1462
1614
|
// resumeSessionlessTransaction()
|
|
1463
1615
|
//
|
|
1464
|
-
// Resume an existing
|
|
1616
|
+
// Resume an existing sessionless transaction using given transactionId
|
|
1465
1617
|
//---------------------------------------------------------------------------
|
|
1466
1618
|
async resumeSessionlessTransaction(transactionId, options = {}) {
|
|
1467
1619
|
errors.assertArgCount(arguments, 1, 2);
|
|
@@ -1781,6 +1933,157 @@ class Connection extends EventEmitter {
|
|
|
1781
1933
|
await this._impl.tpcRollback(normalizedXid);
|
|
1782
1934
|
}
|
|
1783
1935
|
|
|
1936
|
+
//---------------------------------------------------------------------------
|
|
1937
|
+
// directPathLoad()
|
|
1938
|
+
//
|
|
1939
|
+
// Performs a direct path load into the specified table.
|
|
1940
|
+
//---------------------------------------------------------------------------
|
|
1941
|
+
async directPathLoad(schema, table, columns, data) {
|
|
1942
|
+
errors.assertArgCount(arguments, 4, 5);
|
|
1943
|
+
errors.assertParamValue(typeof schema === 'string', 1);
|
|
1944
|
+
errors.assertParamValue(typeof table === 'string', 2);
|
|
1945
|
+
errors.assertParamValue(Array.isArray(columns) && columns.length, 3);
|
|
1946
|
+
if (!Array.isArray(data) || !data.every(Array.isArray))
|
|
1947
|
+
errors.throwErr(errors.ERR_DPL_INVALID_ROW_DATA);
|
|
1948
|
+
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
1949
|
+
return await this._impl.directPathLoad(schema, table, columns, data);
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
_createFetchTypeHandler(fetchLobs) {
|
|
1953
|
+
if (fetchLobs) {
|
|
1954
|
+
// Returning undefined → default behavior → LOB locators
|
|
1955
|
+
return undefined;
|
|
1956
|
+
}
|
|
1957
|
+
// Auto-fetch LOBs
|
|
1958
|
+
return (metadata) => {
|
|
1959
|
+
switch (metadata.dbType) {
|
|
1960
|
+
case types.DB_TYPE_CLOB:
|
|
1961
|
+
case types.DB_TYPE_NCLOB:
|
|
1962
|
+
return { type: types.DB_TYPE_VARCHAR };
|
|
1963
|
+
|
|
1964
|
+
case types.DB_TYPE_BLOB:
|
|
1965
|
+
return { type: types.DB_TYPE_RAW };
|
|
1966
|
+
|
|
1967
|
+
default:
|
|
1968
|
+
return undefined;
|
|
1969
|
+
}
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
async _runPipelineOpWithoutPipelining(resultImpl) {
|
|
1974
|
+
const op = resultImpl.op;
|
|
1975
|
+
const opType = op.opType;
|
|
1976
|
+
let res = {};
|
|
1977
|
+
if (opType === 'commit') {
|
|
1978
|
+
res = await this._commit();
|
|
1979
|
+
} else if (opType === 'execute') {
|
|
1980
|
+
res = await this._execute(op.statement, op.parameters, op.options);
|
|
1981
|
+
if (res.rows) {
|
|
1982
|
+
res.rows = undefined;
|
|
1983
|
+
}
|
|
1984
|
+
} else if (opType === 'executeMany')
|
|
1985
|
+
res = await this._executeMany(op.statement, op.parameters, op.options);
|
|
1986
|
+
else if (['fetchOne', 'fetchMany', 'fetchAll'].includes(opType)) {
|
|
1987
|
+
|
|
1988
|
+
// Force a ResultSet and then fetch rows according to the requested
|
|
1989
|
+
// fetch variant in non-pipeline flow.
|
|
1990
|
+
op.options.resultSet = true;
|
|
1991
|
+
op.options.fetchTypeHandler = this._createFetchTypeHandler(op.fetchLobs);
|
|
1992
|
+
let shouldClose = false;
|
|
1993
|
+
try {
|
|
1994
|
+
res = await this._execute(op.statement, op.parameters, op.options);
|
|
1995
|
+
if (opType === 'fetchOne') {
|
|
1996
|
+
const row = await res.resultSet._getRow();
|
|
1997
|
+
res.rows = row ? [row] : [];
|
|
1998
|
+
shouldClose = true;
|
|
1999
|
+
} else if (opType === 'fetchMany') {
|
|
2000
|
+
if (op.numRows === 0) {
|
|
2001
|
+
res.rows = [];
|
|
2002
|
+
} else {
|
|
2003
|
+
const maxRows = res.resultSet._impl.maxRows;
|
|
2004
|
+
const rowsToFetch = (maxRows > 0) ?
|
|
2005
|
+
Math.min(op.numRows, maxRows) :
|
|
2006
|
+
op.numRows;
|
|
2007
|
+
res.rows = await res.resultSet._doGetRows(rowsToFetch);
|
|
2008
|
+
}
|
|
2009
|
+
shouldClose = true;
|
|
2010
|
+
} else if (opType === 'fetchAll') {
|
|
2011
|
+
res.rows = await res.resultSet._getAllRows();
|
|
2012
|
+
}
|
|
2013
|
+
} finally {
|
|
2014
|
+
if (shouldClose)
|
|
2015
|
+
await res.resultSet._close();
|
|
2016
|
+
delete res.resultSet;
|
|
2017
|
+
}
|
|
2018
|
+
} else
|
|
2019
|
+
errors.throwErr(errors.ERR_PIPELINE_OPERATION_NOT_SUPPORTED, opType);
|
|
2020
|
+
resultImpl.result = res;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
async _runPipelineWithoutPipelining(resultsImpl, continueOnError) {
|
|
2024
|
+
const savedCallTimeout = this.callTimeout;
|
|
2025
|
+
try {
|
|
2026
|
+
|
|
2027
|
+
// For consistency with protocol-level pipelining, do not enforce
|
|
2028
|
+
// call timeout while executing the fallback non-pipelined flow.
|
|
2029
|
+
if (savedCallTimeout > 0)
|
|
2030
|
+
this.callTimeout = 0;
|
|
2031
|
+
for (const resultImpl of resultsImpl) {
|
|
2032
|
+
try {
|
|
2033
|
+
await this._runPipelineOpWithoutPipelining(resultImpl);
|
|
2034
|
+
} catch (err) {
|
|
2035
|
+
if (!continueOnError)
|
|
2036
|
+
throw (err);
|
|
2037
|
+
resultImpl.error = err;
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
return this._buildPipelineResults(resultsImpl);
|
|
2041
|
+
} finally {
|
|
2042
|
+
if (savedCallTimeout > 0)
|
|
2043
|
+
this.callTimeout = savedCallTimeout;
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
_buildPipelineResults(resultsImpl) {
|
|
2048
|
+
const results = [];
|
|
2049
|
+
for (let i = 0; i < resultsImpl.length; i++) {
|
|
2050
|
+
results[i] = resultsImpl[i].result;
|
|
2051
|
+
if (resultsImpl[i].error) {
|
|
2052
|
+
if (!results[i]) results[i] = {};
|
|
2053
|
+
results[i].error = resultsImpl[i].error;
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
return results;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
//---------------------------------------------------------------------------
|
|
2060
|
+
// runPipeline()
|
|
2061
|
+
//
|
|
2062
|
+
// It runs the list of operations and returns an result array.
|
|
2063
|
+
//---------------------------------------------------------------------------
|
|
2064
|
+
async runPipeline(pipeline, continueOnError = false) {
|
|
2065
|
+
errors.assertArgCount(arguments, 1, 2);
|
|
2066
|
+
errors.assertParamValue(typeof continueOnError === 'boolean', 2);
|
|
2067
|
+
errors.assertParamValue(pipeline?.constructor?.name === 'Pipeline', 1);
|
|
2068
|
+
// validate connection state
|
|
2069
|
+
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
|
2070
|
+
const results = [];
|
|
2071
|
+
for (const op of pipeline.operations) {
|
|
2072
|
+
// sample result (will be filled with corresponding operation result,
|
|
2073
|
+
// like rows, rowsAffected, metadata, error)
|
|
2074
|
+
results.push({op, result: {}});
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
// Use protocol-level pipelining only when the server supports it and
|
|
2078
|
+
// when there is more than one operation to benefit from batching.
|
|
2079
|
+
if (this._impl.supportsPipelining() && pipeline.operations.length > 1)
|
|
2080
|
+
return await this._impl.runPipelineWithPipelining(this, results,
|
|
2081
|
+
continueOnError);
|
|
2082
|
+
else
|
|
2083
|
+
return await this._runPipelineWithoutPipelining(results,
|
|
2084
|
+
continueOnError);
|
|
2085
|
+
}
|
|
2086
|
+
|
|
1784
2087
|
//---------------------------------------------------------------------------
|
|
1785
2088
|
// unsubscribe()
|
|
1786
2089
|
//
|
|
@@ -1800,6 +2103,68 @@ class Connection extends EventEmitter {
|
|
|
1800
2103
|
}, 0);
|
|
1801
2104
|
}
|
|
1802
2105
|
|
|
2106
|
+
//---------------------------------------------------------------------------
|
|
2107
|
+
// appContext()
|
|
2108
|
+
//
|
|
2109
|
+
// Add Application Context, keyValues identified by name, namespaceName.
|
|
2110
|
+
//---------------------------------------------------------------------------
|
|
2111
|
+
appContext(namespaceName, keyValues) {
|
|
2112
|
+
errors.assertArgCount([namespaceName, keyValues], 2, 2);
|
|
2113
|
+
errors.assertParamValue(typeof namespaceName === 'string', 1);
|
|
2114
|
+
if (namespaceName.length === 0) {
|
|
2115
|
+
errors.throwErr(errors.ERR_APP_CONTEXT_EMPTY_NAMESPACE);
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
errors.assertParamValue(Array.isArray(keyValues), 2);
|
|
2119
|
+
|
|
2120
|
+
for (const entry of keyValues) {
|
|
2121
|
+
errors.assertParamValue(nodbUtil.isObject(entry) && !Array.isArray(entry), 2);
|
|
2122
|
+
const entries = Object.entries(entry);
|
|
2123
|
+
const [entryKey, entryValue] = entries[0] ?? [];
|
|
2124
|
+
|
|
2125
|
+
errors.assert(entries.length === 1 &&
|
|
2126
|
+
typeof entryKey === 'string' &&
|
|
2127
|
+
typeof entryValue === 'string',
|
|
2128
|
+
errors.ERR_APP_CONTEXT_INVALID_KEY_VALUE,
|
|
2129
|
+
typeof entryKey,
|
|
2130
|
+
typeof entryValue);
|
|
2131
|
+
|
|
2132
|
+
const keyLength = Buffer.byteLength(entryKey);
|
|
2133
|
+
errors.assert(keyLength <= APP_CONTEXT_KEY_MAX_BYTES,
|
|
2134
|
+
errors.ERR_APP_CONTEXT_KEY_TOO_LONG,
|
|
2135
|
+
keyLength,
|
|
2136
|
+
APP_CONTEXT_KEY_MAX_BYTES);
|
|
2137
|
+
|
|
2138
|
+
const valueLength = Buffer.byteLength(entryValue);
|
|
2139
|
+
errors.assert(valueLength <= APP_CONTEXT_VALUE_MAX_BYTES,
|
|
2140
|
+
errors.ERR_APP_CONTEXT_VALUE_TOO_LONG,
|
|
2141
|
+
valueLength,
|
|
2142
|
+
APP_CONTEXT_VALUE_MAX_BYTES);
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
this._impl.appContext(namespaceName, keyValues);
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
//---------------------------------------------------------------------------
|
|
2149
|
+
// clearAppContext()
|
|
2150
|
+
//
|
|
2151
|
+
// Clears the Application Context, keyValues identified by name.
|
|
2152
|
+
//---------------------------------------------------------------------------
|
|
2153
|
+
clearAppContext(namespaceName) {
|
|
2154
|
+
errors.assertArgCount([namespaceName], 1, 1);
|
|
2155
|
+
errors.assertParamValue(typeof namespaceName === 'string', 1);
|
|
2156
|
+
this._impl.clearAppContext(namespaceName);
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
//---------------------------------------------------------------------------
|
|
2160
|
+
// Symbol.asyncDispose
|
|
2161
|
+
//
|
|
2162
|
+
// Implement explicit resource management.
|
|
2163
|
+
//---------------------------------------------------------------------------
|
|
2164
|
+
async [Symbol.asyncDispose]() {
|
|
2165
|
+
await this.close();
|
|
2166
|
+
}
|
|
2167
|
+
|
|
1803
2168
|
}
|
|
1804
2169
|
|
|
1805
2170
|
// adjust functions to support the old callback style and to serialize calls
|
|
@@ -1815,12 +2180,14 @@ nodbUtil.wrapFns(Connection.prototype,
|
|
|
1815
2180
|
"close",
|
|
1816
2181
|
"commit",
|
|
1817
2182
|
"createLob",
|
|
2183
|
+
"directPathLoad",
|
|
1818
2184
|
"execute",
|
|
1819
2185
|
"executeMany",
|
|
1820
2186
|
"getDbObjectClass",
|
|
1821
2187
|
"getQueue",
|
|
1822
2188
|
"getStatementInfo",
|
|
1823
2189
|
"ping",
|
|
2190
|
+
"runPipeline",
|
|
1824
2191
|
"resumeSessionlessTransaction",
|
|
1825
2192
|
"rollback",
|
|
1826
2193
|
"shutdown",
|