.. changelog::
:version: 0.8.3
+ .. change::
+ :tags: bug, sql
+ :tickets: 2842
+ :versions: 0.9.0
+
+ The :class:`.Enum` and :class:`.Boolean` types now bypass
+ any custom (e.g. TypeDecorator) type in use when producing the
+ CHECK constraint for the "non native" type. This so that the custom type
+ isn't involved in the expression within the CHECK, since this
+ expression is against the "impl" value and not the "decorated" value.
+
.. change::
:tags: bug, postgresql
:tickets: 2844
Fixed bug in default compiler plus those of postgresql, mysql, and
mssql to ensure that any literal SQL expression values are
rendered directly as literals, instead of as bound parameters,
- within a CREATE INDEX statement.
+ within a CREATE INDEX statement. This also changes the rendering
+ scheme for other DDL such as constraints.
.. change::
:tags: bug, sql
import codecs
from . import exc, schema, util, processors, events, event
-from .sql import operators
+from .sql import operators, type_coerce
from .sql.expression import _DefaultColumnComparator
from .util import pickle
from .sql.visitors import Visitable
SchemaType._set_table(self, column, table)
e = schema.CheckConstraint(
- column.in_(self.enums),
+ type_coerce(column, self).in_(self.enums),
name=self.name,
_create_rule=util.portable_instancemethod(
self._should_create_constraint)
return
e = schema.CheckConstraint(
- column.in_([0, 1]),
+ type_coerce(column, self).in_([0, 1]),
name=self.name,
_create_rule=util.portable_instancemethod(
self._should_create_constraint)
for name in dialects.__all__:
__import__("sqlalchemy.dialects.%s" % name)
from sqlalchemy.sql import operators, column, table
+from sqlalchemy.schema import CheckConstraint, AddConstraint
from sqlalchemy.engine import default
from sqlalchemy.testing.schema import Table, Column
from sqlalchemy import testing
)
-class EnumTest(fixtures.TestBase):
+class EnumTest(AssertsCompiledSQL, fixtures.TestBase):
@classmethod
def setup_class(cls):
global enum_table, non_native_enum_table, metadata
{'id': 4, 'someenum': 'four'}
)
+ def test_non_native_constraint_custom_type(self):
+ class Foob(object):
+ def __init__(self, name):
+ self.name = name
+
+ class MyEnum(types.SchemaType, TypeDecorator):
+ def __init__(self, values):
+ self.impl = Enum(
+ *[v.name for v in values],
+ name="myenum",
+ native_enum=False
+ )
+
+
+ def _set_table(self, table, column):
+ self.impl._set_table(table, column)
+
+ # future method
+ def process_literal_param(self, value, dialect):
+ return value.name
+
+ def process_bind_param(self, value, dialect):
+ return value.name
+
+ m = MetaData()
+ t1 = Table('t', m, Column('x', MyEnum([Foob('a'), Foob('b')])))
+ const = [c for c in t1.constraints if isinstance(c, CheckConstraint)][0]
+
+ self.assert_compile(
+ AddConstraint(const),
+ "ALTER TABLE t ADD CONSTRAINT myenum CHECK (x IN ('a', 'b'))",
+ dialect=default.DefaultDialect()
+ )
+
+
+
@testing.fails_on('mysql',
"the CHECK constraint doesn't raise an exception for unknown reason")
def test_non_native_constraint(self):
eq_(row['non_native_interval'], None)
-class BooleanTest(fixtures.TestBase, AssertsExecutionResults):
+class BooleanTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompiledSQL):
@classmethod
def setup_class(cls):
global bool_table
testing.db.execute(
"insert into booltest (id, unconstrained_value) values (1, 5)")
+ def test_non_native_constraint_custom_type(self):
+ class Foob(object):
+ def __init__(self, value):
+ self.value = value
+
+ class MyBool(types.SchemaType, TypeDecorator):
+ impl = Boolean()
+
+ def _set_table(self, table, column):
+ self.impl._set_table(table, column)
+
+ # future method
+ def process_literal_param(self, value, dialect):
+ return value.value
+
+ def process_bind_param(self, value, dialect):
+ return value.value
+
+ m = MetaData()
+ t1 = Table('t', m, Column('x', MyBool()))
+ const = [c for c in t1.constraints if isinstance(c, CheckConstraint)][0]
+
+ self.assert_compile(
+ AddConstraint(const),
+ "ALTER TABLE t ADD CHECK (x IN (0, 1))",
+ dialect=dialects.sqlite.dialect()
+ )
+
+
class PickleTest(fixtures.TestBase):
def test_eq_comparison(self):
p1 = PickleType()