Skip to content
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

Unsigned integer read as signed #119

Closed
jnordberg opened this issue Jul 29, 2020 · 8 comments · Fixed by #120
Closed

Unsigned integer read as signed #119

jnordberg opened this issue Jul 29, 2020 · 8 comments · Fixed by #120
Labels
bug Something isn't working

Comments

@jnordberg
Copy link

Sometimes my vapor + fluent application crashes with a NIO-ELT-0-#8 (10): Fatal error: Negative value is not representable after a db update. After this happens the app will crash every time I try to load that record until I manually remove it from the postgres db.

The value is defined with the schema: .field("ram_bytes", .uint32) and when the crash happens it looks like it tries to decode the value as a signed 32 bit integer instead of unsigned. Looking at the db record the value has somehow ended up being a negative value (-1872634973). I haven't been able to reliably reproduce this yet but I've seen it happen several times now.

Stack trace

* thread #10, name = 'NIO-ELT-0-#8', stop reason = Fatal error: Negative value is not representable
    frame #0: 0x00007fff72eb8380 libswiftCore.dylib`_swift_runtime_on_report
    frame #1: 0x00007fff72f32243 libswiftCore.dylib`_swift_stdlib_reportFatalErrorInFile + 211
    frame #2: 0x00007fff72bf91dd libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 525
    frame #3: 0x00007fff72bf8cf7 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 87
    frame #4: 0x00007fff72bf89c3 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 99
    frame #5: 0x00007fff72bf85d5 libswiftCore.dylib`Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 533
    frame #6: 0x00007fff72de048c libswiftCore.dylib`protocol witness for Swift.BinaryInteger.init<A where A1: Swift.BinaryInteger>(A1) -> A in conformance Swift.UInt32 : Swift.BinaryInteger in Swift + 940
    frame #7: 0x00007fff72e8ec48 libswiftCore.dylib`dispatch thunk of Swift.BinaryFloatingPoint.init<A where A1: Swift.BinaryFloatingPoint>(A1) -> A + 8
    frame #8: 0x00007fff72ead449 libswiftCore.dylib`dispatch thunk of Swift.BinaryInteger.init<A where A1: Swift.BinaryInteger>(A1) -> A + 9
    frame #9: 0x0000000100b4f0f9 Run`PostgresData.fwi<I>(type=UInt32, self=PostgresNIO.PostgresData @ 0x0000700000797520) at PostgresData+Int.swift:137:24
    frame #10: 0x0000000100b504d2 Run`FixedWidthInteger.init(postgresData=PostgresNIO.PostgresData @ 0x0000700000797520) at PostgresData+Int.swift:183:38
    frame #11: 0x0000000100b50d9e Run`protocol witness for PostgresDataConvertible.init(postgresData:) in conformance UInt32 at <compiler-generated>:0
    frame #12: 0x0000000100b246bc Run`PostgresDataDecoder.decode<T>(type=UInt32, data=PostgresNIO.PostgresData @ 0x0000700000797520, self=0x0000000102cbaf90) at PostgresDataDecoder.swift:14:43
    frame #13: 0x0000000100b322e7 Run`_PostgreSQLRow.decode<D>(column="products_ram_bytes", type=UInt32, self=PostgresKit._PostgreSQLRow @ 0x00007000007974a0) at PostgresRow+SQL.swift:34:33
    frame #14: 0x0000000100b324bf Run`protocol witness for SQLRow.decode<A>(column:as:) in conformance _PostgreSQLRow at <compiler-generated>:0
    frame #15: 0x0000000100a896d0 Run`_PostgresDatabaseOutput.decode<T>(key=prefix, type=UInt32, self=FluentPostgresDriver._PostgresDatabaseOutput @ 0x00007000007976a0) at PostgresRow+Database.swift:43:14
    frame #16: 0x0000000100a89832 Run`protocol witness for DatabaseOutput.decode<A>(_:as:) in conformance _PostgresDatabaseOutput at <compiler-generated>:0
    frame #17: 0x0000000100a89e95 Run`_SchemaDatabaseOutput.decode<T>(key=string, type=UInt32, self=FluentPostgresDriver._SchemaDatabaseOutput @ 0x0000000102e0dfc0) at PostgresRow+Database.swift:83:25
    frame #18: 0x0000000100a89fad Run`protocol witness for DatabaseOutput.decode<A>(_:as:) in conformance _SchemaDatabaseOutput at <compiler-generated>:0
    frame #19: 0x0000000100065286 Run`FieldProperty.output(output=FluentPostgresDriver._SchemaDatabaseOutput @ 0x0000000102e0dfc0, self=0x0000000102e1a4a0) at Field.swift:100:47
    frame #20: 0x00000001000654fd Run`protocol witness for AnyDatabaseProperty.output(from:) in conformance FieldProperty<A, B> at <compiler-generated>:0
    frame #21: 0x000000010004801e Run`closure #2 in Fields.output(field=0x0000000102e1a4a0, output=FluentPostgresDriver._SchemaDatabaseOutput @ 0x0000000102e0dfc0) at Fields.swift:65:23
    frame #22: 0x0000000100048070 Run`partial apply for closure #2 in Fields.output(from:) at <compiler-generated>:0
    frame #23: 0x0000000100047c54 Run`thunk for @callee_guaranteed (@guaranteed AnyDatabaseProperty) -> (@error @owned Error) at <compiler-generated>:0
    frame #24: 0x0000000100048094 Run`thunk for @callee_guaranteed (@guaranteed AnyDatabaseProperty) -> (@error @owned Error)partial apply at <compiler-generated>:0
    frame #25: 0x00007fff72ce664d libswiftCore.dylib`(extension in Swift):Swift.Sequence.forEach((A.Element) throws -> ()) throws -> () + 381
    frame #26: 0x0000000100047e41 Run`Fields.output(output=FluentPostgresDriver._SchemaDatabaseOutput @ 0x0000000102e0dfc0, self=0x0000000102e0f880) at Fields.swift:64:11
    frame #27: 0x0000000100e22041 Run`protocol witness for Fields.output(from:) in conformance Product at <compiler-generated>:0
    frame #28: 0x00000001000a2493 Run`closure #1 in closure #1 in QueryBuilder.all(output=FluentPostgresDriver._PostgresDatabaseOutput @ 0x0000700000798170, all=0 values) at QueryBuilder.swift:210:27
    frame #29: 0x00000001000a4f23 Run`partial apply for closure #1 in closure #1 in QueryBuilder.all(_:) at <compiler-generated>:0
    frame #30: 0x00000001000a2060 Run`closure #1 in QueryBuilder.all(output=FluentPostgresDriver._PostgresDatabaseOutput @ 0x0000700000798170, onOutput=0x00000001000a2ed0 Run`partial apply forwarder for closure #1 (Swift.Result<A, Swift.Error>) -> () in FluentKit.QueryBuilder.all() -> NIO.EventLoopFuture<Swift.Array<A>> at <compiler-generated>, all=0 values) at QueryBuilder.swift:208:23
    frame #31: 0x00000001000a4456 Run`closure #1 in QueryBuilder.run(output=FluentPostgresDriver._PostgresDatabaseOutput @ 0x0000700000798170, self=0x0000000107814990, onOutput=0x00000001000a21d0 Run`partial apply forwarder for closure #1 (FluentKit.DatabaseOutput) -> () in FluentKit.QueryBuilder.all((Swift.Result<A, Swift.Error>) -> ()) -> NIO.EventLoopFuture<()> at <compiler-generated>) at QueryBuilder.swift:285:13
    frame #32: 0x0000000100a7de24 Run`closure #2 in _FluentPostgresDatabase.execute($0=PostgresNIO.PostgresRow @ 0x00007000007981b0, onOutput=0x00000001000a44b0 Run`partial apply forwarder for closure #1 (FluentKit.DatabaseOutput) -> () in FluentKit.QueryBuilder.run((FluentKit.DatabaseOutput) -> ()) -> NIO.EventLoopFuture<()> at <compiler-generated>, self=FluentPostgresDriver._FluentPostgresDatabase @ 0x0000000107815890) at FluentPostgresDatabase.swift:29:17
    frame #33: 0x0000000100b84498 Run`PostgresParameterizedQuery.respond(message=PostgresNIO.PostgresMessage @ 0x0000700000798cf0, self=0x0000000107815950) at PostgresDatabase+Query.swift:139:17
    frame #34: 0x0000000100b8800a Run`protocol witness for PostgresRequest.respond(to:) in conformance PostgresParameterizedQuery at <compiler-generated>:0
    frame #35: 0x0000000100b3912b Run`PostgresRequestHandler._channelRead(context=0x0000000102d0c6b0, data=NIO.NIOAny @ 0x0000700000799bd0, self=0x0000000102d0a810) at PostgresConnection+Database.swift:64:49
    frame #36: 0x0000000100b39b65 Run`PostgresRequestHandler.channelRead(context=0x0000000102d0c6b0, data=NIO.NIOAny @ 0x0000700000799bd0, self=0x0000000102d0a810) at PostgresConnection+Database.swift:81:22
    frame #37: 0x0000000100b3b131 Run`protocol witness for _ChannelInboundHandler.channelRead(context:data:) in conformance PostgresRequestHandler at <compiler-generated>:0
    frame #38: 0x00000001001369cd Run`ChannelHandlerContext.invokeChannelRead(data=NIO.NIOAny @ 0x0000700000799bd0, self=0x0000000102d0c6b0) at ChannelPipeline.swift:1339:28
    frame #39: 0x0000000100136a61 Run`ChannelHandlerContext.invokeChannelRead(data=NIO.NIOAny @ 0x0000700000799bd0, self=0x0000000102d0c430) at ChannelPipeline.swift:1341:24
    frame #40: 0x000000010013a5d6 Run`ChannelHandlerContext.fireChannelRead(data=NIO.NIOAny @ 0x0000700000799bd0, self=0x0000000102d0fd40) at ChannelPipeline.swift:1152:20
    frame #41: 0x0000000100b7df92 Run`PostgresMessageDecoder.decode(context=0x0000000102d0fd40, buffer=NIO.ByteBuffer @ 0x000070000079a270, self=0x0000000102d0d340) at PostgresMessageDecoder.swift:56:17
    frame #42: 0x0000000100b7e723 Run`protocol witness for ByteToMessageDecoder.decode(context:buffer:) in conformance PostgresMessageDecoder at <compiler-generated>:0
    frame #43: 0x00000001001567fa Run`closure #1 in ByteToMessageHandler.decodeLoop(decoder=0x0000000102d0d340, buffer=NIO.ByteBuffer @ 0x000070000079a270, decodeMode=normal, self=0x0000000102d0b8e0, context=0x0000000102d0fd40, allowEmptyBuffer=false) at Codec.swift:567:49
    frame #44: 0x000000010015e27d Run`partial apply for closure #1 in ByteToMessageHandler.decodeLoop(context:decodeMode:) at <compiler-generated>:0
    frame #45: 0x0000000100155142 Run`ByteToMessageHandler.withNextBuffer(allowEmptyBuffer=false, body=0x000000010015e260 Run`partial apply forwarder for closure #1 (inout A, inout NIO.ByteBuffer) throws -> NIO.DecodingState in NIO.ByteToMessageHandler.(decodeLoop in _F2A740607FEBA425AF6F8C49A24C0AD7)(context: NIO.ChannelHandlerContext, decodeMode: NIO.ByteToMessageHandler<A>.(DecodeMode in _F2A740607FEBA425AF6F8C49A24C0AD7)) throws -> NIO.(B2MDBuffer in _F2A740607FEBA425AF6F8C49A24C0AD7).BufferProcessingResult at <compiler-generated>, self=0x0000000102d0b8e0) at Codec.swift:529:36
    frame #46: 0x0000000100155e9c Run`ByteToMessageHandler.decodeLoop(context=0x0000000102d0fd40, decodeMode=normal, self=0x0000000102d0b8e0) at Codec.swift:563:35
    frame #47: 0x0000000100157c4b Run`ByteToMessageHandler.channelRead(context=0x0000000102d0fd40, data=NIO.NIOAny @ 0x000070000079ae28, self=0x0000000102d0b8e0) at Codec.swift:636:29
    frame #48: 0x00000001001584e9 Run`protocol witness for _ChannelInboundHandler.channelRead(context:data:) in conformance ByteToMessageHandler<A> at <compiler-generated>:0
    frame #49: 0x00000001001369cd Run`ChannelHandlerContext.invokeChannelRead(data=NIO.NIOAny @ 0x000070000079ae28, self=0x0000000102d0fd40) at ChannelPipeline.swift:1339:28
    frame #50: 0x000000010013241d Run`ChannelPipeline.fireChannelRead0(data=NIO.NIOAny @ 0x000070000079ae28, self=0x0000000107606b80) at ChannelPipeline.swift:829:29
    frame #51: 0x00000001000e7eac Run`BaseStreamSocketChannel.readFromSocket(self=0x0000000107606570) at BaseStreamSocketChannel.swift:107:35
    frame #52: 0x00000001000df25c Run`BaseSocketChannel.readable0(self=0x0000000107606570) at BaseSocketChannel.swift:1060:35
    frame #53: 0x00000001000e0e52 Run`BaseSocketChannel.readable(self=0x0000000107606570) at BaseSocketChannel.swift:1044:14
    frame #54: 0x00000001000e22d9 Run`protocol witness for SelectableChannel.readable() in conformance BaseSocketChannel<A> at <compiler-generated>:0
    frame #55: 0x00000001001f7ffa Run`SelectableEventLoop.handleEvent<C>(ev=(rawValue = 4), channel=0x0000000107606570, self=0x0000000102d053a0) at SelectableEventLoop.swift:323:25
    frame #56: 0x00000001001f9b78 Run`closure #1 in closure #2 in SelectableEventLoop.run(ev=NIO.SelectorEvent<NIO.NIORegistration> @ 0x000070000079b7d8, self=0x0000000102d053a0) at SelectableEventLoop.swift:400:30
    frame #57: 0x00000001001f9f09 Run`thunk for @callee_guaranteed (@guaranteed SelectorEvent<NIORegistration>) -> (@error @owned Error) at <compiler-generated>:0
    frame #58: 0x00000001001fe544 Run`partial apply for thunk for @callee_guaranteed (@guaranteed SelectorEvent<NIORegistration>) -> (@error @owned Error) at <compiler-generated>:0
    frame #59: 0x000000010020eb44 Run`Selector.whenReady(strategy=blockUntilTimeout, body=0x00000001001fe530 Run`partial apply forwarder for reabstraction thunk helper from @callee_guaranteed (@guaranteed NIO.SelectorEvent<NIO.NIORegistration>) -> (@error @owned Swift.Error) to @escaping @callee_guaranteed (@in_guaranteed NIO.SelectorEvent<NIO.NIORegistration>) -> (@error @owned Swift.Error) at <compiler-generated>, self=0x0000000102d052f0) at Selector.swift:561:17
  * frame #60: 0x00000001001f9899 Run`closure #2 in SelectableEventLoop.run(self=0x0000000102d053a0, nextReadyTask=0x0000000107509e40) at SelectableEventLoop.swift:395:36
    frame #61: 0x00000001001fd494 Run`partial apply for closure #2 in SelectableEventLoop.run() at <compiler-generated>:0
    frame #62: 0x00000001000cf1ef Run`thunk for @callee_guaranteed () -> (@error @owned Error) at <compiler-generated>:0
    frame #63: 0x00000001001fd4b4 Run`thunk for @callee_guaranteed () -> (@error @owned Error)partial apply at <compiler-generated>:0
    frame #64: 0x00000001001f4292 Run`closure #1 in withAutoReleasePool<T>(execute=0x00000001001fd4a0 Run`reabstraction thunk helper from @callee_guaranteed () -> (@error @owned Swift.Error) to @escaping @callee_guaranteed () -> (@out (), @error @owned Swift.Error)partial apply forwarder with unmangled suffix ".8" at <compiler-generated>) at SelectableEventLoop.swift:23:13
    frame #65: 0x00000001001f42ef Run`partial apply for closure #1 in withAutoReleasePool<A>(_:) at <compiler-generated>:0
    frame #66: 0x00007fff73250d8e libswiftObjectiveC.dylib`ObjectiveC.autoreleasepool<A>(invoking: () throws -> A) throws -> A + 46
    frame #67: 0x00000001001f4239 Run`withAutoReleasePool<T>(execute=0x00000001001fd4a0 Run`reabstraction thunk helper from @callee_guaranteed () -> (@error @owned Swift.Error) to @escaping @callee_guaranteed () -> (@out (), @error @owned Swift.Error)partial apply forwarder with unmangled suffix ".8" at <compiler-generated>) at SelectableEventLoop.swift:22:16
    frame #68: 0x00000001001f8550 Run`SelectableEventLoop.run(self=0x0000000102d053a0) at SelectableEventLoop.swift:394:17
    frame #69: 0x0000000100177f43 Run`static MultiThreadedEventLoopGroup.runTheLoop(thread=0x0000000102d05240, canEventLoopBeShutdownIndividually=false, selectorFactory=0x000000010017f840 Run`partial apply forwarder for NIO.Selector.__allocating_init() throws -> NIO.Selector<A> at <compiler-generated>, initializer=0x000000010017f640 Run`partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed NIO.NIOThread) -> (@out ()) to @escaping @callee_guaranteed (@guaranteed NIO.NIOThread) -> () at <compiler-generated>, callback=0x000000010017f7c0 Run`partial apply forwarder for closure #1 (NIO.SelectableEventLoop) -> () in closure #1 (NIO.NIOThread) -> () in static NIO.MultiThreadedEventLoopGroup.(setupThreadAndEventLoop in _D5D78C61B22284700B9BD1ACFBC25157)(name: Swift.String, selectorFactory: () throws -> NIO.Selector<NIO.NIORegistration>, initializer: (NIO.NIOThread) -> ()) -> NIO.SelectableEventLoop at <compiler-generated>, self=NIO.MultiThreadedEventLoopGroup) at EventLoop.swift:824:22
    frame #70: 0x0000000100178743 Run`closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(t=0x0000000102d05240, selectorFactory=0x000000010017f840 Run`partial apply forwarder for NIO.Selector.__allocating_init() throws -> NIO.Selector<A> at <compiler-generated>, initializer=0x000000010017f640 Run`partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed NIO.NIOThread) -> (@out ()) to @escaping @callee_guaranteed (@guaranteed NIO.NIOThread) -> () at <compiler-generated>, lock=(mutex = 0x0000000102cba430), _loop=0x0000000102d053a0, loopUpAndRunningGroup=0x0000000102cba470) at EventLoop.swift:844:41
    frame #71: 0x000000010017f733 Run`partial apply for closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:selectorFactory:initializer:) at <compiler-generated>:0
    frame #72: 0x0000000100178d3f Run`thunk for @escaping @callee_guaranteed (@guaranteed NIOThread) -> () at <compiler-generated>:0
    frame #73: 0x0000000100244351 Run`partial apply for thunk for @escaping @callee_guaranteed (@guaranteed NIOThread) -> () at <compiler-generated>:0
    frame #74: 0x000000010024b1c3 Run`closure #1 in static ThreadOpsPosix.run($0=(_rawValue = 0x0000000102cba3c0 -> 0x00007fff99c31f58 libswiftCore.dylib`InitialAllocationPool + 23240)) at ThreadPosix.swift:105:13
    frame #75: 0x000000010024b2f9 Run`@objc closure #1 in static ThreadOpsPosix.run(handle:args:detachThread:) at <compiler-generated>:0
    frame #76: 0x0000000102a05c65 libsystem_pthread.dylib`_pthread_start + 148
    frame #77: 0x0000000102a014af libsystem_pthread.dylib`thread_start + 15
