From d5169795024994480d5968cc198cee4b743893a0 Mon Sep 17 00:00:00 2001 From: tjwilson90 Date: Fri, 15 Nov 2019 06:34:17 -0800 Subject: [PATCH] Avoid precision loss in DocValueFormat.RAW#parseLong (#49063) --- .../main/java/org/elasticsearch/search/DocValueFormat.java | 6 ++++++ .../java/org/elasticsearch/search/DocValueFormatTests.java | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/search/DocValueFormat.java b/server/src/main/java/org/elasticsearch/search/DocValueFormat.java index e7f2ae71b155f..4bb406fe370cf 100644 --- a/server/src/main/java/org/elasticsearch/search/DocValueFormat.java +++ b/server/src/main/java/org/elasticsearch/search/DocValueFormat.java @@ -115,6 +115,12 @@ public String format(BytesRef value) { @Override public long parseLong(String value, boolean roundUp, LongSupplier now) { + try { + // Prefer parsing as a long to avoid losing precision + return Long.parseLong(value); + } catch (NumberFormatException e) { + // retry as a double + } double d = Double.parseDouble(value); if (roundUp) { d = Math.ceil(d); diff --git a/server/src/test/java/org/elasticsearch/search/DocValueFormatTests.java b/server/src/test/java/org/elasticsearch/search/DocValueFormatTests.java index 81f5c7982d4d8..d3f4c600bf4e2 100644 --- a/server/src/test/java/org/elasticsearch/search/DocValueFormatTests.java +++ b/server/src/test/java/org/elasticsearch/search/DocValueFormatTests.java @@ -138,6 +138,7 @@ public void testDecimalFormat() { public void testRawParse() { assertEquals(-1L, DocValueFormat.RAW.parseLong("-1", randomBoolean(), null)); assertEquals(1L, DocValueFormat.RAW.parseLong("1", randomBoolean(), null)); + assertEquals(Long.MAX_VALUE - 2, DocValueFormat.RAW.parseLong(Long.toString(Long.MAX_VALUE - 2), randomBoolean(), null)); // not checking exception messages as they could depend on the JVM expectThrows(IllegalArgumentException.class, () -> DocValueFormat.RAW.parseLong("", randomBoolean(), null)); expectThrows(IllegalArgumentException.class, () -> DocValueFormat.RAW.parseLong("abc", randomBoolean(), null)); @@ -146,8 +147,8 @@ public void testRawParse() { assertEquals(1d, DocValueFormat.RAW.parseDouble("1", randomBoolean(), null), 0d); assertEquals(.5, DocValueFormat.RAW.parseDouble("0.5", randomBoolean(), null), 0d); // not checking exception messages as they could depend on the JVM - expectThrows(IllegalArgumentException.class, () -> DocValueFormat.RAW.parseLong("", randomBoolean(), null)); - expectThrows(IllegalArgumentException.class, () -> DocValueFormat.RAW.parseLong("abc", randomBoolean(), null)); + expectThrows(IllegalArgumentException.class, () -> DocValueFormat.RAW.parseDouble("", randomBoolean(), null)); + expectThrows(IllegalArgumentException.class, () -> DocValueFormat.RAW.parseDouble("abc", randomBoolean(), null)); assertEquals(new BytesRef("abc"), DocValueFormat.RAW.parseBytesRef("abc")); }