@@ -156,12 +156,18 @@ def execute(self, sql, *args, **kwargs):
156
156
elif paramstyle == "numeric" :
157
157
158
158
# Escape values
159
- for index , name in placeholders .items ():
160
- i = int (name ) - 1
159
+ for index , i in placeholders .items ():
161
160
if i >= len (args ):
162
- raise RuntimeError ("placeholder (:{}) greater than number of values ( {})" .format (name , _args ))
161
+ raise RuntimeError ("missing value for placeholder (: {})" .format (i + 1 , len ( args ) ))
163
162
tokens [index ] = self ._escape (args [i ])
164
163
164
+ # Check if any values unused
165
+ indices = set (range (len (args ))) - set (placeholders .values ())
166
+ if indices :
167
+ raise RuntimeError ("unused {} ({})" .format (
168
+ "value" if len (indices ) == 1 else "values" ,
169
+ ", " .join ([str (self ._escape (args [index ])) for index in indices ])))
170
+
165
171
# named
166
172
elif paramstyle == "named" :
167
173
@@ -171,6 +177,11 @@ def execute(self, sql, *args, **kwargs):
171
177
raise RuntimeError ("missing value for placeholder (:{})" .format (name ))
172
178
tokens [index ] = self ._escape (kwargs [name ])
173
179
180
+ # Check if any keys unused
181
+ keys = kwargs .keys () - placeholders .values ()
182
+ if keys :
183
+ raise RuntimeError ("unused values ({})" .format (", " .join (keys )))
184
+
174
185
# format
175
186
elif paramstyle == "format" :
176
187
@@ -191,9 +202,16 @@ def execute(self, sql, *args, **kwargs):
191
202
# Escape values
192
203
for index , name in placeholders .items ():
193
204
if name not in kwargs :
194
- raise RuntimeError ("missing value for placeholder (:{} )" .format (name ))
205
+ raise RuntimeError ("missing value for placeholder (%{}s )" .format (name ))
195
206
tokens [index ] = self ._escape (kwargs [name ])
196
207
208
+ # Check if any keys unused
209
+ keys = kwargs .keys () - placeholders .values ()
210
+ if keys :
211
+ raise RuntimeError ("unused {} ({})" .format (
212
+ "value" if len (keys ) == 1 else "values" ,
213
+ ", " .join (keys )))
214
+
197
215
# Join tokens into statement
198
216
statement = "" .join ([str (token ) for token in tokens ])
199
217
@@ -362,9 +380,9 @@ def _parse_placeholder(token):
362
380
return "qmark" , None
363
381
364
382
# numeric
365
- matches = re .search (r"^:(\d+ )$" , token .value )
383
+ matches = re .search (r"^:([1-9]\d* )$" , token .value )
366
384
if matches :
367
- return "numeric" , matches .group (1 )
385
+ return "numeric" , int ( matches .group (1 )) - 1
368
386
369
387
# named
370
388
matches = re .search (r"^:([a-zA-Z]\w*)$" , token .value )
0 commit comments