@jnordberg
Copy link
Author

I can reproduce this by manually setting the database field to a negative value but still baffled on how it could end up negative in the first place

@tanner0101 tanner0101 added the bug Something isn't working label Jul 29, 2020
@tanner0101
Copy link
Member

tanner0101 commented Jul 29, 2020

Postgres doesn't allow unsigned integers:

Because of that, Fluent's Postgres driver is using INT to store Fluent's .uint32 data type. That means your integer is likely overflowing.

If you need to be able to store up to UInt32.max, you could:

  • Store as an .int (and use 4 extra bytes)
  • Store as an .int32 and translate the bit pattern explicitly:
@Field(key: "ram_bytes")
var _ramBytes: Int32

var ramBytes: UInt32 {
    get {
        .init(bitPattern: self._ramBytes)
    }
    set {
        self._ramBytes = .init(bitPattern: newValue)
    }
}

@jnordberg
Copy link
Author

Ah yeah it's an overflow, I was worried it was some weird race because I thought I tested setting numbers above 2^31 and it worked. But testing again I'm able to reliably reproduce by writing 2147483648 to my UInt32 field.

@tanner0101
Copy link
Member

tanner0101 commented Jul 29, 2020

I've started work on a PR to make this limitation clearer. Would you be open to testing it on your project? If so, you can try it by doing:

