summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-03-04 10:54:03 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2021-03-04 10:54:03 -0500
commitbd34d2e4e4daee6e25d3c8a9a43299e883cb8da3 (patch)
tree3ed66d63a3765bc4dea8b72b25c7b38ea5abd350
parent763103407a22f68450c08d731dc7bbc312967dcf (diff)
downloadalembic-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.py24
-rw-r--r--docs/build/unreleased/812.rst12
-rw-r--r--tests/test_mssql.py23
-rw-r--r--tests/test_op.py25
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(