Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.text.CharacterIterator;
import java.text.DateFormat;
Expand Down Expand Up @@ -1012,6 +1011,7 @@ private SchemaAndValue parseMultipleTokensAsTemporal(String token) {
return parseAsTemporal(token);
}


private static SchemaAndValue parseAsNumber(String token) {
// Try to parse as a number ...
BigDecimal decimal = new BigDecimal(token);
Expand All @@ -1032,12 +1032,20 @@ private static SchemaAndValue parseAsNumber(String token) {
}
}

private static boolean isWholeNumber(BigDecimal bd) {
return bd.signum() == 0 || bd.scale() <= 0 || bd.stripTrailingZeros().scale() <= 0;
}

private static final BigDecimal BIGGER_THAN_LONG = new BigDecimal("1e19");

private static SchemaAndValue parseAsExactDecimal(BigDecimal decimal) {
BigDecimal ceil = decimal.setScale(0, RoundingMode.CEILING);
BigDecimal floor = decimal.setScale(0, RoundingMode.FLOOR);
if (ceil.equals(floor)) {
BigInteger num = ceil.toBigIntegerExact();
if (ceil.precision() >= 19 && (num.compareTo(LONG_MIN) < 0 || num.compareTo(LONG_MAX) > 0)) {
BigDecimal abs = decimal.abs();
Comment thread
gharris1727 marked this conversation as resolved.
if (abs.compareTo(BIGGER_THAN_LONG) > 0 || (abs.compareTo(BigDecimal.ONE) < 0 && abs.compareTo(BigDecimal.ZERO) != 0)) {
return null;
}
if (isWholeNumber(decimal)) {
BigInteger num = decimal.toBigIntegerExact();
if (num.compareTo(LONG_MIN) < 0 || num.compareTo(LONG_MAX) > 0) {
return null;
}
long integral = num.longValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,17 @@ public void shouldParseFractionalPartsAsIntegerWhenNoFractionalPart() {
assertEquals(new SchemaAndValue(Schema.FLOAT32_SCHEMA, 66000.0008f), Values.parseString("66000.0008"));
}

@Test
Comment thread
gharris1727 marked this conversation as resolved.
public void avoidCpuAndMemoryIssuesConvertingExtremeBigDecimals() {
String parsingBig = "1e+100000000"; // new BigDecimal().setScale(0, RoundingMode.FLOOR) takes around two minutes and uses 3GB;
BigDecimal valueBig = new BigDecimal(parsingBig);
assertEquals(new SchemaAndValue(Decimal.schema(-100000000), valueBig), Values.parseString(parsingBig), "parsing number that's too big");

String parsingSmall = "1e-100000000";
BigDecimal valueSmall = new BigDecimal(parsingSmall);
assertEquals(new SchemaAndValue(Schema.FLOAT32_SCHEMA, (float) valueSmall.doubleValue()), Values.parseString(parsingSmall), "parsing number that's too big, strictly this should return a bigdecimal");
}

protected void assertParsed(String input) {
assertParsed(input, input);
}
Expand Down