Skip to content

Commit

Permalink
Adjust mssql accommodate existing_type and type
Browse files Browse the repository at this point in the history
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: sqlalchemy#812
  • Loading branch information
zzzeek committed Mar 4, 2021
1 parent 7631034 commit bd34d2e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 12 deletions.
24 changes: 15 additions & 9 deletions alembic/ddl/mssql.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,24 @@ def alter_column(
**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(
Expand Down
12 changes: 12 additions & 0 deletions docs/build/unreleased/812.rst
Original file line number Diff line number Diff line change
@@ -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.

23 changes: 20 additions & 3 deletions tests/test_mssql.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -79,10 +80,26 @@ def test_alter_column_rename_quoted_mssql(self):
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")
Expand Down
25 changes: 25 additions & 0 deletions tests/test_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,31 @@ def test_alter_column_schema_schema_type_named(self):
"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(
Expand Down

0 comments on commit bd34d2e

Please sign in to comment.