oracledb 6.10.0 → 7.0.0

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