<p dir="auto"><strong>Migrated issue, originally created by Anonymous</strong></p>
<p dir="auto">Not sure what the precise problem is here, but on my system I get the following exception with the current sqlalchemy trunk from Subversion (revision 1344)</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[15:27:20,845](2006-04-27) [engine](engine): DELETE FROM managers WHERE managers.person_id = %(person_id)s
[15:27:20,845](2006-04-27) [engine](engine): [1}, {'person_id': 2}]({'person_id':)
Traceback (most recent call last):
  File &quot;polymorph2.py&quot;, line 130, in ?
    objectstore.commit()
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/objectstore.py&quot;, line 250, in commit
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/objectstore.py&quot;, line 81, in flush
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py&quot;, line 249, in flush
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py&quot;, line 374, in execute
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py&quot;, line 540, in execute
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py&quot;, line 540, in execute
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py&quot;, line 544, in execute
  File &quot;build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/mapper.py&quot;, line 661, in delete_obj
sqlalchemy.exceptions.CommitError: ConcurrencyError - updated rowcount 1 does not match number of objects updated 2"><pre class="notranslate"><code class="notranslate">[15:27:20,845](2006-04-27) [engine](engine): DELETE FROM managers WHERE managers.person_id = %(person_id)s
[15:27:20,845](2006-04-27) [engine](engine): [1}, {'person_id': 2}]({'person_id':)
Traceback (most recent call last):
  File "polymorph2.py", line 130, in ?
    objectstore.commit()
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/objectstore.py", line 250, in commit
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/objectstore.py", line 81, in flush
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py", line 249, in flush
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py", line 374, in execute
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py", line 540, in execute
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py", line 540, in execute
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/unitofwork.py", line 544, in execute
  File "build/bdist.darwin-8.6.0-Power_Macintosh/egg/sqlalchemy/mapping/mapper.py", line 661, in delete_obj
sqlalchemy.exceptions.CommitError: ConcurrencyError - updated rowcount 1 does not match number of objects updated 2
</code></pre></div>
<p dir="auto"><strong>Describe the bug</strong><br>
The column name <code class="notranslate">values</code> is causing a bug when doing an upsert with MySQL (using <code class="notranslate">pymysql</code>).<br>
For testing purposes, you can change the column name in the variable <code class="notranslate">values_column_name</code> to something else than <code class="notranslate">values</code> and then you will see that no errors occur.</p>
<p dir="auto"><strong>To Reproduce</strong></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from sqlalchemy import create_engine, Column, Integer, MetaData, Table, Text
from sqlalchemy.dialects.mysql.dml import insert as mysql_insert

# config
table_name = 'test_upsert_mysql'
engine = create_engine(CONNECTION_STRING) # please put your connection string to a MySQL database here
engine.execute(f'DROP TABLE IF EXISTS {table_name};') # reset previous tests

values_column_name = 'values' # change this to anything else than &quot;values&quot; and there shall be no bug

# table model
table = Table('test_upsert_mysql',
              MetaData(bind=engine),
              Column('profileid', Integer(), primary_key=True, nullable=False),
              Column(values_column_name, Integer()))
table.create()

# test upsert
values = [{'profileid':1, values_column_name:1}]
insert_stmt = mysql_insert(table).values(values)
upsert = insert_stmt.on_duplicate_key_update({values_column_name:getattr(insert_stmt.inserted, values_column_name)})
engine.execute(upsert)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span> <span class="pl-k">import</span> <span class="pl-s1">create_engine</span>, <span class="pl-v">Column</span>, <span class="pl-v">Integer</span>, <span class="pl-v">MetaData</span>, <span class="pl-v">Table</span>, <span class="pl-v">Text</span>
<span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span>.<span class="pl-s1">dialects</span>.<span class="pl-s1">mysql</span>.<span class="pl-s1">dml</span> <span class="pl-k">import</span> <span class="pl-s1">insert</span> <span class="pl-k">as</span> <span class="pl-s1">mysql_insert</span>

<span class="pl-c"># config</span>
<span class="pl-s1">table_name</span> <span class="pl-c1">=</span> <span class="pl-s">'test_upsert_mysql'</span>
<span class="pl-s1">engine</span> <span class="pl-c1">=</span> <span class="pl-en">create_engine</span>(<span class="pl-v">CONNECTION_STRING</span>) <span class="pl-c"># please put your connection string to a MySQL database here</span>
<span class="pl-s1">engine</span>.<span class="pl-en">execute</span>(<span class="pl-s">f'DROP TABLE IF EXISTS <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">table_name</span><span class="pl-kos">}</span></span>;'</span>) <span class="pl-c"># reset previous tests</span>

<span class="pl-s1">values_column_name</span> <span class="pl-c1">=</span> <span class="pl-s">'values'</span> <span class="pl-c"># change this to anything else than "values" and there shall be no bug</span>

<span class="pl-c"># table model</span>
<span class="pl-s1">table</span> <span class="pl-c1">=</span> <span class="pl-v">Table</span>(<span class="pl-s">'test_upsert_mysql'</span>,
              <span class="pl-v">MetaData</span>(<span class="pl-s1">bind</span><span class="pl-c1">=</span><span class="pl-s1">engine</span>),
              <span class="pl-v">Column</span>(<span class="pl-s">'profileid'</span>, <span class="pl-v">Integer</span>(), <span class="pl-s1">primary_key</span><span class="pl-c1">=</span><span class="pl-c1">True</span>, <span class="pl-s1">nullable</span><span class="pl-c1">=</span><span class="pl-c1">False</span>),
              <span class="pl-v">Column</span>(<span class="pl-s1">values_column_name</span>, <span class="pl-v">Integer</span>()))
<span class="pl-s1">table</span>.<span class="pl-en">create</span>()

<span class="pl-c"># test upsert</span>
<span class="pl-s1">values</span> <span class="pl-c1">=</span> [{<span class="pl-s">'profileid'</span>:<span class="pl-c1">1</span>, <span class="pl-s1">values_column_name</span>:<span class="pl-c1">1</span>}]
<span class="pl-s1">insert_stmt</span> <span class="pl-c1">=</span> <span class="pl-en">mysql_insert</span>(<span class="pl-s1">table</span>).<span class="pl-en">values</span>(<span class="pl-s1">values</span>)
<span class="pl-s1">upsert</span> <span class="pl-c1">=</span> <span class="pl-s1">insert_stmt</span>.<span class="pl-en">on_duplicate_key_update</span>({<span class="pl-s1">values_column_name</span>:<span class="pl-en">getattr</span>(<span class="pl-s1">insert_stmt</span>.<span class="pl-s1">inserted</span>, <span class="pl-s1">values_column_name</span>)})
<span class="pl-s1">engine</span>.<span class="pl-en">execute</span>(<span class="pl-s1">upsert</span>)</pre></div>
<p dir="auto"><strong>Error</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
&lt;ipython-input-5-6e7be1d0a0c8&gt; in &lt;module&gt;
     20 insert_stmt = mysql_insert(table).values(values)
     21 upsert = insert_stmt.on_duplicate_key_update({values_column_name:getattr(insert_stmt.inserted, values_column_name)})
---&gt; 22 engine.execute(upsert)

&lt;string&gt; in execute(self, statement, *multiparams, **params)

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/util/deprecations.py in warned(fn, *args, **kwargs)
    388         if not skip_warning:
    389             _warn_with_version(message, version, wtype, stacklevel=3)
--&gt; 390         return fn(*args, **kwargs)
    391 
    392     doc = func.__doc__ is not None and func.__doc__ or &quot;&quot;

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in execute(self, statement, *multiparams, **params)
   3105         &quot;&quot;&quot;
   3106         connection = self.connect(close_with_result=True)
-&gt; 3107         return connection.execute(statement, *multiparams, **params)
   3108 
   3109     @util.deprecated_20(

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in execute(self, statement, *multiparams, **params)
   1260             )
   1261         else:
-&gt; 1262             return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS)
   1263 
   1264     def _execute_function(self, func, multiparams, params, execution_options):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/sql/elements.py in _execute_on_connection(self, connection, multiparams, params, execution_options, _force)
    322     ):
    323         if _force or self.supports_execution:
