From: Mike Bayer Date: Thu, 10 May 2018 15:39:06 +0000 (-0400) Subject: SQL Server is not native boolean; add new flag for CHECK constraint X-Git-Tag: rel_1_3_0b1~190 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bd1d6012dcbe5fbc6d1097a79d85b972b0d4fd8a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git SQL Server is not native boolean; add new flag for CHECK constraint Fixed a 1.2 regression caused by :ticket:`4061` where the SQL Server "BIT" type would be considered to be "native boolean". The goal here was to avoid creating a CHECK constraint on the column, however the bigger issue is that the BIT value does not behave like a true/false constant and cannot be interpreted as a standalone expression, e.g. "WHERE ". The SQL Server dialect now goes back to being non-native boolean, but with an extra flag that still avoids creating the CHECK constraint. Change-Id: I4765d2a2a00b0d14f50282603cc4d48d4739dac1 Fixes: #4250 --- diff --git a/doc/build/changelog/unreleased_12/4250.rst b/doc/build/changelog/unreleased_12/4250.rst new file mode 100644 index 0000000000..d28bc1d4d9 --- /dev/null +++ b/doc/build/changelog/unreleased_12/4250.rst @@ -0,0 +1,12 @@ +.. change:: + :tags: bug, mssql + :tickets: 4250 + + Fixed a 1.2 regression caused by :ticket:`4061` where the SQL Server + "BIT" type would be considered to be "native boolean". The goal here + was to avoid creating a CHECK constraint on the column, however the bigger + issue is that the BIT value does not behave like a true/false constant + and cannot be interpreted as a standalone expression, e.g. + "WHERE ". The SQL Server dialect now goes back to being + non-native boolean, but with an extra flag that still avoids creating + the CHECK constraint. diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index f55f7e74df..2975a6c693 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -1820,7 +1820,8 @@ class MSDialect(default.DefaultDialect): ischema_names = ischema_names - supports_native_boolean = True + supports_native_boolean = False + non_native_boolean_check_constraint = False supports_unicode_binds = True postfetch_lastrowid = True diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 5806fe2a93..099e694b68 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -63,6 +63,7 @@ class DefaultDialect(interfaces.Dialect): supports_native_enum = False supports_native_boolean = False + non_native_boolean_check_constraint = True supports_simple_order_by_label = True diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 573fda98fc..a2ae9de502 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -1643,7 +1643,8 @@ class Boolean(Emulated, TypeEngine, SchemaType): def _should_create_constraint(self, compiler, **kw): if not self._is_impl_for_variant(compiler.dialect, kw): return False - return not compiler.dialect.supports_native_boolean + return not compiler.dialect.supports_native_boolean and \ + compiler.dialect.non_native_boolean_check_constraint @util.dependencies("sqlalchemy.sql.schema") def _set_table(self, schema, column, table): diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py index b9458c5706..4cdf14dc9e 100644 --- a/lib/sqlalchemy/testing/suite/test_types.py +++ b/lib/sqlalchemy/testing/suite/test_types.py @@ -612,6 +612,48 @@ class BooleanTest(_LiteralRoundTripFixture, fixtures.TablesTest): (None, None) ) + def test_whereclause(self): + # testing "WHERE " renders a compatible expression + boolean_table = self.tables.boolean_table + + with config.db.connect() as conn: + conn.execute( + boolean_table.insert(), + [ + {'id': 1, 'value': True, 'unconstrained_value': True}, + {'id': 2, 'value': False, 'unconstrained_value': False} + ] + ) + + eq_( + conn.scalar( + select([boolean_table.c.id]).where(boolean_table.c.value) + ), + 1 + ) + eq_( + conn.scalar( + select([boolean_table.c.id]).where( + boolean_table.c.unconstrained_value) + ), + 1 + ) + eq_( + conn.scalar( + select([boolean_table.c.id]).where(~boolean_table.c.value) + ), + 2 + ) + eq_( + conn.scalar( + select([boolean_table.c.id]).where( + ~boolean_table.c.unconstrained_value) + ), + 2 + ) + + + class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest): __requires__ = 'json_type',