diff --git lib/mysql/connector/cursor.py lib/mysql/connector/cursor.py index 7cc7362..50da908 100644 --- lib/mysql/connector/cursor.py +++ lib/mysql/connector/cursor.py @@ -48,6 +48,8 @@ RE_SQL_SPLIT_STMTS = re.compile( b''';(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''') RE_SQL_FIND_PARAM = re.compile( b'''%s(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''') +RE_SQL_PYTHON_REPLACE_PARAM = re.compile('%\(.*?\)s') +RE_SQL_PYTHON_CAPTURE_PARAM_NAME = re.compile('%\((.*?)\)s') ERR_NO_RESULT_TO_FETCH = "No result set to fetch from" @@ -1076,7 +1078,7 @@ class MySQLCursorPrepared(MySQLCursor): self._connection.unread_result = True self._have_result = True - def execute(self, operation, params=(), multi=False): # multi is unused + def execute(self, operation, params=None, multi=False): # multi is unused """Prepare and execute a MySQL Prepared Statement This method will preare the given operation and execute it using @@ -1085,6 +1087,21 @@ class MySQLCursorPrepared(MySQLCursor): If the cursor instance already had a prepared statement, it is first closed. """ + if type(params) == dict: + query_replacement_keys = re.findall(RE_SQL_PYTHON_CAPTURE_PARAM_NAME, operation) + operation = re.sub(RE_SQL_PYTHON_REPLACE_PARAM, '?', operation) + + if len(set(query_replacement_keys)) != len(params): + raise errors.ProgrammingError( + "Not all parameters were used in the SQL statement") + + #Replace params dict with params tuple in correct order. + try: + params = tuple([ params[key] for key in query_replacement_keys]) + except KeyError: + raise errors.ProgrammingError( + "Not all parameters were used in the SQL statement") + if operation is not self._executed: if self._prepared: self._connection.cmd_stmt_close(self._prepared['statement_id'])