From: Mike Bayer Date: Fri, 20 Apr 2018 15:44:09 +0000 (-0400) Subject: Refactor "get" to allow for pluggable identity token schemes X-Git-Tag: rel_1_3_0b1~200 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43f278356d94b5342a1020a9a97feea0bb7cd88f;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Refactor "get" to allow for pluggable identity token schemes Fixed regression in 1.2 within sharded query feature where the new "identity_token" element was not being correctly considered within the scope of a lazy load operation, when searching the identity map for a related many-to-one element. The new behavior will allow for making use of the "id_chooser" in order to determine the best identity key to retrieve from the identity map. In order to achieve this, some refactoring of 1.2's "identity_token" approach has made some slight changes to the implementation of ``ShardedQuery`` which should be noted for other derivations of this class. Change-Id: I04fa60535deec2d0cdec89f602935dfebeb9eb9d Fixes: #4228 --- diff --git a/doc/build/changelog/unreleased_12/4228.rst b/doc/build/changelog/unreleased_12/4228.rst new file mode 100644 index 0000000000..c0e503e3bd --- /dev/null +++ b/doc/build/changelog/unreleased_12/4228.rst @@ -0,0 +1,13 @@ +.. change:: + :tags: bug, orm + :tickets: 4228 + + Fixed regression in 1.2 within sharded query feature where the + new "identity_token" element was not being correctly considered within + the scope of a lazy load operation, when searching the identity map + for a related many-to-one element. The new behavior will allow for + making use of the "id_chooser" in order to determine the best identity + key to retrieve from the identity map. In order to achieve this, some + refactoring of 1.2's "identity_token" approach has made some slight changes + to the implementation of ``ShardedQuery`` which should be noted for other + derivations of this class. diff --git a/lib/sqlalchemy/ext/baked.py b/lib/sqlalchemy/ext/baked.py index 86eee831b0..f4d71f4103 100644 --- a/lib/sqlalchemy/ext/baked.py +++ b/lib/sqlalchemy/ext/baked.py @@ -446,12 +446,10 @@ class Result(object): """ query = self.bq.steps[0](self.session) - return query._get_impl(ident, self._load_on_ident) + return query._get_impl(ident, self._load_on_pk_identity) - def _load_on_ident(self, query, key): - """Load the given identity key from the database.""" - - ident = key[1] + def _load_on_pk_identity(self, query, primary_key_identity): + """Load the given primary key identity from the database.""" mapper = query._mapper_zero() @@ -465,10 +463,11 @@ class Result(object): # None present in ident - turn those comparisons # into "IS NULL" - if None in ident: + if None in primary_key_identity: nones = set([ _get_params[col].key for col, value in - zip(mapper.primary_key, ident) if value is None + zip(mapper.primary_key, primary_key_identity) + if value is None ]) _lcl_get_clause = sql_util.adapt_criterion_to_null( _lcl_get_clause, nones) @@ -490,11 +489,13 @@ class Result(object): bq = bq._clone() bq._cache_key += (_get_clause, ) - bq = bq.with_criteria(setup, tuple(elem is None for elem in ident)) + bq = bq.with_criteria( + setup, tuple(elem is None for elem in primary_key_identity)) params = dict([ (_get_params[primary_key].key, id_val) - for id_val, primary_key in zip(ident, mapper.primary_key) + for id_val, primary_key + in zip(primary_key_identity, mapper.primary_key) ]) result = list(bq.for_session(self.session).params(**params)) diff --git a/lib/sqlalchemy/ext/horizontal_shard.py b/lib/sqlalchemy/ext/horizontal_shard.py index 039a4656b1..266bd784ed 100644 --- a/lib/sqlalchemy/ext/horizontal_shard.py +++ b/lib/sqlalchemy/ext/horizontal_shard.py @@ -62,30 +62,65 @@ class ShardedQuery(Query): # were done, this is where it would happen return iter(partial) - def _get_impl(self, ident, fallback_fn): - # TODO: the "ident" here should be getting the identity token - # which indicates that this area can likely be simplified, as the - # token will fall through into _execute_and_instances - def _fallback(query, ident): + @classmethod + def _identity_lookup( + cls, session, mapper, primary_key_identity, identity_token=None, + **kw): + """override the default Query._identity_lookup method so that we + search for a given non-token primary key identity across all + possible identity tokens (e.g. shard ids). + + """ + + if identity_token is not None: + return super(ShardedQuery, cls)._identity_lookup( + session, mapper, primary_key_identity, + identity_token=identity_token, + **kw + ) + else: + q = cls([mapper], session) + for shard_id in q.id_chooser(q, primary_key_identity): + obj = super(ShardedQuery, cls)._identity_lookup( + session, mapper, primary_key_identity, + identity_token=shard_id, + **kw + ) + if obj is not None: + return obj + + return None + + def _get_impl( + self, primary_key_identity, db_load_fn, identity_token=None): + """Override the default Query._get_impl() method so that we emit + a query to the DB for each possible identity token, if we don't + have one already. + + """ + def _db_load_fn(query, primary_key_identity): + # load from the database. The original db_load_fn will + # use the given Query object to load from the DB, so our + # shard_id is what will indicate the DB that we query from. if self._shard_id is not None: - return fallback_fn(self, ident) + return db_load_fn(self, primary_key_identity) else: - ident = util.to_list(ident) + ident = util.to_list(primary_key_identity) + # build a ShardedQuery for each shard identifier and + # try to load from the DB for shard_id in self.id_chooser(self, ident): q = self.set_shard(shard_id) - o = fallback_fn(q, ident) + o = db_load_fn(q, ident) if o is not None: return o else: return None - if self._shard_id is not None: + if identity_token is None and self._shard_id is not None: identity_token = self._shard_id - else: - identity_token = None return super(ShardedQuery, self)._get_impl( - ident, _fallback, identity_token=identity_token) + primary_key_identity, _db_load_fn, identity_token=identity_token) class ShardedSession(Session): diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index 3599aa3e74..1728b2d378 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -180,23 +180,37 @@ def load_on_ident(query, key, else: ident = None + return load_on_pk_identity( + query, ident, refresh_state=refresh_state, + with_for_update=with_for_update, + only_load_props=only_load_props + ) + + +def load_on_pk_identity(query, primary_key_identity, + refresh_state=None, with_for_update=None, + only_load_props=None): + + """Load the given primary key identity from the database.""" + if refresh_state is None: q = query._clone() q._get_condition() else: q = query._clone() - if ident is not None: + if primary_key_identity is not None: mapper = query._mapper_zero() (_get_clause, _get_params) = mapper._get_clause # None present in ident - turn those comparisons # into "IS NULL" - if None in ident: + if None in primary_key_identity: nones = set([ _get_params[col].key for col, value in - zip(mapper.primary_key, ident) if value is None + zip(mapper.primary_key, primary_key_identity) + if value is None ]) _get_clause = sql_util.adapt_criterion_to_null( _get_clause, nones) @@ -206,7 +220,8 @@ def load_on_ident(query, key, params = dict([ (_get_params[primary_key].key, id_val) - for id_val, primary_key in zip(ident, mapper.primary_key) + for id_val, primary_key + in zip(primary_key_identity, mapper.primary_key) ]) q._params = params diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 42f1b26732..6d2b144e32 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -879,32 +879,68 @@ class Query(object): """ return self._get_impl( - ident, loading.load_on_ident) + ident, loading.load_on_pk_identity) - def _get_impl(self, ident, fallback_fn, identity_token=None): + @classmethod + def _identity_lookup( + cls, session, mapper, primary_key_identity, identity_token=None, + passive=attributes.PASSIVE_OFF): + """Locate an object in the identity map. + + Given a primary key identity, constructs an identity key and then + looks in the session's identity map. If present, the object may + be run through unexpiration rules (e.g. load unloaded attributes, + check if was deleted). + + :param session: Session in use + :param mapper: target mapper + :param primary_key_identity: the primary key we are searching for, as + a tuple. + :param identity_token: identity token that should be used to create + the identity key. Used as is, however overriding subclasses can + repurpose this in order to interpret the value in a special way, + such as if None then look among multple target tokens. + :param passive: passive load flag passed to + :func:`.loading.get_from_identity`, which impacts the behavior if + the object is found; the object may be validated and/or unexpired + if the flag allows for SQL to be emitted. + :return: None if the object is not found in the identity map, *or* + if the object was unexpired and found to have been deleted. + if passive flags disallow SQL and the object is expired, returns + PASSIVE_NO_RESULT. In all other cases the instance is returned. + + .. versionadded:: 1.2.7 + + """ + key = mapper.identity_key_from_primary_key( + primary_key_identity, identity_token=identity_token) + return loading.get_from_identity( + session, key, passive) + + def _get_impl( + self, primary_key_identity, db_load_fn, identity_token=None): # convert composite types to individual args - if hasattr(ident, '__composite_values__'): - ident = ident.__composite_values__() + if hasattr(primary_key_identity, '__composite_values__'): + primary_key_identity = primary_key_identity.__composite_values__() - ident = util.to_list(ident) + primary_key_identity = util.to_list(primary_key_identity) mapper = self._only_full_mapper_zero("get") - if len(ident) != len(mapper.primary_key): + if len(primary_key_identity) != len(mapper.primary_key): raise sa_exc.InvalidRequestError( "Incorrect number of values in identifier to formulate " "primary key for query.get(); primary key columns are %s" % ','.join("'%s'" % c for c in mapper.primary_key)) - key = mapper.identity_key_from_primary_key( - ident, identity_token=identity_token) - if not self._populate_existing and \ not mapper.always_refresh and \ self._for_update_arg is None: - instance = loading.get_from_identity( - self.session, key, attributes.PASSIVE_OFF) + instance = self._identity_lookup( + self.session, mapper, primary_key_identity, + identity_token=identity_token) + if instance is not None: self._get_existing_condition() # reject calls for id in identity map but class @@ -913,7 +949,7 @@ class Query(object): return None return instance - return fallback_fn(self, key) + return db_load_fn(self, primary_key_identity) @_generative() def correlate(self, *args): diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 4312747ac5..00c83cea49 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -576,7 +576,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): return attributes.ATTR_EMPTY pending = not state.key - ident_key = None + primary_key_identity = None if ( (not passive & attributes.SQL_OK and not self.use_get) @@ -599,28 +599,36 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): # if we have a simple primary key load, check the # identity map without generating a Query at all if self.use_get: - ident = self._get_ident_for_use_get( + primary_key_identity = self._get_ident_for_use_get( session, state, passive ) - if attributes.PASSIVE_NO_RESULT in ident: + if attributes.PASSIVE_NO_RESULT in primary_key_identity: return attributes.PASSIVE_NO_RESULT - elif attributes.NEVER_SET in ident: + elif attributes.NEVER_SET in primary_key_identity: return attributes.NEVER_SET - if _none_set.issuperset(ident): + if _none_set.issuperset(primary_key_identity): return None - ident_key = self.mapper.identity_key_from_primary_key(ident) - instance = loading.get_from_identity(session, ident_key, passive) + # look for this identity in the identity map. Delegate to the + # Query class in use, as it may have special rules for how it + # does this, including how it decides what the correct + # identity_token would be for this identity + instance = session._query_cls._identity_lookup( + session, self.mapper, primary_key_identity, + passive=passive + ) + if instance is not None: return instance elif not passive & attributes.SQL_OK or \ not passive & attributes.RELATED_OBJECT_OK: return attributes.PASSIVE_NO_RESULT - return self._emit_lazyload(session, state, ident_key, passive) + return self._emit_lazyload( + session, state, primary_key_identity, passive) def _get_ident_for_use_get(self, session, state, passive): instance_mapper = state.manager.mapper @@ -648,7 +656,8 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): @util.dependencies( "sqlalchemy.orm.strategy_options") def _emit_lazyload( - self, strategy_options, session, state, ident_key, passive): + self, strategy_options, session, state, + primary_key_identity, passive): # emit lazy load now using BakedQuery, to cut way down on the overhead # of generating queries. # there are two big things we are trying to guard against here: @@ -707,8 +716,8 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): if self.use_get: if self._raise_on_sql: self._invoke_raise_load(state, passive, "raise_on_sql") - return q(session)._load_on_ident( - session.query(self.mapper), ident_key) + return q(session)._load_on_pk_identity( + session.query(self.mapper), primary_key_identity) if self.parent_property.order_by: q.add_criteria( diff --git a/test/ext/test_horizontal_shard.py b/test/ext/test_horizontal_shard.py index a5ea44e04d..0bcacad378 100644 --- a/test/ext/test_horizontal_shard.py +++ b/test/ext/test_horizontal_shard.py @@ -372,3 +372,46 @@ class SelectinloadRegressionTest(fixtures.DeclarativeMappedTest): result = session.query(Book).options(selectinload('pages')).all() eq_(result, [book]) + + +class LazyLoadFromIdentityMapTest(fixtures.DeclarativeMappedTest): + @classmethod + def setup_classes(cls): + Base = cls.DeclarativeBasic + + class Book(Base): + __tablename__ = 'book' + id = Column(Integer, primary_key=True) + pages = relationship('Page', backref='book') + + class Page(Base): + __tablename__ = 'page' + id = Column(Integer, primary_key=True) + book_id = Column(ForeignKey('book.id')) + + def test_lazy_load_from_identity_map(self): + session = ShardedSession( + shards={"test": testing.db}, + shard_chooser=lambda *args: 'test', + id_chooser=lambda *args: ['test'], + query_chooser=lambda *args: ['test'] + ) + + Book, Page = self.classes("Book", "Page") + book = Book() + book.pages.append(Page()) + + session.add(book) + session.commit() + + book = session.query(Book).first() + page = session.query(Page).first() + + def go(): + eq_(page.book, book) + + # doesn't emit SQL + self.assert_sql_count( + testing.db, + go, + 0) diff --git a/test/profiles.txt b/test/profiles.txt index a6fe2137e9..7b53862698 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -169,11 +169,11 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.6_sqlite_pys # TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mysql_mysqldb_dbapiunicode_cextensions 417531 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mysql_mysqldb_dbapiunicode_nocextensions 417545 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mysql_mysqldb_dbapiunicode_nocextensions 417538 test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_cextensions 417545 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 417524 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_cextensions 417552 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 417531 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 417538 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_cextensions 417538 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 417538 test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.6_mysql_mysqldb_dbapiunicode_cextensions 445502 test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.6_mysql_mysqldb_dbapiunicode_nocextensions 445502 test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.6_postgresql_psycopg2_dbapiunicode_cextensions 445502 @@ -198,63 +198,63 @@ test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.6_sqlite_py # TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_dbapiunicode_cextensions 17988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_dbapiunicode_nocextensions 17988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 17988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 17988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 17988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 17988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_mysql_mysqldb_dbapiunicode_cextensions 18988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_mysql_mysqldb_dbapiunicode_nocextensions 18988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_postgresql_psycopg2_dbapiunicode_cextensions 18988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 18988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_sqlite_pysqlite_dbapiunicode_cextensions 18988 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 18988 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_dbapiunicode_cextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_dbapiunicode_nocextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_mysql_mysqldb_dbapiunicode_cextensions 19987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_mysql_mysqldb_dbapiunicode_nocextensions 19987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_postgresql_psycopg2_dbapiunicode_cextensions 19987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 19987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_sqlite_pysqlite_dbapiunicode_cextensions 19987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 19987 # 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 2.7_mysql_mysqldb_dbapiunicode_cextensions 96501 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_dbapiunicode_nocextensions 98253 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 86999 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 88751 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 84453 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 86205 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_mysql_mysqldb_dbapiunicode_cextensions 98271 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_mysql_mysqldb_dbapiunicode_nocextensions 100025 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_postgresql_psycopg2_dbapiunicode_cextensions 89519 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 91273 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_sqlite_pysqlite_dbapiunicode_cextensions 86020 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 87774 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_dbapiunicode_cextensions 97500 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_dbapiunicode_nocextensions 99252 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 87998 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 89750 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 85499 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 87204 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_mysql_mysqldb_dbapiunicode_cextensions 99270 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_mysql_mysqldb_dbapiunicode_nocextensions 101024 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_postgresql_psycopg2_dbapiunicode_cextensions 90518 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 92272 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_sqlite_pysqlite_dbapiunicode_cextensions 87019 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 88773 # 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 2.7_mysql_mysqldb_dbapiunicode_cextensions 18788 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_dbapiunicode_nocextensions 18964 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_cextensions 18188 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 18412 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_cextensions 17999 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 18222 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_mysql_mysqldb_dbapiunicode_cextensions 19263 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_mysql_mysqldb_dbapiunicode_nocextensions 19507 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_dbapiunicode_cextensions 18753 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_dbapiunicode_nocextensions 18976 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_cextensions 18153 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 18376 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_cextensions 18070 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 18294 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_mysql_mysqldb_dbapiunicode_cextensions 19275 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_mysql_mysqldb_dbapiunicode_nocextensions 19519 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_postgresql_psycopg2_dbapiunicode_cextensions 18683 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 18927 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_sqlite_pysqlite_dbapiunicode_cextensions 18505 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 18737 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_sqlite_pysqlite_dbapiunicode_cextensions 18517 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 18749 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_load -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_cextensions 1194 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1211 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1131 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1148 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_cextensions 965 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 982 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_mysql_mysqldb_dbapiunicode_cextensions 1231 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_mysql_mysqldb_dbapiunicode_nocextensions 1250 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_postgresql_psycopg2_dbapiunicode_cextensions 1145 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 1164 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_sqlite_pysqlite_dbapiunicode_cextensions 992 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 1011 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_cextensions 1195 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1212 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1132 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1149 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_cextensions 966 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 983 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_mysql_mysqldb_dbapiunicode_cextensions 1232 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_mysql_mysqldb_dbapiunicode_nocextensions 1251 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_postgresql_psycopg2_dbapiunicode_cextensions 1146 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 1165 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_sqlite_pysqlite_dbapiunicode_cextensions 993 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 1012 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_no_load @@ -288,9 +288,9 @@ test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.6_sqlite_pysqlite_dbapiu # TEST: test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_mysql_mysqldb_dbapiunicode_cextensions 178136 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_mysql_mysqldb_dbapiunicode_nocextensions 182435 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_cextensions 168499 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_mysql_mysqldb_dbapiunicode_cextensions 178129 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_mysql_mysqldb_dbapiunicode_nocextensions 182442 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_cextensions 168506 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 172812 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 161507 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 165813 @@ -303,18 +303,18 @@ test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.6_sq # TEST: test.aaa_profiling.test_orm.SessionTest.test_expire_lots -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_mysql_mysqldb_dbapiunicode_cextensions 1151 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1151 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1154 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1153 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1134 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1139 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_mysql_mysqldb_dbapiunicode_cextensions 1264 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_mysql_mysqldb_dbapiunicode_nocextensions 1264 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_postgresql_psycopg2_dbapiunicode_cextensions 1264 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 1263 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_sqlite_pysqlite_dbapiunicode_cextensions 1251 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 1273 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_mysql_mysqldb_dbapiunicode_cextensions 1142 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1149 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1133 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1151 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1149 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1138 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_mysql_mysqldb_dbapiunicode_cextensions 1271 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_mysql_mysqldb_dbapiunicode_nocextensions 1251 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_postgresql_psycopg2_dbapiunicode_cextensions 1261 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 1259 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_sqlite_pysqlite_dbapiunicode_cextensions 1267 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 1264 # TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect @@ -506,4 +506,4 @@ test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.6_postgresql_psyco test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 6567,413,6801,17811,1171,2666 test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6659,418,6921,18880,1276,2700 test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.6_postgresql_psycopg2_dbapiunicode_cextensions 6537,404,6933,18213,1170,2714 -test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 6627,409,7069,19324,1272,2755 +test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 6634,409,7069,19324,1272,2755