]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
fill out all distinguising fields for AliasedInsp
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 17 Aug 2022 17:06:51 +0000 (13:06 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 17 Aug 2022 20:53:38 +0000 (16:53 -0400)
Hardened the cache key strategy for the :func:`_orm.aliased` and
:func:`_orm.with_polymorphic` constructs. While no issue involving actual
statements being cached can easily be demonstrated (if at all), these two
constructs were not including enough of what makes them unique in their
cache keys for caching on the aliased construct alone to be accurate.

Fixes: #8401
Change-Id: I13d14985b6965f398edd9494601d8ae89ac641f2
(cherry picked from commit a58f1b9c698dc7be29d43f2c4c21de8918943f77)

doc/build/changelog/unreleased_14/8401.rst [new file with mode: 0644]
lib/sqlalchemy/orm/util.py
test/orm/test_cache_key.py
test/sql/test_resultset.py

diff --git a/doc/build/changelog/unreleased_14/8401.rst b/doc/build/changelog/unreleased_14/8401.rst
new file mode 100644 (file)
index 0000000..119c6cf
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: orm, bug
+    :tickets: 8401
+
+    Hardened the cache key strategy for the :func:`_orm.aliased` and
+    :func:`_orm.with_polymorphic` constructs. While no issue involving actual
+    statements being cached can easily be demonstrated (if at all), these two
+    constructs were not including enough of what makes them unique in their
+    cache keys for caching on the aliased construct alone to be accurate.
index 56aa9ff6c744d6190ccd68b22ee1bc26660f5127..6f3278ed7891643a2bcb90227a5345ab202344b7 100644 (file)
@@ -650,6 +650,19 @@ class AliasedInsp(
 
     """
 
+    _cache_key_traversal = [
+        ("name", visitors.ExtendedInternalTraversal.dp_string),
+        ("_adapt_on_names", visitors.ExtendedInternalTraversal.dp_boolean),
+        ("_use_mapper_path", visitors.ExtendedInternalTraversal.dp_boolean),
+        ("_target", visitors.ExtendedInternalTraversal.dp_inspectable),
+        ("selectable", visitors.ExtendedInternalTraversal.dp_clauseelement),
+        (
+            "with_polymorphic_mappers",
+            visitors.InternalTraversal.dp_has_cache_key_list,
+        ),
+        ("polymorphic_on", visitors.InternalTraversal.dp_clauseelement),
+    ]
+
     def __init__(
         self,
         entity,
@@ -756,12 +769,6 @@ class AliasedInsp(
     def entity_namespace(self):
         return self.entity
 
-    _cache_key_traversal = [
-        ("name", visitors.ExtendedInternalTraversal.dp_string),
-        ("_adapt_on_names", visitors.ExtendedInternalTraversal.dp_boolean),
-        ("selectable", visitors.ExtendedInternalTraversal.dp_clauseelement),
-    ]
-
     @property
     def class_(self):
         """Return the mapped class ultimately represented by this
index f42e59216a00c83645a44eef08343d69c824dabd..daf963952c817e020bf8ae1a2a33b8707033ca96 100644 (file)
@@ -5,6 +5,7 @@ from sqlalchemy import Column
 from sqlalchemy import func
 from sqlalchemy import inspect
 from sqlalchemy import Integer
+from sqlalchemy import literal_column
 from sqlalchemy import null
 from sqlalchemy import select
 from sqlalchemy import Table
@@ -63,8 +64,19 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest):
     def test_mapper_and_aliased(self):
         User, Address, Keyword = self.classes("User", "Address", "Keyword")
 
+        addresses_table = self.tables.addresses
+
         self._run_cache_key_fixture(
-            lambda: (inspect(User), inspect(Address), inspect(aliased(User))),
+            lambda: (
+                inspect(User),
+                inspect(Address),
+                inspect(aliased(User)),
+                inspect(aliased(aliased(User, addresses_table))),
+                inspect(aliased(aliased(User), addresses_table.select())),
+                inspect(aliased(Address)),
+                inspect(aliased(Address, addresses_table.select())),
+                inspect(aliased(User, addresses_table.select())),
+            ),
             compare_values=True,
         )
 
@@ -606,6 +618,94 @@ class PolyCacheKeyTest(CacheKeyFixture, _poly_fixtures._Polymorphic):
             compare_values=True,
         )
 
+    def test_wpoly_cache_keys(self):
+        Person, Manager, Engineer, Boss = self.classes(
+            "Person", "Manager", "Engineer", "Boss"
+        )
+
+        meb_stmt = inspect(
+            with_polymorphic(Person, [Manager, Engineer, Boss])
+        ).selectable
+        me_stmt = inspect(
+            with_polymorphic(Person, [Manager, Engineer])
+        ).selectable
+
+        self._run_cache_key_fixture(
+            lambda: (
+                inspect(Person),
+                inspect(
+                    aliased(Person, me_stmt),
+                ),
+                inspect(
+                    aliased(Person, meb_stmt),
+                ),
+                inspect(
+                    with_polymorphic(Person, [Manager, Engineer]),
+                ),
+                # aliased=True is the same as flat=True for default selectable
+                inspect(
+                    with_polymorphic(
+                        Person, [Manager, Engineer], aliased=True
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(Person, [Manager, Engineer], flat=True),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person, [Manager, Engineer], flat=True, innerjoin=True
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person,
+                        [Manager, Engineer],
+                        flat=True,
+                        _use_mapper_path=True,
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person,
+                        [Manager, Engineer],
+                        flat=True,
+                        adapt_on_names=True,
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person, [Manager, Engineer], selectable=meb_stmt
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person,
+                        [Manager, Engineer],
+                        selectable=meb_stmt,
+                        aliased=True,
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(Person, [Manager, Engineer, Boss]),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person,
+                        [Manager, Engineer, Boss],
+                        polymorphic_on=literal_column("foo"),
+                    ),
+                ),
+                inspect(
+                    with_polymorphic(
+                        Person,
+                        [Manager, Engineer, Boss],
+                        polymorphic_on=literal_column("bar"),
+                    ),
+                ),
+            ),
+            compare_values=True,
+        )
+
     def test_wp_queries(self):
         Person, Manager, Engineer, Boss = self.classes(
             "Person", "Manager", "Engineer", "Boss"
index 13ffc5eebdfbd087465b83ea204c53c922969fde..13190f915f9e28c87c58247c35399d5a84eccc5e 100644 (file)
@@ -732,6 +732,7 @@ class CursorResultTest(fixtures.TablesTest):
             lambda: r._mapping["foo"],
         )
 
+    @testing.skip_if("+aiosqlite", "unknown issue")
     @testing.combinations(
         (True,),
         (False,),