Hi all,

I recently ran into an issue where one of our `sqlalchemy-migrate` 
downgrade scripts was failing because it was trying to drop an index twice.

The root cause appears to be that SQLAlchemy's `idx.drop()` call does not 
update the `indexes` set for  the associated table.

I've attached a test case which hopefully explains the situation a little 
better.

My question is: is this expected behavior? Given that `index.create` 
mutates `table.indexes`, should we expect `index.drop` to do the inverse 
and remove it?

My naive assumption that it should, but if that wrong, I'd love to hear why.

Thanks!

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


import sqlalchemy as sa


def test_drop_index():
    """Dropping an index does not remove its reference from associated tables.

    The real-world breakage occurs when you combine this behavior w/
    sqlalchemy-migrate's `drop_column`:

        idx_on_colA.drop()
        tableX.drop_column('colA') # <- This will attempt to DROP INDEX again!

    The problem is that when sqlalchemy-migrate goes to delete the column, it
    erronoeously still sees the index present on `colA` and so attempts to
    re-drop the index before dropping the column. Since the index from the
    DB's perspective is no longer present, we get an error.

    The workaround we have is:

        idx_on_colA.drop()
        tableX.indexes.remove(idx_on_colA)

    See:
        https://review.openstack.org/#/c/22628/1/nova/db/sqlalchemy/migrate_repo/versions/144_add_node_to_migrations.py,unified

    Versions affected:
        This affects 0.8.0b2 and earlier.
    """
    engine = sa.create_engine('sqlite:///')
    engine.echo = True
    meta = sa.MetaData(engine)
    users = sa.Table('users', meta,
                     sa.Column('id', sa.Integer, primary_key=True),
                     sa.Column('email', sa.Unicode))

    assert len(users.indexes) == 0
    email_idx = sa.Index('idx_users_email', users.c.email)
    meta.create_all()

    assert len(users.indexes) == 1
    email_idx.drop()

    # This fails, sinces `users` retains a ref to `email_idx`
    assert len(users.indexes) == 0, 'email_idx still present'


if __name__ == '__main__':
    test_drop_index()

Reply via email to