Skip to content

Commit b6fe018

Browse files
committed
Clarify the argument/parameter count mismatch exception
Fixes: #178.
1 parent c484a47 commit b6fe018

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

asyncpg/protocol/prepared_stmt.pyx

+25-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
66

77

8+
from asyncpg import exceptions
9+
10+
811
@cython.final
912
cdef class PreparedStatementState:
1013

@@ -92,18 +95,34 @@ cdef class PreparedStatementState:
9295
Codec codec
9396

9497
if len(args) > 32767:
95-
raise ValueError('number of arguments cannot exceed 32767')
98+
raise exceptions.InterfaceError(
99+
'the number of query arguments cannot exceed 32767')
96100

97101
self._ensure_args_encoder()
98102
self._ensure_rows_decoder()
99103

100104
writer = WriteBuffer.new()
101105

102-
if self.args_num != len(args):
103-
raise ValueError(
104-
'number of arguments ({}) does not match '
105-
'number of parameters ({})'.format(
106-
len(args), self.args_num))
106+
num_args_passed = len(args)
107+
if self.args_num != num_args_passed:
108+
hint = 'Check the query against the passed list of arguments.'
109+
110+
if self.args_num == 0:
111+
# If the server was expecting zero arguments, it is likely
112+
# that the user tried to parametrize a statement that does
113+
# not support parameters.
114+
hint += (r' Note that parameters are supported only in'
115+
r' SELECT, INSERT, UPDATE, DELETE, and VALUES'
116+
r' statements, and will *not* work in statements '
117+
r' like CREATE VIEW or DECLARE CURSOR.')
118+
119+
raise exceptions.InterfaceError(
120+
'the server expects {x} argument{s} for this query, '
121+
'{y} {w} passed'.format(
122+
x=self.args_num, s='s' if self.args_num != 1 else '',
123+
y=num_args_passed,
124+
w='was' if num_args_passed == 1 else 'were'),
125+
hint=hint)
107126

108127
if self.have_text_args:
109128
writer.write_int16(self.args_num)

tests/test_prepare.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import unittest
1212

1313
from asyncpg import _testbase as tb
14+
from asyncpg import exceptions
1415

1516

1617
class TestPrepare(tb.ConnectedTestCase):
@@ -540,8 +541,9 @@ async def test_prepare_28_max_args(self):
540541
args = ','.join('${}'.format(i) for i in range(1, N + 1))
541542
query = 'SELECT ARRAY[{}]'.format(args)
542543

543-
with self.assertRaisesRegex(ValueError,
544-
'number of arguments cannot exceed 32767'):
544+
with self.assertRaisesRegex(
545+
exceptions.InterfaceError,
546+
'the number of query arguments cannot exceed 32767'):
545547
await self.con.fetchval(query, *range(1, N + 1))
546548

547549
async def test_prepare_29_duplicates(self):
@@ -556,3 +558,14 @@ async def test_prepare_29_duplicates(self):
556558
self.assertEqual(r[0], 1)
557559
self.assertEqual(r[1], 2)
558560
self.assertEqual(r[2], 3)
561+
562+
async def test_prepare_30_invalid_arg_count(self):
563+
with self.assertRaisesRegex(
564+
exceptions.InterfaceError,
565+
'the server expects 1 argument for this query, 0 were passed'):
566+
await self.con.fetchval('SELECT $1::int')
567+
568+
with self.assertRaisesRegex(
569+
exceptions.InterfaceError,
570+
'the server expects 0 arguments for this query, 1 was passed'):
571+
await self.con.fetchval('SELECT 1', 1)

0 commit comments

Comments
 (0)