]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
turn off deduping for col expressions
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Sep 2021 18:11:38 +0000 (14:11 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 4 Sep 2021 14:50:16 +0000 (10:50 -0400)
Fixed ORM issue where column expressions passed to ``query()`` or
ORM-enabled ``select()`` would be deduplicated on the identity of the
object, such as a phrase like ``select(A.id, null(), null())`` would
produce only one "NULL" expression, which previously was not the case in
1.3. However, the change also allows for ORM expressions to render as given
as well, such as ``select(A.data, A.data)`` will produce a result row with
two columns.

Fixes: #6979
Change-Id: I4dd59d4c7b1baa711b686379eb959f87c44841c4

doc/build/changelog/unreleased_14/6979.rst [new file with mode: 0644]
doc/build/orm/tutorial.rst
lib/sqlalchemy/orm/context.py
lib/sqlalchemy/orm/strategies.py
test/orm/test_query.py
test/profiles.txt

diff --git a/doc/build/changelog/unreleased_14/6979.rst b/doc/build/changelog/unreleased_14/6979.rst
new file mode 100644 (file)
index 0000000..cdf89bb
--- /dev/null
@@ -0,0 +1,11 @@
+.. change::
+    :tags: bug, orm, regression
+    :tickets: 6979
+
+    Fixed ORM issue where column expressions passed to ``query()`` or
+    ORM-enabled ``select()`` would be deduplicated on the identity of the
+    object, such as a phrase like ``select(A.id, null(), null())`` would
+    produce only one "NULL" expression, which previously was not the case in
+    1.3. However, the change also allows for ORM expressions to render as given
+    as well, such as ``select(A.data, A.data)`` will produce a result row with
+    two columns.
index 2592195e9891e4a2b1f0ffb21d53a38776fe7b0f..1f99a503a48e1042d2ff8e9cbc6e27ce8c924a4b 100644 (file)
@@ -655,7 +655,8 @@ class:
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
-            users.nickname AS users_nickname
+            users.nickname AS users_nickname,
+            users.name AS users_name__1
     FROM users
     [...] ()
     {stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')> ed
@@ -694,7 +695,8 @@ entities are present in the call to :meth:`~.Session.query`, can be controlled u
     SELECT user_alias.id AS user_alias_id,
             user_alias.name AS user_alias_name,
             user_alias.fullname AS user_alias_fullname,
-            user_alias.nickname AS user_alias_nickname
+            user_alias.nickname AS user_alias_nickname,
+            user_alias.name AS user_alias_name__1
     FROM users AS user_alias
     [...] (){stop}
     <User(name='ed', fullname='Ed Jones', nickname='eddie')>
index 9318bb16346992f91b406e318d31424822c06cc1..85c736e12e56da8b4422a48a1a614f1250b90955 100644 (file)
@@ -187,6 +187,12 @@ class ORMCompileState(CompileState):
     def __init__(self, *arg, **kw):
         raise NotImplementedError()
 
+    def _append_dedupe_col_collection(self, obj, col_collection):
+        dedupe = self.dedupe_columns
+        if obj not in dedupe:
+            dedupe.add(obj)
+            col_collection.append(obj)
+
     @classmethod
     def _column_naming_convention(cls, label_style, legacy):
 
@@ -443,6 +449,7 @@ class ORMFromStatementCompileState(ORMCompileState):
 
         self.primary_columns = []
         self.secondary_columns = []
+        self.dedupe_columns = set()
         self.create_eager_joins = []
         self._fallback_from_clauses = []
 
@@ -645,6 +652,7 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
 
         self.primary_columns = []
         self.secondary_columns = []
+        self.dedupe_columns = set()
         self.eager_joins = {}
         self.extra_criteria_entities = {}
         self.create_eager_joins = []
@@ -765,8 +773,6 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
 
         # PART II
 
-        self.dedupe_cols = True
-
         self._for_update_arg = query._for_update_arg
 
         for entity in self._entities:
@@ -1036,9 +1042,8 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
         # put FOR UPDATE on the inner query, where MySQL will honor it,
         # as well as if it has an OF so PostgreSQL can use it.
         inner = self._select_statement(
-            util.unique_list(self.primary_columns + order_by_col_expr)
-            if self.dedupe_cols
-            else (self.primary_columns + order_by_col_expr),
+            self.primary_columns
+            + [c for c in order_by_col_expr if c not in self.dedupe_columns],
             self.from_clauses,
             self._where_criteria,
             self._having_criteria,
@@ -1116,9 +1121,7 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
             self.primary_columns += to_add
 
         statement = self._select_statement(
-            util.unique_list(self.primary_columns + self.secondary_columns)
-            if self.dedupe_cols
-            else (self.primary_columns + self.secondary_columns),
+            self.primary_columns + self.secondary_columns,
             tuple(self.from_clauses) + tuple(self.eager_joins.values()),
             self._where_criteria,
             self._having_criteria,
@@ -2822,6 +2825,7 @@ class _RawColumnEntity(_ColumnEntity):
             # result due to the __eq__() method, so use deannotated
             column = column._deannotate()
 
+        compile_state.dedupe_columns.add(column)
         compile_state.primary_columns.append(column)
         self._fetch_column = column
 
@@ -2949,6 +2953,7 @@ class _ORMColumnEntity(_ColumnEntity):
         ):
             compile_state._fallback_from_clauses.append(ezero.selectable)
 
+        compile_state.dedupe_columns.add(column)
         compile_state.primary_columns.append(column)
         self._fetch_column = column
 
index 069e5e667443ea50e715d1de51b6899d5499840c..4f361be2c9dbe2bb139ffa94a450afae48ab9f79 100644 (file)
@@ -157,7 +157,7 @@ class UninstrumentedColumnLoader(LoaderStrategy):
         for c in self.columns:
             if adapter:
                 c = adapter.columns[c]
-            column_collection.append(c)
+            compile_state._append_dedupe_col_collection(c, column_collection)
 
     def create_row_processor(
         self,
@@ -206,7 +206,7 @@ class ColumnLoader(LoaderStrategy):
                 else:
                     c = adapter.columns[c]
 
-            column_collection.append(c)
+            compile_state._append_dedupe_col_collection(c, column_collection)
 
         fetch = self.columns[0]
         if adapter:
@@ -296,7 +296,7 @@ class ExpressionColumnLoader(ColumnLoader):
         for c in columns:
             if adapter:
                 c = adapter.columns[c]
-            column_collection.append(c)
+            compile_state._append_dedupe_col_collection(c, column_collection)
 
         fetch = columns[0]
         if adapter:
@@ -2335,7 +2335,9 @@ class JoinedLoader(AbstractRelationshipLoader):
                 if localparent.persist_selectable.c.contains_column(col):
                     if adapter:
                         col = adapter.columns[col]
-                    compile_state.primary_columns.append(col)
+                    compile_state._append_dedupe_col_collection(
+                        col, compile_state.primary_columns
+                    )
 
         if self.parent_property.order_by:
             compile_state.eager_order_by += tuple(
index 878e914b6e4948e69397a42d920eb414566da6f5..41fe30420cb46656e8530ac0b8e4f1cb51271419 100644 (file)
@@ -173,7 +173,7 @@ class OnlyReturnTuplesTest(QueryTest):
         assert isinstance(row._mapping, collections_abc.Mapping)
 
 
-class RowTupleTest(QueryTest):
+class RowTupleTest(QueryTest, AssertsCompiledSQL):
     run_setup_mappers = None
 
     @testing.combinations((True,), (False,), argnames="legacy")
@@ -216,6 +216,46 @@ class RowTupleTest(QueryTest):
 
         eq_(row.uname, "jack")
 
+    @testing.combinations(
+        (
+            lambda s, User: (User.id, User.name, User.name),
+            "users.id AS users_id, users.name AS users_name, "
+            "users.name AS users_name__1",
+            (7, "jack", "jack"),
+        ),
+        (
+            lambda s, User: (User.id, User.name, User.id, User.name, null()),
+            "users.id AS users_id, users.name AS users_name, "
+            "users.id AS users_id__1, users.name AS users_name__1, "
+            "NULL AS anon_1",
+            (7, "jack", 7, "jack", None),
+        ),
+        (
+            lambda s, User: (User.id,) + tuple([null()] * 3),
+            "users.id AS users_id, NULL AS anon_1, NULL AS anon__1, "
+            "NULL AS anon__1",
+            (7, None, None, None),
+        ),
+    )
+    def test_dupe_cols(self, test_case, expected_sql, expected_row):
+        """test #6979"""
+        User, users = self.classes.User, self.tables.users
+
+        mapper(User, users)
+
+        s = fixture_session()
+
+        expressions = testing.resolve_lambda(test_case, **locals())
+        expected_num = len(expressions)
+
+        q = s.query(*expressions)
+
+        self.assert_compile(q, "SELECT %s FROM users" % expected_sql)
+
+        row = q.order_by(User.id).first()
+        eq_(row, expected_row)
+        eq_(len(row), expected_num)
+
     @testing.combinations(
         (lambda s, users: s.query(users),),
         (lambda s, User: s.query(User.id, User.name),),
@@ -5012,21 +5052,20 @@ class DistinctTest(QueryTest, AssertsCompiledSQL):
             q,
             "SELECT anon_1.users_id AS anon_1_users_id, "
             "anon_1.users_name AS anon_1_users_name, "
-            "anon_1.addresses_email_address AS "
-            "anon_1_addresses_email_address, "
+            "anon_1.addresses_email_address "
+            "AS anon_1_addresses_email_address, "
             "addresses_1.id AS addresses_1_id, "
             "addresses_1.user_id AS addresses_1_user_id, "
             "addresses_1.email_address AS addresses_1_email_address "
             "FROM (SELECT DISTINCT users.id AS users_id, "
             "users.name AS users_name, "
-            "addresses.email_address AS addresses_email_address "
-            "FROM users, addresses "
-            "ORDER BY users.name, addresses.email_address "
-            "LIMIT :param_1) AS anon_1 LEFT OUTER JOIN "
-            "addresses AS addresses_1 "
+            "addresses.email_address AS addresses_email_address FROM users, "
+            "addresses ORDER BY users.name, addresses.email_address "
+            "LIMIT :param_1) AS anon_1 "
+            "LEFT OUTER JOIN addresses AS addresses_1 "
             "ON anon_1.users_id = addresses_1.user_id "
-            "ORDER BY anon_1.users_name, "
-            "anon_1.addresses_email_address, addresses_1.id",
+            "ORDER BY anon_1.users_name, anon_1.addresses_email_address, "
+            "addresses_1.id",
         )
 
     def test_columns_augmented_sql_three(self):
index 48f24a51197d2ddc8e79e12e91927e04f62e9088..b99be2346628e6f62ba26155345f6d6e132c30f8 100644 (file)
@@ -150,34 +150,34 @@ test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_
 
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 49105
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 60305
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 52905
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 65005
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 52805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 64905
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation
 
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 47805
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 59005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 51605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 63705
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 51505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 63605
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations
 
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 47305
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 56005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 50505
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 60105
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 51705
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 60405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 54805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 64405
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations
 
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 46405
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 55105
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 49605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 59205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 50805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 59505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 53905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 63505
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle
 
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 45105
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 45205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48905
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 47705
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 52305
 
@@ -185,29 +185,29 @@ test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle x86_64_linux_cp
 
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 47305
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 56005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 50505
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 60105
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 50405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 60005
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations
 
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 46405
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 55105
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 49605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 59205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 49505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 59105
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations
 
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 31005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 33605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 33905
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 36805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 30905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 33505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 33705
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 36605
 
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations
 
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 30105
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 32705
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 33005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 35905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 30005
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 32605
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 32805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 35705
 
 # TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set
 
@@ -239,17 +239,17 @@ test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching
 
 # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline
 
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 15230
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26243
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 15259
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 27276
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 15236
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26249
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 15264
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 27281
 
 # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols
 
 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 21341
 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26354
-test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 21383
-test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 27400
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 21382
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 27399
 
 # TEST: test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased
 
@@ -276,29 +276,29 @@ test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain x86_64_linux_cpy
 
 test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 95938
 test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 96088
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 103339
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 103539
 test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 103689
 
 # TEST: test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased
 
 test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 93988
 test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 94138
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 101689
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 101889
 test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 102039
 
 # TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query
 
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 488629
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 490471
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 520595
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 522437
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 496829
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 498671
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 528695
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 530537
 
 # TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results
 
 test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 425805
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 442805
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 430905
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 450005
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 443405
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 431505
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 450605
 
 # TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity
 
@@ -309,24 +309,24 @@ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_
 
 # TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity
 
-test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 102068
-test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 106785
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 102029
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 106786
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 106348
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 112356
 
 # TEST: test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks
 
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 19795
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 20281
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 20743
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 21311
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 19799
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 20301
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 20739
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 21307
 
 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_load
 
-test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 1336
-test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1370
-test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 1398
-test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 1443
+test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 1339
+test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1373
+test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 1399
+test.aaa_profiling.test_orm.MergeTest.test_merge_load x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 1444
 
 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_no_load
 
@@ -337,24 +337,24 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_no_load x86_64_linux_cpython_3.
 
 # TEST: test.aaa_profiling.test_orm.QueryTest.test_query_cols
 
-test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 5854
-test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6614
-test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 6172
-test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 6962
+test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 5844
+test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6604
+test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 6152
+test.aaa_profiling.test_orm.QueryTest.test_query_cols x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 6942
 
 # TEST: test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results
 
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 251005
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 269005
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 261905
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 281405
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 251605
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 269605
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 262205
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 281705
 
 # TEST: test.aaa_profiling.test_orm.SessionTest.test_expire_lots
 
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 1135
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1160
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 1278
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 1259
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 1149
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1144
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_cextensions 1269
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots x86_64_linux_cpython_3.9_sqlite_pysqlite_dbapiunicode_nocextensions 1258
 
 # TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect