[ 
https://issues.apache.org/jira/browse/TINKERPOP-2363?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18117322#comment-18117322
 ] 

ASF GitHub Bot commented on TINKERPOP-2363:
-------------------------------------------

bitflicker64 opened a new pull request, #3672:
URL: https://github.com/apache/tinkerpop/pull/3672

   https://issues.apache.org/jira/browse/TINKERPOP-2363
   
   ## Problem
   
   `IntIO` inherits `dictify` from `LongIO`. The guard there validates against 
the Java `long` range, but the pack it then calls is `IntIO`'s `int32_pack`:
   
   ```python
   class LongIO(_GraphBinaryTypeIO):
       byte_format_pack = int64_pack
   
       @classmethod
       def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
           if obj < -9223372036854775808 or obj > 9223372036854775807:
               raise Exception("Value too big, please use bigint Gremlin type")
           else:
               cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, 
to_extend)
               to_extend.extend(cls.byte_format_pack(obj))   # int32_pack when 
cls is IntIO
               return to_extend
   
   
   class IntIO(LongIO):
       python_type = IntType          # plain python int
       byte_format_pack = int32_pack
   ```
   
   Python 3 has a single arbitrary precision `int`, so `python_type = IntType` 
matches every plain `int`. Any value between the Java `int` and `long` bounds 
clears the guard and then dies in the packer:
   
   ```
   struct.error: 'i' format requires -2147483648 <= number <= 2147483647
   ```
   
   The traceback stops inside `struct` and names neither the value, nor the 
binding it came from, nor `statics.long`.
   
   GraphSON coerces the same values (`Int64` since TINKERPOP-2360), so a script 
that works on GraphSON fails on GraphBinary, which has been the Python default 
since 3.6.1 (TINKERPOP-2723).
   
   ## Why it bites
   
   TINKERPOP-2943 is the same bug reported against `g.V(2**31 + 1)` on a graph 
with more than 2^31 vertices. It was closed as a duplicate of this ticket, with 
the promotion fix suggested in the comments.
   
   Any Python client that round trips element ids into bindings is exposed, and 
only once the graph is large enough for ids to cross 2^31. Below that boundary 
the identical code is fine, so it presents as flakiness rather than a type 
problem. It was found here while loading a 34.7M edge dataset against 
JanusGraph 1.1.0: one load completed, the next identical one aborted partway 
through, depending on where id allocation happened to land.
   
   ## Fix
   
   `IntIO` gets its own `dictify`:
   
   - inside the Java `int` range, write `DataType.int`, byte for byte as before
   - outside it but inside the Java `long` range, write `DataType.long`
   - beyond that, the existing `Value too big, please use bigint Gremlin type` 
error
   
   `statics.long` and `statics.bigint` keep working as explicit overrides.
   
   Promotion is skipped when `as_value` is true, since a value-only write has 
no type code in front of it to change. The one such call site is `Duration`'s 
nanosecond field, whose value is `timedelta.microseconds * 1000` and cannot 
overflow `int32`.
   
   The structural `int32_pack` writes (collection lengths, bytecode instruction 
counts, `BigDecimal.scale`, string byte lengths) call the packer directly 
rather than going through `writer.to_dict`, so nothing that has to stay four 
bytes is touched.
   
   ## Tests
   
   Added to `tests/unit/io/test_graphbinaryV1.py`:
   
   - round trip of `2**31`, `-2**31 - 1`, `3000000000`, and the `int64` bounds
   - exact wire bytes at the boundary: `0x01` for `2**31 - 1` and `-2**31`, 
`0x02` one step outside, so a value that already fits is never widened
   - `2**63` and `-2**63 - 1` still raise
   - promotion through nested lists and dict values, the shape the original 
report failed on
   - `bool` still resolves to the Boolean serializer, since `bool` subclasses 
`int`
   
   `pytest tests/unit` passes, 114 tests. The reproduction was confirmed 
against this branch before and after the change; it has not been run against a 
live Gremlin Server.
   
   ## Open questions
   
   - TINKERPOP-2363 also covers `BigInteger`. That half now looks handled by 
`BigIntIO` (TINKERPOP-3275), so this PR only takes the `int`/`long` part. Say 
so if you would rather close the ticket in one pass.
   - GraphSON goes one step further and promotes past the Java `long` range to 
`BigInteger`. This keeps the existing explicit error instead. Happy to match 
GraphSON if you prefer.
   - `ShortIO` inherits the same mismatched guard, but `short` is an explicit 
opt in through `statics`, so overflowing it is a caller's choice rather than a 
silent default. Left out to keep this focused.
   




> GraphBinary and numerics for Python
> -----------------------------------
>
>                 Key: TINKERPOP-2363
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-2363
>             Project: TinkerPop
>          Issue Type: Improvement
>          Components: python
>    Affects Versions: 3.4.6
>            Reporter: Stephen Mallette
>            Priority: Critical
>
> After TINKERPOP-2360 we've started down the path of coercing python numerics 
> to Java type ranges. GraphBinary doesn't do that and therefore switching 
> serializers from GraphSON to GraphBinary will have the potential to result in 
> error if the python numeric overflows the Java integer space. In addition, we 
> don't support {{BigInteger}} serialization apparently so that remains a 
> problem. This ticket should just sort out GraphBinary and numbers all at once.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to