diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-03-18 11:43:47 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-03-18 11:43:47 -0400 |
| commit | 0a0c7c73729152b7606509b6e750371106dfdd46 (patch) | |
| tree | ce7e8e6b751d41df8cbfd7543dbf342bf6125a7f /lib/sqlalchemy/sql | |
| parent | 5adc0c56eb4cda1e135d175f2bf1c43179b8f752 (diff) | |
| download | sqlalchemy-0a0c7c73729152b7606509b6e750371106dfdd46.tar.gz | |
implement content hashing for custom_op, not identity
Fixed critical SQL caching issue where use of the :meth:`_sql.Operators.op`
custom operator function would not produce an appropriate cache key,
leading to reduce the effectiveness of the SQL cache.
Fixes: #9506
Change-Id: I3eab1ddb5e09a811ad717161a59df0884cdf70ed
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/operators.py | 20 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/traversals.py | 2 |
2 files changed, 19 insertions, 3 deletions
diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index c973126ca..ab9ddf85c 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -41,6 +41,7 @@ from typing import Dict from typing import Generic from typing import Optional from typing import Set +from typing import Tuple from typing import Type from typing import TYPE_CHECKING from typing import TypeVar @@ -52,6 +53,7 @@ from ..util.typing import Literal from ..util.typing import Protocol if typing.TYPE_CHECKING: + from .cache_key import CacheConst from .type_api import TypeEngine _T = TypeVar("_T", bound=Any) @@ -415,10 +417,24 @@ class custom_op(OperatorType, Generic[_T]): self.python_impl = python_impl def __eq__(self, other: Any) -> bool: - return isinstance(other, custom_op) and other.opstring == self.opstring + return ( + isinstance(other, custom_op) + and other._hash_key() == self._hash_key() + ) def __hash__(self) -> int: - return id(self) + return hash(self._hash_key()) + + def _hash_key(self) -> Union[CacheConst, Tuple[Any, ...]]: + return ( + self.__class__, + self.opstring, + self.precedence, + self.is_comparison, + self.natural_self_precedent, + self.eager_grouping, + self.return_type._static_cache_key if self.return_type else None, + ) def __call__( self, diff --git a/lib/sqlalchemy/sql/traversals.py b/lib/sqlalchemy/sql/traversals.py index 4b55560ec..96758a7ad 100644 --- a/lib/sqlalchemy/sql/traversals.py +++ b/lib/sqlalchemy/sql/traversals.py @@ -767,7 +767,7 @@ class TraversalComparatorStrategy(HasTraversalDispatch, util.MemoizedSlots): def visit_operator( self, attrname, left_parent, left, right_parent, right, **kw ): - return left is right + return left == right def visit_type( self, attrname, left_parent, left, right_parent, right, **kw |
