Index creation silently dropped when referencing relation

Issue #2380 resolved
Former user created an issue

(original reporter: rbu) SQLAlchemy (0.7.2 here) silently ignores Index() declarations when they do not reference a proper column when it should at least issue a warning (if not even find out the related column).

For example, with a declarative model such as this:

class Fnord(Base):
    __tablename__ = 'fnord'
    id = Column(Integer, primary_key=True)
    other_id = Column(Integer, ForeignKey(Other.id))
    other = relationship(Other)

this will create an index:

Index("ix_fnord_other", Fnord.other_id)

but this will not:

Index("ix_fnord_other", Fnord.other)

Even nonsensical statements such as

Index("ix_fnord_other")

do not create at least a warning.

Comments (3)

  1. Mike Bayer repo owner
    • assigned issue to
    • changed component to orm
    • changed milestone to 0.7.5

    here's a patch:

    diff -r 8c05a3bf6599f92bbf8d2246123597e8966f3a52 lib/sqlalchemy/schema.py
    --- a/lib/sqlalchemy/schema.py  Wed Jan 18 12:42:54 2012 -0500
    +++ b/lib/sqlalchemy/schema.py  Fri Jan 20 11:17:48 2012 -0500
    @@ -2172,6 +2172,8 @@
             self.table = None
             # will call _set_parent() if table-bound column
             # objects are present
    +        if not columns:
    +            raise exc.ArgumentError("No column names or expressions given.")
             ColumnCollectionMixin.__init__(self, *columns)
             self.name = name
             self.unique = kw.pop('unique', False)
    @@ -2984,9 +2986,11 @@
        return element
    
     def _to_schema_column_or_string(element):
    -  if hasattr(element, '__clause_element__'):
    -      element = element.__clause_element__()
    -  return element
    +    if hasattr(element, '__clause_element__'):
    +        element = element.__clause_element__()
    +    if not isinstance(element, (basestring, expression.ColumnElement)):
    +        raise exc.ArgumentError("Element %r is not a string name or column element" % element)
    +    return element
    
     class _CreateDropBase(DDLElement):
         """Base class for DDL constucts that represent CREATE and DROP or
    diff -r 8c05a3bf6599f92bbf8d2246123597e8966f3a52 test/sql/test_metadata.py
    --- a/test/sql/test_metadata.py Wed Jan 18 12:42:54 2012 -0500
    +++ b/test/sql/test_metadata.py Fri Jan 20 11:17:48 2012 -0500
    @@ -644,7 +644,7 @@
                     "Column('x', String(), table=<bar>), schema=None)"),
                 (schema.DefaultGenerator(for_update=True), 
                     "DefaultGenerator(for_update=True)"),
    -            (schema.Index("bar"), "Index('bar')"),
    +            (schema.Index("bar", "c"), "Index('bar')"),
                 (i1, "Index('bar', Column('x', Integer(), table=<foo>))"),
                 (schema.FetchedValue(), "FetchedValue()"),
                 (ck,
    

    tests to add are:

    from sqlalchemy import *
    
    m = MetaData()
    
    # raises (this is an existing raise, might already have a test for this)
    t1 = Table('t', m, Column('x', Integer), Index("foo", "q"))
    
    # raises
    Index("foo", 5)
    
    # raises
    Index("foo")
    
    # raises
    t2 = Table('t2', m, Column('x', Integer))
    class SomethingLikeARelationship(object):
        def __clause_element__(self):
            return t2
    
    Index("foo", SomethingLikeARelationship())
    

    }}}

  2. Log in to comment