Bug #67146 MySQLCursor.executemany() fails when using the pyformat parameter style
Submitted: 9 Oct 2012 14:11 Modified: 1 Dec 2012 0:27
Reporter: mike bayer Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / Python Severity:S1 (Critical)
Version:1.0.7 OS:Any
Assigned to: Geert Vanderkelen CPU Architecture:Any

[9 Oct 2012 14:11] mike bayer
Description:
.paramstyle reports "pyformat" as the default parameter style, however this format is broken when using executemany().

This is against mysql-connector as returned by "bzr clone lp:myconnpy"

How to repeat:
from mysql import connector

# from pep-249
# paramstyle
#
# String constant stating the type of parameter marker
# formatting expected by the interface. Possible values are
# ...
# 'pyformat' Python extended format codes,
# e.g. '...WHERE name=%(name)s'
assert connector.paramstyle == 'pyformat'

conn = connector.connect(user='scott', password='tiger',
                            database='test', host='localhost')

cursor = conn.cursor()

cursor.execute("""
create table if not exists test( x integer, y integer) engine='InnoDB'
""")

# 'format' style with executemany() - works
cursor.executemany("insert into test(x, y) values (%s, %s)",
      [(1, 2), (3, 4)]
)

# 'pyformat' with execute() - works
cursor.execute("insert into test(x, y) values (%(x)s, %(y)s)",
      {"x": 1, "y": 2}
)

# 'pyformat' style with executemany() - broken
cursor.executemany("insert into test(x, y) values (%(x)s, %(y)s)",
      [{"x":1, "y":2}, {"x":3, "y":4}]
)

"""
output:

Traceback (most recent call last):
  File "mysqlconnector_execmany.py", line 21, in <module>
    [{"x":1, "y":2}, {"x":3, "y":4}]
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mysql/connector/cursor.py", line 437, in executemany
    values.append(fmt % self._process_params(params))
ValueError: incomplete format
"""

Suggested fix:
default to positional paramstyle for a quick fix, or fix executemany().
[9 Oct 2012 14:13] mike bayer
also note mysql-connector is non-functional with SQLAlchemy with this issue.
[12 Oct 2012 10:17] Geert Vanderkelen
Verified using Connector/Python 1.0.7 and trunk.
[1 Dec 2012 0:27] John Russell
Added to changelog for 1.0.8: 

The executemany() function now supports the pyformat parameter style.
In the pyformat style, all the substitution variables are passed in
using a single dictionary parameter, and the % format specifier is
encoded like %(dict_key)s for a string. MySQLCursor.executemany() can
now use both ANSI C printf and Python extended format codes.