# Buggy code
def visit_on_duplicate_key_update(self, on_duplicate, **kw):
    if on_duplicate._parameter_ordering:
        parameter_ordering = [
            elements._column_as_key(key) for key in on_duplicate._parameter_ordering
        ]
        ordered_keys = set(parameter_ordering)
        cols = [
            self.statement.table.c[key]
            for key in parameter_ordering
            if key in self.statement.table.c
        ] + [c for c in self.statement.table.c if c.key not in ordered_keys]
    else:
        cols = self.statement.table.c

    clauses = []
    # traverses through all table columns to preserve table column order
    for column in (col for col in cols if col.key in on_duplicate.update):
        val = on_duplicate.update[column.key]

        if elements._is_literal(val):
            val = elements.BindParameter(None, val, type_=column.type)
            value_text = self.process(val.self_group(), use_schema=False)
        else:

            def replace(obj):
                if isinstance(obj, elements.BindParameter) and obj.type._isnull:
                    obj = obj._clone()
                    obj.type = column.type
                    return obj
                elif (
                    isinstance(obj, elements.ColumnClause)
                    and obj.table is on_duplicate.inserted_alias
                ):
                    obj = literal_column(
                        "VALUES(" + self.preparer.quote(column.name) + ")"
                    )
                    return obj
                else:
                    # element is not replaced
                    return None

            val = visitors.replacement_traverse(val, {}, replace)
            value_text = self.process(val.self_group(), use_schema=False)

        name_text = self.preparer.quote(column.name)
        clauses.append("%s = %s" % (name_text, value_text))

    non_matching = set(on_duplicate.update) - set(c.key for c in cols)
    if non_matching:
        util.warn(
            "Additional column names not matching "
            "any column keys in table '%s': %s"
            % (
                self.statement.table.name,
                (", ".join("'%s'" % c for c in non_matching)),
            )
        )

    return "ON DUPLICATE KEY UPDATE " + ", ".join(clauses)


# Traceback (AttributeError)
Traceback (most recent call last):
File "./reproduction.py", line 315, in <module>
Score.__table__.create()
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 925, in create
bind._run_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2095, in _run_visitor
conn._run_visitor(visitorcallable, element, **kwargs)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1656, in _run_visitor
visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 145, in traverse_single
return meth(obj, **kw)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 854, in visit_table
_is_metadata_operation=_is_metadata_operation,
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/event/attr.py", line 322, in __call__
fn(*args, **kw)
File "./reproduction.py", line 152, in create_after_all_dependencies
CreateTrigger(self)(*args, **kwargs)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 256, in __call__
return bind.execute(self.against(target))
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1011, in execute
return meth(self, multiparams, params)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 72, in _execute_on_connection
return connection._execute_ddl(self, multiparams, params)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1066, in _execute_ddl
else None,
File "<string>", line 1, in <lambda>
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 481, in compile
return self._compiler(dialect, bind=bind, **kw)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 29, in _compiler
return dialect.ddl_compiler(dialect, self, **kw)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 325, in __init__
self.string = self.process(self.statement, **compile_kwargs)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 355, in process
return obj._compiler_dispatch(self, **kwargs)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/ext/compiler.py", line 441, in <lambda>
lambda *arg, **kw: existing(*arg, **kw),
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/ext/compiler.py", line 486, in __call__
return fn(element, compiler, **kw)
File "./reproduction.py", line 199, in visit_create_trigger_mysql
compiled_query = sql_compiler.process(element.trigger.query, literal_binds=True)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 355, in process
return obj._compiler_dispatch(self, **kwargs)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 96, in _compiler_dispatch
return meth(self, **kw)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 2515, in visit_insert
insert_stmt._post_values_clause, **kw
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 355, in process
return obj._compiler_dispatch(self, **kwargs)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 96, in _compiler_dispatch
return meth(self, **kw)
File "….virtualenvs/yeepa/lib/python2.7/site-packages/sqlalchemy/dialects/mysql/base.py", line 1400, in visit_on_duplicate_key_update
cols = self.statement.table.c
AttributeError: 'MySQLCompiler_mysqldb' object has no attribute 'statement'

# Fixed code
def visit_on_duplicate_key_update(self, on_duplicate, **kw):
    statement = self.current_executable

    if on_duplicate._parameter_ordering:
        parameter_ordering = [
            elements._column_as_key(key) for key in on_duplicate._parameter_ordering
        ]
        ordered_keys = set(parameter_ordering)
        cols = [
            statement.table.c[key]
            for key in parameter_ordering
            if key in statement.table.c
        ] + [c for c in statement.table.c if c.key not in ordered_keys]
    else:
        cols = statement.table.c

    clauses = []
    # traverses through all table columns to preserve table column order
    for column in (col for col in cols if col.key in on_duplicate.update):
        val = on_duplicate.update[column.key]

        if elements._is_literal(val):
            val = elements.BindParameter(None, val, type_=column.type)
            value_text = self.process(val.self_group(), use_schema=False)
        else:

            def replace(obj):
                if isinstance(obj, elements.BindParameter) and obj.type._isnull:
                    obj = obj._clone()
                    obj.type = column.type
                    return obj
                elif (
                    isinstance(obj, elements.ColumnClause)
                    and obj.table is on_duplicate.inserted_alias
                ):
                    obj = literal_column(
                        "VALUES(" + self.preparer.quote(column.name) + ")"
                    )
                    return obj
                else:
                    # element is not replaced
                    return None

            val = visitors.replacement_traverse(val, {}, replace)
            value_text = self.process(val.self_group(), use_schema=False)

        name_text = self.preparer.quote(column.name)
        clauses.append("%s = %s" % (name_text, value_text))

    non_matching = set(on_duplicate.update) - set(c.key for c in cols)
    if non_matching:
        util.warn(
            "Additional column names not matching "
            "any column keys in table '%s': %s"
            % (
                self.statement.table.name,
                (", ".join("'%s'" % c for c in non_matching)),
            )
        )

    return "ON DUPLICATE KEY UPDATE " + ", ".join(clauses)