Skip to content

Commit

Permalink
Merge pull request #219 from IanMcCurdy/AllowDecimalWithNoIntegerPart
Browse files Browse the repository at this point in the history
Fix issues with Decimal input parameters
  • Loading branch information
IanMcCurdy authored Nov 14, 2023
2 parents 567f550 + e91ec22 commit 55bc11b
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 8 deletions.
69 changes: 64 additions & 5 deletions lib/protocol/Writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ var REGEX = {
DATE: /(\d{4})-(\d{2})-(\d{2})/,
TIME: /(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)/,
TIMESTAMP: /(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)/,
DECIMAL: /^([+-])?(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/
// DECIMAL will match "" and ".", both of which are invalid, requires an
// additional check
DECIMAL: /^([+-])?(\d*)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$/
};

const maxDecimalMantissaLen = 34;

function Writer(types, useCesu8) {
this._types = types.map(normalizeType);
this.reset();
Expand Down Expand Up @@ -589,20 +593,75 @@ Writer.prototype[TypeCode.SECONDDATE] = function writeSecondDate(value) {
throw createNotImplementedError();
};

function setChar(str, i, c) {
if(i >= str.length) return str;
return str.substring(0, i) + c + str.substring(i + 1);
}

function trimLeadingZeroes(str) {
var i = 0;
while(i < str.length && str[i] === '0') {
++i;
}
return str.substring(i);
}

function trimTrailingZeroes(str) {
var i = str.length - 1;
while(i >= 0 && str[i] === '0') {
--i;
}
return str.substring(0, i + 1);
}

function stringToDecimal(str) {
/* jshint bitwise:false */
var dec = str.match(REGEX.DECIMAL);
if (!dec) {
// REGEX.DECIMAL will match "." and "" despite these being invalid.
if (!dec || str === "." || str === "") {
throw createInputError('DECIMAL');
}
var sign = dec[1] === '-' ? -1 : 1;
var mInt = dec[2] || '0';
var mInt = dec[2] || '';
var mFrac = dec[3] || '';
var exp = ~~dec[4];

mFrac = trimTrailingZeroes(mFrac);
var mantissa = trimLeadingZeroes(mInt + mFrac);
if(mantissa.length === 0) mantissa = "0";
exp -= mFrac.length

// round to maxDecimalMantissaLen digits and increment exp appropriately
if(mantissa.length > maxDecimalMantissaLen) {
var followDigit = mantissa[maxDecimalMantissaLen];
exp += (mantissa.length - maxDecimalMantissaLen)
mantissa = mantissa.substring(0, maxDecimalMantissaLen);
if(followDigit > '4') {
// round up
var i = maxDecimalMantissaLen - 1;
while(i >= 0 && mantissa[i] === '9') {
i -= 1;
}
// i = index of first non-9 digit from back
if(i === -1) {
exp += mantissa.length;
mantissa = "1";
} else {
exp += mantissa.length - 1 - i;
mantissa = mantissa.substring(0, i + 1);
mantissa = setChar(mantissa, i, String.fromCharCode(mantissa.charCodeAt(i) + 1));
}
} else if(mantissa[maxDecimalMantissaLen - 1] === '0') {
var trimmed = trimTrailingZeroes(mantissa);
exp += (maxDecimalMantissaLen - trimmed.length);
mantissa = trimmed;
}
}

return {
s: sign,
m: mInt + mFrac,
e: exp - mFrac.length
m: mantissa,
e: exp
};
}

Expand Down
10 changes: 7 additions & 3 deletions lib/util/bignum.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ var BIN_10_35_5 = 29383;
var BIN_10_35_6 = 16993;
var BIN_10_35_7 = 19;

/* max values for UInt */
var UInt64Max = '18446744073709551615';
var UInt64MaxLen = 20;

function _readInt64(buffer, offset, unsigned) {

var x, y, s, y0, y1, x0, x1, x2;
Expand Down Expand Up @@ -141,10 +145,10 @@ function isUInt64(value) {
if (typeof value === 'number') {
return true;
}
if (value.length < 20) {
if (value.length < UInt64MaxLen) {
return true;
}
if (value.length === 20 && value < '18446744073709551616') {
if (value.length === UInt64MaxLen && value <= UInt64Max) {
return true;
}
return false;
Expand Down Expand Up @@ -775,4 +779,4 @@ exports.writeUInt128LE = writeUInt128;
exports.readDec128 = readDec128;
exports.writeDec128 = writeDec128;
exports.readDecFloat = readDecFloat;
exports.readDecFixed = readDecFixed;
exports.readDecFixed = readDecFixed;
179 changes: 179 additions & 0 deletions test/fixtures/parametersData.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,182 @@ exports.EMOJI = {
'🍩'
]
};

exports.DECIMAL = {
part: {
argumentCount: 1,
buffer: new Buffer(
'057b000000000000000000000000004030' + // 123
'057b0000000000000000000000000040b0' + // -123
'057b000000000000000000000000004030' + // 123
'057b0000000000000000000000000040b0' + // -123
'057b00000000000000000000000000a430' + // 123e50
'057b00000000000000000000000000dcaf' + // -123e-50
'057b000000000000000000000000004030' + // 123
'057b0000000000000000000000000040b0' + // -123
'057b000000000000000000000000004030' + // 123
'057b000000000000000000000000003a30' + // 0.123
'057b000000000000000000000000003ab0' + // -0.123
'057b000000000000000000000000003a30' + // 0.123
'057b000000000000000000000000003ab0' + // -0.123
'0500000000000000000000000000004030' + // 0
'0500000000000000000000000000004030' + // 0
'0500000000000000000000000000004030' + // 0
'0500000000000000000000000000004030' + // 0
'0540e20100000000000000000000003a30' + // 123.456
'0540e20100000000000000000000003ab0' + // -123.456
'0540e20100000000000000000000003a30' + // 123.456
'0540e20100000000000000000000003ab0' + // -123.456
'05ffffffffffffffffffffffffffff4030' + // max 112 bit unsigned int
'05ffffffffffffffffffffffffffff3009' + // max112UInt * 10^-5000
'05ffffffffffffffffffffffffffff40b0' + // -max112UInt
'05ffffffffffffffffffffffffffff50d7' + // -max112UInt * 10^5000
'05ffffffffffffffffffffffffffff5430' + // max112UInt * 10^10
'05ffffffffffffffffffffffffffff54b0' + // -max112UInt * 10^10
'05ffffffffffffffffffffffffffff2c30' + // max112UInt * 10^-10
'05ffffffffffffffffffffffffffff2cb0' + // -max112UInt * 10^-10
'0500000000000000000000000000004130' + // max112UInt + 1
'05000000000000000000000000000041b0' + // -(max112UInt + 1)
'05f3af967ed05c82de3297ff6fde3c6030' + // 1234567890123456789012345678901235
'05f3af967ed05c82de3297ff6fde3c0230' + // 123.4567890123456789012345678901235
'05f3af967ed05c82de3297ff6fde3c60b0' + // -1234567890123456789012345678901235
'05f3af967ed05c82de3297ff6fde3c02b0' + // -123.4567890123456789012345678901235
'057b00000000000000000000000000d42f' + // 123 * 10^-54
'057b00000000000000000000000000d4af' + // -123 * 10^-54
'05fdffffff638e8d37c087adbe09ed4130' + // 9999999999999999999999999999999997
'05feffffff638e8d37c087adbe09ed4130' + // 9999999999999999999999999999999998
'05ffffffff638e8d37c087adbe09ed4130' + // 9999999999999999999999999999999999
'0501000000000000000000000000008430' + // 10000000000000000000000000000000000
'0501000000000000000000000000008430' + // 10000000000000000000000000000000000
'0501000000000000000000000000008430' + // 10000000000000000000000000000000000
'0501000000000000000000000000008430' + // 10000000000000000000000000000000000
'0501000000000000000000000000008430' + // 10000000000000000000000000000000000
'05010000000a5bc138938d44c64d314230' + // 10000000000000000000000000000000010
'05010000000a5bc138938d44c64d314230' + // 10000000000000000000000000000000010
'05010000000a5bc138938d44c64d314230' + // 10000000000000000000000000000000010
'05010000000a5bc138938d44c64d314230' + // 10000000000000000000000000000000010
'05010000000a5bc138938d44c64d314230' + // 10000000000000000000000000000000010
'0501000000000000000000000000008630' + // 100000000000000000000000000000000000
'05fe7fc6a47e8d03000000000000006830' + // 99999999999999800000000000000000000
'05ffffffff638e8d37c087adbe09ed4330' + // 99999999999999999999999999999999990
'0501000000000000000000000000008630' + // 100000000000000000000000000000000000
'05fe7fc6a47e8d03000000000000001ab0' + // -0.0000999999999999998
'05d30a3f4eeee073c3f60fe98e01004e30', 'hex') // 1234567890123456789012345678910000000
},
types: [
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
TypeCode.DECIMAL,
],
values: [
123,
-123,
"123",
"-123",
"123e50",
"-123e-50",
"00000123",
"-00000123",
"123.",
".123",
"-.123",
"00000.123",
"-00000.123",
"0.",
"00000.",
".0",
".00000",
"000123.456",
"-000123.456",
"123.456000",
"-123.456000",
"5192296858534827628530496329220095", // max 112 bit unsigned int
"5192296858534827628530496329220095e-5000",
"-5192296858534827628530496329220095",
"-5192296858534827628530496329220095e5000",
"51922968585348276285304963292200950000000000",
"-51922968585348276285304963292200950000000000",
"519229685853482762853049.6329220095",
"-519229685853482762853049.6329220095",
"5192296858534827628530496329220096", // max 112 bit + 1
"-5192296858534827628530496329220096",
"12345678901234567890123456789012345678901234567890",
"123.45678901234567890123456789012345678901234567890",
"-12345678901234567890123456789012345678901234567890",
"-123.45678901234567890123456789012345678901234567890",
".000000000000000000000000000000000000000000000000000123",
"-.000000000000000000000000000000000000000000000000000123",
"9999999999999999999999999999999997",
"9999999999999999999999999999999998",
"9999999999999999999999999999999999",
"10000000000000000000000000000000000",
"10000000000000000000000000000000001",
"10000000000000000000000000000000002",
"10000000000000000000000000000000003",
"10000000000000000000000000000000004",
"10000000000000000000000000000000005",
"10000000000000000000000000000000006",
"10000000000000000000000000000000007",
"10000000000000000000000000000000008",
"10000000000000000000000000000000009",
"99999999999999999999999999999999999",
"99999999999999799999999999999999999",
"99999999999999999999999999999999994",
"99999999999999999999999999999999995",
"-00000000000000000000000000000000000000009999999999999979999999999999999999999999999999.99900000000000e-50",
"1234567890123456789012345678909999999"
]
};
14 changes: 14 additions & 0 deletions test/lib.Writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ describe('Lib', function () {
});
});

it('should write decimal types', function (done) {
var test = data.DECIMAL;
var writer = Writer.create(test);
writer.getParameters(SIZE, function (err, buffer) {
if (err) {
return done(err);
}
buffer.should.eql(test.part.buffer);
done();
});
});

it('should get WriteLobRequest', function (done) {
var writer = new Writer([TypeCode.BLOB]);
var stream = new lib.util.stream.Readable();
Expand Down Expand Up @@ -383,6 +395,8 @@ describe('Lib', function () {
Writer.prototype.setValues.bind(writer, [false]).should.throw();
// Regex does not match
Writer.prototype.setValues.bind(writer, ['1^6']).should.throw();
Writer.prototype.setValues.bind(writer, ['']).should.throw();
Writer.prototype.setValues.bind(writer, ['.']).should.throw();
});

it('should raise wrong input type error for DATE', function () {
Expand Down

0 comments on commit 55bc11b

Please sign in to comment.