@@ -181,57 +181,60 @@ def __exit__(self, exc_type, exc_val, exc_tb):
181181
182182def _replace_numeric_markers (operation , string_parameters , paramstyle ):
183183 """
184- Replaces qname , format, and numeric markers in the given operation, from
184+ Replaces qmark , format, and numeric markers in the given operation, from
185185 the string_parameters list.
186186
187- Raises ProgrammingError on wrong number of parameters or bindings
188- when using qmark. There is no error checking on numeric parameters.
187+ Raises ProgrammingError on wrong number of parameters or markers.
188+ For numeric markers there has to be enough parameters to satisfy
189+ every marker and there has to bo no unused parameter.
189190 """
190- def replace_markers (marker , op , parameters ):
191- param_count = len (parameters )
192- marker_index = 0
193- start_offset = 0
194- while True :
195- found_offset = op .find (marker , start_offset )
196- if not found_offset > - 1 :
197- break
198- if marker_index < param_count :
199- op = op [:found_offset ]+ op [found_offset :].replace (marker , parameters [marker_index ], 1 )
200- start_offset = found_offset + len (parameters [marker_index ])
201- marker_index += 1
202- else :
203- raise ProgrammingError ("Incorrect number of bindings "
204- "supplied. The current statement uses "
205- "%d or more, and there are %d "
206- "supplied." % (marker_index + 1 ,
207- param_count ))
208- if marker_index != 0 and marker_index != param_count :
209- raise ProgrammingError ("Incorrect number of bindings "
210- "supplied. The current statement uses "
211- "%d or more, and there are %d supplied." %
212- (marker_index + 1 , param_count ))
213- return op
214-
215- # replace qmark parameters and format parameters
216- # If paramstyle is explicitly specified don't try to substitue them all
217- if paramstyle == 'qmark' or paramstyle is None :
218- operation = replace_markers ('?' , operation , string_parameters )
219- if paramstyle == 'format' or paramstyle is None :
220- operation = replace_markers (r'%s' , operation , string_parameters )
221-
222- # replace numbered parameters
223- if paramstyle == 'numeric' or paramstyle is None :
224- operation = re .sub (r'(:)(\d+)' , r'{\2}' , operation )
225- # offset by one
226- operation = operation .format (* ['' ] + string_parameters )
227-
228- if paramstyle in ['named' , 'pyformat' ]:
191+ RE_QMARK = r'(?P<qmark>\?)'
192+ RE_FORMAT = r'(?P<format>%s)'
193+ RE_NUMERIC = r'(?P<numeric>:(?P<index>\d+))'
194+ RE_ALL = '|' .join ([RE_QMARK , RE_FORMAT , RE_NUMERIC ])
195+
196+ if paramstyle is not None :
197+ if paramstyle in ['named' , 'pyformat' ]:
198+ raise ProgrammingError (
199+ "Paramstyle '%s' is not compatible with parameters passed as "
200+ "list. Please use a dict for your parameters instead "
201+ "or specify a different paramstyle" % paramstyle )
202+
203+ if paramstyle not in ['qmark' , 'format' , 'numeric' ]:
204+ raise ProgrammingError (
205+ "Paramstyle '%s' is not supported. Please use a different one" )
206+
207+ param_count = len (string_parameters )
208+ used_positional_indexes = set ()
209+ used_numeric_indexes = set ()
210+
211+ def replace_marker (match ):
212+ if paramstyle is not None and match .group (paramstyle ) is None :
213+ return match .group (0 )
214+
215+ if match .group ('index' ) is not None :
216+ param_index = int (match .group ('index' )) - 1
217+ used_numeric_indexes .add (param_index )
218+ else :
219+ param_index = len (used_positional_indexes )
220+ used_positional_indexes .add (param_index )
221+
222+ if param_index >= param_count :
223+ raise ProgrammingError (
224+ "Incorrect number of bindings supplied. The current statement "
225+ "uses %d or more, and there are %d supplied." % (
226+ param_index , param_count ))
227+
228+ return string_parameters [param_index ]
229+
230+ operation = re .sub (RE_ALL , replace_marker , operation )
231+
232+ marker_count = len (used_numeric_indexes | used_positional_indexes )
233+ if marker_count < param_count :
229234 raise ProgrammingError (
230- "paramstyle '%s' is not compatible with parameters passed as List."
231- "please use a dict for you parameters instead or specify"
232- " a different paramstyle" ,
233- paramstyle
234- )
235+ "Incorrect number of bindings supplied. The current statement "
236+ "uses %d, and there are %d supplied." % (
237+ marker_count , param_count ))
235238
236239 return operation
237240
0 commit comments