Skip to content

Commit eeb989c

Browse files
committed
Merge branch '3.8-dev'
2 parents 8b5ef0a + 9c7a54c commit eeb989c

13 files changed

Lines changed: 782 additions & 92 deletions

File tree

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
9494
9595
This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>.
9696
97+
* Modified mathematical operators to prevent overflows in steps such as `sum()` and 'sack()' to prefer promotion to the next highest number type.
9798
* Added `DateTime` ontop of the existing 'datetime' grammar.
9899
* Added UUID() + UUID(value) to grammar
99100
* Modified `TraversalStrategy` construction in Javascript where configurations are now supplied as a `Map` of options.

docs/src/dev/provider/gremlin-semantics.asciidoc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ TinkerPop performs type promotion a.k.a type casting for Numbers. Numbers are By
8585
Double, BigInteger, and BigDecimal. In general, numbers are compared using semantic equivalence, without regard for
8686
their specific type, e.g. `1 == 1.0`.
8787
88-
Numeric types are promoted as follows:
88+
For comparisons numeric types are promoted as follows:
8989
9090
* First determine whether to use floating point or not. If any numbers in the comparison are floating point then we
9191
convert all of them to floating point.
@@ -104,6 +104,16 @@ convert all of them to floating point.
104104
BigDecimal and BigInteger may not be supported depending on the language and Storage, therefore the behavior of type
105105
casting for these two types can vary depending on a Graph provider.
106106
107+
For numeric type mathematical operations (div/mul/add/sub), types are promoted as follows:
108+
109+
On math operations (when used in steps such as sum/sack) the highest common number class between
110+
the two inputs is used. Any number being floating point forces a floating point result.
111+
If an overflow occurs (either integer or floating-point), the method promotes the precision
112+
by increasing the bit width, until a suitable type is found. If no suitable type exists
113+
(e.g., for very large integers beyond 64-bit), an Arithmetic Exception is thrown.
114+
For floating-point numbers, if double overflows, the result is Double.POSITIVE_INFINITY
115+
or Double.NEGATIVE_INFINITY instead of an exception.
116+
107117
[[gremlin-semantics-concepts]]
108118
== Comparability, Equality, Orderability, and Equivalence
109119

docs/src/upgrade/release-3.8.x.asciidoc

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,47 @@ complete list of all the modifications that are part of this release.
3030
3131
=== Upgrading for Users
3232
33+
==== Auto promotion of number types
34+
35+
Previously, operations like sum or sack that involved mathematical calculations did not automatically promote the result
36+
to a larger numeric type (e.g., from int to long) when needed. As a result, values could wrap around within their current
37+
type, leading to unexpected behavior. This issue has now been resolved by enabling automatic type promotion for results.
38+
39+
Now, any mathematical operations such as Add, Sub, Mul, and Div will now automatically promote to the next numeric type
40+
if an overflow is detected. For integers, the promotion sequence is: byte → short → int → long → overflow exception. For
41+
floating-point numbers, the sequence is: float → double → infinity.
42+
43+
The following example showcases the change in overflow behavior between 3.7.3 and 3.8.0
44+
45+
[source,groovy]
46+
----
47+
// 3.7.3
48+
gremlin> g.inject([Byte.MAX_VALUE, (byte) 1], [Short.MAX_VALUE, (short) 1], [Integer.MAX_VALUE,1], [Long.MAX_VALUE, 1l]).sum(local)
49+
==>-128 // byte
50+
==>-32768 // short
51+
==>-2147483648 // int
52+
==>-9223372036854775808 // long
53+
54+
gremlin> g.inject([Float.MAX_VALUE, Float.MAX_VALUE], [Double.MAX_VALUE, Double.MAX_VALUE]).sum(local)
55+
==>Infinity // float
56+
==>Infinity // double
57+
58+
// 3.8.0
59+
gremlin> g.inject([Byte.MAX_VALUE, (byte) 1], [Short.MAX_VALUE, (short) 1], [Integer.MAX_VALUE,1]).sum(local)
60+
==>128 // short
61+
==>32768 // int
62+
==>2147483648 // long
63+
64+
gremlin> g.inject([Long.MAX_VALUE, 1l]).sum(local)
65+
// throws java.lang.ArithmeticException: long overflow
66+
67+
gremlin> g.inject([Float.MAX_VALUE, Float.MAX_VALUE], [Double.MAX_VALUE, Double.MAX_VALUE]).sum(local)
68+
==>6.805646932770577E38 // double
69+
==>Infinity // double
70+
----
71+
72+
See link:https://issues.apache.org/jira/browse/TINKERPOP-3115[TINKERPOP-3115] for more details.
73+
3374
==== The Switch from Date to OffsetDateTime
3475
The default implementation for date type in Gremlin is now changed from the `java.util.Date` to the more encompassing `java.time.OffsetDateTime`. This means the reference implementation for all date manipulation steps, `asDate()`, `dateAdd()`, and `dateDiff()`, as well as helper methods `datetime()`, will return `OffsetDateTime`, whose string representation will be in ISO 8601 format.
3576
@@ -254,11 +295,6 @@ The GLVs will only support GraphBinary V4 and GraphSON support has been removed.
254295
that was available in most GLVs has been removed. GraphBinary is a more compact format and has support for the same
255296
types. This should lead to increased performance for users upgrading from any version of GraphSON to GraphBinary.
256297
257-
==== Improved handling of integer overflows
258-
259-
Integer overflows caused by addition and multiplication operations will throw an exception instead of being silently
260-
skipped with incorrect result.
261-
262298
==== Gremlin Lang Float Literals Default to Double
263299
264300
The `GremlinLangScriptEngine` has been modified to treat float literals without explicit type suffixes (like 'm', 'f',
@@ -334,6 +370,26 @@ link:https://tinkerpop.apache.org/docs/3.8.0/dev/provider/#gherkin-tests-suite[P
334370
335371
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3136[TINKERPOP-3136]
336372
373+
==== Auto promotion of number types
374+
375+
Previously, operations like sum or sack that involved mathematical calculations did not automatically promote the result
376+
to a larger numeric type (e.g., from int to long) when needed. As a result, values could wrap around within their current
377+
type, leading to unexpected behavior. This issue has now been resolved by enabling automatic type promotion for results.
378+
379+
Now, any mathematical operations such as Add, Sub, Mul, and Div will now automatically promote to the next numeric type
380+
if an overflow is detected. For integers, the promotion sequence is: byte → short → int → long → overflow exception. For
381+
floating-point numbers, the sequence is: float → double → infinity.
382+
383+
As a example the following query...
384+
385+
"""
386+
g.withSack(32767s).inject(1s).sack(sum).sack()
387+
"""
388+
389+
Before would return a short overflow exception or wrap to -1 depending on language, but now returns 32769i.
390+
391+
See link:https://issues.apache.org/jira/browse/TINKERPOP-3115[TINKERPOP-3115] for more details.
392+
337393
==== The Switch from Date to OffsetDateTime
338394
339395
The default implementation for date type in Gremlin is now changed from the deprecated `java.util.Date` to the more encompassing `java.time.OffsetDateTime`. This means the reference implementation for all date manipulation steps, `asDate()`, `dateAdd()`, and `dateDiff()`, as well as helper methods `datetime()`, will return `OffsetDateTime`, whose string representation will be in ISO 8601 format.

0 commit comments

Comments
 (0)