oracledb 6.5.0 → 6.6.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 (59) hide show
  1. package/README.md +2 -2
  2. package/build/Release/oracledb-6.6.0-darwin-arm64.node +0 -0
  3. package/build/Release/oracledb-6.6.0-darwin-arm64.node-buildinfo.txt +1 -0
  4. package/build/Release/oracledb-6.6.0-darwin-x64.node +0 -0
  5. package/build/Release/oracledb-6.6.0-darwin-x64.node-buildinfo.txt +1 -0
  6. package/build/Release/oracledb-6.6.0-js-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-6.6.0-linux-arm64.node +0 -0
  8. package/build/Release/oracledb-6.6.0-linux-arm64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.6.0-linux-x64.node +0 -0
  10. package/build/Release/oracledb-6.6.0-linux-x64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.6.0-win32-x64.node +0 -0
  12. package/build/Release/oracledb-6.6.0-win32-x64.node-buildinfo.txt +1 -0
  13. package/examples/README.md +4 -0
  14. package/lib/configProviders/azure.js +167 -0
  15. package/lib/configProviders/base.js +99 -0
  16. package/lib/configProviders/ociobject.js +203 -0
  17. package/lib/connection.js +28 -12
  18. package/lib/constants.js +1 -0
  19. package/lib/errors.js +68 -1
  20. package/lib/impl/datahandlers/buffer.js +2 -2
  21. package/lib/impl/datahandlers/constants.js +3 -1
  22. package/lib/impl/datahandlers/vector.js +24 -9
  23. package/lib/impl/lob.js +27 -0
  24. package/lib/impl/resultset.js +26 -1
  25. package/lib/lob.js +52 -1
  26. package/lib/oracledb.js +61 -34
  27. package/lib/pool.js +7 -0
  28. package/lib/thin/connection.js +232 -16
  29. package/lib/thin/dbObject.js +4 -0
  30. package/lib/thin/lob.js +193 -1
  31. package/lib/thin/pool.js +15 -0
  32. package/lib/thin/protocol/capabilities.js +2 -0
  33. package/lib/thin/protocol/constants.js +30 -1
  34. package/lib/thin/protocol/messages/index.js +5 -1
  35. package/lib/thin/protocol/messages/lobOp.js +17 -5
  36. package/lib/thin/protocol/messages/transactionChangeState.js +99 -0
  37. package/lib/thin/protocol/messages/transactionSwitch.js +139 -0
  38. package/lib/thin/protocol/messages/withData.js +37 -8
  39. package/lib/thin/protocol/protocol.js +4 -0
  40. package/lib/thin/sqlnet/networkSession.js +2 -1
  41. package/lib/thin/sqlnet/packet.js +3 -1
  42. package/lib/thin/sqlnet/paramParser.js +87 -50
  43. package/lib/thin/sqlnet/sessionAtts.js +13 -1
  44. package/lib/thin/statement.js +4 -0
  45. package/lib/thin/statementCache.js +5 -0
  46. package/lib/transformer.js +1 -2
  47. package/lib/types.js +1 -1
  48. package/lib/util.js +62 -2
  49. package/lib/version.js +1 -1
  50. package/package.json +1 -1
  51. package/build/Release/oracledb-6.5.0-darwin-x64.node +0 -0
  52. package/build/Release/oracledb-6.5.0-darwin-x64.node-buildinfo.txt +0 -1
  53. package/build/Release/oracledb-6.5.0-js-buildinfo.txt +0 -1
  54. package/build/Release/oracledb-6.5.0-linux-arm64.node +0 -0
  55. package/build/Release/oracledb-6.5.0-linux-arm64.node-buildinfo.txt +0 -1
  56. package/build/Release/oracledb-6.5.0-linux-x64.node +0 -0
  57. package/build/Release/oracledb-6.5.0-linux-x64.node-buildinfo.txt +0 -1
  58. package/build/Release/oracledb-6.5.0-win32-x64.node +0 -0
  59. package/build/Release/oracledb-6.5.0-win32-x64.node-buildinfo.txt +0 -1
