summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorGord Thompson <gord@gordthompson.com>2021-03-06 12:19:13 -0700
committerMike Bayer <mike_mp@zzzcomputing.com>2021-03-06 22:27:59 -0500
commit506b88de5e428fd4ad2feff663ba53e2dbb28891 (patch)
tree4da8bb1166928480cec3dc9668d1a1a6175dd087 /lib/sqlalchemy/sql
parent1f3ef9817453faa021544841d10b5b7107b57916 (diff)
downloadsqlalchemy-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.py7
-rw-r--r--lib/sqlalchemy/sql/elements.py29
-rw-r--r--lib/sqlalchemy/sql/naming.py11
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py6
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},