oracledb 5.5.0 → 6.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 (107) hide show
  1. package/CHANGELOG.md +1 -1875
  2. package/LICENSE.txt +8 -222
  3. package/NOTICE.txt +1 -1
  4. package/README.md +38 -30
  5. package/SECURITY.md +38 -0
  6. package/build/Release/oracledb-6.0.0-darwin-x64.node +0 -0
  7. package/build/Release/oracledb-6.0.0-darwin-x64.node-buildinfo.txt +1 -0
  8. package/build/Release/oracledb-6.0.0-js-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.0.0-linux-arm64.node +0 -0
  10. package/build/Release/oracledb-6.0.0-linux-arm64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.0.0-linux-x64.node +0 -0
  12. package/build/Release/oracledb-6.0.0-linux-x64.node-buildinfo.txt +1 -0
  13. package/build/Release/oracledb-6.0.0-win32-x64.node +0 -0
  14. package/build/Release/oracledb-6.0.0-win32-x64.node-buildinfo.txt +1 -0
  15. package/examples/README.md +113 -0
  16. package/examples/dbconfig.js +100 -0
  17. package/examples/example.js +156 -0
  18. package/index.js +26 -0
  19. package/lib/aqDeqOptions.js +146 -7
  20. package/lib/aqEnqOptions.js +59 -7
  21. package/lib/aqMessage.js +118 -7
  22. package/lib/aqQueue.js +242 -53
  23. package/lib/connection.js +1324 -465
  24. package/lib/constants.js +203 -0
  25. package/lib/dbObject.js +346 -32
  26. package/lib/errors.js +781 -0
  27. package/lib/impl/aqDeqOptions.js +197 -0
  28. package/lib/impl/aqEnqOptions.js +89 -0
  29. package/lib/impl/aqMessage.js +134 -0
  30. package/lib/impl/aqQueue.js +81 -0
  31. package/lib/impl/connection.js +529 -0
  32. package/lib/impl/dbObject.js +159 -0
  33. package/lib/impl/index.js +59 -0
  34. package/lib/impl/lob.js +85 -0
  35. package/lib/impl/pool.js +195 -0
  36. package/lib/impl/resultset.js +223 -0
  37. package/lib/impl/sodaCollection.js +174 -0
  38. package/lib/impl/sodaDatabase.js +81 -0
  39. package/lib/impl/sodaDocCursor.js +63 -0
  40. package/lib/impl/sodaDocument.js +98 -0
  41. package/lib/impl/sodaOperation.js +109 -0
  42. package/lib/lob.js +156 -68
  43. package/lib/oracledb.js +1047 -345
  44. package/lib/pool.js +654 -465
  45. package/lib/poolStatistics.js +23 -9
  46. package/lib/queryStream.js +14 -7
  47. package/lib/resultset.js +291 -183
  48. package/lib/settings.js +191 -0
  49. package/lib/sodaCollection.js +214 -201
  50. package/lib/sodaDatabase.js +107 -71
  51. package/lib/sodaDocCursor.js +44 -32
  52. package/lib/sodaDocument.js +76 -14
  53. package/lib/sodaOperation.js +131 -118
  54. package/lib/thin/connection.js +1038 -0
  55. package/lib/thin/dbObject.js +629 -0
  56. package/lib/thin/index.js +40 -0
  57. package/lib/thin/lob.js +188 -0
  58. package/lib/thin/pool.js +481 -0
  59. package/lib/thin/protocol/buffer.js +1040 -0
  60. package/lib/thin/protocol/capabilities.js +116 -0
  61. package/lib/thin/protocol/constants.js +764 -0
  62. package/lib/thin/protocol/encryptDecrypt.js +185 -0
  63. package/lib/thin/protocol/messages/auth.js +348 -0
  64. package/lib/thin/protocol/messages/base.js +475 -0
  65. package/lib/thin/protocol/messages/commit.js +56 -0
  66. package/lib/thin/protocol/messages/dataType.js +382 -0
  67. package/lib/thin/protocol/messages/execute.js +312 -0
  68. package/lib/thin/protocol/messages/fetch.js +60 -0
  69. package/lib/thin/protocol/messages/index.js +53 -0
  70. package/lib/thin/protocol/messages/lobOp.js +200 -0
  71. package/lib/thin/protocol/messages/logOff.js +53 -0
  72. package/lib/thin/protocol/messages/ping.js +56 -0
  73. package/lib/thin/protocol/messages/protocol.js +78 -0
  74. package/lib/thin/protocol/messages/rollback.js +56 -0
  75. package/lib/thin/protocol/messages/sessionRelease.js +60 -0
  76. package/lib/thin/protocol/messages/withData.js +811 -0
  77. package/lib/thin/protocol/oson.js +660 -0
  78. package/lib/thin/protocol/packet.js +520 -0
  79. package/lib/thin/protocol/protocol.js +202 -0
  80. package/lib/thin/protocol/utils.js +88 -0
  81. package/lib/thin/resultSet.js +122 -0
  82. package/lib/thin/sqlnet/connStrategy.js +175 -0
  83. package/lib/thin/sqlnet/constants.js +199 -0
  84. package/lib/thin/sqlnet/ezConnectResolver.js +488 -0
  85. package/lib/thin/sqlnet/navNodes.js +870 -0
  86. package/lib/thin/sqlnet/networkSession.js +620 -0
  87. package/lib/thin/sqlnet/ntTcp.js +525 -0
  88. package/lib/thin/sqlnet/nvStrToNvPair.js +783 -0
  89. package/lib/thin/sqlnet/packet.js +405 -0
  90. package/lib/thin/sqlnet/paramParser.js +205 -0
  91. package/lib/thin/sqlnet/sessionAtts.js +160 -0
  92. package/lib/thin/statement.js +301 -0
  93. package/lib/thin/util.js +289 -0
  94. package/lib/transformer.js +250 -0
  95. package/lib/types.js +357 -0
  96. package/lib/util.js +194 -110
  97. package/lib/version.js +36 -0
  98. package/package/README.md +33 -30
  99. package/package/install.js +89 -64
  100. package/package/prunebinaries.js +60 -12
  101. package/package.json +3 -3
  102. package/build/Release/oracledb-5.5.0-darwin-x64.node +0 -0
  103. package/build/Release/oracledb-5.5.0-darwin-x64.node-buildinfo.txt +0 -1
  104. package/build/Release/oracledb-5.5.0-linux-x64.node +0 -0
  105. package/build/Release/oracledb-5.5.0-linux-x64.node-buildinfo.txt +0 -1
  106. package/build/Release/oracledb-5.5.0-win32-x64.node +0 -0
  107. package/build/Release/oracledb-5.5.0-win32-x64.node-buildinfo.txt +0 -1