--&gt; 324             return connection._execute_clauseelement(
    325                 self, multiparams, params, execution_options
    326             )

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _execute_clauseelement(self, elem, multiparams, params, execution_options)
   1449             linting=self.dialect.compiler_linting | compiler.WARN_LINTING,
   1450         )
-&gt; 1451         ret = self._execute_context(
   1452             dialect,
   1453             dialect.execution_ctx_cls._init_compiled,

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _execute_context(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)
   1811 
   1812         except BaseException as e:
-&gt; 1813             self._handle_dbapi_exception(
   1814                 e, statement, parameters, cursor, context
   1815             )

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _handle_dbapi_exception(self, e, statement, parameters, cursor, context)
   1996                 )
   1997             else:
-&gt; 1998                 util.raise_(exc_info[1], with_traceback=exc_info[2])
   1999 
   2000         finally:

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/util/compat.py in raise_(***failed resolving arguments***)
    205 
    206         try:
--&gt; 207             raise exception
    208         finally:
    209             # credit to

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _execute_context(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)
   1768                             break
   1769                 if not evt_handled:
-&gt; 1770                     self.dialect.do_execute(
   1771                         cursor, statement, parameters, context
   1772                     )

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/default.py in do_execute(self, cursor, statement, parameters, context)
    715 
    716     def do_execute(self, cursor, statement, parameters, context=None):
