aliased column overrides don't override

Issue #650 resolved
Former user created an issue

When using MySQL 4 table reflection with assign_mapper and a table column override, updating an object causes the following error:

sqlalchemy.exceptions.ConcurrentModificationError: Updated rowcount 0 does not match number of objects updated 1

The table setup looks like:

user_table = Table('ur', sac.get_metadata('default'), 
                   Column('cs_rid', Integer, primary_key=True, key='id'), 
                   autoload=True)

class User(object):
    pass

assign_mapper(sac.session_context, User, user_table)

Upon removing the primary_key statement from the Column, the exception disappears.

Comments (7)

  1. jek

    When aliased user columns (key=) are processed after autoload, ColumnCollection.add includes them via column.key, alongside the originals which had column.key == collumn.name.

    This affects all autoloads, not related to mysql reflection in particular.

  2. jek
    • changed milestone to 0.3.9

    A fix for the case above is straightforward, but more thought needs to go into what the expected behavior is with regard to existing autoloaded keys and constraints, especially if the override specifies different pk/fk keying than the original.

  3. Mike Bayer repo owner
    • changed milestone to 0.5.0

    here's a patch, make _link_to_name public too:

    Index: lib/sqlalchemy/schema.py
    ===================================================================
    --- lib/sqlalchemy/schema.py    (revision 5527)
    +++ lib/sqlalchemy/schema.py    (working copy)
    @@ -769,7 +769,7 @@
    
         __visit_name__ = 'foreign_key'
    
    -    def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None, deferrable=None, initially=None):
    +    def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None, deferrable=None, initially=None, _link_to_name=False):
             """
             Construct a column-level FOREIGN KEY.
    
    @@ -812,6 +812,7 @@
             self.ondelete = ondelete
             self.deferrable = deferrable
             self.initially = initially
    +        self._link_to_name = _link_to_name
    
         def __repr__(self):
             return "ForeignKey(%r)" % self._get_colspec()
    @@ -888,10 +889,16 @@
                     else:
                         _column = table.c[colname](colname)
                 except KeyError, e:
    -                raise exc.NoReferencedColumnError(
    -                    "Could not create ForeignKey '%s' on table '%s': "
    -                    "table '%s' has no column named '%s'" % (
    -                    self._colspec, parenttable.name, table.name, str(e)))
    +                _column = None
    +                if self._link_to_name:
    +                    for c in table.c:
    +                        if c.name == colname:
    +                            _column = c
    +                if not _column:
    +                    raise exc.NoReferencedColumnError(
    +                        "Could not create ForeignKey '%s' on table '%s': "
    +                        "table '%s' has no column named '%s'" % (
    +                        self._colspec, parenttable.name, table.name, e))
    
             elif hasattr(self._colspec, '__clause_element__'):
                 _column = self._colspec.__clause_element__()
    @@ -1191,7 +1198,7 @@
         """
         __visit_name__ = 'foreign_key_constraint'
    
    -    def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, use_alter=False, deferrable=None, initially=None):
    +    def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, use_alter=False, deferrable=None, initially=None, _link_to_name=False):
             """Construct a composite-capable FOREIGN KEY.
    
             columns
    @@ -1235,6 +1242,7 @@
             self.elements = util.OrderedSet()
             self.onupdate = onupdate
             self.ondelete = ondelete
    +        self._link_to_name = _link_to_name
             if self.name is None and use_alter:
                 raise exc.ArgumentError("Alterable ForeignKey/ForeignKeyConstraint requires a name")
             self.use_alter = use_alter
    @@ -1247,7 +1255,7 @@
                     self.append_element(c, r)
    
         def append_element(self, col, refcol):
    -        fk = ForeignKey(refcol, constraint=self, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete, use_alter=self.use_alter)
    +        fk = ForeignKey(refcol, constraint=self, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete, use_alter=self.use_alter, _link_to_name=self._link_to_name)
             fk._set_parent(self.table.c[col](col))
             self._append_fk(fk)
    
    Index: lib/sqlalchemy/databases/sqlite.py
    ===================================================================
    --- lib/sqlalchemy/databases/sqlite.py  (revision 5527)
    +++ lib/sqlalchemy/databases/sqlite.py  (working copy)
    @@ -522,7 +522,7 @@
                 if refspec not in fk[1](1):
                     fk[1](1).append(refspec)
             for name, value in fks.iteritems():
    -            table.append_constraint(schema.ForeignKeyConstraint(value[0](0), value[1](1)))
    +            table.append_constraint(schema.ForeignKeyConstraint(value[0](0), value[1](1), _link_to_name=True))
             # check for UNIQUE indexes
             c = connection.execute("%sindex_list(%s)" % (pragma, qtable))
             unique_indexes = []
    
  4. Log in to comment