swift package edit postgres-nio --revision tn-int-fix

Or by adding this to your Package.swift file:

.package(url: "https://github.com/vapor/postgres-nio.git", .branch("tn-int-fix"))

This should do a few things:

1: Deprecate PostgresData conversion methods that can cause overflow
2: Raise a debug-mode only assertion if unsafe conversion is detected
3: Use bitPattern conversion to prevent overflow in release mode

I'm interested to see if:

  • The assertion indeed spots this issue in your code in debug mode
  • The bitPattern fix causes your program to not crash in release mode

@jnordberg
Copy link
Author

Debug build gives me the runtime error but only when accessing loading the model in question, could it be made a static check instead? Would it work to set @available(deprecated) on those enum cases?

Building in production mode and setting the value to a negative value in the database crashes with this error when loading the model:

[1]    41465 illegal hardware instruction  .build/release/Run

@tanner0101
Copy link
Member

Thanks for taking a look at this.

Debug build gives me the runtime error but only when accessing loading the model in question

Great 👍

could it be made a static check instead? Would it work to set @available(deprecated) on those enum cases?

I've already set all of the methods as deprecated, but due to how Fluent dynamically casts model types that isn't going to show up in your model. I don't think there is a way to make this a static check. Especially under the constraint that it should continue building and working when compiled in release mode. Ideally the developer will encounter this error in a development environment and not when updating production.

Building in production mode and setting the value to a negative value in the database crashes with this error when loading the model.

Hmm. That seems like a potential mis-compile to me. Try clearing the .build folder and rebuilding.

@jnordberg
Copy link
Author

Yup, when clearing .build and recompiling it works. Modified the database to -1 and my model reads 4294967295

@tanner0101
Copy link
Member

tanner0101 commented Jul 30, 2020

Great, thanks for testing that. With this fix your code should stop crashing and work in release mode. As far as PostgresNIO is concerned, the UInt32 is being stored correctly. It's just that PostgreSQL (and potentially other clients) don't agree on the value.

The most efficient way forward would be the "Store as an .int32 and translate the bit pattern explicitly" solution mentioned above. The caveat here being that the value may look wrong in the database to other clients.

The safest way forward would be to upgrade the field to an .int64. This would require 4 extra bytes of storage for each value and a database migration though.

Thanks again for helping test this and for reporting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants