-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Coerce decimal strings for whole number types by truncating the decimal part #25835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -312,13 +312,7 @@ public List<Field> createFields(String name, Number value, | |
| DOUBLE("double", NumericType.DOUBLE) { | ||
| @Override | ||
| Double parse(Object value, boolean coerce) { | ||
| if (value instanceof Number) { | ||
| return ((Number) value).doubleValue(); | ||
| } | ||
| if (value instanceof BytesRef) { | ||
| value = ((BytesRef) value).utf8ToString(); | ||
| } | ||
| return Double.parseDouble(value.toString()); | ||
| return objectToDouble(value); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -389,20 +383,20 @@ public List<Field> createFields(String name, Number value, | |
| BYTE("byte", NumericType.BYTE) { | ||
| @Override | ||
| Byte parse(Object value, boolean coerce) { | ||
| double doubleValue = objectToDouble(value); | ||
|
|
||
| if (doubleValue < Byte.MIN_VALUE || doubleValue > Byte.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a byte"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
|
|
||
| if (value instanceof Number) { | ||
| double doubleValue = ((Number) value).doubleValue(); | ||
| if (doubleValue < Byte.MIN_VALUE || doubleValue > Byte.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a byte"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
| return ((Number) value).byteValue(); | ||
| } | ||
| if (value instanceof BytesRef) { | ||
| value = ((BytesRef) value).utf8ToString(); | ||
| } | ||
| return Byte.parseByte(value.toString()); | ||
|
|
||
| return (byte) doubleValue; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -445,29 +439,25 @@ Number valueForSearch(Number value) { | |
| SHORT("short", NumericType.SHORT) { | ||
| @Override | ||
| Short parse(Object value, boolean coerce) { | ||
| double doubleValue = objectToDouble(value); | ||
|
|
||
| if (doubleValue < Short.MIN_VALUE || doubleValue > Short.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a short"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
|
|
||
| if (value instanceof Number) { | ||
| double doubleValue = ((Number) value).doubleValue(); | ||
| if (doubleValue < Short.MIN_VALUE || doubleValue > Short.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a short"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
| return ((Number) value).shortValue(); | ||
| } | ||
| if (value instanceof BytesRef) { | ||
| value = ((BytesRef) value).utf8ToString(); | ||
| } | ||
| return Short.parseShort(value.toString()); | ||
|
|
||
| return (short) doubleValue; | ||
| } | ||
|
|
||
| @Override | ||
| Short parse(XContentParser parser, boolean coerce) throws IOException { | ||
| int value = parser.intValue(coerce); | ||
| if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a short"); | ||
| } | ||
| return (short) value; | ||
| return parser.shortValue(coerce); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -501,20 +491,20 @@ Number valueForSearch(Number value) { | |
| INTEGER("integer", NumericType.INT) { | ||
| @Override | ||
| Integer parse(Object value, boolean coerce) { | ||
| double doubleValue = objectToDouble(value); | ||
|
|
||
| if (doubleValue < Integer.MIN_VALUE || doubleValue > Integer.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for an integer"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
|
|
||
| if (value instanceof Number) { | ||
| double doubleValue = ((Number) value).doubleValue(); | ||
| if (doubleValue < Integer.MIN_VALUE || doubleValue > Integer.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for an integer"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
| return ((Number) value).intValue(); | ||
| } | ||
| if (value instanceof BytesRef) { | ||
| value = ((BytesRef) value).utf8ToString(); | ||
| } | ||
| return Integer.parseInt(value.toString()); | ||
|
|
||
| return (int) doubleValue; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -612,20 +602,27 @@ public List<Field> createFields(String name, Number value, | |
| LONG("long", NumericType.LONG) { | ||
| @Override | ||
| Long parse(Object value, boolean coerce) { | ||
| double doubleValue = objectToDouble(value); | ||
|
|
||
| if (doubleValue < Long.MIN_VALUE || doubleValue > Long.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a long"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
|
|
||
| if (value instanceof Number) { | ||
| double doubleValue = ((Number) value).doubleValue(); | ||
| if (doubleValue < Long.MIN_VALUE || doubleValue > Long.MAX_VALUE) { | ||
| throw new IllegalArgumentException("Value [" + value + "] is out of range for a long"); | ||
| } | ||
| if (!coerce && doubleValue % 1 != 0) { | ||
| throw new IllegalArgumentException("Value [" + value + "] has a decimal part"); | ||
| } | ||
| return ((Number) value).longValue(); | ||
| } | ||
| if (value instanceof BytesRef) { | ||
| value = ((BytesRef) value).utf8ToString(); | ||
|
|
||
| // longs need special handling so we don't lose precision while parsing | ||
| String stringValue = (value instanceof BytesRef) ? ((BytesRef) value).utf8ToString() : value.toString(); | ||
|
|
||
| try { | ||
| return Long.parseLong(stringValue); | ||
| } catch (NumberFormatException e) { | ||
| return (long) Double.parseDouble(stringValue); | ||
|
||
| } | ||
| return Long.parseLong(value.toString()); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -781,6 +778,23 @@ boolean hasDecimalPart(Object number) { | |
| return Math.signum(Double.parseDouble(value.toString())); | ||
| } | ||
|
|
||
| /** | ||
| * Converts an Object to a double by checking it against known types first | ||
| */ | ||
| private static double objectToDouble(Object value) { | ||
| double doubleValue; | ||
|
|
||
| if (value instanceof Number) { | ||
| doubleValue = ((Number) value).doubleValue(); | ||
| } else if (value instanceof BytesRef) { | ||
| doubleValue = Double.parseDouble(((BytesRef) value).utf8ToString()); | ||
| } else { | ||
| doubleValue = Double.parseDouble(value.toString()); | ||
| } | ||
|
|
||
| return doubleValue; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| public static final class NumberFieldType extends MappedFieldType { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I deleted your comment by mistake, so I am adding it back:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed it should be changed to be consistent, but let's do it in a separate PR? Thinking more about it, I'm wondering whether we should remove the
coerceoption instead. I opened #25861.