--&gt; 717         cursor.execute(statement, parameters)
    718 
    719     def do_execute_no_params(self, cursor, statement, context=None):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in execute(self, query, args)
    159             pass
    160 
--&gt; 161         query = self.mogrify(query, args)
    162 
    163         result = self._query(query)

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in mogrify(self, query, args)
    138 
    139         if args is not None:
--&gt; 140             query = query % self._escape_args(args, conn)
    141 
    142         return query

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in _escape_args(self, args, conn)
    118                 args = {ensure_bytes(key): ensure_bytes(val) for
    119                         (key, val) in args.items()}
--&gt; 120             return {key: conn.literal(val) for (key, val) in args.items()}
    121         else:
    122             # If it's not a dictionary let's try escaping it anyways.

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in &lt;dictcomp&gt;(.0)
    118                 args = {ensure_bytes(key): ensure_bytes(val) for
    119                         (key, val) in args.items()}
--&gt; 120             return {key: conn.literal(val) for (key, val) in args.items()}
    121         else:
    122             # If it's not a dictionary let's try escaping it anyways.

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/connections.py in literal(self, obj)
    467         Non-standard, for internal use; do not use this in your applications.
    468         &quot;&quot;&quot;
--&gt; 469         return self.escape(obj, self.encoders)
    470 
    471     def escape_string(self, s):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/connections.py in escape(self, obj, mapping)
    460                 ret = &quot;_binary&quot; + ret
    461             return ret
--&gt; 462         return converters.escape_item(obj, self.charset, mapping=mapping)
    463 
    464     def literal(self, obj):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/converters.py in escape_item(val, charset, mapping)
     25         val = encoder(val, charset, mapping)
     26     else:
---&gt; 27         val = encoder(val, mapping)
     28     return val
     29 

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/converters.py in escape_unicode(value, mapping)
    121 
    122 def escape_unicode(value, mapping=None):
--&gt; 123     return u&quot;'%s'&quot; % _escape_unicode(value)
    124 
    125 def escape_str(value, mapping=None):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/converters.py in _escape_unicode(value, mapping)
     76     Value should be unicode
     77     &quot;&quot;&quot;
---&gt; 78     return value.translate(_escape_table)
     79 
     80 if PY2:

AttributeError: 'function' object has no attribute 'translate'"><pre class="notranslate"><code class="notranslate">---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
&lt;ipython-input-5-6e7be1d0a0c8&gt; in &lt;module&gt;
     20 insert_stmt = mysql_insert(table).values(values)
     21 upsert = insert_stmt.on_duplicate_key_update({values_column_name:getattr(insert_stmt.inserted, values_column_name)})
---&gt; 22 engine.execute(upsert)

&lt;string&gt; in execute(self, statement, *multiparams, **params)

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/util/deprecations.py in warned(fn, *args, **kwargs)
    388         if not skip_warning:
    389             _warn_with_version(message, version, wtype, stacklevel=3)
