diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-03-04 10:54:03 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-03-04 10:54:03 -0500 |
commit | bd34d2e4e4daee6e25d3c8a9a43299e883cb8da3 (patch) | |
tree | 3ed66d63a3765bc4dea8b72b25c7b38ea5abd350 | |
parent | 763103407a22f68450c08d731dc7bbc312967dcf (diff) | |
download | alembic-bd34d2e4e4daee6e25d3c8a9a43299e883cb8da3.tar.gz |
Adjust mssql accommodate existing_type and type
Fixed bug where the "existing_type" parameter, which the MSSQL dialect
requires in order to change the nullability of a column in the absence of
also changing the column type, would cause an ALTER COLUMN operation to
incorrectly render a second ALTER statement without the nullability if a
new type were also present, as the MSSQL-specific contract did not
anticipate all three of "nullability", "type_" and "existing_type" being
sent at the same time.
Change-Id: Ia95b6c3e9276cc067fd773928f9678ab429d5670
Fixes: #812
-rw-r--r-- | alembic/ddl/mssql.py | 24 | ||||
-rw-r--r-- | docs/build/unreleased/812.rst | 12 | ||||
-rw-r--r-- | tests/test_mssql.py | 23 | ||||
-rw-r--r-- | tests/test_op.py | 25 |
4 files changed, 72 insertions, 12 deletions
diff --git a/alembic/ddl/mssql.py b/alembic/ddl/mssql.py index 18e09f8..8a99ee6 100644 --- a/alembic/ddl/mssql.py +++ b/alembic/ddl/mssql.py @@ -75,18 +75,24 @@ class MSSQLImpl(DefaultImpl): **kw ): - if nullable is not None and existing_type is None: - if type_ is not None: - existing_type = type_ + if nullable is not None: + if existing_type is None: + if type_ is not None: + existing_type = type_ + # the NULL/NOT NULL alter will handle + # the type alteration + type_ = None + else: + raise util.CommandError( + "MS-SQL ALTER COLUMN operations " + "with NULL or NOT NULL require the " + "existing_type or a new type_ be passed." + ) + elif type_ is not None: # the NULL/NOT NULL alter will handle # the type alteration + existing_type = type_ type_ = None - else: - raise util.CommandError( - "MS-SQL ALTER COLUMN operations " - "with NULL or NOT NULL require the " - "existing_type or a new type_ be passed." - ) used_default = False if sqla_compat._server_default_is_identity( diff --git a/docs/build/unreleased/812.rst b/docs/build/unreleased/812.rst new file mode 100644 index 0000000..d4c8032 --- /dev/null +++ b/docs/build/unreleased/812.rst @@ -0,0 +1,12 @@ +.. change:: + :tags: bug, mssql, operations + :tickets: 812 + + Fixed bug where the "existing_type" parameter, which the MSSQL dialect + requires in order to change the nullability of a column in the absence of + also changing the column type, would cause an ALTER COLUMN operation to + incorrectly render a second ALTER statement without the nullability if a + new type were also present, as the MSSQL-specific contract did not + anticipate all three of "nullability", "type_" and "existing_type" being + sent at the same time. + diff --git a/tests/test_mssql.py b/tests/test_mssql.py index 0c8b3ae..e9a7493 100644 --- a/tests/test_mssql.py +++ b/tests/test_mssql.py @@ -3,6 +3,7 @@ from sqlalchemy import Column from sqlalchemy import exc from sqlalchemy import Integer +from sqlalchemy import String from alembic import command from alembic import op @@ -79,10 +80,26 @@ class OpTest(TestBase): op.alter_column("t", "c", new_column_name="SomeFancyName") context.assert_("EXEC sp_rename 't.c', [SomeFancyName], 'COLUMN'") - def test_alter_column_new_type(self): + @combinations((True,), (False,), argnames="pass_existing_type") + @combinations((True,), (False,), argnames="change_nullability") + def test_alter_column_type_and_nullability( + self, pass_existing_type, change_nullability + ): context = op_fixture("mssql") - op.alter_column("t", "c", type_=Integer) - context.assert_("ALTER TABLE t ALTER COLUMN c INTEGER") + + args = dict(type_=Integer) + if pass_existing_type: + args["existing_type"] = String(15) + + if change_nullability: + args["nullable"] = False + + op.alter_column("t", "c", **args) + + if change_nullability: + context.assert_("ALTER TABLE t ALTER COLUMN c INTEGER NOT NULL") + else: + context.assert_("ALTER TABLE t ALTER COLUMN c INTEGER") def test_alter_column_dont_touch_constraints(self): context = op_fixture("mssql") diff --git a/tests/test_op.py b/tests/test_op.py index 58a6a86..93bba28 100644 --- a/tests/test_op.py +++ b/tests/test_op.py @@ -462,6 +462,31 @@ class OpTest(TestBase): "ALTER TABLE foo.t ADD CONSTRAINT xyz CHECK (c IN (0, 1))", ) + @combinations((True,), (False,), argnames="pass_existing_type") + @combinations((True,), (False,), argnames="change_nullability") + def test_generic_alter_column_type_and_nullability( + self, pass_existing_type, change_nullability + ): + # this test is also on the mssql dialect in test_mssql + context = op_fixture() + + args = dict(type_=Integer) + if pass_existing_type: + args["existing_type"] = String(15) + + if change_nullability: + args["nullable"] = False + + op.alter_column("t", "c", **args) + + if change_nullability: + context.assert_( + "ALTER TABLE t ALTER COLUMN c SET NOT NULL", + "ALTER TABLE t ALTER COLUMN c TYPE INTEGER", + ) + else: + context.assert_("ALTER TABLE t ALTER COLUMN c TYPE INTEGER") + def test_alter_column_schema_type_existing_type(self): context = op_fixture("mssql", native_boolean=False) op.alter_column( |