node-firebird 2.3.3 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +544 -6
- package/lib/callback.d.ts +20 -0
- package/lib/callback.js +6 -16
- package/lib/firebird.msg.json +1370 -1370
- package/lib/gdscodes.d.ts +1519 -1520
- package/lib/gdscodes.js +5 -5
- package/lib/ieee754-decimal.d.ts +38 -0
- package/lib/ieee754-decimal.js +71 -118
- package/lib/index.d.ts +37 -338
- package/lib/index.js +97 -86
- package/lib/messages.d.ts +6 -0
- package/lib/messages.js +135 -162
- package/lib/pool.d.ts +23 -0
- package/lib/pool.js +34 -47
- package/lib/srp.d.ts +51 -0
- package/lib/srp.js +62 -72
- package/lib/types.d.ts +375 -0
- package/lib/types.js +22 -0
- package/lib/unix-crypt.d.ts +1 -0
- package/lib/unix-crypt.js +126 -152
- package/lib/utils.d.ts +16 -0
- package/lib/utils.js +24 -48
- package/lib/wire/connection.d.ts +100 -0
- package/lib/wire/connection.js +1029 -1009
- package/lib/wire/const.d.ts +567 -0
- package/lib/wire/const.js +620 -599
- package/lib/wire/database.d.ts +57 -0
- package/lib/wire/database.js +111 -108
- package/lib/wire/eventConnection.d.ts +16 -0
- package/lib/wire/eventConnection.js +29 -31
- package/lib/wire/fbEventManager.d.ts +45 -0
- package/lib/wire/fbEventManager.js +38 -57
- package/lib/wire/serialize.d.ts +97 -0
- package/lib/wire/serialize.js +42 -141
- package/lib/wire/service.d.ts +66 -0
- package/lib/wire/service.js +374 -401
- package/lib/wire/socket.d.ts +59 -0
- package/lib/wire/socket.js +79 -40
- package/lib/wire/statement.d.ts +25 -0
- package/lib/wire/statement.js +13 -9
- package/lib/wire/transaction.d.ts +21 -0
- package/lib/wire/transaction.js +33 -61
- package/lib/wire/xsqlvar.d.ts +175 -0
- package/lib/wire/xsqlvar.js +169 -269
- package/package.json +12 -4
- package/src/callback.ts +55 -0
- package/{poc/node_modules/node-firebird/lib/gdscodes.js → src/gdscodes.ts} +3 -3
- package/{poc/node_modules/node-firebird/lib/ieee754-decimal.js → src/ieee754-decimal.ts} +7 -14
- package/src/index.ts +157 -0
- package/{poc/node_modules/node-firebird/lib/messages.js → src/messages.ts} +163 -162
- package/src/pool.ts +209 -0
- package/{poc/node_modules/node-firebird/lib/srp.js → src/srp.ts} +74 -33
- package/src/types.ts +419 -0
- package/{poc/node_modules/node-firebird/lib/unix-crypt.js → src/unix-crypt.ts} +6 -12
- package/{poc/node_modules/node-firebird/lib/utils.js → src/utils.ts} +11 -20
- package/{poc/node_modules/node-firebird/lib/wire/connection.js → src/wire/connection.ts} +611 -129
- package/{poc/node_modules/node-firebird/lib/wire/const.js → src/wire/const.ts} +96 -9
- package/{poc/node_modules/node-firebird/lib/wire/database.js → src/wire/database.ts} +110 -44
- package/{poc/node_modules/node-firebird/lib/wire/eventConnection.js → src/wire/eventConnection.ts} +29 -14
- package/{poc/node_modules/node-firebird/lib/wire/fbEventManager.js → src/wire/fbEventManager.ts} +39 -30
- package/{poc/node_modules/node-firebird/lib/wire/serialize.js → src/wire/serialize.ts} +78 -59
- package/{poc/node_modules/node-firebird/lib/wire/service.js → src/wire/service.ts} +90 -88
- package/src/wire/socket.ts +262 -0
- package/src/wire/statement.ts +71 -0
- package/{poc/node_modules/node-firebird/lib/wire/transaction.js → src/wire/transaction.ts} +25 -19
- package/{poc/node_modules/node-firebird/lib/wire/xsqlvar.js → src/wire/xsqlvar.ts} +244 -143
- package/.eslintrc.json +0 -12
- package/.github/workflows/codeql.yml +0 -76
- package/.github/workflows/node.js.yml +0 -95
- package/BIGINT_MIGRATION.md +0 -374
- package/CI_DEBUGGING_GUIDE.md +0 -148
- package/ENCRYPTION_CALLBACK.md +0 -152
- package/FIREBIRD_LOG_FEATURE.md +0 -145
- package/MINIMAL_CHANGES_SUMMARY.md +0 -136
- package/PR_SUMMARY.md +0 -96
- package/ROADMAP.md +0 -223
- package/SRP_PROTOCOL.md +0 -482
- package/poc/README.md +0 -160
- package/poc/helpers.js +0 -59
- package/poc/node_modules/.package-lock.json +0 -14
- package/poc/node_modules/node-firebird/.eslintrc.json +0 -12
- package/poc/node_modules/node-firebird/.github/workflows/codeql.yml +0 -76
- package/poc/node_modules/node-firebird/.github/workflows/node.js.yml +0 -95
- package/poc/node_modules/node-firebird/BIGINT_MIGRATION.md +0 -374
- package/poc/node_modules/node-firebird/CI_DEBUGGING_GUIDE.md +0 -148
- package/poc/node_modules/node-firebird/ENCRYPTION_CALLBACK.md +0 -152
- package/poc/node_modules/node-firebird/FIREBIRD_LOG_FEATURE.md +0 -145
- package/poc/node_modules/node-firebird/LICENSE +0 -373
- package/poc/node_modules/node-firebird/MINIMAL_CHANGES_SUMMARY.md +0 -136
- package/poc/node_modules/node-firebird/PR_SUMMARY.md +0 -96
- package/poc/node_modules/node-firebird/README.md +0 -794
- package/poc/node_modules/node-firebird/ROADMAP.md +0 -223
- package/poc/node_modules/node-firebird/SRP_PROTOCOL.md +0 -482
- package/poc/node_modules/node-firebird/lib/callback.js +0 -38
- package/poc/node_modules/node-firebird/lib/gdscodes.d.ts +0 -1524
- package/poc/node_modules/node-firebird/lib/index.d.ts +0 -316
- package/poc/node_modules/node-firebird/lib/index.js +0 -128
- package/poc/node_modules/node-firebird/lib/pool.js +0 -108
- package/poc/node_modules/node-firebird/lib/wire/socket.js +0 -175
- package/poc/node_modules/node-firebird/lib/wire/statement.js +0 -48
- package/poc/node_modules/node-firebird/package.json +0 -38
- package/poc/node_modules/node-firebird/vitest.config.js +0 -24
- package/poc/package-lock.json +0 -21
- package/poc/package.json +0 -12
- package/poc/reproduce-fixed.js +0 -150
- package/poc/reproduce.js +0 -133
- package/vitest.config.js +0 -27
- /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg +0 -0
- /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg.json +0 -0
package/lib/gdscodes.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* GDS Error codes
|
|
3
4
|
* Extracted from https://www.firebirdsql.org/pdfrefdocs/Firebird-2.1-ErrorCodes.pdf
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GDSCode = void 0;
|
|
6
8
|
const GDSCode = {
|
|
7
9
|
/** Arithmetic exception, numeric overflow, or string */
|
|
8
10
|
ARITH_EXCEPT: 335544321,
|
|
@@ -1521,11 +1523,9 @@ const GDSCode = {
|
|
|
1521
1523
|
/** Unknown switch "@1" */
|
|
1522
1524
|
FBSVCMGR_SWITCH_UNKNOWN: 336986118
|
|
1523
1525
|
};
|
|
1524
|
-
|
|
1526
|
+
exports.GDSCode = GDSCode;
|
|
1525
1527
|
+function makeEnum(_enum) {
|
|
1526
|
-
for (k in _enum)
|
|
1528
|
+
for (var k in _enum)
|
|
1527
1529
|
_enum[_enum[k]] = k;
|
|
1528
1530
|
Object.freeze(_enum);
|
|
1529
1531
|
}(GDSCode);
|
|
1530
|
-
|
|
1531
|
-
module.exports = { GDSCode };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IEEE 754-2008 Decimal Floating Point Support
|
|
3
|
+
*
|
|
4
|
+
* This module implements encoding and decoding of IEEE 754 Decimal64 and Decimal128
|
|
5
|
+
* formats using the BID (Binary Integer Decimal) encoding.
|
|
6
|
+
*
|
|
7
|
+
* Based on the decimal-java library from FirebirdSQL:
|
|
8
|
+
* https://github.com/FirebirdSQL/decimal-java
|
|
9
|
+
*
|
|
10
|
+
* References:
|
|
11
|
+
* - IEEE 754-2008 Standard
|
|
12
|
+
* - https://en.wikipedia.org/wiki/Decimal64_floating-point_format
|
|
13
|
+
* - https://en.wikipedia.org/wiki/Decimal128_floating-point_format
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Encode a number to IEEE 754 Decimal64 format (8 bytes)
|
|
17
|
+
* @param {number|string|BigInt} value - The value to encode
|
|
18
|
+
* @returns {Buffer} - 8-byte buffer containing the Decimal64 encoding
|
|
19
|
+
*/
|
|
20
|
+
export declare function encodeDecimal64(value: number | string | bigint | Buffer | null | undefined): Buffer;
|
|
21
|
+
/**
|
|
22
|
+
* Decode IEEE 754 Decimal64 format (8 bytes) to a string
|
|
23
|
+
* @param {Buffer} buffer - 8-byte buffer containing the Decimal64 encoding
|
|
24
|
+
* @returns {string|number} - Decoded value as string or special value
|
|
25
|
+
*/
|
|
26
|
+
export declare function decodeDecimal64(buffer: Buffer): string | number;
|
|
27
|
+
/**
|
|
28
|
+
* Encode a number to IEEE 754 Decimal128 format (16 bytes)
|
|
29
|
+
* @param {number|string|BigInt} value - The value to encode
|
|
30
|
+
* @returns {Buffer} - 16-byte buffer containing the Decimal128 encoding
|
|
31
|
+
*/
|
|
32
|
+
export declare function encodeDecimal128(value: number | string | bigint | Buffer | null | undefined): Buffer;
|
|
33
|
+
/**
|
|
34
|
+
* Decode IEEE 754 Decimal128 format (16 bytes) to a string
|
|
35
|
+
* @param {Buffer} buffer - 16-byte buffer containing the Decimal128 encoding
|
|
36
|
+
* @returns {string|number} - Decoded value as string or special value
|
|
37
|
+
*/
|
|
38
|
+
export declare function decodeDecimal128(buffer: Buffer): string | number;
|
package/lib/ieee754-decimal.js
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* IEEE 754-2008 Decimal Floating Point Support
|
|
3
|
-
*
|
|
4
|
+
*
|
|
4
5
|
* This module implements encoding and decoding of IEEE 754 Decimal64 and Decimal128
|
|
5
6
|
* formats using the BID (Binary Integer Decimal) encoding.
|
|
6
|
-
*
|
|
7
|
+
*
|
|
7
8
|
* Based on the decimal-java library from FirebirdSQL:
|
|
8
9
|
* https://github.com/FirebirdSQL/decimal-java
|
|
9
|
-
*
|
|
10
|
+
*
|
|
10
11
|
* References:
|
|
11
12
|
* - IEEE 754-2008 Standard
|
|
12
13
|
* - https://en.wikipedia.org/wiki/Decimal64_floating-point_format
|
|
13
14
|
* - https://en.wikipedia.org/wiki/Decimal128_floating-point_format
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.encodeDecimal64 = encodeDecimal64;
|
|
18
|
+
exports.decodeDecimal64 = decodeDecimal64;
|
|
19
|
+
exports.encodeDecimal128 = encodeDecimal128;
|
|
20
|
+
exports.decodeDecimal128 = decodeDecimal128;
|
|
16
21
|
// IEEE 754 Decimal64 constants (16 decimal digits of precision)
|
|
17
22
|
const DECIMAL64_BIAS = 398;
|
|
18
23
|
const DECIMAL64_MAX_EXPONENT = 369;
|
|
19
24
|
const DECIMAL64_MIN_EXPONENT = -398;
|
|
20
25
|
const DECIMAL64_MAX_COEFFICIENT = 9999999999999999n; // 16 digits
|
|
21
|
-
|
|
22
26
|
// IEEE 754 Decimal128 constants (34 decimal digits of precision)
|
|
23
27
|
const DECIMAL128_BIAS = 6176;
|
|
24
28
|
const DECIMAL128_MAX_EXPONENT = 6111;
|
|
25
29
|
const DECIMAL128_MIN_EXPONENT = -6176;
|
|
26
30
|
const DECIMAL128_MAX_COEFFICIENT = 9999999999999999999999999999999999n; // 34 digits
|
|
27
|
-
|
|
28
31
|
// Special value patterns
|
|
29
32
|
const DECIMAL64_INFINITY = 0x7800000000000000n;
|
|
30
|
-
const DECIMAL64_NEG_INFINITY =
|
|
31
|
-
const DECIMAL64_NAN =
|
|
32
|
-
const DECIMAL64_SNAN =
|
|
33
|
-
|
|
33
|
+
const DECIMAL64_NEG_INFINITY = 0xf800000000000000n;
|
|
34
|
+
const DECIMAL64_NAN = 0x7c00000000000000n;
|
|
35
|
+
const DECIMAL64_SNAN = 0x7e00000000000000n;
|
|
34
36
|
const DECIMAL128_INFINITY_HIGH = 0x7800000000000000n;
|
|
35
|
-
const DECIMAL128_NEG_INFINITY_HIGH =
|
|
36
|
-
const DECIMAL128_NAN_HIGH =
|
|
37
|
-
const DECIMAL128_SNAN_HIGH =
|
|
38
|
-
|
|
37
|
+
const DECIMAL128_NEG_INFINITY_HIGH = 0xf800000000000000n;
|
|
38
|
+
const DECIMAL128_NAN_HIGH = 0x7c00000000000000n;
|
|
39
|
+
const DECIMAL128_SNAN_HIGH = 0x7e00000000000000n;
|
|
39
40
|
/**
|
|
40
41
|
* Encode a number to IEEE 754 Decimal64 format (8 bytes)
|
|
41
42
|
* @param {number|string|BigInt} value - The value to encode
|
|
@@ -46,7 +47,6 @@ function encodeDecimal64(value) {
|
|
|
46
47
|
if (value === null || value === undefined) {
|
|
47
48
|
return Buffer.alloc(8);
|
|
48
49
|
}
|
|
49
|
-
|
|
50
50
|
if (typeof value === 'number') {
|
|
51
51
|
if (isNaN(value)) {
|
|
52
52
|
return bigIntToBuffer(DECIMAL64_NAN, 8);
|
|
@@ -56,25 +56,20 @@ function encodeDecimal64(value) {
|
|
|
56
56
|
}
|
|
57
57
|
value = value.toString();
|
|
58
58
|
}
|
|
59
|
-
|
|
60
59
|
if (Buffer.isBuffer(value)) {
|
|
61
60
|
return value.slice(0, 8);
|
|
62
61
|
}
|
|
63
|
-
|
|
64
62
|
// Parse the decimal string
|
|
65
63
|
const str = value.toString();
|
|
66
64
|
const sign = str.startsWith('-') ? 1n : 0n;
|
|
67
65
|
const absStr = str.replace(/^-/, '');
|
|
68
|
-
|
|
69
66
|
// Handle zero
|
|
70
67
|
if (parseFloat(absStr) === 0) {
|
|
71
68
|
return bigIntToBuffer(sign << 63n, 8);
|
|
72
69
|
}
|
|
73
|
-
|
|
74
70
|
// Parse coefficient and exponent
|
|
75
71
|
let coefficient, exponent;
|
|
76
72
|
const eIndex = absStr.toLowerCase().indexOf('e');
|
|
77
|
-
|
|
78
73
|
if (eIndex !== -1) {
|
|
79
74
|
const mantissa = absStr.substring(0, eIndex).replace('.', '');
|
|
80
75
|
coefficient = mantissa === '' || mantissa === '-' ? 0n : BigInt(mantissa);
|
|
@@ -82,54 +77,48 @@ function encodeDecimal64(value) {
|
|
|
82
77
|
const dotIndex = absStr.indexOf('.');
|
|
83
78
|
if (dotIndex !== -1 && dotIndex < eIndex) {
|
|
84
79
|
exponent = parseInt(expPart) - (eIndex - dotIndex - 1);
|
|
85
|
-
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
86
82
|
exponent = parseInt(expPart);
|
|
87
83
|
}
|
|
88
|
-
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
89
86
|
const dotIndex = absStr.indexOf('.');
|
|
90
87
|
if (dotIndex !== -1) {
|
|
91
88
|
const withoutDot = absStr.replace('.', '');
|
|
92
89
|
coefficient = withoutDot === '' || withoutDot === '-' ? 0n : BigInt(withoutDot);
|
|
93
90
|
exponent = -(absStr.length - dotIndex - 1);
|
|
94
|
-
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
95
93
|
coefficient = absStr === '' || absStr === '-' ? 0n : BigInt(absStr);
|
|
96
94
|
exponent = 0;
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
|
-
|
|
100
97
|
// Normalize: remove trailing zeros
|
|
101
98
|
while (coefficient % 10n === 0n && coefficient !== 0n && exponent < DECIMAL64_MAX_EXPONENT) {
|
|
102
99
|
coefficient /= 10n;
|
|
103
100
|
exponent++;
|
|
104
101
|
}
|
|
105
|
-
|
|
106
102
|
// Check coefficient range
|
|
107
103
|
if (coefficient > DECIMAL64_MAX_COEFFICIENT) {
|
|
108
104
|
throw new Error(`Coefficient ${coefficient} exceeds Decimal64 maximum`);
|
|
109
105
|
}
|
|
110
|
-
|
|
111
106
|
// Adjust exponent with bias
|
|
112
107
|
const biasedExponent = exponent + DECIMAL64_BIAS;
|
|
113
108
|
if (biasedExponent < 0 || biasedExponent > 767) {
|
|
114
109
|
throw new Error(`Exponent ${exponent} out of Decimal64 range`);
|
|
115
110
|
}
|
|
116
|
-
|
|
117
111
|
// Encode using BID (Binary Integer Decimal) format
|
|
118
112
|
// Bit layout: S(1) | Combination(5) | Exponent continuation(8) | Coefficient continuation(50)
|
|
119
|
-
|
|
120
113
|
let encoded = 0n;
|
|
121
|
-
|
|
122
114
|
// Sign bit (bit 63)
|
|
123
115
|
encoded |= sign << 63n;
|
|
124
|
-
|
|
125
116
|
// Split coefficient into MSD and continuation
|
|
126
117
|
const msd = Number(coefficient / 1000000000000000n); // Most significant digit
|
|
127
118
|
const coeffCont = coefficient % 1000000000000000n; // Lower 15 digits (50 bits max)
|
|
128
|
-
|
|
129
119
|
const expBigInt = BigInt(biasedExponent);
|
|
130
120
|
const expTop = (expBigInt >> 8n) & 0x3n; // Top 2 bits of exponent (bits 9-8)
|
|
131
|
-
const expLow = expBigInt &
|
|
132
|
-
|
|
121
|
+
const expLow = expBigInt & 0xffn; // Lower 8 bits of exponent (bits 7-0)
|
|
133
122
|
if (msd <= 7) {
|
|
134
123
|
// Combination: G0 G1 G2 G3 G4 where G0 G1 = expTop, G2 G3 G4 = MSD
|
|
135
124
|
const combo = (expTop << 3n) | BigInt(msd);
|
|
@@ -137,20 +126,19 @@ function encodeDecimal64(value) {
|
|
|
137
126
|
// Exponent continuation (8 bits at position 57-50)
|
|
138
127
|
encoded |= expLow << 50n;
|
|
139
128
|
// Coefficient continuation (50 bits at position 49-0)
|
|
140
|
-
encoded |= coeffCont &
|
|
141
|
-
}
|
|
129
|
+
encoded |= coeffCont & 0x3ffffffffffffn;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
142
132
|
// Combination: 11 G2 G3 G4 where G2 = (MSD-8), G3 G4 = expTop
|
|
143
133
|
const combo = 0x18n | ((BigInt(msd - 8) & 0x1n) << 2n) | expTop;
|
|
144
134
|
encoded |= combo << 58n;
|
|
145
135
|
// Exponent continuation (8 bits at position 57-50)
|
|
146
136
|
encoded |= expLow << 50n;
|
|
147
137
|
// Coefficient continuation (50 bits at position 49-0)
|
|
148
|
-
encoded |= coeffCont &
|
|
138
|
+
encoded |= coeffCont & 0x3ffffffffffffn;
|
|
149
139
|
}
|
|
150
|
-
|
|
151
140
|
return bigIntToBuffer(encoded, 8);
|
|
152
141
|
}
|
|
153
|
-
|
|
154
142
|
/**
|
|
155
143
|
* Decode IEEE 754 Decimal64 format (8 bytes) to a string
|
|
156
144
|
* @param {Buffer} buffer - 8-byte buffer containing the Decimal64 encoding
|
|
@@ -160,27 +148,22 @@ function decodeDecimal64(buffer) {
|
|
|
160
148
|
if (buffer.length !== 8) {
|
|
161
149
|
throw new Error('Decimal64 buffer must be 8 bytes');
|
|
162
150
|
}
|
|
163
|
-
|
|
164
151
|
const encoded = bufferToBigInt(buffer);
|
|
165
|
-
|
|
166
152
|
// Extract sign
|
|
167
153
|
const sign = (encoded >> 63n) & 0x1n;
|
|
168
|
-
|
|
169
154
|
// Extract combination field (bits 62-58, 5 bits)
|
|
170
|
-
const combo = (encoded >> 58n) &
|
|
171
|
-
|
|
172
|
-
if ((combo & 0x1En) === 0x1En) {
|
|
155
|
+
const combo = (encoded >> 58n) & 0x1fn;
|
|
156
|
+
if ((combo & 0x1en) === 0x1en) {
|
|
173
157
|
// Special value (NaN or Infinity)
|
|
174
158
|
if ((combo & 0x1n) === 0n) {
|
|
175
159
|
return sign ? -Infinity : Infinity;
|
|
176
|
-
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
177
162
|
return NaN;
|
|
178
163
|
}
|
|
179
164
|
}
|
|
180
|
-
|
|
181
165
|
// Decode exponent and coefficient
|
|
182
166
|
let exponent, coefficient, msd;
|
|
183
|
-
|
|
184
167
|
if ((combo & 0x18n) !== 0x18n) {
|
|
185
168
|
// Combination: G0 G1 G2 G3 G4 where G0 G1 != 11
|
|
186
169
|
// MSD is G2 G3 G4 (bits 2-0 of combo)
|
|
@@ -188,53 +171,52 @@ function decodeDecimal64(buffer) {
|
|
|
188
171
|
// Exponent top 2 bits are G0 G1 (bits 4-3 of combo)
|
|
189
172
|
const expTop = (combo >> 3n) & 0x3n;
|
|
190
173
|
// Exponent continuation is bits 57-50 (8 bits)
|
|
191
|
-
const expLow = (encoded >> 50n) &
|
|
174
|
+
const expLow = (encoded >> 50n) & 0xffn;
|
|
192
175
|
exponent = (expTop << 8n) | expLow;
|
|
193
176
|
// Coefficient continuation is bits 49-0 (50 bits)
|
|
194
|
-
const coeffCont = encoded &
|
|
177
|
+
const coeffCont = encoded & 0x3ffffffffffffn;
|
|
195
178
|
coefficient = BigInt(msd) * 1000000000000000n + coeffCont;
|
|
196
|
-
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
197
181
|
// Combination: 11 G2 G3 G4 (MSD 8-9)
|
|
198
182
|
// MSD is 8 + G2 (bit 2 of combo)
|
|
199
183
|
msd = 8 + Number((combo >> 2n) & 0x1n);
|
|
200
184
|
// Exponent top 2 bits are G3 G4 (bits 1-0 of combo)
|
|
201
185
|
const expTop = combo & 0x3n;
|
|
202
186
|
// Exponent continuation is bits 57-50 (8 bits)
|
|
203
|
-
const expLow = (encoded >> 50n) &
|
|
187
|
+
const expLow = (encoded >> 50n) & 0xffn;
|
|
204
188
|
exponent = (expTop << 8n) | expLow;
|
|
205
189
|
// Coefficient continuation is bits 49-0 (50 bits)
|
|
206
|
-
const coeffCont = encoded &
|
|
190
|
+
const coeffCont = encoded & 0x3ffffffffffffn;
|
|
207
191
|
coefficient = BigInt(msd) * 1000000000000000n + coeffCont;
|
|
208
192
|
}
|
|
209
|
-
|
|
210
193
|
// Remove bias from exponent
|
|
211
194
|
const unbias = Number(exponent) - DECIMAL64_BIAS;
|
|
212
|
-
|
|
213
195
|
// Build result string
|
|
214
196
|
const coeffStr = coefficient.toString();
|
|
215
197
|
const signStr = sign ? '-' : '';
|
|
216
|
-
|
|
217
198
|
// Special case: if coefficient is 0, just return "0" regardless of exponent
|
|
218
199
|
if (coefficient === 0n) {
|
|
219
200
|
return signStr + '0';
|
|
220
201
|
}
|
|
221
|
-
|
|
222
202
|
if (unbias === 0) {
|
|
223
203
|
return signStr + coeffStr;
|
|
224
|
-
}
|
|
204
|
+
}
|
|
205
|
+
else if (unbias > 0) {
|
|
225
206
|
return signStr + coeffStr + '0'.repeat(unbias);
|
|
226
|
-
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
227
209
|
const absExp = -unbias;
|
|
228
210
|
if (absExp >= coeffStr.length) {
|
|
229
211
|
return signStr + '0.' + '0'.repeat(absExp - coeffStr.length) + coeffStr;
|
|
230
|
-
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
231
214
|
const intPart = coeffStr.substring(0, coeffStr.length - absExp);
|
|
232
215
|
const fracPart = coeffStr.substring(coeffStr.length - absExp);
|
|
233
216
|
return signStr + intPart + '.' + fracPart;
|
|
234
217
|
}
|
|
235
218
|
}
|
|
236
219
|
}
|
|
237
|
-
|
|
238
220
|
/**
|
|
239
221
|
* Encode a number to IEEE 754 Decimal128 format (16 bytes)
|
|
240
222
|
* @param {number|string|BigInt} value - The value to encode
|
|
@@ -245,7 +227,6 @@ function encodeDecimal128(value) {
|
|
|
245
227
|
if (value === null || value === undefined) {
|
|
246
228
|
return Buffer.alloc(16);
|
|
247
229
|
}
|
|
248
|
-
|
|
249
230
|
if (typeof value === 'number') {
|
|
250
231
|
if (isNaN(value)) {
|
|
251
232
|
const buf = Buffer.alloc(16);
|
|
@@ -259,27 +240,22 @@ function encodeDecimal128(value) {
|
|
|
259
240
|
}
|
|
260
241
|
value = value.toString();
|
|
261
242
|
}
|
|
262
|
-
|
|
263
243
|
if (Buffer.isBuffer(value)) {
|
|
264
244
|
return value.slice(0, 16);
|
|
265
245
|
}
|
|
266
|
-
|
|
267
246
|
// Parse the decimal string
|
|
268
247
|
const str = value.toString();
|
|
269
248
|
const sign = str.startsWith('-') ? 1n : 0n;
|
|
270
249
|
const absStr = str.replace(/^-/, '');
|
|
271
|
-
|
|
272
250
|
// Handle zero
|
|
273
251
|
if (parseFloat(absStr) === 0) {
|
|
274
252
|
const buf = Buffer.alloc(16);
|
|
275
253
|
bufferWriteBigInt(buf, sign << 63n, 0, 8);
|
|
276
254
|
return buf;
|
|
277
255
|
}
|
|
278
|
-
|
|
279
256
|
// Parse coefficient and exponent
|
|
280
257
|
let coefficient, exponent;
|
|
281
258
|
const eIndex = absStr.toLowerCase().indexOf('e');
|
|
282
|
-
|
|
283
259
|
if (eIndex !== -1) {
|
|
284
260
|
const mantissa = absStr.substring(0, eIndex).replace('.', '');
|
|
285
261
|
coefficient = mantissa === '' || mantissa === '-' ? 0n : BigInt(mantissa);
|
|
@@ -287,56 +263,49 @@ function encodeDecimal128(value) {
|
|
|
287
263
|
const dotIndex = absStr.indexOf('.');
|
|
288
264
|
if (dotIndex !== -1 && dotIndex < eIndex) {
|
|
289
265
|
exponent = parseInt(expPart) - (eIndex - dotIndex - 1);
|
|
290
|
-
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
291
268
|
exponent = parseInt(expPart);
|
|
292
269
|
}
|
|
293
|
-
}
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
294
272
|
const dotIndex = absStr.indexOf('.');
|
|
295
273
|
if (dotIndex !== -1) {
|
|
296
274
|
const withoutDot = absStr.replace('.', '');
|
|
297
275
|
coefficient = withoutDot === '' || withoutDot === '-' ? 0n : BigInt(withoutDot);
|
|
298
276
|
exponent = -(absStr.length - dotIndex - 1);
|
|
299
|
-
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
300
279
|
coefficient = absStr === '' || absStr === '-' ? 0n : BigInt(absStr);
|
|
301
280
|
exponent = 0;
|
|
302
281
|
}
|
|
303
282
|
}
|
|
304
|
-
|
|
305
283
|
// Normalize: remove trailing zeros
|
|
306
284
|
while (coefficient % 10n === 0n && coefficient !== 0n && exponent < DECIMAL128_MAX_EXPONENT) {
|
|
307
285
|
coefficient /= 10n;
|
|
308
286
|
exponent++;
|
|
309
287
|
}
|
|
310
|
-
|
|
311
288
|
// Check coefficient range
|
|
312
289
|
if (coefficient > DECIMAL128_MAX_COEFFICIENT) {
|
|
313
290
|
throw new Error(`Coefficient ${coefficient} exceeds Decimal128 maximum`);
|
|
314
291
|
}
|
|
315
|
-
|
|
316
292
|
// Adjust exponent with bias
|
|
317
293
|
const biasedExponent = exponent + DECIMAL128_BIAS;
|
|
318
294
|
if (biasedExponent < 0 || biasedExponent > 12287) {
|
|
319
295
|
throw new Error(`Exponent ${exponent} out of Decimal128 range`);
|
|
320
296
|
}
|
|
321
|
-
|
|
322
297
|
// Encode using BID format
|
|
323
298
|
// Bit layout: S(1) | Combination(5) | Exponent continuation(12) | Coefficient continuation(110)
|
|
324
|
-
|
|
325
299
|
const expBigInt = BigInt(biasedExponent);
|
|
326
|
-
|
|
327
300
|
// Split coefficient into MSD and continuation
|
|
328
301
|
const msd = Number(coefficient / 1000000000000000000000000000000000n); // Most significant digit (10^33)
|
|
329
302
|
const coeffCont = coefficient % 1000000000000000000000000000000000n; // Lower 33 digits (110 bits max)
|
|
330
|
-
|
|
331
303
|
let high = 0n;
|
|
332
304
|
let low = coeffCont & ((1n << 64n) - 1n); // Lower 64 bits of coefficient
|
|
333
|
-
|
|
334
305
|
// Sign bit (bit 127)
|
|
335
306
|
high |= sign << 63n;
|
|
336
|
-
|
|
337
307
|
const expTop = (expBigInt >> 12n) & 0x3n; // Top 2 bits of exponent (bits 13-12)
|
|
338
|
-
const expLow = expBigInt &
|
|
339
|
-
|
|
308
|
+
const expLow = expBigInt & 0xfffn; // Lower 12 bits of exponent (bits 11-0)
|
|
340
309
|
if (msd <= 7) {
|
|
341
310
|
// Combination: G0 G1 G2 G3 G4 where G0 G1 = expTop, G2 G3 G4 = MSD
|
|
342
311
|
const combo = (expTop << 3n) | BigInt(msd);
|
|
@@ -344,23 +313,22 @@ function encodeDecimal128(value) {
|
|
|
344
313
|
// Exponent continuation (12 bits at position 121-110, which is bits 57-46 in high)
|
|
345
314
|
high |= expLow << 46n;
|
|
346
315
|
// Coefficient continuation high 46 bits (bits 109-64, which is bits 45-0 in high)
|
|
347
|
-
high |= (coeffCont >> 64n) &
|
|
348
|
-
}
|
|
316
|
+
high |= (coeffCont >> 64n) & 0x3fffffffffffn;
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
349
319
|
// Combination: 11 G2 G3 G4 where G2 = (MSD-8), G3 G4 = expTop
|
|
350
320
|
const combo = 0x18n | ((BigInt(msd - 8) & 0x1n) << 2n) | expTop;
|
|
351
321
|
high |= combo << 58n;
|
|
352
322
|
// Exponent continuation (12 bits at position 121-110)
|
|
353
323
|
high |= expLow << 46n;
|
|
354
324
|
// Coefficient continuation high 46 bits
|
|
355
|
-
high |= (coeffCont >> 64n) &
|
|
325
|
+
high |= (coeffCont >> 64n) & 0x3fffffffffffn;
|
|
356
326
|
}
|
|
357
|
-
|
|
358
327
|
const buf = Buffer.alloc(16);
|
|
359
328
|
bufferWriteBigInt(buf, high, 0, 8);
|
|
360
329
|
bufferWriteBigInt(buf, low, 8, 8);
|
|
361
330
|
return buf;
|
|
362
331
|
}
|
|
363
|
-
|
|
364
332
|
/**
|
|
365
333
|
* Decode IEEE 754 Decimal128 format (16 bytes) to a string
|
|
366
334
|
* @param {Buffer} buffer - 16-byte buffer containing the Decimal128 encoding
|
|
@@ -370,28 +338,23 @@ function decodeDecimal128(buffer) {
|
|
|
370
338
|
if (buffer.length !== 16) {
|
|
371
339
|
throw new Error('Decimal128 buffer must be 16 bytes');
|
|
372
340
|
}
|
|
373
|
-
|
|
374
341
|
const high = bufferToBigInt(buffer.slice(0, 8));
|
|
375
342
|
const low = bufferToBigInt(buffer.slice(8, 16));
|
|
376
|
-
|
|
377
343
|
// Extract sign
|
|
378
344
|
const sign = (high >> 63n) & 0x1n;
|
|
379
|
-
|
|
380
345
|
// Check for special values
|
|
381
|
-
const combo = (high >> 58n) &
|
|
382
|
-
|
|
383
|
-
if ((combo & 0x1En) === 0x1En) {
|
|
346
|
+
const combo = (high >> 58n) & 0x1fn;
|
|
347
|
+
if ((combo & 0x1en) === 0x1en) {
|
|
384
348
|
// Special value (NaN or Infinity)
|
|
385
349
|
if ((combo & 0x1n) === 0n) {
|
|
386
350
|
return sign ? -Infinity : Infinity;
|
|
387
|
-
}
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
388
353
|
return NaN;
|
|
389
354
|
}
|
|
390
355
|
}
|
|
391
|
-
|
|
392
356
|
// Decode exponent and coefficient
|
|
393
357
|
let exponent, coefficient, msd;
|
|
394
|
-
|
|
395
358
|
if ((combo & 0x18n) !== 0x18n) {
|
|
396
359
|
// Combination: G0 G1 G2 G3 G4 where G0 G1 != 11
|
|
397
360
|
// MSD is G2 G3 G4 (bits 2-0 of combo)
|
|
@@ -399,55 +362,54 @@ function decodeDecimal128(buffer) {
|
|
|
399
362
|
// Exponent top 2 bits are G0 G1 (bits 4-3 of combo)
|
|
400
363
|
const expTop = (combo >> 3n) & 0x3n;
|
|
401
364
|
// Exponent continuation is bits 121-110 (bits 57-46 in high, 12 bits)
|
|
402
|
-
const expLow = (high >> 46n) &
|
|
365
|
+
const expLow = (high >> 46n) & 0xfffn;
|
|
403
366
|
exponent = (expTop << 12n) | expLow;
|
|
404
367
|
// Coefficient continuation is bits 109-0 (bits 45-0 in high + all 64 bits in low = 110 bits)
|
|
405
|
-
const coeffHigh = high &
|
|
368
|
+
const coeffHigh = high & 0x3fffffffffffn; // 46 bits
|
|
406
369
|
coefficient = (coeffHigh << 64n) | low; // Combine with low 64 bits
|
|
407
370
|
coefficient = BigInt(msd) * 1000000000000000000000000000000000n + coefficient;
|
|
408
|
-
}
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
409
373
|
// Combination: 11 G2 G3 G4 (MSD 8-9)
|
|
410
374
|
// MSD is 8 + G2 (bit 2 of combo)
|
|
411
375
|
msd = 8 + Number((combo >> 2n) & 0x1n);
|
|
412
376
|
// Exponent top 2 bits are G3 G4 (bits 1-0 of combo)
|
|
413
377
|
const expTop = combo & 0x3n;
|
|
414
378
|
// Exponent continuation is bits 121-110 (12 bits)
|
|
415
|
-
const expLow = (high >> 46n) &
|
|
379
|
+
const expLow = (high >> 46n) & 0xfffn;
|
|
416
380
|
exponent = (expTop << 12n) | expLow;
|
|
417
381
|
// Coefficient continuation is bits 109-0 (110 bits)
|
|
418
|
-
const coeffHigh = high &
|
|
382
|
+
const coeffHigh = high & 0x3fffffffffffn; // 46 bits
|
|
419
383
|
coefficient = (coeffHigh << 64n) | low;
|
|
420
384
|
coefficient = BigInt(msd) * 1000000000000000000000000000000000n + coefficient;
|
|
421
385
|
}
|
|
422
|
-
|
|
423
386
|
// Remove bias
|
|
424
387
|
const unbias = Number(exponent) - DECIMAL128_BIAS;
|
|
425
|
-
|
|
426
388
|
// Build result string
|
|
427
389
|
const coeffStr = coefficient.toString();
|
|
428
390
|
const signStr = sign ? '-' : '';
|
|
429
|
-
|
|
430
391
|
// Special case: if coefficient is 0, just return "0"
|
|
431
392
|
if (coefficient === 0n) {
|
|
432
393
|
return signStr + '0';
|
|
433
394
|
}
|
|
434
|
-
|
|
435
395
|
if (unbias === 0) {
|
|
436
396
|
return signStr + coeffStr;
|
|
437
|
-
}
|
|
397
|
+
}
|
|
398
|
+
else if (unbias > 0) {
|
|
438
399
|
return signStr + coeffStr + '0'.repeat(unbias);
|
|
439
|
-
}
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
440
402
|
const absExp = -unbias;
|
|
441
403
|
if (absExp >= coeffStr.length) {
|
|
442
404
|
return signStr + '0.' + '0'.repeat(absExp - coeffStr.length) + coeffStr;
|
|
443
|
-
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
444
407
|
const intPart = coeffStr.substring(0, coeffStr.length - absExp);
|
|
445
408
|
const fracPart = coeffStr.substring(coeffStr.length - absExp);
|
|
446
409
|
return signStr + intPart + '.' + fracPart;
|
|
447
410
|
}
|
|
448
411
|
}
|
|
449
412
|
}
|
|
450
|
-
|
|
451
413
|
/**
|
|
452
414
|
* Convert a BigInt to a Buffer (big-endian)
|
|
453
415
|
* @param {BigInt} value - The BigInt value
|
|
@@ -458,12 +420,11 @@ function bigIntToBuffer(value, size) {
|
|
|
458
420
|
const buf = Buffer.alloc(size);
|
|
459
421
|
let val = BigInt(value.toString());
|
|
460
422
|
for (let i = size - 1; i >= 0; i--) {
|
|
461
|
-
buf[i] = Number(val &
|
|
423
|
+
buf[i] = Number(val & 0xffn);
|
|
462
424
|
val >>= 8n;
|
|
463
425
|
}
|
|
464
426
|
return buf;
|
|
465
427
|
}
|
|
466
|
-
|
|
467
428
|
/**
|
|
468
429
|
* Convert a Buffer to BigInt (big-endian)
|
|
469
430
|
* @param {Buffer} buffer
|
|
@@ -476,7 +437,6 @@ function bufferToBigInt(buffer) {
|
|
|
476
437
|
}
|
|
477
438
|
return result;
|
|
478
439
|
}
|
|
479
|
-
|
|
480
440
|
/**
|
|
481
441
|
* Write BigInt to buffer at offset (big-endian)
|
|
482
442
|
* @param {Buffer} buffer
|
|
@@ -487,14 +447,7 @@ function bufferToBigInt(buffer) {
|
|
|
487
447
|
function bufferWriteBigInt(buffer, value, offset, size) {
|
|
488
448
|
let val = BigInt(value.toString());
|
|
489
449
|
for (let i = offset + size - 1; i >= offset; i--) {
|
|
490
|
-
buffer[i] = Number(val &
|
|
450
|
+
buffer[i] = Number(val & 0xffn);
|
|
491
451
|
val >>= 8n;
|
|
492
452
|
}
|
|
493
453
|
}
|
|
494
|
-
|
|
495
|
-
module.exports = {
|
|
496
|
-
encodeDecimal64,
|
|
497
|
-
decodeDecimal64,
|
|
498
|
-
encodeDecimal128,
|
|
499
|
-
decodeDecimal128
|
|
500
|
-
};
|