--&gt; 390         return fn(*args, **kwargs)
    391 
    392     doc = func.__doc__ is not None and func.__doc__ or ""

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in execute(self, statement, *multiparams, **params)
   3105         """
   3106         connection = self.connect(close_with_result=True)
-&gt; 3107         return connection.execute(statement, *multiparams, **params)
   3108 
   3109     @util.deprecated_20(

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in execute(self, statement, *multiparams, **params)
   1260             )
   1261         else:
-&gt; 1262             return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS)
   1263 
   1264     def _execute_function(self, func, multiparams, params, execution_options):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/sql/elements.py in _execute_on_connection(self, connection, multiparams, params, execution_options, _force)
    322     ):
    323         if _force or self.supports_execution:
--&gt; 324             return connection._execute_clauseelement(
    325                 self, multiparams, params, execution_options
    326             )

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _execute_clauseelement(self, elem, multiparams, params, execution_options)
   1449             linting=self.dialect.compiler_linting | compiler.WARN_LINTING,
   1450         )
-&gt; 1451         ret = self._execute_context(
   1452             dialect,
   1453             dialect.execution_ctx_cls._init_compiled,

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _execute_context(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)
   1811 
   1812         except BaseException as e:
-&gt; 1813             self._handle_dbapi_exception(
   1814                 e, statement, parameters, cursor, context
   1815             )

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _handle_dbapi_exception(self, e, statement, parameters, cursor, context)
   1996                 )
   1997             else:
-&gt; 1998                 util.raise_(exc_info[1], with_traceback=exc_info[2])
   1999 
   2000         finally:

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/util/compat.py in raise_(***failed resolving arguments***)
    205 
    206         try:
--&gt; 207             raise exception
    208         finally:
    209             # credit to

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/base.py in _execute_context(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)
   1768                             break
   1769                 if not evt_handled:
-&gt; 1770                     self.dialect.do_execute(
   1771                         cursor, statement, parameters, context
   1772                     )

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/sqlalchemy/engine/default.py in do_execute(self, cursor, statement, parameters, context)
    715 
    716     def do_execute(self, cursor, statement, parameters, context=None):
--&gt; 717         cursor.execute(statement, parameters)
    718 
    719     def do_execute_no_params(self, cursor, statement, context=None):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in execute(self, query, args)
    159             pass
    160 
--&gt; 161         query = self.mogrify(query, args)
    162 
    163         result = self._query(query)

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in mogrify(self, query, args)
    138 
    139         if args is not None:
--&gt; 140             query = query % self._escape_args(args, conn)
    141 
    142         return query

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in _escape_args(self, args, conn)
    118                 args = {ensure_bytes(key): ensure_bytes(val) for
    119                         (key, val) in args.items()}
--&gt; 120             return {key: conn.literal(val) for (key, val) in args.items()}
    121         else:
    122             # If it's not a dictionary let's try escaping it anyways.

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/cursors.py in &lt;dictcomp&gt;(.0)
    118                 args = {ensure_bytes(key): ensure_bytes(val) for
    119                         (key, val) in args.items()}
--&gt; 120             return {key: conn.literal(val) for (key, val) in args.items()}
    121         else:
    122             # If it's not a dictionary let's try escaping it anyways.

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/connections.py in literal(self, obj)
    467         Non-standard, for internal use; do not use this in your applications.
    468         """
--&gt; 469         return self.escape(obj, self.encoders)
    470 
    471     def escape_string(self, s):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/connections.py in escape(self, obj, mapping)
    460                 ret = "_binary" + ret
    461             return ret
--&gt; 462         return converters.escape_item(obj, self.charset, mapping=mapping)
    463 
    464     def literal(self, obj):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/converters.py in escape_item(val, charset, mapping)
     25         val = encoder(val, charset, mapping)
     26     else:
---&gt; 27         val = encoder(val, mapping)
     28     return val
     29 

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/converters.py in escape_unicode(value, mapping)
    121 
    122 def escape_unicode(value, mapping=None):
--&gt; 123     return u"'%s'" % _escape_unicode(value)
    124 
    125 def escape_str(value, mapping=None):

~/anaconda3/envs/pangres-dev/lib/python3.8/site-packages/pymysql/converters.py in _escape_unicode(value, mapping)
     76     Value should be unicode
     77     """
---&gt; 78     return value.translate(_escape_table)
     79 
     80 if PY2:

AttributeError: 'function' object has no attribute 'translate'
</code></pre></div>
<p dir="auto"><strong>Versions.</strong></p>
<ul dir="auto">
<li>OS: Pop!_OS 20.04 LTS</li>
<li>Python: 3.8.5</li>
<li>SQLAlchemy: 1.4.18</li>
<li>Database: MySQL</li>
<li>DBAPI: pymysql 0.10.1</li>
</ul>
<p dir="auto"><strong>Additional context</strong><br>
This came to my attention via an <a href="https://github.com/ThibTrip/pangres/issues/34" data-hovercard-type="issue" data-hovercard-url="/ThibTrip/pangres/issues/34/hovercard">issue</a> thtat a user of my library <code class="notranslate">pangres</code> created.</p>
<p dir="auto"><strong>Have a nice day!</strong></p>