Skip to content
Open
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
2 changes: 1 addition & 1 deletion asyncpg/protocol/prepared_stmt.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cdef class PreparedStatementState:

ConnectionSettings settings

int16_t args_num
uint16_t args_num
bint have_text_args
tuple args_codecs

Expand Down
15 changes: 8 additions & 7 deletions asyncpg/protocol/prepared_stmt.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,10 @@ cdef class PreparedStatementState:
raise exceptions.InternalClientError(
f'Bind: expected a sequence, got {type(args).__name__}')

if len(args) > 32767:
# PostgreSQL reads the 16-bit parameter count as unsigned
if len(args) > 65535:
raise exceptions.InterfaceError(
'the number of query arguments cannot exceed 32767')
'the number of query arguments cannot exceed 65535')

writer = WriteBuffer.new()

Expand All @@ -155,15 +156,15 @@ cdef class PreparedStatementState:
hint=hint)

if self.have_text_args:
writer.write_int16(self.args_num)
writer.write_int16(<int16_t>self.args_num)
for idx in range(self.args_num):
codec = <Codec>(self.args_codecs[idx])
writer.write_int16(<int16_t>codec.format)
else:
# All arguments are in binary format
writer.write_int32(0x00010001)

writer.write_int16(self.args_num)
writer.write_int16(<int16_t>self.args_num)

for idx in range(self.args_num):
arg = args[idx]
Expand Down Expand Up @@ -286,7 +287,7 @@ cdef class PreparedStatementState:

cdef _set_args_desc(self, object desc):
self.parameters_desc = _decode_parameters_desc(desc)
self.args_num = <int16_t>(len(self.parameters_desc))
self.args_num = <uint16_t>(len(self.parameters_desc))

cdef _decode_row(self, const char* cbuf, ssize_t buf_len):
cdef:
Expand Down Expand Up @@ -345,12 +346,12 @@ cdef class PreparedStatementState:
cdef _decode_parameters_desc(object desc):
cdef:
ReadBuffer reader
int16_t nparams
uint16_t nparams
uint32_t p_oid
list result = []

reader = ReadBuffer.new_message_parser(desc)
nparams = reader.read_int16()
nparams = <uint16_t>reader.read_int16()

for i from 0 <= i < nparams:
p_oid = <uint32_t>reader.read_int32()
Expand Down
9 changes: 7 additions & 2 deletions tests/test_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,13 +536,18 @@ async def test_prepare_27_max_cacheable_statement_size(self):
self.assertEqual(len(cache), 2)

async def test_prepare_28_max_args(self):
N = 32768
N = 65535
args = ','.join('${}::int4'.format(i) for i in range(1, N + 1))
query = 'SELECT cardinality(ARRAY[{}])'.format(args)
self.assertEqual(await self.con.fetchval(query, *range(1, N + 1)), N)

N = 65536
args = ','.join('${}'.format(i) for i in range(1, N + 1))
query = 'SELECT ARRAY[{}]'.format(args)

with self.assertRaisesRegex(
exceptions.InterfaceError,
'the number of query arguments cannot exceed 32767'):
'the number of query arguments cannot exceed 65535'):
await self.con.fetchval(query, *range(1, N + 1))

async def test_prepare_29_duplicates(self):
Expand Down