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 [email protected].
To post to this group, send email to [email protected].
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()