Skip to content

Use unsigned int for tid #287

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

Merged
merged 1 commit into from
May 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions asyncpg/protocol/codecs/tid.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

cdef tid_encode(ConnectionSettings settings, WriteBuffer buf, obj):
cdef int overflow = 0
cdef long block, offset
cdef unsigned long block, offset

if not (cpython.PyTuple_Check(obj) or cpython.PyList_Check(obj)):
raise TypeError(
Expand All @@ -18,25 +18,24 @@ cdef tid_encode(ConnectionSettings settings, WriteBuffer buf, obj):
'invalid number of elements in tid tuple, expecting 2')

try:
block = cpython.PyLong_AsLong(obj[0])
block = cpython.PyLong_AsUnsignedLong(obj[0])
except OverflowError:
overflow = 1

# "long" and "long long" have the same size for x86_64, need an extra check
if overflow or (sizeof(block) > 4 and (block < -2147483648 or
block > 2147483647)):
if overflow or (sizeof(block) > 4 and block > 4294967295):
raise OverflowError(
'block too big to be encoded as INT4: {!r}'.format(obj[0]))
'block too big to be encoded as UINT4: {!r}'.format(obj[0]))

try:
offset = cpython.PyLong_AsLong(obj[1])
offset = cpython.PyLong_AsUnsignedLong(obj[1])
overflow = 0
except OverflowError:
overflow = 1

if overflow or offset < -32768 or offset > 32767:
if overflow or offset > 65535:
raise OverflowError(
'offset too big to be encoded as INT2: {!r}'.format(obj[1]))
'offset too big to be encoded as UINT2: {!r}'.format(obj[1]))

buf.write_int32(6)
buf.write_int32(<int32_t>block)
Expand All @@ -45,11 +44,11 @@ cdef tid_encode(ConnectionSettings settings, WriteBuffer buf, obj):

cdef tid_decode(ConnectionSettings settings, FastReadBuffer buf):
cdef:
int32_t block
int16_t offset
uint32_t block
uint16_t offset

block = hton.unpack_int32(buf.read(4))
offset = hton.unpack_int16(buf.read(2))
block = <uint32_t>hton.unpack_int32(buf.read(4))
offset = <uint16_t>hton.unpack_int16(buf.read(2))

return (block, offset)

Expand Down
26 changes: 15 additions & 11 deletions tests/test_codecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,13 @@ def _timezone(offset):
asyncpg.Circle((0.0, 0.0), 100),
]),
('tid', 'tid', [
(0, 2),
(100, 200),
(0, 0),
(2147483647, 0),
(4294967295, 0),
(0, 32767),
(0, 65535),
(4294967295, 65535),
]),
]

Expand Down Expand Up @@ -611,20 +617,18 @@ async def test_invalid_input(self):
[1, 2, 3],
(4,),
]),
('tid', OverflowError, 'block too big to be encoded as INT4', [
('tid', OverflowError, 'block too big to be encoded as UINT4', [
(-1, 0),
(2**256, 0),
(decimal.Decimal("2000000000000000000000000000000"), 0),
(0xffffffff, 0),
(2**31, 0),
(-2**31 - 1, 0),
(0xffffffff + 1, 0),
(2**32, 0),
]),
('tid', OverflowError, 'offset too big to be encoded as INT2', [
('tid', OverflowError, 'offset too big to be encoded as UINT2', [
(0, -1),
(0, 2**256),
(0, decimal.Decimal("2000000000000000000000000000000")),
(0, 0xffff),
(0, 0xffff + 1),
(0, 0xffffffff),
(0, 32768),
(0, -32769),
(0, 65536),
]),
]

Expand Down