@@ -0,0 +1,660 @@
1
+ // Copyright (c) 2023, Oracle and/or its affiliates.
2
+
3
+ //-----------------------------------------------------------------------------
4
+ //
5
+ // This software is dual-licensed to you under the Universal Permissive License
6
+ // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
7
+ // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
8
+ // either license.
9
+ //
10
+ // If you elect to accept the software under the Apache License, Version 2.0,
11
+ // the following applies:
12
+ //
13
+ // Licensed under the Apache License, Version 2.0 (the "License");
14
+ // you may not use this file except in compliance with the License.
15
+ // You may obtain a copy of the License at
16
+ //
17
+ // https://www.apache.org/licenses/LICENSE-2.0
18
+ //
19
+ // Unless required by applicable law or agreed to in writing, software
20
+ // distributed under the License is distributed on an "AS IS" BASIS,
21
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ // See the License for the specific language governing permissions and
23
+ // limitations under the License.
24
+ //
25
+ //-----------------------------------------------------------------------------
26
+
27
+ 'use strict';
28
+
29
+ const { BaseBuffer, GrowableBuffer } = require('./buffer.js');
30
+ const constants = require("./constants.js");
31
+ const errors = require("../../errors.js");
32
+ const types = require("../../types.js");
33
+ const util = require("util");
34
+
35
+ /**
36
+ * Class used for decodeing
37
+ */
38
+ class OsonDecoder extends BaseBuffer {
39
+
40
+ //---------------------------------------------------------------------------
41
+ // _decodeContainerNode()
42
+ //
43
+ // Decodes a container node (object or array) from the tree segment and
44
+ // returns the JavaScript equivalent.
45
+ //---------------------------------------------------------------------------
46
+ _decodeContainerNode(nodeType) {
47
+
48
+ // determine the number of children by examining the 4th and 5th most
49
+ // significant bits of the node type; determine the offsets in the tree
50
+ // segment to the field ids array and the value offsets array
51
+ let container, offsetsPos, fieldIdsPos;
52
+ let numChildren = this._getNumChildren(nodeType);
53
+ const isObject = ((nodeType & 0x40) === 0);
54
+ if (numChildren === undefined) {
55
+ const offset = this._getOffset(nodeType);
56
+ offsetsPos = this.pos;
57
+ this.pos = this.treeSegPos + offset;
58
+ const sharedNodeType = this.readUInt8();
59
+ numChildren = this._getNumChildren(sharedNodeType);
60
+ container = (isObject) ? {} : new Array(numChildren);
61
+ fieldIdsPos = this.pos;
62
+ } else if (isObject) {
63
+ container = {};
64
+ fieldIdsPos = this.pos;
65
+ offsetsPos = this.pos + this.fieldIdLength * numChildren;
66
+ } else {
67
+ container = new Array(numChildren);
68
+ offsetsPos = this.pos;
69
+ }
70
+
71
+ for (let i = 0; i < numChildren; i++) {
72
+ let name;
73
+ if (isObject) {
74
+ let fieldId;
75
+ if (this.fieldIdLength === 1) {
76
+ fieldId = this.buf[fieldIdsPos];
77
+ } else if (this.fieldIdLength == 2) {
78
+ fieldId = this.buf.readUInt16BE(fieldIdsPos);
79
+ } else {
80
+ fieldId = this.buf.readUInt32BE(fieldIdsPos);
81
+ }
82
+ name = this.fieldNames[fieldId - 1];
83
+ fieldIdsPos += this.fieldIdLength;
84
+ }
85
+ this.pos = offsetsPos;
86
+ const offset = this._getOffset(nodeType);
87
+ offsetsPos = this.pos;
88
+ this.pos = this.treeSegPos + offset;
89
+ if (isObject) {
90
+ container[name] = this._decodeNode();
91
+ } else {
92
+ container[i] = this._decodeNode();
93
+ }
94
+ }
95
+
96
+ return container;
97
+ }
98
+
99
+ //---------------------------------------------------------------------------
100
+ // _decodeNode()
101
+ //
102
+ // Decodes a node from the tree segment and returns the JavaScript
103
+ // equivalent.
104
+ //---------------------------------------------------------------------------
105
+ _decodeNode() {
106
+
107
+ // if the most significant bit is set the node refers to a container
108
+ const nodeType = this.readUInt8();
109
+ if (nodeType & 0x80) {
110
+ return this._decodeContainerNode(nodeType);
111
+ }
112
+
113
+ // handle simple scalars
114
+ if (nodeType === constants.TNS_JSON_TYPE_NULL) {
115
+ return null;
116
+ } else if (nodeType === constants.TNS_JSON_TYPE_TRUE) {
117
+ return true;
118
+ } else if (nodeType === constants.TNS_JSON_TYPE_FALSE) {
119
+ return false;
120
+
121
+ // handle fixed length scalars
122
+ } else if (nodeType === constants.TNS_JSON_TYPE_DATE ||
123
+ nodeType === constants.TNS_JSON_TYPE_TIMESTAMP7) {
124
+ return this.parseOracleDate(this.readBytes(7));
125
+ } else if (nodeType === constants.TNS_JSON_TYPE_TIMESTAMP) {
126
+ return this.parseOracleDate(this.readBytes(11));
127
+ } else if (nodeType === constants.TNS_JSON_TYPE_TIMESTAMP_TZ) {
128
+ return this.parseOracleDate(this.readBytes(13));
129
+ } else if (nodeType === constants.TNS_JSON_TYPE_BINARY_FLOAT) {
130
+ return this.parseBinaryFloat(this.readBytes(4));
131
+ } else if (nodeType === constants.TNS_JSON_TYPE_BINARY_DOUBLE) {
132
+ return this.parseBinaryDouble(this.readBytes(8));
133
+
134
+ // handle scalars with lengths stored outside the node itself
135
+ } else if (nodeType === constants.TNS_JSON_TYPE_STRING_LENGTH_UINT8) {
136
+ return this.readBytes(this.readUInt8()).toString();
137
+ } else if (nodeType === constants.TNS_JSON_TYPE_STRING_LENGTH_UINT16) {
138
+ return this.readBytes(this.readUInt16BE()).toString();
139
+ } else if (nodeType === constants.TNS_JSON_TYPE_STRING_LENGTH_UINT32) {
140
+ return this.readBytes(this.readUInt32BE()).toString();
141
+ } else if (nodeType === constants.TNS_JSON_TYPE_NUMBER_LENGTH_UINT8) {
142
+ return parseFloat(this.readOracleNumber());
143
+ } else if (nodeType === constants.TNS_JSON_TYPE_BINARY_LENGTH_UINT16) {
144
+ return Buffer.from(this.readBytes(this.readUInt16BE()));
145
+ } else if (nodeType === constants.TNS_JSON_TYPE_BINARY_LENGTH_UINT32) {
146
+ return Buffer.from(this.readBytes(this.readUInt32BE()));
147
+ }
148
+
149
+ // handle number/decimal with length stored inside the node itself
150
+ const typeBits = nodeType & 0xf0;
151
+ if (typeBits === 0x20 || typeBits === 0x60) {
152
+ const len = nodeType & 0x0f;
153
+ return parseFloat(this.parseOracleNumber(this.readBytes(len + 1)));
154
+
155
+ // handle integer with length stored inside the node itself
156
+ } else if (typeBits === 0x40 || typeBits === 0x50) {
157
+ const len = nodeType & 0x0f;
158
+ return parseFloat(this.parseOracleNumber(this.readBytes(len)));
159
+
160
+ // handle string with length stored inside the node itself
161
+ } else if ((nodeType & 0xe0) == 0) {
162
+ if (nodeType === 0)
163
+ return '';
164
+ return this.readBytes(nodeType).toString();
165
+ }
166
+
167
+ errors.throwErr(errors.ERR_UNSUPPORTED_DATA_TYPE_IN_JSON, nodeType);
168
+ }
169
+
170
+ //---------------------------------------------------------------------------
171
+ // _getNumChildren()
172
+ //
173
+ // Returns the number of children a container has. This is determined by
174
+ // looking at the 4th and 5th most significant bits of the node type.
175
+ //
176
+ // 00 - number of children is uint8_t
177
+ // 01 - number of children is uint16_t
178
+ // 10 - number of children is uint32_t
179
+ // 11 - field ids are shared with another object whose offset follows
180
+ //
181
+ // In the latter case the value undefined is returned and the number of
182
+ // children must be read from the shared object at the specified offset.
183
+ //---------------------------------------------------------------------------
184
+ _getNumChildren(nodeType) {
185
+ const childrenBits = (nodeType & 0x18);
186
+ if (childrenBits === 0) {
187
+ return this.readUInt8();
188
+ } else if (childrenBits === 0x08) {
189
+ return this.readUInt16BE();
190
+ } else if (childrenBits === 0x10) {
191
+ return this.readUInt32BE();
192
+ }
193
+ }
194
+
195
+ //---------------------------------------------------------------------------
196
+ // _getOffset()
197
+ //
198
+ // Returns an offset. The offset will be either a 16-bit or 32-bit value
199
+ // depending on the value of the 3rd significant bit of the node type.
200
+ //---------------------------------------------------------------------------
201
+ _getOffset(nodeType) {
202
+ if (nodeType & 0x20) {
203
+ return this.readUInt32BE();
204
+ } else {
205
+ return this.readUInt16BE();
206
+ }
207
+ }
208
+
209
+ //---------------------------------------------------------------------------
210
+ // decode()
211
+ //
212
+ // Decodes the OSON and returns a JavaScript object corresponding to its
213
+ // contents.
214
+ //---------------------------------------------------------------------------
215
+ decode() {
216
+
217
+ // parse root header
218
+ const magic = this.readBytes(3);
219
+ if (magic[0] !== constants.TNS_JSON_MAGIC_BYTE_1 ||
220
+ magic[1] !== constants.TNS_JSON_MAGIC_BYTE_2 ||
221
+ magic[2] !== constants.TNS_JSON_MAGIC_BYTE_3) {
222
+ errors.throwErr(errors.ERR_UNEXPECTED_DATA, magic.toString('hex'));
223
+ }
224
+ const version = this.readUInt8();
225
+ if (version !== constants.TNS_JSON_VERSION) {
226
+ errors.throwErr(errors.ERR_OSON_VERSION_NOT_SUPPORTED, version);
227
+ }
228
+ const flags = this.readUInt16BE();
229
+
230
+ // scalar values are much simpler
231
+ if (flags & constants.TNS_JSON_FLAG_IS_SCALAR) {
232
+ if (flags & constants.TNS_JSON_FLAG_TREE_SEG_UINT32) {
233
+ this.skipBytes(4);
234
+ } else {
235
+ this.skipBytes(2);
236
+ }
237
+ return this._decodeNode();
238
+ }
239
+
240
+ // determine the number of field names
241
+ let numFieldNames;
242
+ if (flags & constants.TNS_JSON_FLAG_NUM_FNAMES_UINT32) {
243
+ numFieldNames = this.readUInt32BE();
244
+ this.fieldIdLength = 4;
245
+ } else if (flags & constants.TNS_JSON_FLAG_NUM_FNAMES_UINT16) {
246
+ numFieldNames = this.readUInt16BE();
247
+ this.fieldIdLength = 2;
248
+ } else {
249
+ numFieldNames = this.readUInt8();
250
+ this.fieldIdLength = 1;
251
+ }
252
+
253
+ // determine the size of the field names segment
254
+ let fieldNameOffsetsSize, fieldNamesSegSize;
255
+ if (flags & constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32) {
256
+ fieldNameOffsetsSize = 4;
257
+ fieldNamesSegSize = this.readUInt32BE();
258
+ } else {
259
+ fieldNameOffsetsSize = 2;
260
+ fieldNamesSegSize = this.readUInt16BE();
261
+ }
262
+
263
+ // skip the size of the tree segment
264
+ if (flags & constants.TNS_JSON_FLAG_TREE_SEG_UINT32) {
265
+ this.skipBytes(4);
266
+ } else {
267
+ this.skipBytes(2);
268
+ }
269
+
270
+ // skip the number of "tiny" nodes
271
+ this.skipBytes(2);
272
+
273
+ // skip the hash id array
274
+ let hashIdSize;
275
+ if (flags & constants.TNS_JSON_FLAG_HASH_ID_UINT8) {
276
+ hashIdSize = 1;
277
+ } else if (flags & constants.TNS_JSON_FLAG_HASH_ID_UINT16) {
278
+ hashIdSize = 2;
279
+ } else {
280
+ hashIdSize = 4;
281
+ }
282
+ this.skipBytes(numFieldNames * hashIdSize);
283
+
284
+ // skip over the field name offsets and field names
285
+ let fieldNameOffsetsPos = this.pos;
286
+ this.skipBytes(numFieldNames * fieldNameOffsetsSize);
287
+ const fieldNamesPos = this.pos;
288
+ this.skipBytes(fieldNamesSegSize);
289
+
290
+ // determine the names of the fields
291
+ this.fieldNames = new Array(numFieldNames);
292
+ for (let i = 0; i < numFieldNames; i++) {
293
+ let offset = fieldNamesPos;
294
+ if (flags & constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32) {
295
+ offset += this.buf.readUInt32BE(fieldNameOffsetsPos);
296
+ fieldNameOffsetsPos += 4;
297
+ } else {
298
+ offset += this.buf.readUInt16BE(fieldNameOffsetsPos);
299
+ fieldNameOffsetsPos += 2;
300
+ }
301
+ const len = this.buf[offset];
302
+ const name = this.buf.subarray(offset + 1, offset + len + 1).toString();
303
+ this.fieldNames[i] = name;
304
+ }
305
+
306
+ // determine tree segment position in the buffer
307
+ this.treeSegPos = this.pos;
308
+
309
+ // decode the root node
310
+ return this._decodeNode();
311
+ }
312
+
313
+ }
314
+
315
+ class OsonFieldName {
316
+
317
+ constructor(name) {
318
+ this.name = name;
319
+ this.nameBytes = Buffer.from(name);
320
+ if (this.nameBytes.length > 255) {
321
+ errors.throwErr(errors.ERR_OSON_FIELD_NAME_LIMITATION);
322
+ }
323
+ this.hashId = BigInt(0x811C9DC5);
324
+ const multiplier = BigInt(16777619);
325
+ const mask = BigInt(0xffffffff);
326
+ for (let i = 0; i < this.nameBytes.length; i++) {
327
+ const c = BigInt(this.nameBytes[i]);
328
+ this.hashId = ((this.hashId ^ c) * multiplier) & mask;
329
+ }
330
+ this.hashId = Number(this.hashId) & 0xff;
331
+ }
332
+
333
+ }
334
+
335
+ class OsonFieldNamesSegment extends GrowableBuffer {
336
+
337
+ constructor(value) {
338
+ super();
339
+ this.fieldNamesMap = new Map();
340
+ this.fieldNames = [];
341
+ this._examineNode(value);
342
+ this._processFieldNames();
343
+ }
344
+
345
+ //---------------------------------------------------------------------------
346
+ // _exmaineNode()
347
+ //
348
+ // Examines the value. If it contains fields, unique names are retained. The
349
+ // values are then examined to see if they also contain fields. Arrays are
350
+ // examined to determine they contain elements that contain fields.
351
+ //---------------------------------------------------------------------------
352
+ _examineNode(value) {
353
+ if (Array.isArray(value)) {
354
+ for (let element of value) {
355
+ this._examineNode(element);
356
+ }
357
+ } else if (value && Array.isArray(value.fields)) {
358
+ for (let i = 0; i < value.fields.length; i++) {
359
+ const name = value.fields[i];
360
+ const element = value.values[i];
361
+ if (!this.fieldNamesMap.has(name)) {
362
+ const fieldName = new OsonFieldName(name);
363
+ this.fieldNamesMap.set(name, fieldName);
364
+ this.fieldNames.push(fieldName);
365
+ fieldName.offset = this.pos;
366
+ this.writeUInt8(fieldName.nameBytes.length);
367
+ this.writeBytes(fieldName.nameBytes);
368
+ }
369
+ this._examineNode(element);
370
+ }
371
+ }
372
+ }
373
+
374
+ //---------------------------------------------------------------------------
375
+ // _processFieldNames()
376
+ //
377
+ // Processes the field names in preparation for encoding within OSON.
378
+ //---------------------------------------------------------------------------
379
+ _processFieldNames() {
380
+ this.fieldNames.sort((a, b) => {
381
+ if (a.hashId < b.hashId)
382
+ return -1;
383
+ if (a.hashId > b.hashId)
384
+ return 1;
385
+ if (a.nameBytes.length < b.nameBytes.length)
386
+ return -1;
387
+ if (a.nameBytes.length > b.nameBytes.length)
388
+ return 1;
389
+ if (a.name < b.name)
390
+ return -1;
391
+ if (a.name > b.name)
392
+ return 1;
393
+ return 0;
394
+ });
395
+ for (let i = 0; i < this.fieldNames.length; i++) {
396
+ this.fieldNames[i].fieldId = i + 1;
397
+ }
398
+ if (this.fieldNames.length < 256) {
399
+ this.fieldIdSize = 1;
400
+ } else if (this.fieldNames.length < 65536) {
401
+ this.fieldIdSize = 2;
402
+ } else {
403
+ this.fieldIdSize = 4;
404
+ }
405
+ }
406
+
407
+ }
408
+
409
+ class OsonTreeSegment extends GrowableBuffer {
410
+
411
+ //---------------------------------------------------------------------------
412
+ // _encodeArray()
413
+ //
414
+ // Encodes an array in the OSON tree segment.
415
+ //---------------------------------------------------------------------------
416
+ _encodeArray(value, fnamesSeg) {
417
+ this._encodeContainer(constants.TNS_JSON_TYPE_ARRAY, value.length);
418
+ let offsetsBufPos = 0;
419
+ const offsetsBuf = this.reserveBytes(value.length * 4);
420
+ for (let element of value) {
421
+ offsetsBuf.writeUInt32BE(this.pos, offsetsBufPos);
422
+ offsetsBufPos += 4;
423
+ this.encodeNode(element, fnamesSeg);
424
+ }
425
+ }
426
+
427
+ //---------------------------------------------------------------------------
428
+ // _encodeContainer()
429
+ //
430
+ // Encodes the first part of a container (array or object) in the OSON tree
431
+ // segment.
432
+ //---------------------------------------------------------------------------
433
+ _encodeContainer(nodeType, numChildren) {
434
+ nodeType |= 0x20; // use uint32_t for offsets
435
+ if (numChildren > 65535) {
436
+ nodeType |= 0x10; // num children is uint32_t
437
+ } else if (numChildren > 255) {
438
+ nodeType |= 0x08; // num children is uint16_t
439
+ }
440
+ this.writeUInt8(nodeType);
441
+ if (numChildren < 256) {
442
+ this.writeUInt8(numChildren);
443
+ } else if (numChildren < 65536) {
444
+ this.writeUInt16BE(numChildren);
445
+ } else {
446
+ this.writeUInt32BE(numChildren);
447
+ }
448
+ }
449
+
450
+ //---------------------------------------------------------------------------
451
+ // _encodeObject()
452
+ //
453
+ // Encodes an object in the OSON tree segment.
454
+ //---------------------------------------------------------------------------
455
+ _encodeObject(value, fnamesSeg) {
456
+ const numChildren = value.values.length;
457
+ this._encodeContainer(constants.TNS_JSON_TYPE_OBJECT, numChildren);
458
+ let fieldIdOffset = 0;
459
+ let valueOffset = numChildren * fnamesSeg.fieldIdSize;
460
+ const buf = this.reserveBytes(numChildren * (fnamesSeg.fieldIdSize + 4));
461
+ for (let i = 0; i < value.fields.length; i++) {
462
+ const fieldName = fnamesSeg.fieldNamesMap.get(value.fields[i]);
463
+ if (fnamesSeg.fieldIdSize == 1) {
464
+ buf[fieldIdOffset] = fieldName.fieldId;
465
+ } else if (fnamesSeg.fieldIdSize == 2) {
466
+ buf.writeUInt16BE(fieldName.fieldId, fieldIdOffset);
467
+ } else {
468
+ buf.writeUInt32BE(fieldName.fieldId, fieldIdOffset);
469
+ }
470
+ buf.writeUInt32BE(this.pos, valueOffset);
471
+ fieldIdOffset += fnamesSeg.fieldIdSize;
472
+ valueOffset += 4;
473
+ this.encodeNode(value.values[i], fnamesSeg);
474
+ }
475
+ }
476
+
477
+ //---------------------------------------------------------------------------
478
+ // encodeNode()
479
+ //
480
+ // Encodes a value (node) in the OSON tree segment.
481
+ //---------------------------------------------------------------------------
482
+ encodeNode(value, fnamesSeg) {
483
+
484
+ // handle null
485
+ if (value === undefined || value === null) {
486
+ this.writeUInt8(constants.TNS_JSON_TYPE_NULL);
487
+
488
+ // handle booleans
489
+ } else if (typeof value === 'boolean') {
490
+ if (value) {
491
+ this.writeUInt8(constants.TNS_JSON_TYPE_TRUE);
492
+ } else {
493
+ this.writeUInt8(constants.TNS_JSON_TYPE_FALSE);
494
+ }
495
+
496
+ // handle numbers
497
+ } else if (typeof value === 'number') {
498
+ this.writeUInt8(constants.TNS_JSON_TYPE_NUMBER_LENGTH_UINT8);
499
+ this.writeOracleNumber(value.toString());
500
+
501
+ // handle strings
502
+ } else if (typeof value === 'string') {
503
+ const buf = Buffer.from(value);
504
+ if (buf.length < 256) {
505
+ this.writeUInt8(constants.TNS_JSON_TYPE_STRING_LENGTH_UINT8);
506
+ this.writeUInt8(buf.length);
507
+ } else if (buf.length < 65536) {
508
+ this.writeUInt8(constants.TNS_JSON_TYPE_STRING_LENGTH_UINT16);
509
+ this.writeUInt16BE(buf.length);
510
+ } else {
511
+ this.writeUInt8(constants.TNS_JSON_TYPE_STRING_LENGTH_UINT32);
512
+ this.writeUInt32BE(buf.length);
513
+ }
514
+ if (buf.length > 0) {
515
+ this.writeBytes(buf);
516
+ }
517
+
518
+ // handle dates
519
+ } else if (util.isDate(value)) {
520
+ if (value.getUTCMilliseconds() === 0) {
521
+ this.writeUInt8(constants.TNS_JSON_TYPE_TIMESTAMP7);
522
+ this.writeOracleDate(value, types.DB_TYPE_DATE, false);
523
+ } else {
524
+ this.writeUInt8(constants.TNS_JSON_TYPE_TIMESTAMP);
525
+ this.writeOracleDate(value, types.DB_TYPE_TIMESTAMP, false);
526
+ }
527
+
528
+ // handle buffers
529
+ } else if (Buffer.isBuffer(value)) {
530
+ if (value.length < 65536) {
531
+ this.writeUInt8(constants.TNS_JSON_TYPE_BINARY_LENGTH_UINT16);
532
+ this.writeUInt16BE(value.length);
533
+ } else {
534
+ this.writeUInt8(constants.TNS_JSON_TYPE_BINARY_LENGTH_UINT32);
535
+ this.writeUInt32BE(value.length);
536
+ }
537
+ this.writeBytes(value);
538
+
539
+ // handle arrays
540
+ } else if (Array.isArray(value)) {
541
+ this._encodeArray(value, fnamesSeg);
542
+
543
+ // handle objects
544
+ } else {
545
+ this._encodeObject(value, fnamesSeg);
546
+ }
547
+
548
+ }
549
+
550
+ }
551
+
552
+ class OsonEncoder extends GrowableBuffer {
553
+
554
+ //---------------------------------------------------------------------------
555
+ // encode()
556
+ //
557
+ // Encodes the value as OSON and returns a buffer containing the OSON bytes.
558
+ //---------------------------------------------------------------------------
559
+ encode(value) {
560
+
561
+ // determine flags to use
562
+ let fnamesSeg;
563
+ let flags = constants.TNS_JSON_FLAG_INLINE_LEAF;
564
+ if (Array.isArray(value) || (value && Array.isArray(value.fields))) {
565
+ flags |= constants.TNS_JSON_FLAG_HASH_ID_UINT8 |
566
+ constants.TNS_JSON_FLAG_TINY_NODES_STAT;
567
+ fnamesSeg = new OsonFieldNamesSegment(value);
568
+ if (fnamesSeg.fieldNames.length > 65535) {
569
+ flags |= constants.TNS_JSON_FLAG_NUM_FNAMES_UINT32;
570
+ } else if (fnamesSeg.fieldNames.length > 255) {
571
+ flags |= constants.TNS_JSON_FLAG_NUM_FNAMES_UINT16;
572
+ }
573
+ if (fnamesSeg.pos > 65535) {
574
+ flags |= constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32;
575
+ }
576
+ } else {
577
+ flags |= constants.TNS_JSON_FLAG_IS_SCALAR;
578
+ }
579
+
580
+ // encode values into the tree segment
581
+ const treeSeg = new OsonTreeSegment();
582
+ treeSeg.encodeNode(value, fnamesSeg);
583
+ if (treeSeg.pos > 65535) {
584
+ flags |= constants.TNS_JSON_FLAG_TREE_SEG_UINT32;
585
+ }
586
+
587
+ // write initial header
588
+ this.writeUInt8(constants.TNS_JSON_MAGIC_BYTE_1);
589
+ this.writeUInt8(constants.TNS_JSON_MAGIC_BYTE_2);
590
+ this.writeUInt8(constants.TNS_JSON_MAGIC_BYTE_3);
591
+ this.writeUInt8(constants.TNS_JSON_VERSION);
592
+ this.writeUInt16BE(flags);
593
+
594
+ // write extended header (when value is not scalar)
595
+ if (fnamesSeg) {
596
+
597
+ // write number of field names
598
+ if (fnamesSeg.fieldNames.length < 256) {
599
+ this.writeUInt8(fnamesSeg.fieldNames.length);
600
+ } else if (fnamesSeg.fieldNames.length < 65536) {
601
+ this.writeUInt16BE(fnamesSeg.fieldNames.length);
602
+ } else {
603
+ this.writeUInt32BE(fnamesSeg.fieldNames.length);
604
+ }
605
+
606
+ // write size of field names segment
607
+ if (fnamesSeg.pos < 65536) {
608
+ this.writeUInt16BE(fnamesSeg.pos);
609
+ } else {
610
+ this.writeUInt32BE(fnamesSeg.pos);
611
+ }
612
+
613
+ }
614
+
615
+ // write size of tree segment
616
+ if (treeSeg.pos < 65536) {
617
+ this.writeUInt16BE(treeSeg.pos);
618
+ } else {
619
+ this.writeUInt32BE(treeSeg.pos);
620
+ }
621
+
622
+ // write remainder of header and any data (when value is not scalar)
623
+ if (fnamesSeg) {
624
+
625
+ // write number of "tiny" nodes (always zero)
626
+ this.writeUInt16BE(0);
627
+
628
+ // write array of hash ids
629
+ for (let fieldName of fnamesSeg.fieldNames) {
630
+ this.writeUInt8(fieldName.hashId);
631
+ }
632
+
633
+ // write array of field name offsets
634
+ for (let fieldName of fnamesSeg.fieldNames) {
635
+ if (fnamesSeg.pos < 65536) {
636
+ this.writeUInt16BE(fieldName.offset);
637
+ } else {
638
+ this.writeUInt32BE(fieldName.offset);
639
+ }
640
+ }
641
+
642
+ // write field names
643
+ if (fnamesSeg.pos > 0) {
644
+ this.writeBytes(fnamesSeg.buf.subarray(0, fnamesSeg.pos));
645
+ }
646
+
647
+ }
648
+
649
+ // write tree segment data
650
+ this.writeBytes(treeSeg.buf.subarray(0, treeSeg.pos));
651
+
652
+ return this.buf.subarray(0, this.pos);
653
+ }
654
+
655
+ }
656
+
657
+ module.exports = {
658
+ OsonDecoder,
659
+ OsonEncoder
660
+ };