--- /dev/null
+.. change::
+ :tags: bug, schema
+ :tickets: 5367
+
+ The :paramref:`.Enum.create_constraint` and
+ :paramref:`.Boolean.create_constraint` parameters now default to False,
+ indicating when a so-called "non-native" version of these two datatypes is
+ created, a CHECK constraint will not be generated by default. These CHECK
+ constraints present schema-management maintenance complexities that should
+ be opted in to, rather than being turned on by default.
+
which the column is constrained towards.
The :class:`.Enum` type will make use of the backend's native "ENUM"
- type if one is available; otherwise, it uses a VARCHAR datatype and
- produces a CHECK constraint. Use of the backend-native enum type
- can be disabled using the :paramref:`.Enum.native_enum` flag, and
- the production of the CHECK constraint is configurable using the
- :paramref:`.Enum.create_constraint` flag.
+ type if one is available; otherwise, it uses a VARCHAR datatype.
+ An option also exists to automatically produce a CHECK constraint
+ when the VARCHAR (so called "non-native") variant is produced;
+ see the :paramref:`.Enum.create_constraint` flag.
The :class:`.Enum` type also provides in-Python validation of string
values during both read and write operations. When reading a value
result-set processing for this Enum's data. This is set
automatically based on the presence of unicode label strings.
- :param create_constraint: defaults to True. When creating a non-native
- enumerated type, also build a CHECK constraint on the database
- against the valid values.
+ :param create_constraint: defaults to False. When creating a
+ non-native enumerated type, also build a CHECK constraint on the
+ database against the valid values.
- .. versionadded:: 1.1 - added :paramref:`.Enum.create_constraint`
- which provides the option to disable the production of the
- CHECK constraint for a non-native enumerated type.
+ .. note:: it is strongly recommended that the CHECK constraint
+ have an explicit name in order to support schema-management
+ concerns. This can be established either by setting the
+ :paramref:`.Enum.name` parameter or by setting up an
+ appropriate naming convention; see
+ :ref:`constraint_naming_conventions` for background.
+
+ .. versionchanged:: 1.4 - this flag now defaults to False, meaning
+ no CHECK constraint is generated for a non-native enumerated
+ type.
:param metadata: Associate this type directly with a ``MetaData``
object. For types that exist on the target database as an
"""
self.native_enum = kw.pop("native_enum", True)
- self.create_constraint = kw.pop("create_constraint", True)
+ self.create_constraint = kw.pop("create_constraint", False)
self.values_callable = kw.pop("values_callable", None)
self._sort_key_function = kw.pop("sort_key_function", NO_ARG)
length_arg = kw.pop("length", NO_ARG)
that the values persisted are simple true/false values. For all
backends, only the Python values ``None``, ``True``, ``False``, ``1``
or ``0`` are accepted as parameter values. For those backends that
- don't support a "native boolean" datatype, a CHECK constraint is also
- created on the target column. Production of the CHECK constraint
- can be disabled by passing the :paramref:`.Boolean.create_constraint`
- flag set to ``False``.
+ don't support a "native boolean" datatype, an option exists to
+ also create a CHECK constraint on the target column
.. versionchanged:: 1.2 the :class:`.Boolean` datatype now asserts that
incoming Python values are already in pure boolean form.
__visit_name__ = "boolean"
native = True
- def __init__(self, create_constraint=True, name=None, _create_events=True):
+ def __init__(
+ self, create_constraint=False, name=None, _create_events=True
+ ):
"""Construct a Boolean.
- :param create_constraint: defaults to True. If the boolean
+ :param create_constraint: defaults to False. If the boolean
is generated as an int/smallint, also create a CHECK constraint
on the table that ensures 1 or 0 as a value.
+ .. note:: it is strongly recommended that the CHECK constraint
+ have an explicit name in order to support schema-management
+ concerns. This can be established either by setting the
+ :paramref:`.Boolean.name` parameter or by setting up an
+ appropriate naming convention; see
+ :ref:`constraint_naming_conventions` for background.
+
+ .. versionchanged:: 1.4 - this flag now defaults to False, meaning
+ no CHECK constraint is generated for a non-native enumerated
+ type.
+
+
+
:param name: if a CHECK constraint is generated, specify
the name of the constraint.
t1 = Table(
"sometable",
MetaData(),
- Column("somecolumn", Enum("x", "y", "z", native_enum=False)),
+ Column(
+ "somecolumn",
+ Enum("x", "y", "z", native_enum=False, create_constraint=True),
+ ),
)
self.assert_compile(
schema.CreateTable(t1),
t1 = Table(
"sometable",
MetaData(),
- Column("somecolumn", Enum("x", "y", "z", native_enum=False)),
+ Column(
+ "somecolumn",
+ Enum("x", "y", "z", native_enum=False, create_constraint=True),
+ ),
)
self.assert_compile(
schema.CreateTable(t1),
metadata,
Column(
"bar",
- Enum("one", "two", "three", name="myenum", native_enum=False),
+ Enum(
+ "one",
+ "two",
+ "three",
+ name="myenum",
+ create_constraint=True,
+ native_enum=False,
+ ),
),
)
"foo",
metadata,
Column(
- "bar", Enum("B", util.u("Ü"), name="myenum", native_enum=False)
+ "bar",
+ Enum(
+ "B",
+ util.u("Ü"),
+ name="myenum",
+ create_constraint=True,
+ native_enum=False,
+ ),
),
)
t1 = Table(
"foo",
metadata,
- Column("bar", Enum("one", "two", "three", name="myenum")),
+ Column(
+ "bar",
+ Enum(
+ "one",
+ "two",
+ "three",
+ name="myenum",
+ create_constraint=True,
+ ),
+ ),
)
def go():
"my_col",
array_cls(
enum_cls(
- "foo", "bar", "baz", name="my_enum", native_enum=False
+ "foo",
+ "bar",
+ "baz",
+ name="my_enum",
+ create_constraint=True,
+ native_enum=False,
)
),
),
def test_column_defaults_ddl(self):
t = Table(
- "t", MetaData(), Column("x", Boolean, server_default=sql.false())
+ "t",
+ MetaData(),
+ Column(
+ "x",
+ Boolean(create_constraint=True),
+ server_default=sql.false(),
+ ),
)
self.assert_compile(
def test_boolean_constraint_type_doesnt_double(self):
m1 = MetaData()
- t1 = Table("x", m1, Column("flag", Boolean()))
+ t1 = Table("x", m1, Column("flag", Boolean(create_constraint=True)))
eq_(
len([c for c in t1.constraints if isinstance(c, CheckConstraint)]),
1,
def test_enum_constraint_type_doesnt_double(self):
m1 = MetaData()
- t1 = Table("x", m1, Column("flag", Enum("a", "b", "c")))
+ t1 = Table(
+ "x",
+ m1,
+ Column("flag", Enum("a", "b", "c", create_constraint=True)),
+ )
eq_(
len([c for c in t1.constraints if isinstance(c, CheckConstraint)]),
1,
naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
)
- u1 = Table("user", m1, Column("x", Boolean(name="foo")))
+ u1 = Table(
+ "user",
+ m1,
+ Column("x", Boolean(name="foo", create_constraint=True)),
+ )
# constraint is not hit
eq_(
[c for c in u1.constraints if isinstance(c, CheckConstraint)][
naming_convention={"ck": "ck_%(table_name)s_%(column_0_name)s"}
)
- u1 = Table("user", m1, Column("x", Boolean()))
+ u1 = Table("user", m1, Column("x", Boolean(create_constraint=True)))
# constraint is not hit
is_(
[c for c in u1.constraints if isinstance(c, CheckConstraint)][
naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
)
- u1 = Table("user", m1, Column("x", Enum("a", "b", name="foo")))
+ u1 = Table(
+ "user",
+ m1,
+ Column("x", Enum("a", "b", name="foo", create_constraint=True)),
+ )
eq_(
[c for c in u1.constraints if isinstance(c, CheckConstraint)][
0
)
u1 = Table(
- "user", m1, Column("x", Enum("a", "b", name=naming.conv("foo")))
+ "user",
+ m1,
+ Column(
+ "x",
+ Enum(
+ "a", "b", name=naming.conv("foo"), create_constraint=True
+ ),
+ ),
)
eq_(
[c for c in u1.constraints if isinstance(c, CheckConstraint)][
naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
)
- u1 = Table("user", m1, Column("x", Boolean()))
+ u1 = Table("user", m1, Column("x", Boolean(create_constraint=True)))
# constraint gets special _defer_none_name
is_(
[c for c in u1.constraints if isinstance(c, CheckConstraint)][
def test_schematype_no_ck_name_boolean_no_name(self):
m1 = MetaData() # no naming convention
- u1 = Table("user", m1, Column("x", Boolean()))
+ u1 = Table("user", m1, Column("x", Boolean(create_constraint=True)))
# constraint gets special _defer_none_name
is_(
[c for c in u1.constraints if isinstance(c, CheckConstraint)][
@classmethod
def define_tables(cls, metadata):
+ # note create_constraint has changed in 1.4 as of #5367
Table(
"enum_table",
metadata,
Column("id", Integer, primary_key=True),
- Column("someenum", Enum("one", "two", "three", name="myenum")),
+ Column(
+ "someenum",
+ Enum(
+ "one",
+ "two",
+ "three",
+ name="myenum",
+ create_constraint=True,
+ ),
+ ),
)
Table(
"non_native_enum_table",
metadata,
Column("id", Integer, primary_key=True, autoincrement=False),
- Column("someenum", Enum("one", "two", "three", native_enum=False)),
+ Column(
+ "someenum",
+ Enum(
+ "one",
+ "two",
+ "three",
+ native_enum=False,
+ create_constraint=True,
+ ),
+ ),
Column(
"someotherenum",
Enum(
"one",
"two",
"three",
- create_constraint=False,
native_enum=False,
validate_strings=True,
),
"stdlib_enum_table",
metadata,
Column("id", Integer, primary_key=True),
- Column("someenum", Enum(cls.SomeEnum)),
+ Column("someenum", Enum(cls.SomeEnum, create_constraint=True)),
)
Table(
Enum(
cls.SomeOtherEnum,
values_callable=EnumTest.get_enum_string_values,
+ create_constraint=True,
),
),
)
Column(
"data",
Enum(
- "one", "two", "three", native_enum=False, name="e1"
+ "one",
+ "two",
+ "three",
+ native_enum=False,
+ name="e1",
+ create_constraint=True,
).with_variant(
- Enum("four", "five", "six", native_enum=False, name="e2"),
+ Enum(
+ "four",
+ "five",
+ "six",
+ native_enum=False,
+ name="e2",
+ create_constraint=True,
+ ),
"some_other_db",
),
),
Column(
"data",
Enum(
- "one", "two", "three", native_enum=False, name="e1"
+ "one",
+ "two",
+ "three",
+ native_enum=False,
+ name="e1",
+ create_constraint=True,
).with_variant(
- Enum("four", "five", "six", native_enum=False, name="e2"),
+ Enum(
+ "four",
+ "five",
+ "six",
+ native_enum=False,
+ name="e2",
+ create_constraint=True,
+ ),
testing.db.dialect.name,
),
),
class MyEnum(TypeDecorator):
def __init__(self, values):
self.impl = Enum(
- *[v.name for v in values], name="myenum", native_enum=False
+ *[v.name for v in values],
+ name="myenum",
+ native_enum=False,
+ create_constraint=True
)
# future method
are created with checkfirst=False"""
e = engines.mock_engine()
- t = Table("t1", MetaData(), Column("x", Enum("x", "y", name="pge")))
+ t = Table(
+ "t1",
+ MetaData(),
+ Column("x", Enum("x", "y", name="pge", create_constraint=True)),
+ )
t.create(e, checkfirst=False)
# basically looking for the start of
# the constraint, or the ENUM def itself,
"""test edge cases for booleans. Note that the main boolean test suite
is now in testing/suite/test_types.py
+ the default value of create_constraint was changed to False in
+ version 1.4 with #5367.
+
"""
__backend__ = True
"boolean_table",
metadata,
Column("id", Integer, primary_key=True, autoincrement=False),
- Column("value", Boolean),
- Column("unconstrained_value", Boolean(create_constraint=False)),
+ Column("value", Boolean(create_constraint=True)),
+ Column("unconstrained_value", Boolean()),
)
@testing.fails_on(
self.value = value
class MyBool(TypeDecorator):
- impl = Boolean()
+ impl = Boolean(create_constraint=True)
# future method
def process_literal_param(self, value, dialect):