diff options
| author | Gord Thompson <gord@gordthompson.com> | 2021-03-06 12:19:13 -0700 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-03-06 22:27:59 -0500 |
| commit | 506b88de5e428fd4ad2feff663ba53e2dbb28891 (patch) | |
| tree | 4da8bb1166928480cec3dc9668d1a1a6175dd087 /lib/sqlalchemy/sql | |
| parent | 1f3ef9817453faa021544841d10b5b7107b57916 (diff) | |
| download | sqlalchemy-506b88de5e428fd4ad2feff663ba53e2dbb28891.tar.gz | |
Fix named CHECK constraint name omitted on repeated creates
Fixed issue where the CHECK constraint generated by :class:`_types.Boolean`
or :class:`_types.Enum` would fail to render the naming convention
correctly after the first compilation, due to an unintended change of state
within the name given to the constraint. This issue was first introduced in
0.9 in the fix for issue #3067, and the fix revises the approach taken at
that time which appears to have been more involved than what was needed.
Co-authored-by: Mike Bayer <mike_mp@zzzcomputing.com>
Fixes: #6007
Change-Id: I7ecff0a9d86191520f6841b3922a5af5a6971fba
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 29 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/naming.py | 11 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 6 |
4 files changed, 12 insertions, 41 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index c6fa6072e..d48bca14e 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -4902,16 +4902,13 @@ class IdentifierPreparer(object): def format_constraint(self, constraint, _alembic_quote=True): naming = util.preloaded.sql_naming - if isinstance(constraint.name, elements._defer_name): + if constraint.name is elements._NONE_NAME: name = naming._constraint_name_for_table( constraint, constraint.table ) if name is None: - if isinstance(constraint.name, elements._defer_none_name): - return None - else: - name = constraint.name + return None else: name = constraint.name diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 85200bf25..b26918f2f 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -4979,33 +4979,8 @@ class conv(_truncated_label): __slots__ = () -class _defer_name(_truncated_label): - """mark a name as 'deferred' for the purposes of automated name - generation. - - """ - - __slots__ = () - - def __new__(cls, value): - if value is None: - return _NONE_NAME - elif isinstance(value, conv): - return value - else: - return super(_defer_name, cls).__new__(cls, value) - - def __reduce__(self): - return self.__class__, (util.text_type(self),) - - -class _defer_none_name(_defer_name): - """indicate a 'deferred' name that was ultimately the value None.""" - - __slots__ = () - - -_NONE_NAME = _defer_none_name("_unnamed_") +_NONE_NAME = util.symbol("NONE_NAME") +"""indicate a 'deferred' name that was ultimately the value None.""" # for backwards compatibility in case # someone is re-implementing the diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py index 005c41683..b79316435 100644 --- a/lib/sqlalchemy/sql/naming.py +++ b/lib/sqlalchemy/sql/naming.py @@ -13,8 +13,7 @@ import re from . import events # noqa -from .elements import _defer_name -from .elements import _defer_none_name +from .elements import _NONE_NAME from .elements import conv from .schema import CheckConstraint from .schema import Column @@ -57,7 +56,7 @@ class ConventionDict(object): return getattr(col, attrname) def _key_constraint_name(self): - if isinstance(self._const_name, (type(None), _defer_none_name)): + if self._const_name in (None, _NONE_NAME): raise exc.InvalidRequestError( "Naming convention including " "%(constraint_name)s token requires that " @@ -160,14 +159,14 @@ def _constraint_name_for_table(const, table): and ( const.name is None or "constraint_name" in convention - or isinstance(const.name, _defer_name) + or const.name is _NONE_NAME ) ): return conv( convention % ConventionDict(const, table, metadata.naming_convention) ) - elif isinstance(convention, _defer_none_name): + elif convention is _NONE_NAME: return None @@ -203,7 +202,7 @@ def _constraint_name(const, table): ) elif isinstance(table, Table): - if isinstance(const.name, (conv, _defer_name)): + if isinstance(const.name, conv) or const.name is _NONE_NAME: return newname = _constraint_name_for_table(const, table) diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 3484b3ac8..d075ef77d 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -22,7 +22,7 @@ from . import type_api from .base import _bind_or_error from .base import NO_ARG from .base import SchemaEventTarget -from .elements import _defer_name +from .elements import _NONE_NAME from .elements import quoted_name from .elements import Slice from .elements import TypeCoerce as type_coerce # noqa @@ -1659,7 +1659,7 @@ class Enum(Emulated, String, SchemaType): e = schema.CheckConstraint( type_coerce(column, self).in_(self.enums), - name=_defer_name(self.name), + name=_NONE_NAME if self.name is None else self.name, _create_rule=util.portable_instancemethod( self._should_create_constraint, {"variant_mapping": variant_mapping}, @@ -1868,7 +1868,7 @@ class Boolean(Emulated, TypeEngine, SchemaType): e = schema.CheckConstraint( type_coerce(column, self).in_([0, 1]), - name=_defer_name(self.name), + name=_NONE_NAME if self.name is None else self.name, _create_rule=util.portable_instancemethod( self._should_create_constraint, {"variant_mapping": variant_mapping}, |
