-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
On 01/22/2016 07:44 AM, Michal Petrucha wrote: > Hello people, > > I'm having difficluty changing the type of a column from Boolean > to Integer on SQLite. Boolean generates an integer column with a > CHECK constraint; changing the type should just drop the constraint > (on SQLite at least). > > The problem is, when batch_op processes a command like this: > > batch_op.alter_column(name, type_=sa.Integer(), > existing_type=sa.Boolean()) > > errors out with errors looking something like this: > > Traceback (most recent call last): File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/operations/batch.py", > line 314, in drop_constraint del > self.named_constraints[const.name] KeyError: '_unnamed_' > > During handling of the above exception, another exception > occurred: > > Traceback (most recent call last): File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /bin/alembic", > line 11, in <module> sys.exit(main()) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/config.py", > line 471, in main CommandLine(prog=prog).main(argv=argv) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/config.py", > line 465, in main self.run_cmd(cfg, options) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/config.py", > line 448, in run_cmd **dict((k, getattr(options, k)) for k in > kwarg) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/command.py", > line 174, in upgrade script.run_env() File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/script/base.py", > line 397, in run_env util.load_python_file(self.dir, 'env.py') File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/util/pyfiles.py", > line 81, in load_python_file module = load_module_py(module_id, > path) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/util/compat.py", > line 68, in load_module_py module_id, path).load_module(module_id) > File "<frozen importlib._bootstrap>", line 539, in > _check_name_wrapper File "<frozen importlib._bootstrap>", line > 1614, in load_module File "<frozen importlib._bootstrap>", line > 596, in _load_module_shim File "<frozen importlib._bootstrap>", > line 1220, in load File "<frozen importlib._bootstrap>", line 1200, > in _load_unlocked File "<frozen importlib._bootstrap>", line 1129, > in _exec File "<frozen importlib._bootstrap>", line 1471, in > exec_module File "<frozen importlib._bootstrap>", line 321, in > _call_with_frames_removed File "migrations/env.py", line 78, in > <module> run_migrations_online() File "migrations/env.py", line 73, > in run_migrations_online context.run_migrations() File "<string>", > line 8, in run_migrations File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/runtime/environment.py", > line 797, in run_migrations > self.get_context().run_migrations(**kw) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/runtime/migration.py", > line 312, in run_migrations step.migration_fn(**kw) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/migrations/versions /eaab6fc3ef59_.py", > line 25, in upgrade batch_op.alter_column('c1', type_=sa.Integer(), > existing_type=sa.Boolean()) File > "/usr/lib64/python3.4/contextlib.py", line 66, in __exit__ > next(self.gen) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/operations/base.py", > line 299, in batch_alter_table impl.flush() File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/operations/batch.py", > line 76, in flush fn(*arg, **kw) File > "/home/koniiiik/expermients/alembic-sqlite-boolint/env-alembic-boolint /lib/python3.4/site-packages/alembic/operations/batch.py", > line 316, in drop_constraint raise ValueError("No such constraint: > '%s'" % const.name) ValueError: No such constraint: '_unnamed_' > > We're using a naming convention, and it does apply correctly when > the table is created. I also tried passing the naming convention as > an argument to batch_alter_table, but it doesn't seem to make any > difference. > > '_unnamed_' appears to be a sentinel value that the Boolean type > sets if you don't pass it an explicit name for the CHECK > constraint, and it seems that for some reason, it doesn't get > properly replaced with the name provided by the naming convention > before batch_op starts processing queued operations. that should not be the case, but typically a naming convention for a CHECK constraint includes the "name" given to the constraint itself, which is the "constraint_name" token in the string. I see in batch_op.alter_column(name, type_=sa.Integer(), existing_type=sa.Boolean()) you aren't giving it the constraint name, that's actually where the "_unnamed_" is coming from. I just added a test for this and it seems that this existing_type is where the problem comes from, not the batch migration. So setting create_constraint=False resolves the issue: def _boolean_fixture(self): t = Table( 'hasbool', self.metadata, Column('x', Boolean(create_constraint=True, name='ck1')) ) t.create(self.conn) def test_bool_change(self): self._boolean_fixture() with self.op.batch_alter_table("hasbool") as batch_op: batch_op.alter_column( 'x', type_=Integer, existing_type=Boolean( create_constraint=False, name='ck1')) however, it's still copying the constraint, and adding a DROP is not working so I have to just cerate an issue for this, sorry. https://bitbucket.org/zzzeek/alembic/issues/354/cant-change-type-of-bool ean-w-batch > > I put up a sample project reproducing the issue here: > https://github.com/koniiiik/alembic-sqlite-boolint I would have > created a test for the alembic test suite, but it's not obvious to > me how to properly do that. > > Am I doing something wrong here, or is this a bug? > > > In the interest of avoiding the XY problem, here's how I found > this issue. > > The actual problem I'm trying to solve is renaming a Boolean column > in a way that works both on SQLite and MS SQL. The regular > alter_column changing just the name works on SQLite, but errors out > on MS SQL, because on MS SQL, the Boolean type is represented by a > column of type BIT with an additional CHECK constraint. (This seems > kind of redundant to me, but it's the way things are.) > > When running the column rename operation against MS SQL, it errors > out, because MS SQL does not cascande column renames to > constraints. That's why as a workaround I tried to do the > following: > > batch_op.alter_column(old_name, type_=sa.Integer(), > existing_type=sa.Boolean()) batch_op.alter_column(old_name, > new_column_name=new_name) batch_op.alter_column(new_name, > type_=sa.Boolean(), existing_type=sa.Integer()) > > This works OK on MS SQL, but not on SQLite as described above. > > Can anyone help me come up with the best way of renaming a Boolean > column on both backends? I'm about to try creating a new column > with the new name, copying the data from the old column, and > dropping the old one, but that's a really convoluted approach. > > Thanks in advance for your help. > > Michal > -- You received this message because you are subscribed to the Google Groups "sqlalchemy-alembic" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy-alembic+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.