@@ -60,7 +60,13 @@ class ThinConnectionImpl extends ConnectionImpl {
60
60
  async close() {
61
61
  try {
62
62
  if (this._protocol.txnInProgress) {
63
- await this.rollback();
63
+ if (this.tpcContext) {
64
+ const message = this.createTpcRollbackMessage();
65
+ await this._protocol._processMessage(message);
66
+ } else {
67
+ await this.rollback();
68
+ }
69
+ this.tpcContext = null;
64
70
  }
65
71
  if (this._drcpEnabled) {
66
72
  await this._sessRelease();
@@ -385,6 +391,9 @@ class ThinConnectionImpl extends ConnectionImpl {
385
391
  info.elementType = this._parseTDSAttr(buf, info.elementTypeInfo);
386
392
  if (info.elementType === types.DB_TYPE_OBJECT) {
387
393
  await this._getElementTypeObj(info);
394
+ if (info.elementTypeClass.isXmlType) {
395
+ info.elementType = types.DB_TYPE_XMLTYPE;
396
+ }
388
397
  }
389
398
  } else {
390
399
  if (info.attributes) { // skip for XML type as it has no attributes.
@@ -439,6 +448,27 @@ class ThinConnectionImpl extends ConnectionImpl {
439
448
  end;
440
449
  end if;
441
450
  end;`;
451
+
452
+ // get column and datatype information in case of %ROWTYPE handling.
453
+ const getColumnsSQL = `
454
+ SELECT
455
+ column_name,
456
+ data_type,
457
+ data_type_owner,
458
+ case
459
+ when data_type in
460
+ ('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2', 'RAW')
461
+ then data_length
462
+ else 0
463
+ end,
464
+ nvl(data_precision, 0),
465
+ nvl(data_scale, 0)
466
+ from all_tab_cols
467
+ where owner = :owner
468
+ and table_name = :name
469
+ and hidden_column != 'YES'
470
+ order by column_id`;
471
+
442
472
  const binds = [
443
473
  {
444
474
  name: "full_name",
@@ -517,32 +547,105 @@ class ThinConnectionImpl extends ConnectionImpl {
517
547
  return info;
518
548
 
519
549
  // process TDS and attributes cursor
520
- info.version = result.outBinds.version;
521
- const attrRows = await result.outBinds.attrs_rc.getRows(1000, {});
522
- if (attrRows.length > 0) {
523
- // Its an object not a collection.
550
+ if (info.name.endsWith('%ROWTYPE')) {
551
+ const bindVal = [
552
+ {
553
+ name: "owner",
554
+ type: types.DB_TYPE_VARCHAR,
555
+ maxSize: 128,
556
+ dir: constants.BIND_IN,
557
+ values: [result.outBinds.schema],
558
+ },
559
+ {
560
+ name: "name",
561
+ type: types.DB_TYPE_VARCHAR,
562
+ maxSize: 128,
563
+ dir: constants.BIND_IN,
564
+ values: [info.name.substring(0, info.name.length - 8)]
565
+ }
566
+ ];
567
+ const val = await this.execute(
568
+ getColumnsSQL, 1, bindVal, options, false
569
+ );
570
+ const attrRows = await val.resultSet._getAllRows();
524
571
  info.attributes = [];
525
572
  for (const row of attrRows) {
526
- const attr = { name: row[1] };
527
- if (row[4]) {
528
- attr.type = types.DB_TYPE_OBJECT;
529
- attr.typeClass = this._getDbObjectType(row[4], row[3], row[5], row[6]);
530
- if (attr.typeClass.partial) {
531
- this._partialDbObjectTypes.push(attr.typeClass);
573
+ const metaData = {
574
+ name: row[0],
575
+ dataType: row[1],
576
+ dataTypeOwner: row[2],
577
+ maxSize: row[3],
578
+ dataPrecision: row[4],
579
+ dataScale: row[5],
580
+ };
581
+ if (!metaData.dataTypeOwner) {
582
+ const startPos = row[1].indexOf('(');
583
+ const endPos = row[1].indexOf(')');
584
+ if (endPos > startPos) {
585
+ metaData.dataType = metaData.dataType.substring(0, startPos) +
586
+ metaData.dataType.substring(
587
+ endPos + 1, metaData.dataType.length
588
+ );
532
589
  }
533
- } else {
534
- attr.type = types.getTypeByColumnTypeName(row[3]);
535
590
  }
536
- info.attributes.push(attr);
591
+ this._addAttr(info.attributes, metaData);
537
592
  }
538
- }
593
+ } else {
594
+ info.version = result.outBinds.version;
595
+ const attrRows = await result.outBinds.attrs_rc._getAllRows();
596
+ if (attrRows.length > 0) {
597
+ // Its an object not a collection.
598
+ info.attributes = [];
599
+ for (const row of attrRows) {
600
+ const metaData = {
601
+ name: row[1],
602
+ dataType: row[3],
603
+ dataTypeOwner: row[4],
604
+ packageName: row[5],
605
+ oid: row[6]
606
+ };
607
+ this._addAttr(info.attributes, metaData);
608
+ }
539
609
 
540
- await this._parseTDS(result.outBinds.tds, info);
610
+ }
611
+ await this._parseTDS(result.outBinds.tds, info);
612
+ }
541
613
  info.partial = false;
542
614
  return info;
543
615
 
544
616
  }
545
617
 
618
+ //---------------------------------------------------------------------------
619
+ // _addAttr()
620
+ //
621
+ // Populates "attributes" object present in "attrList".
622
+ //---------------------------------------------------------------------------
623
+ _addAttr(attributes, attrInfo) {
624
+ const attr = { name: attrInfo.name };
625
+ if (attrInfo.dataTypeOwner) {
626
+ attr.type = types.DB_TYPE_OBJECT;
627
+ attr.typeClass = this._getDbObjectType(
628
+ attrInfo.dataTypeOwner,
629
+ attrInfo.dataType,
630
+ attrInfo.packageName,
631
+ attrInfo.oid
632
+ );
633
+
634
+ if (attr.typeClass.isXmlType) {
635
+ attr.type = types.DB_TYPE_XMLTYPE;
636
+ }
637
+ if (attr.typeClass.partial) {
638
+ this._partialDbObjectTypes.push(attr.typeClass);
639
+ }
640
+ } else {
641
+ attr.type = types.getTypeByColumnTypeName(attrInfo.dataType);
642
+ attr.maxSize = attrInfo.maxSize;
643
+ attr.precision = attrInfo.dataPrecision;
644
+ attr.scale = attrInfo.dataScale;
645
+ }
646
+ attributes.push(attr);
647
+ }
648
+
546
649
  //---------------------------------------------------------------------------
547
650
  // _populatePartialDbObjectTypes()
548
651
  //
@@ -633,6 +736,7 @@ class ThinConnectionImpl extends ConnectionImpl {
633
736
  this.serviceName = '';
634
737
  this.remoteAddress = '';
635
738
  this.comboKey = null; // used in changePassword API
739
+ this.tpcContext = null;
636
740
 
637
741
  this.nscon = new nsi();
638
742
  finalizationRegistry.register(this, this.nscon);
@@ -948,6 +1052,14 @@ class ThinConnectionImpl extends ConnectionImpl {
948
1052
  this._dbOp = dbOp;
949
1053
  }
950
1054
 
1055
+ setExternalName(value) {
1056
+ this.externalName = value;
1057
+ }
1058
+
1059
+ setInternalName(value) {
1060
+ this.internalName = value;
1061
+ }
1062
+
951
1063
  setClientInfo(clientInfo) {
952
1064
  this._clientInfoModified = true;
953
1065
  this._clientInfo = clientInfo;
@@ -986,6 +1098,102 @@ class ThinConnectionImpl extends ConnectionImpl {
986
1098
  return lobImpl;
987
1099
  }
988
1100
 
1101
+ // Check the state returned by the tpcCommit() call.
1102
+ checkTpcCommitState(state, onePhase) {
1103
+ if ((onePhase && state !== constants.TNS_TPC_TXN_STATE_READ_ONLY
1104
+ && state !== constants.TNS_TPC_TXN_STATE_COMMITTED) ||
1105
+ (!onePhase && state !== constants.TNS_TPC_TXN_STATE_FORGOTTEN)) {
1106
+ errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, state);
1107
+ }
1108
+ }
1109
+
1110
+ // Creates a two-phase commit message suitable for committing a transaction.
1111
+ createTpcCommitMessage(xid, onePhase) {
1112
+ const message = new messages.TransactionChangeStateMessage(this);
1113
+ message.operation = constants.TNS_TPC_TXN_COMMIT;
1114
+ message.state = (onePhase == 0) ? constants.TNS_TPC_TXN_STATE_COMMITTED :
1115
+ constants.TNS_TPC_TXN_STATE_READ_ONLY;
1116
+ message.xid = xid;
1117
+ message.context = this.tpcContext;
1118
+ return message;
1119
+ }
1120
+
1121
+ // Creates a two-phase commit rollback message suitable for use in both
1122
+ // the close() method and explicitly by the user.
1123
+ createTpcRollbackMessage(xid = null) {
1124
+ const message = new messages.TransactionChangeStateMessage(this);
1125
+ message.operation = constants.TNS_TPC_TXN_ABORT;
1126
+ message.state = constants.TNS_TPC_TXN_STATE_ABORTED;
1127
+ message.xid = xid;
1128
+ message.context = this.tpcContext;
1129
+ return message;
1130
+ }
1131
+
1132
+ //---------------------------------------------------------------------------
1133
+ // tpcBegin()
1134
+ //---------------------------------------------------------------------------
1135
+ async tpcBegin(xid, flags, timeout) {
1136
+ const message = new messages.TransactionSwitchMessage(this);
1137
+ message.operation = constants.TNS_TPC_TXN_START;
1138
+ message.xid = xid;
1139
+ message.flags = flags;
1140
+ message.timeout = timeout;
1141
+ await this._protocol._processMessage(message);
1142
+ this.tpcContext = message.context;
1143
+ }
1144
+
1145
+ //---------------------------------------------------------------------------
1146
+ // tpcCommit()
1147
+ //---------------------------------------------------------------------------
1148
+ async tpcCommit(xid, onePhase) {
1149
+ const message = this.createTpcCommitMessage(xid, onePhase);
1150
+ await this._protocol._processMessage(message);
1151
+ this.checkTpcCommitState(message.state, onePhase);
1152
+ }
1153
+
1154
+ //---------------------------------------------------------------------------
1155
+ // tpcEnd()
1156
+ //---------------------------------------------------------------------------
1157
+ async tpcEnd(xid, flags) {
1158
+ const message = new messages.TransactionSwitchMessage(this);
1159
+ message.operation = constants.TNS_TPC_TXN_DETACH;
1160
+ message.xid = xid;
1161
+ message.context = this.tpcContext;
1162
+ message.flags = flags;
1163
+ await this._protocol._processMessage(message);
1164
+ this.tpcContext = null;
1165
+ }
1166
+
1167
+ //---------------------------------------------------------------------------
1168
+ // tpcPrepare()
1169
+ //---------------------------------------------------------------------------
1170
+ async tpcPrepare(xid) {
1171
+ const message = new messages.TransactionChangeStateMessage(this);
1172
+ message.operation = constants.TNS_TPC_TXN_PREPARE;
1173
+ message.xid = xid;
1174
+ message.context = this.tpcContext;
1175
+ await this._protocol._processMessage(message);
1176
+ if (message.state === constants.TNS_TPC_TXN_STATE_REQUIRES_COMMIT) {
1177
+ return true;
1178
+ } else if (message.state === constants.TNS_TPC_TXN_STATE_READ_ONLY) {
1179
+ return false;
1180
+ }
1181
+
1182
+ errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state);
1183
+ }
1184
+
1185
+ //---------------------------------------------------------------------------
1186
+ // tpcRollback()
1187
+ //---------------------------------------------------------------------------
1188
+ async tpcRollback(xid) {
1189
+ const message = this.createTpcRollbackMessage(xid);
1190
+ await this._protocol._processMessage(message);
1191
+ if (message.state !== constants.TNS_TPC_TXN_STATE_ABORTED) {
1192
+ errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state);
1193
+ }
1194
+ }
1195
+
1196
+
989
1197
  //---------------------------------------------------------------------------
990
1198
  // Returns the statement cache size for the statement cache maintained by
991
1199
  // the connection object
@@ -1009,6 +1217,10 @@ class ThinConnectionImpl extends ConnectionImpl {
1009
1217
  return '';
1010
1218
  }
1011
1219
 
1220
+ getExternalName() {
1221
+ return this.externalName;
1222
+ }
1223
+
1012
1224
  //---------------------------------------------------------------------------
1013
1225
  // Returns the Oracle Database instance name associated with the connection.
1014
1226
  //---------------------------------------------------------------------------
@@ -1016,6 +1228,10 @@ class ThinConnectionImpl extends ConnectionImpl {
1016
1228
  return this.instanceName;
1017
1229
  }
1018
1230
 
1231
+ getInternalName() {
1232
+ return this.internalName;
1233
+ }
1234
+
1019
1235
  //---------------------------------------------------------------------------
1020
1236
  // Returns the Oracle Database domain name associated with the connection.
1021
1237
  //---------------------------------------------------------------------------
@@ -397,10 +397,14 @@ class ThinDbObjectImpl extends DbObjectImpl {
397
397
  case types.DB_TYPE_BOOLEAN:
398
398
  return buf.readBool();
399
399
  case types.DB_TYPE_OBJECT:
400
+ case types.DB_TYPE_XMLTYPE:
400
401
  isNull = buf.getIsAtomicNull();
401
402
  if (isNull)
402
403
  return null;
403
404
  obj = new ThinDbObjectImpl(typeClass);
405
+ if (obj._objType.isXmlType) {
406
+ return readXML(obj._objType._connection, buf.readBytesWithLength());
407
+ }
404
408
  if (obj._objType.isCollection || this._objType.isCollection) {
405
409
  obj.packedData = Buffer.from(buf.readBytesWithLength());
406
410
  } else {
package/lib/thin/lob.js CHANGED
@@ -31,6 +31,7 @@ const LobImpl = require('../impl/lob.js');
31
31
  const constants = require('./protocol/constants.js');
32
32
  const LobOpMessage = require('./protocol/messages/lobOp.js');
33
33
  const errors = require('../errors.js');
34
+ const types = require('../types.js');
34
35
 
35
36
  class ThinLobImpl extends LobImpl {
36
37
 
@@ -54,15 +55,31 @@ class ThinLobImpl extends LobImpl {
54
55
  await this.conn._protocol._processMessage(message);
55
56
  if (options.operation === constants.TNS_LOB_OP_READ) {
56
57
  return (message.data) ? message.data : null;
58
+ } else if (
59
+ options.operation === constants.TNS_LOB_OP_FILE_EXISTS ||
60
+ options.operation === constants.TNS_LOB_OP_FILE_ISOPEN
61
+ ) {
62
+ return message.boolFlag;
57
63
  } else {
58
64
  return message.amount;
59
65
  }
60
66
  }
61
67
 
68
+ //---------------------------------------------------------------------------
69
+ // getChunkSize()
70
+ //
71
+ // Internal method for returning the chunk size of the LOB.
72
+ //---------------------------------------------------------------------------
62
73
  getChunkSize() {
63
74
  return this._chunkSize;
64
75
  }
65
76
 
77
+ //---------------------------------------------------------------------------
78
+ // _getChunkSizeAsync()
79
+ //
80
+ // Internal method for returning the chunk size of the LOB fetched from
81
+ // the database.
82
+ //---------------------------------------------------------------------------
66
83
  async _getChunkSizeAsync() {
67
84
  this.checkConn();
68
85
  const options = {
@@ -73,29 +90,76 @@ class ThinLobImpl extends LobImpl {
73
90
  this._chunkSize = this._pieceSize = await this._sendMessage(options);
74
91
  }
75
92
 
93
+ //---------------------------------------------------------------------------
94
+ // getLength()
95
+ //
96
+ // Internal method for returning the length of a LOB.
97
+ //---------------------------------------------------------------------------
76
98
  getLength() {
77
99
  return this._length;
78
100
  }
79
101
 
102
+ //---------------------------------------------------------------------------
103
+ // getPieceSize()
104
+ //
105
+ // Internal method returning the size to use for each piece that is
106
+ // transferred when reading from the LOB.
107
+ //---------------------------------------------------------------------------
80
108
  getPieceSize() {
81
109
  return this._pieceSize;
82
110
  }
83
111
 
112
+ //---------------------------------------------------------------------------
113
+ // setPieceSize()
114
+ //
115
+ // Internal method to set the pieceSize for LOBs.
116
+ //---------------------------------------------------------------------------
84
117
  setPieceSize(value) {
85
118
  this._pieceSize = value;
86
119
  }
87
120
 
121
+ //---------------------------------------------------------------------------
122
+ // getType()
123
+ //
124
+ // Internal method returning the datatype of LOBs.
125
+ //---------------------------------------------------------------------------
88
126
  getType() {
89
127
  return this.dbType;
90
128
  }
91
129
 
130
+ //---------------------------------------------------------------------------
131
+ // getData()
132
+ //
133
+ // Internal method returning the data obtained from the database.
134
+ //---------------------------------------------------------------------------
92
135
  async getData(offset = 1, len = this._length) {
136
+ let shouldClose = false;
93
137
  if (!len) {
94
138
  len = this._length;
95
139
  }
96
- return await this.read(offset, len);
140
+ if (this.dbType === types.DB_TYPE_BFILE) {
141
+ if (!await this.isFileOpen()) {
142
+ shouldClose = true;
143
+ await this.openFile();
144
+ }
145
+ }
146
+ let data;
147
+ // if read fails and BFILE was opened by application, we close it.
148
+ try {
149
+ data = await this.read(offset, len);
150
+ } finally {
151
+ if (shouldClose) {
152
+ await this.closeFile();
153
+ }
154
+ }
155
+ return data;
97
156
  }
98
157
 
158
+ //---------------------------------------------------------------------------
159
+ // read()
160
+ //
161
+ // Internal method for reading a portion (or all) of the data in the LOB.
162
+ //---------------------------------------------------------------------------
99
163
  async read(offset, length) {
100
164
  this.checkConn();
101
165
  const options = {
@@ -108,6 +172,11 @@ class ThinLobImpl extends LobImpl {
108
172
  return await this._sendMessage(options);
109
173
  }
110
174
 
175
+ //---------------------------------------------------------------------------
176
+ // write()
177
+ //
178
+ // Internal method for writing data to the LOB object.
179
+ //---------------------------------------------------------------------------
111
180
  async write(offset, data) {
112
181
  this.checkConn();
113
182
  const options = {
@@ -120,6 +189,11 @@ class ThinLobImpl extends LobImpl {
120
189
  this._length += data.length;
121
190
  }
122
191
 
192
+ //---------------------------------------------------------------------------
193
+ // getCsfrm()
194
+ //
195
+ // Return the character set encoding used by the LOB.
196
+ //---------------------------------------------------------------------------
123
197
  getCsfrm() {
124
198
  if (this.dbType._csfrm !== constants.CSFRM_NCHAR) {
125
199
  if (this._locator[constants.TNS_LOB_LOC_OFFSET_FLAG_3] &
@@ -155,11 +229,60 @@ class ThinLobImpl extends LobImpl {
155
229
  await this._getChunkSizeAsync();
156
230
  }
157
231
 
232
+ //---------------------------------------------------------------------------
233
+ // fileExists()
234
+ //
235
+ // Internal method for returning whether the file referenced by a BFILE
236
+ // exists.
237
+ //---------------------------------------------------------------------------
238
+ async fileExists() {
239
+ this.checkConn();
240
+ const options = {
241
+ operation: constants.TNS_LOB_OP_FILE_EXISTS,
242
+ sourceLobImpl: this,
243
+ };
244
+ return await this._sendMessage(options);
245
+ }
246
+
247
+ //---------------------------------------------------------------------------
248
+ // getDirFileName()
249
+ //
250
+ // Internal method for returning the directory alias and name of the file
251
+ // referenced by a BFILE
252
+ //---------------------------------------------------------------------------
253
+ getDirFileName() {
254
+ const dirNameOffset = constants.TNS_LOB_LOC_FIXED_OFFSET + 2;
255
+ const dirNameLen = this._locator.readUInt16BE(
256
+ constants.TNS_LOB_LOC_FIXED_OFFSET
257
+ );
258
+ const fileNameOffset = constants.TNS_LOB_LOC_FIXED_OFFSET + dirNameLen + 4;
259
+ const fileNameLen = this._locator.readUInt16BE(
260
+ dirNameOffset + dirNameLen
261
+ );
262
+ const dirName = this._locator.slice(
263
+ dirNameOffset, dirNameOffset + dirNameLen
264
+ ).toString();
265
+ const fileName = this._locator.slice(
266
+ fileNameOffset, fileNameOffset + fileNameLen
267
+ ).toString();
268
+ return { dirName: dirName, fileName: fileName };
269
+ }
270
+
271
+ //---------------------------------------------------------------------------
272
+ // checkConn()
273
+ //
274
+ // Internal method to check the connection.
275
+ //---------------------------------------------------------------------------
158
276
  checkConn() {
159
277
  if (!this.conn.nscon.connected)
160
278
  errors.throwErr(errors.ERR_INVALID_CONNECTION);
161
279
  }
162
280
 
281
+ //---------------------------------------------------------------------------
282
+ // close()
283
+ //
284
+ // Internal method to close the LOBs using piggyback mechanism.
285
+ //---------------------------------------------------------------------------
163
286
  close() {
164
287
  this.checkConn();
165
288
  if (this._isTempLob) {
@@ -169,6 +292,25 @@ class ThinLobImpl extends LobImpl {
169
292
  }
170
293
  }
171
294
 
295
+ //---------------------------------------------------------------------------
296
+ // closeFile()
297
+ //
298
+ // Internal method to close the opened file for BFILE LOBs.
299
+ //---------------------------------------------------------------------------
300
+ async closeFile() {
301
+ this.checkConn();
302
+ const options = {
303
+ operation: constants.TNS_LOB_OP_FILE_CLOSE,
304
+ sourceLobImpl: this,
305
+ };
306
+ await this._sendMessage(options);
307
+ }
308
+
309
+ //---------------------------------------------------------------------------
310
+ // init()
311
+ //
312
+ // Internal method to initialize LOBs.
313
+ //---------------------------------------------------------------------------
172
314
  init(conn, locator, dbType, len, chunkSize) {
173
315
  this.dirtyLength = false;
174
316
  this.conn = conn;
@@ -184,6 +326,56 @@ class ThinLobImpl extends LobImpl {
184
326
  this._pieceSize = chunkSize;
185
327
  }
186
328
 
329
+ //---------------------------------------------------------------------------
330
+ // isFileOpen()
331
+ //
332
+ // Internal method to check if the file is already open.
333
+ //---------------------------------------------------------------------------
334
+ async isFileOpen() {
335
+ const options = {
336
+ operation: constants.TNS_LOB_OP_FILE_ISOPEN,
337
+ sourceLobImpl: this
338
+ };
339
+ await this._sendMessage(options);
340
+ }
341
+
342
+ //---------------------------------------------------------------------------
343
+ // openFile()
344
+ //
345
+ // Internal method for opening file (BFILE).
346
+ //---------------------------------------------------------------------------
347
+ async openFile() {
348
+ this.checkConn();
349
+ const options = {
350
+ operation: constants.TNS_LOB_OP_FILE_OPEN,
351
+ sourceLobImpl: this,
352
+ amount: constants.TNS_LOB_OPEN_READ_ONLY,
353
+ sendAmount: true
354
+ };
355
+ return await this._sendMessage(options);
356
+ }
357
+
358
+ //---------------------------------------------------------------------------
359
+ // setDirFileName()
360
+ //
361
+ // Internal method for setting the directory alias and name of the file
362
+ // referenced by a BFILE
363
+ //---------------------------------------------------------------------------
364
+ setDirFileName(dirObject) {
365
+ const dirNameLen = Buffer.byteLength(dirObject.dirName);
366
+ const dirNameOffset = constants.TNS_LOB_LOC_FIXED_OFFSET + 2;
367
+ const fileNameOffset = dirNameOffset + dirNameLen + 2;
368
+ const fileNameLen = Buffer.byteLength(dirObject.fileName);
369
+ const newLocLen = fileNameOffset + fileNameLen;
370
+ const newLocator = Buffer.allocUnsafe(newLocLen);
371
+ this._locator.copy(newLocator, 0, 0, constants.TNS_LOB_LOC_FIXED_OFFSET + 1);
372
+ newLocator.writeUInt16BE(dirNameLen, constants.TNS_LOB_LOC_FIXED_OFFSET);
373
+ newLocator.write(dirObject.dirName, dirNameOffset);
374
+ newLocator.writeInt16BE(fileNameLen, dirNameOffset + dirNameLen);
375
+ newLocator.write(dirObject.fileName, fileNameOffset);
376
+ this._locator = newLocator;
377
+ }
378
+
187
379
  }
188
380
 
189
381
  module.exports = ThinLobImpl;
package/lib/thin/pool.js CHANGED
@@ -64,6 +64,7 @@ class ThinPoolImpl extends PoolImpl {
64
64
  this._usedConnectionList = new Set();
65
65
  this._password = params.password;
66
66
  this._walletPassword = params.walletPassword;
67
+ this._walletContent = params.walletContent;
67
68
  this._obfuscatedPassword = [];
68
69
  this._obfuscatedWalletPassword = [];
69
70
  this._token = params.token;
@@ -88,6 +89,13 @@ class ThinPoolImpl extends PoolImpl {
88
89
  this._obfuscatedWalletPassword = obj.obfuscatedValue;
89
90
  this._userConfig.walletPassword = null;
90
91
  }
92
+ // wallet content obfuscation
93
+ if (this._walletContent !== undefined) {
94
+ const obj = protocolUtil.setObfuscatedValue(this._walletContent);
95
+ this._walletContent = obj.value;
96
+ this._obfuscatedWalletContent = obj.obfuscatedValue;
97
+ this._userConfig.walletConent = null;
98
+ }
91
99
  // token obfuscation
92
100
  if (this._token !== undefined) {
93
101
  const obj = protocolUtil.setObfuscatedValue(this._token);
@@ -172,6 +180,13 @@ class ThinPoolImpl extends PoolImpl {
172
180
  this._obfuscatedWalletPassword);
173
181
  }
174
182
 
183
+ // deobfuscate wallet content
184
+ if (clonedAttrs.walletContent === null) {
185
+ clonedAttrs.walletContent =
186
+ protocolUtil.getDeobfuscatedValue(this._walletContent,
187
+ this._obfuscatedWalletContent);
188
+ }
189
+
175
190
  // deobfuscate token and private key
176
191
  // check for token expiry
177
192
  if (clonedAttrs.token === null) {
@@ -118,6 +118,8 @@ class Capabilities {
118
118
  constants.TNS_CCAP_CTB_IMPLICIT_POOL;
119
119
  this.compileCaps[constants.TNS_CCAP_TTC5] =
120
120
  constants.TNS_CCAP_VECTOR_SUPPORT;
121
+ this.compileCaps[constants.TNS_CCAP_VECTOR_FEATURES] =
122
+ constants.TNS_CCAP_VECTOR_FEATURE_BINARY;
121
123
  }
122
124
 
123
125
  initRuntimeCaps() {