@@ -156,12 +156,18 @@ def execute(self, sql, *args, **kwargs):
156156 elif paramstyle == "numeric" :
157157
158158 # Escape values
159- for index , name in placeholders .items ():
160- i = int (name ) - 1
159+ for index , i in placeholders .items ():
161160 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 ) ))
163162 tokens [index ] = self ._escape (args [i ])
164163
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+
165171 # named
166172 elif paramstyle == "named" :
167173
@@ -171,6 +177,11 @@ def execute(self, sql, *args, **kwargs):
171177 raise RuntimeError ("missing value for placeholder (:{})" .format (name ))
172178 tokens [index ] = self ._escape (kwargs [name ])
173179
180+ # Check if any keys unused
181+ keys = kwargs .keys () - placeholders .values ()
182+ if keys :
183+ raise RuntimeError ("unused values ({})" .format (", " .join (keys )))
184+
174185 # format
175186 elif paramstyle == "format" :
176187
@@ -191,9 +202,16 @@ def execute(self, sql, *args, **kwargs):
191202 # Escape values
192203 for index , name in placeholders .items ():
193204 if name not in kwargs :
194- raise RuntimeError ("missing value for placeholder (:{} )" .format (name ))
205+ raise RuntimeError ("missing value for placeholder (%{}s )" .format (name ))
195206 tokens [index ] = self ._escape (kwargs [name ])
196207
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+
197215 # Join tokens into statement
198216 statement = "" .join ([str (token ) for token in tokens ])
199217
@@ -362,9 +380,9 @@ def _parse_placeholder(token):
362380 return "qmark" , None
363381
364382 # numeric
365- matches = re .search (r"^:(\d+ )$" , token .value )
383+ matches = re .search (r"^:([1-9]\d* )$" , token .value )
366384 if matches :
367- return "numeric" , matches .group (1 )
385+ return "numeric" , int ( matches .group (1 )) - 1
368386
369387 # named
370388 matches = re .search (r"^:([a-zA-Z]\w*)$" , token .value )
0 commit comments