From: Mike Bayer Date: Sun, 7 Jul 2019 15:12:31 +0000 (-0400) Subject: Allow duplicate columns in from clauses and selectables X-Git-Tag: rel_1_4_0b1~800 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aceefb508ccd0911f52ff0e50324b3fefeaa3f16;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Allow duplicate columns in from clauses and selectables The :func:`.select` construct and related constructs now allow for duplication of column labels and columns themselves in the columns clause, mirroring exactly how column expressions were passed in. This allows the tuples returned by an executed result to match what was SELECTed for in the first place, which is how the ORM :class:`.Query` works, so this establishes better cross-compatibility between the two constructs. Additionally, it allows column-positioning-sensitive structures such as UNIONs (i.e. :class:`.CompoundSelect`) to be more intuitively constructed in those cases where a particular column might appear in more than one place. To support this change, the :class:`.ColumnCollection` has been revised to support duplicate columns as well as to allow integer index access. Fixes: #4753 Change-Id: Ie09a8116f05c367995c1e43623c51e07971d3bf0 --- diff --git a/doc/build/changelog/migration_14.rst b/doc/build/changelog/migration_14.rst index f0e99e7eab..1fa89c2aec 100644 --- a/doc/build/changelog/migration_14.rst +++ b/doc/build/changelog/migration_14.rst @@ -394,6 +394,86 @@ configured to raise an exception using the Python warnings filter. Behavior Changes - Core ======================== +.. _change_4753: + +SELECT objects and derived FROM clauses allow for duplicate columns and column labels +------------------------------------------------------------------------------------- + +This change allows that the :func:`.select` construct now allows for duplicate +column labels as well as duplicate column objects themselves, so that result +tuples are organized and ordered in the identical way in that the columns were +selected. The ORM :class:`.Query` already works this way, so this change +allows for greater cross-compatibility between the two, which is a key goal of +the 2.0 transition:: + + >>> from sqlalchemy import column, select + >>> c1, c2, c3, c4 = column('c1'), column('c2'), column('c3'), column('c4') + >>> stmt = select([c1, c2, c3.label('c2'), c2, c4]) + >>> print(stmt) + SELECT c1, c2, c3 AS c2, c2, c4 + +To support this change, the :class:`.ColumnCollection` used by +:class:`.SelectBase` as well as for derived FROM clauses such as subqueries +also support duplicate columns; this includes the new +:attr:`.SelectBase.selected_columns` attribute, the deprecated ``SelectBase.c`` +attribute, as well as the :attr:`.FromClause.c` attribute seen on constructs +such as :class:`.Subquery` and :class:`.Alias`:: + + >>> list(stmt.selected_columns) + [ + , + , + , + , + + ] + + >>> print(stmt.subquery().select()) + SELECT anon_1.c1, anon_1.c2, anon_1.c2, anon_1.c2, anon_1.c4 + FROM (SELECT c1, c2, c3 AS c2, c2, c4) AS anon_1 + +:class:`.ColumnCollection` also allows access by integer index to support +when the string "key" is ambiguous:: + + >>> stmt.selected_columns[2] + + +To suit the use of :class:`.ColumnCollection` in objects such as +:class:`.Table` and :class:`.PrimaryKeyConstraint`, the old "deduplicating" +behavior which is more critical for these objects is preserved in a new class +:class:`.DedupeColumnCollection`. + +The change includes that the familiar warning ``"Column %r on table %r being +replaced by %r, which has the same key. Consider use_labels for select() +statements."`` is **removed**; the :meth:`.Select.apply_labels` is still +available and is still used by the ORM for all SELECT operations, however it +does not imply deduplication of column objects, although it does imply +deduplication of implicitly generated labels:: + + >>> from sqlalchemy import table + >>> user = table('user', column('id'), column('name')) + >>> stmt = select([user.c.id, user.c.name, user.c.id]).apply_labels() + >>> print(stmt) + SELECT "user".id AS user_id, "user".name AS user_name, "user".id AS id_1 + FROM "user" + +Finally, the change makes it easier to create UNION and other +:class:`.CompoundSelect` objects, by ensuring that the number and position +of columns in a SELECT statement mirrors what was given, in a use case such +as:: + + >>> s1 = select([user, user.c.id]) + >>> s2 = select([c1, c2, c3]) + >>> from sqlalchemy import union + >>> u = union(s1, s2) + >>> print(u) + SELECT "user".id, "user".name, "user".id + FROM "user" UNION SELECT c1, c2, c3 + + + +:ticket:`4753` + .. _change_4712: Connection-level transactions can now be inactive based on subtransaction diff --git a/doc/build/changelog/unreleased_14/4753.rst b/doc/build/changelog/unreleased_14/4753.rst new file mode 100644 index 0000000000..50617feecd --- /dev/null +++ b/doc/build/changelog/unreleased_14/4753.rst @@ -0,0 +1,21 @@ +.. change:: + :tags: change,engine + :tickets: 4753 + + The :func:`.select` construct and related constructs now allow for + duplication of column labels and columns themselves in the columns clause, + mirroring exactly how column expressions were passed in. This allows + the tuples returned by an executed result to match what was SELECTed + for in the first place, which is how the ORM :class:`.Query` works, so + this establishes better cross-compatibility between the two constructs. + Additionally, it allows column-positioning-sensitive structures such as + UNIONs (i.e. :class:`.CompoundSelect`) to be more intuitively constructed + in those cases where a particular column might appear in more than one + place. To support this change, the :class:`.ColumnCollection` has been + revised to support duplicate columns as well as to allow integer index + access. + + .. seealso:: + + :ref:`change_4753` + diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index 842730c5bf..868c64ed38 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -878,7 +878,8 @@ class OracleCompiler(compiler.SQLCompiler): for_update._copy_internals() for elem in for_update.of: - select = select.column(elem) + if not select.selected_columns.contains_column(elem): + select = select.column(elem) # Wrap the middle select and add the hint inner_subquery = select.alias() diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 33a474576f..5e8d25647b 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -45,6 +45,7 @@ from .. import log from .. import schema from .. import sql from .. import util +from ..sql import base as sql_base from ..sql import coercions from ..sql import expression from ..sql import operators @@ -1455,7 +1456,11 @@ class Mapper(InspectionAttr): def _configure_properties(self): # Column and other ClauseElement objects which are mapped - self.columns = self.c = util.OrderedProperties() + + # TODO: technically this should be a DedupeColumnCollection + # however DCC needs changes and more tests to fully cover + # storing columns under a separate key name + self.columns = self.c = sql_base.ColumnCollection() # object attribute names mapped to MapperProperty objects self._props = util.OrderedDict() @@ -1781,7 +1786,7 @@ class Mapper(InspectionAttr): or prop.columns[0] is self.polymorphic_on ) - self.columns[key] = col + self.columns.add(col, key) for col in prop.columns + prop._orig_columns: for col in col.proxy_set: self._columntoproperty[col] = prop diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 13402e7f42..b5c49ee05f 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -528,7 +528,7 @@ class Query(object): """ - stmt = self._compile_context(labels=self._with_labels).statement + stmt = self._compile_context(for_statement=True).statement if self._params: stmt = stmt.params(self._params) @@ -3843,7 +3843,7 @@ class Query(object): update_op.exec_() return update_op.rowcount - def _compile_context(self, labels=True): + def _compile_context(self, for_statement=False): if self.dispatch.before_compile: for fn in self.dispatch.before_compile: new_query = fn(self) @@ -3855,7 +3855,8 @@ class Query(object): if context.statement is not None: return context - context.labels = labels + context.labels = not for_statement or self._with_labels + context.dedupe_cols = True context._for_update_arg = self._for_update_arg @@ -3909,7 +3910,9 @@ class Query(object): order_by_col_expr = [] inner = sql.select( - context.primary_columns + order_by_col_expr, + util.unique_list(context.primary_columns + order_by_col_expr) + if context.dedupe_cols + else (context.primary_columns + order_by_col_expr), context.whereclause, from_obj=context.froms, use_labels=context.labels, @@ -3979,7 +3982,11 @@ class Query(object): context.froms += tuple(context.eager_joins.values()) statement = sql.select( - context.primary_columns + context.secondary_columns, + util.unique_list( + context.primary_columns + context.secondary_columns + ) + if context.dedupe_cols + else (context.primary_columns + context.secondary_columns), context.whereclause, from_obj=context.froms, use_labels=context.labels, @@ -4290,8 +4297,7 @@ class Bundle(InspectionAttr): """ self.name = self._label = name self.exprs = exprs - self.c = self.columns = ColumnCollection() - self.columns.update( + self.c = self.columns = ColumnCollection( (getattr(col, "key", col._label), col) for col in exprs ) self.single_entity = kw.pop("single_entity", self.single_entity) @@ -4658,6 +4664,7 @@ class QueryContext(object): "whereclause", "order_by", "labels", + "dedupe_cols", "_for_update_arg", "runid", "partials", diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py index a84843c4bc..da384bdabc 100644 --- a/lib/sqlalchemy/sql/base.py +++ b/lib/sqlalchemy/sql/base.py @@ -499,26 +499,209 @@ class SchemaVisitor(ClauseVisitor): __traverse_options__ = {"schema_visitor": True} -class ColumnCollection(util.OrderedProperties): - """An ordered dictionary that stores a list of ColumnElement - instances. +class ColumnCollection(object): + """Collection of :class:`.ColumnElement` instances, typically for + selectables. + + The :class:`.ColumnCollection` has both mapping- and sequence- like + behaviors. A :class:`.ColumnCollection` usually stores :class:`.Column` + objects, which are then accessible both via mapping style access as well + as attribute access style. The name for which a :class:`.Column` would + be present is normally that of the :paramref:`.Column.key` parameter, + however depending on the context, it may be stored under a special label + name:: + + >>> from sqlalchemy import Column, Integer + >>> from sqlalchemy.sql import ColumnCollection + >>> x, y = Column('x', Integer), Column('y', Integer) + >>> cc = ColumnCollection(columns=[x, y]) + >>> cc.x + Column('x', Integer(), table=None) + >>> cc.y + Column('y', Integer(), table=None) + >>> cc['x'] + Column('x', Integer(), table=None) + >>> cc['y'] + + :class`.ColumnCollection` also indexes the columns in order and allows + them to be accessible by their integer position:: + + >>> cc[0] + Column('x', Integer(), table=None) + >>> cc[1] + Column('y', Integer(), table=None) + + .. versionadded:: 1.4 :class:`.ColumnCollection` allows integer-based + index access to the collection. + + Iterating the collection yields the column expressions in order:: + + >>> list(cc) + [Column('x', Integer(), table=None), + Column('y', Integer(), table=None)] + + The base :class:`.ColumnCollection` object can store duplicates, which can + mean either two columns with the same key, in which case the column + returned by key access is **arbitrary**:: + + >>> x1, x2 = Column('x', Integer), Column('x', Integer) + >>> cc = ColumnCollection(columns=[x1, x2]) + >>> list(cc) + [Column('x', Integer(), table=None), + Column('x', Integer(), table=None)] + >>> cc['x'] is x1 + False + >>> cc['x'] is x2 + True + + Or it can also mean the same column multiple times. These cases are + supported as :class:`.ColumnCollection` is used to represent the columns in + a SELECT statement which may include duplicates. + + A special subclass :class:`.DedupeColumnCollection` exists which instead + maintains SQLAlchemy's older behavior of not allowing duplicates; this + collection is used for schema level objects like :class:`.Table` and + :class:`.PrimaryKeyConstraint` where this deduping is helpful. The + :class:`.DedupeColumnCollection` class also has additional mutation methods + as the schema constructs have more use cases that require removal and + replacement of columns. + + .. versionchanged:: 1.4 :class:`.ColumnCollection` now stores duplicate + column keys as well as the same column in multiple positions. The + :class:`.DedupeColumnCollection` class is added to maintain the + former behavior in those cases where deduplication as well as + additional replace/remove operations are needed. - Overrides the ``__eq__()`` method to produce SQL clauses between - sets of correlated columns. """ - __slots__ = "_all_columns" + __slots__ = "_collection", "_index", "_colset" - def __init__(self, *columns): - super(ColumnCollection, self).__init__() - object.__setattr__(self, "_all_columns", []) - for c in columns: - self.add(c) + def __init__(self, columns=None): + object.__setattr__(self, "_colset", set()) + object.__setattr__(self, "_index", {}) + object.__setattr__(self, "_collection", []) + if columns: + self._initial_populate(columns) + + def _initial_populate(self, iter_): + self._populate_separate_keys(iter_) + + @property + def _all_columns(self): + return [col for (k, col) in self._collection] + + def keys(self): + return [k for (k, col) in self._collection] + + def __len__(self): + return len(self._collection) + + def __iter__(self): + # turn to a list first to maintain over a course of changes + return iter([col for k, col in self._collection]) + + def __getitem__(self, key): + try: + return self._index[key] + except KeyError: + if isinstance(key, util.int_types): + raise IndexError(key) + else: + raise + + def __getattr__(self, key): + try: + return self._index[key] + except KeyError: + raise AttributeError(key) + + def __contains__(self, key): + if key not in self._index: + if not isinstance(key, util.string_types): + raise exc.ArgumentError( + "__contains__ requires a string argument" + ) + return False + else: + return True + + def compare(self, other): + for l, r in util.zip_longest(self, other): + if l is not r: + return False + else: + return True + + def __eq__(self, other): + return self.compare(other) + + def get(self, key, default=None): + if key in self._index: + return self._index[key] + else: + return default def __str__(self): return repr([str(c) for c in self]) + def __setitem__(self, key, value): + raise NotImplementedError() + + def __delitem__(self, key): + raise NotImplementedError() + + def __setattr__(self, key, obj): + raise NotImplementedError() + + def clear(self): + raise NotImplementedError() + + def remove(self, column): + raise NotImplementedError() + + def update(self, iter_): + raise NotImplementedError() + + __hash__ = None + + def _populate_separate_keys(self, iter_): + """populate from an iterator of (key, column)""" + cols = list(iter_) + self._collection[:] = cols + self._colset.update(c for k, c in self._collection) + self._index.update( + (idx, c) for idx, (k, c) in enumerate(self._collection) + ) + self._index.update({k: col for k, col in reversed(self._collection)}) + + def add(self, column, key=None): + if key is None: + key = column.key + + l = len(self._collection) + self._collection.append((key, column)) + self._colset.add(column) + self._index[l] = column + if key not in self._index: + self._index[key] = column + + def __getstate__(self): + return {"_collection": self._collection, "_index": self._index} + + def __setstate__(self, state): + object.__setattr__(self, "_index", state["_index"]) + object.__setattr__(self, "_collection", state["_collection"]) + object.__setattr__( + self, "_colset", {col for k, col in self._collection} + ) + + def contains_column(self, col): + return col in self._colset + + def as_immutable(self): + return ImmutableColumnCollection(self) + def corresponding_column(self, column, require_embedded=False): """Given a :class:`.ColumnElement`, return the exported :class:`.ColumnElement` object from this :class:`.ColumnCollection` @@ -554,11 +737,11 @@ class ColumnCollection(util.OrderedProperties): return True # don't dig around if the column is locally present - if self.contains_column(column): + if column in self._colset: return column col, intersect = None, None target_set = column.proxy_set - cols = self._all_columns + cols = [c for (k, c) in self._collection] for c in cols: expanded_proxy_set = set(_expand_cloned(c.proxy_set)) i = target_set.intersection(expanded_proxy_set) @@ -610,165 +793,167 @@ class ColumnCollection(util.OrderedProperties): col, intersect = c, i return col - def replace(self, column): - """add the given column to this collection, removing unaliased - versions of this column as well as existing columns with the - same key. - e.g.:: +class DedupeColumnCollection(ColumnCollection): + """A :class:`.ColumnCollection that maintains deduplicating behavior. - t = Table('sometable', metadata, Column('col1', Integer)) - t.columns.replace(Column('col1', Integer, key='columnone')) + This is useful by schema level objects such as :class:`.Table` and + :class:`.PrimaryKeyConstraint`. The collection includes more + sophisticated mutator methods as well to suit schema objects which + require mutable column collections. - will remove the original 'col1' from the collection, and add - the new column under the name 'columnname'. - - Used by schema.Column to override columns during table reflection. - - """ - remove_col = None - if column.name in self and column.key != column.name: - other = self[column.name] - if other.name == other.key: - remove_col = other - del self._data[other.key] - - if column.key in self._data: - remove_col = self._data[column.key] - - self._data[column.key] = column - if remove_col is not None: - self._all_columns[:] = [ - column if c is remove_col else c for c in self._all_columns - ] - else: - self._all_columns.append(column) + .. versionadded: 1.4 - def add(self, column): - """Add a column to this collection. + """ - The key attribute of the column will be used as the hash key - for this dictionary. + def add(self, column, key=None): + if key is not None and column.key != key: + raise exc.ArgumentError( + "DedupeColumnCollection requires columns be under " + "the same key as their .key" + ) + key = column.key - """ - if not column.key: + if key is None: raise exc.ArgumentError( "Can't add unnamed column to column collection" ) - self[column.key] = column - - def __delitem__(self, key): - raise NotImplementedError() - - def __setattr__(self, key, obj): - raise NotImplementedError() - def __setitem__(self, key, value): - if key in self: + if key in self._index: - # this warning is primarily to catch select() statements - # which have conflicting column names in their exported - # columns collection + existing = self._index[key] - existing = self[key] - - if existing is value: + if existing is column: return - if not existing.shares_lineage(value): - util.warn( - "Column %r on table %r being replaced by " - "%r, which has the same key. Consider " - "use_labels for select() statements." - % (key, getattr(existing, "table", None), value) - ) + self.replace(column) # pop out memoized proxy_set as this # operation may very well be occurring # in a _make_proxy operation - util.memoized_property.reset(value, "proxy_set") + util.memoized_property.reset(column, "proxy_set") + else: + l = len(self._collection) + self._collection.append((key, column)) + self._colset.add(column) + self._index[l] = column + self._index[key] = column + + def _populate_separate_keys(self, iter_): + """populate from an iterator of (key, column)""" + cols = list(iter_) - self._all_columns.append(value) - self._data[key] = value + replace_col = [] + for k, col in cols: + if col.key != k: + raise exc.ArgumentError( + "DedupeColumnCollection requires columns be under " + "the same key as their .key" + ) + if col.name in self._index and col.key != col.name: + replace_col.append(col) + elif col.key in self._index: + replace_col.append(col) + else: + self._index[k] = col + self._collection.append((k, col)) + self._colset.update(c for (k, c) in self._collection) + self._index.update( + (idx, c) for idx, (k, c) in enumerate(self._collection) + ) + for col in replace_col: + self.replace(col) - def clear(self): - raise NotImplementedError() + def extend(self, iter_): + self._populate_separate_keys((col.key, col) for col in iter_) def remove(self, column): - del self._data[column.key] - self._all_columns[:] = [ - c for c in self._all_columns if c is not column + if column not in self._colset: + raise ValueError( + "Can't remove column %r; column is not in this collection" + % column + ) + del self._index[column.key] + self._colset.remove(column) + self._collection[:] = [ + (k, c) for (k, c) in self._collection if c is not column ] - - def update(self, iter_): - cols = list(iter_) - all_col_set = set(self._all_columns) - self._all_columns.extend( - c for label, c in cols if c not in all_col_set + self._index.update( + {idx: col for idx, (k, col) in enumerate(self._collection)} ) - self._data.update((label, c) for label, c in cols) + # delete higher index + del self._index[len(self._collection)] - def extend(self, iter_): - cols = list(iter_) - all_col_set = set(self._all_columns) - self._all_columns.extend(c for c in cols if c not in all_col_set) - self._data.update((c.key, c) for c in cols) + def replace(self, column): + """add the given column to this collection, removing unaliased + versions of this column as well as existing columns with the + same key. - __hash__ = None + e.g.:: - def __eq__(self, other): - l = [] - for c in getattr(other, "_all_columns", other): - for local in self._all_columns: - if c.shares_lineage(local): - l.append(c == local) - return elements.and_(*l) + t = Table('sometable', metadata, Column('col1', Integer)) + t.columns.replace(Column('col1', Integer, key='columnone')) - def __contains__(self, other): - if not isinstance(other, util.string_types): - raise exc.ArgumentError("__contains__ requires a string argument") - return util.OrderedProperties.__contains__(self, other) + will remove the original 'col1' from the collection, and add + the new column under the name 'columnname'. - def __getstate__(self): - return {"_data": self._data, "_all_columns": self._all_columns} + Used by schema.Column to override columns during table reflection. - def __setstate__(self, state): - object.__setattr__(self, "_data", state["_data"]) - object.__setattr__(self, "_all_columns", state["_all_columns"]) + """ - def contains_column(self, col): - return col in set(self._all_columns) + remove_col = set() + # remove up to two columns based on matches of name as well as key + if column.name in self._index and column.key != column.name: + other = self._index[column.name] + if other.name == other.key: + remove_col.add(other) + + if column.key in self._index: + remove_col.add(self._index[column.key]) + + new_cols = [] + replaced = False + for k, col in self._collection: + if col in remove_col: + if not replaced: + replaced = True + new_cols.append((column.key, column)) + else: + new_cols.append((k, col)) - def as_immutable(self): - return ImmutableColumnCollection(self._data, self._all_columns) + if remove_col: + self._colset.difference_update(remove_col) + if not replaced: + new_cols.append((column.key, column)) -class SeparateKeyColumnCollection(ColumnCollection): - """Column collection that maintains a string name separate from the - column itself""" + self._colset.add(column) + self._collection[:] = new_cols - def __init__(self, cols_plus_names=None): - super(ColumnCollection, self).__init__() - object.__setattr__(self, "_all_columns", []) - if cols_plus_names: - self.update(cols_plus_names) + self._index.clear() + self._index.update( + {idx: col for idx, (k, col) in enumerate(self._collection)} + ) + self._index.update(self._collection) - def replace(self, column): - raise NotImplementedError() - def add(self, column): - raise NotImplementedError() +class ImmutableColumnCollection(util.ImmutableContainer, ColumnCollection): + __slots__ = ("_parent",) - def remove(self, column): - raise NotImplementedError() + def __init__(self, collection): + object.__setattr__(self, "_parent", collection) + object.__setattr__(self, "_colset", collection._colset) + object.__setattr__(self, "_index", collection._index) + object.__setattr__(self, "_collection", collection._collection) + def __getstate__(self): + return {"_parent": self._parent} -class ImmutableColumnCollection(util.ImmutableProperties, ColumnCollection): - def __init__(self, data, all_columns): - util.ImmutableProperties.__init__(self, data) - object.__setattr__(self, "_all_columns", all_columns) + def __setstate__(self, state): + parent = state["_parent"] + self.__init__(parent) - extend = remove = util.ImmutableProperties._immutable + add = extend = remove = util.ImmutableContainer._immutable class ColumnSet(util.ordered_column_set): diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 13219ee687..ea7e890e74 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -1828,7 +1828,6 @@ class SQLCompiler(Compiled): result_expr = _CompileLabel( col_expr, name, alt_names=(column._key_label,) ) - elif ( asfrom and isinstance(column, elements.ColumnClause) @@ -1897,6 +1896,7 @@ class SQLCompiler(Compiled): """ cloned = {} column_translate = [{}] + created = set() def visit(element, **kw): if element in column_translate[-1]: @@ -1906,7 +1906,6 @@ class SQLCompiler(Compiled): return cloned[element] newelem = cloned[element] = element._clone() - if ( newelem._is_from_clause and newelem._is_join @@ -1921,6 +1920,8 @@ class SQLCompiler(Compiled): selectable_ = selectable.Select( [right.element], use_labels=True ).alias() + created.add(selectable_) + created.update(selectable_.c) for c in selectable_.c: c._key_label = c.key @@ -1971,6 +1972,11 @@ class SQLCompiler(Compiled): if barrier_select: column_translate.append({}) kw["transform_clue"] = "inside_select" + if not newelem._is_select_container: + froms = newelem.froms + newelem._raw_columns = list(newelem.selected_columns) + newelem._from_obj.update(froms) + newelem._reset_memoizations() newelem._copy_internals(clone=visit, **kw) if barrier_select: del column_translate[-1] @@ -1984,17 +1990,33 @@ class SQLCompiler(Compiled): def _transform_result_map_for_nested_joins( self, select, transformed_select ): - inner_col = dict( - (c._key_label, c) for c in transformed_select.inner_columns - ) - - d = dict((inner_col[c._key_label], c) for c in select.inner_columns) - - self._result_columns = [ - (key, name, tuple([d.get(col, col) for col in objs]), typ) - for key, name, objs, typ in self._result_columns + self._result_columns[:] = [ + result_rec + if col is tcol + else ( + result_rec[0], + name, + tuple([col if obj is tcol else obj for obj in result_rec[2]]), + result_rec[3], + ) + for result_rec, (name, col), (tname, tcol) in zip( + self._result_columns, + select._columns_plus_names, + transformed_select._columns_plus_names, + ) ] + # TODO: it's not anticipated that we need to correct anon_map + # however if we do, this is what it looks like: + # for (name, col), (tname, tcol) in zip( + # select._columns_plus_names, + # transformed_select._columns_plus_names, + # ): + # if isinstance(name, elements._anonymous_label) and name != tname: + # m1 = re.match(r"^%\((\d+ .+?)\)s$", name) + # m2 = re.match(r"^%\((\d+ .+?)\)s$", tname) + # self.anon_map[m1.group(1)] = self.anon_map[m2.group(1)] + _default_stack_entry = util.immutabledict( [("correlate_froms", frozenset()), ("asfrom_froms", frozenset())] ) diff --git a/lib/sqlalchemy/sql/dml.py b/lib/sqlalchemy/sql/dml.py index 5a9be7c629..66e92a63cc 100644 --- a/lib/sqlalchemy/sql/dml.py +++ b/lib/sqlalchemy/sql/dml.py @@ -48,8 +48,9 @@ class UpdateBase( named_with_column = False def _generate_fromclause_column_proxies(self, fromclause): - for col in self._returning: - col._make_proxy(fromclause) + fromclause._columns._populate_separate_keys( + col._make_proxy(fromclause) for col in self._returning + ) def _process_colparams(self, parameters): def process_single(p): diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 5b44422227..735a125d73 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -184,6 +184,7 @@ class ClauseElement(roles.SQLRole, Visitable): _is_returns_rows = False _is_text_clause = False _is_from_container = False + _is_select_container = False _is_select_statement = False _order_by_label_element = None @@ -856,8 +857,7 @@ class ColumnElement( co._proxies = [self] if selectable._is_clone_of is not None: co._is_clone_of = selectable._is_clone_of.columns.get(key) - selectable._columns[key] = co - return co + return key, co def cast(self, type_): """Produce a type cast, i.e. ``CAST( AS )``. @@ -887,6 +887,12 @@ class ColumnElement( """ return Label(name, self, self.type) + def _anon_label(self, seed): + while self._is_clone_of is not None: + self = self._is_clone_of + + return _anonymous_label("%%(%d %s)s" % (id(self), seed or "anon")) + @util.memoized_property def anon_label(self): """provides a constant 'anonymous label' for this ColumnElement. @@ -901,12 +907,11 @@ class ColumnElement( expressions and function calls. """ - while self._is_clone_of is not None: - self = self._is_clone_of + return self._anon_label(getattr(self, "name", None)) - return _anonymous_label( - "%%(%d %s)s" % (id(self), getattr(self, "name", "anon")) - ) + @util.memoized_property + def _label_anon_label(self): + return self._anon_label(getattr(self, "_label", None)) class BindParameter(roles.InElementRole, ColumnElement): @@ -3951,7 +3956,7 @@ class Label(roles.LabeledColumnExprRole, ColumnElement): return self.element._from_objects def _make_proxy(self, selectable, name=None, **kw): - e = self.element._make_proxy( + key, e = self.element._make_proxy( selectable, name=name if name else self.name, disallow_is_literal=True, @@ -3959,7 +3964,7 @@ class Label(roles.LabeledColumnExprRole, ColumnElement): e._proxies.append(self) if self._type is not None: e.type = self._type - return e + return key, e class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement): @@ -4214,7 +4219,6 @@ class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement): self, selectable, name=None, - attach=True, name_is_truncatable=False, disallow_is_literal=False, **kw @@ -4249,9 +4253,7 @@ class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement): if selectable._is_clone_of is not None: c._is_clone_of = selectable._is_clone_of.columns.get(c.key) - if attach: - selectable._columns[c.key] = c - return c + return c.key, c class CollationClause(ColumnElement): diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py index 04fb16a809..2feb6fd5f3 100644 --- a/lib/sqlalchemy/sql/functions.py +++ b/lib/sqlalchemy/sql/functions.py @@ -118,7 +118,8 @@ class FunctionElement(Executable, ColumnElement, FromClause): """ - return ColumnCollection(self.label(None)) + col = self.label(None) + return ColumnCollection(columns=[(col.key, col)]) @util.memoized_property def clauses(self): diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index d39bc9832b..23c58dc4e6 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -40,7 +40,7 @@ from . import roles from . import type_api from . import visitors from .base import _bind_or_error -from .base import ColumnCollection +from .base import DedupeColumnCollection from .base import DialectKWArgs from .base import SchemaEventTarget from .coercions import _document_text_coercion @@ -538,7 +538,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause): self.indexes = set() self.constraints = set() - self._columns = ColumnCollection() + self._columns = DedupeColumnCollection() PrimaryKeyConstraint( _implicit_generated=True )._set_parent_with_dispatch(self) @@ -1607,13 +1607,13 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): ) c.table = selectable - selectable._columns.add(c) if selectable._is_clone_of is not None: c._is_clone_of = selectable._is_clone_of.columns[c.key] if self.primary_key: selectable.primary_key.add(c) - c.dispatch.after_parent_attach(c, selectable) - return c + if fk: + selectable.foreign_keys.update(fk) + return c.key, c def get_children(self, schema_visitor=False, **kwargs): if schema_visitor: @@ -1983,19 +1983,20 @@ class ForeignKey(DialectKWArgs, SchemaItem): self._set_target_column(_column) def _set_target_column(self, column): + assert isinstance(self.parent.table, Table) + # propagate TypeEngine to parent if it didn't have one if self.parent.type._isnull: self.parent.type = column.type # super-edgy case, if other FKs point to our column, # they'd get the type propagated out also. - if isinstance(self.parent.table, Table): - def set_type(fk): - if fk.parent.type._isnull: - fk.parent.type = column.type + def set_type(fk): + if fk.parent.type._isnull: + fk.parent.type = column.type - self.parent._setup_on_memoized_fks(set_type) + self.parent._setup_on_memoized_fks(set_type) self.column = column @@ -2072,7 +2073,8 @@ class ForeignKey(DialectKWArgs, SchemaItem): def _set_table(self, column, table): # standalone ForeignKey - create ForeignKeyConstraint # on the hosting Table when attached to the Table. - if self.constraint is None and isinstance(table, Table): + assert isinstance(table, Table) + if self.constraint is None: self.constraint = ForeignKeyConstraint( [], [], @@ -2088,7 +2090,6 @@ class ForeignKey(DialectKWArgs, SchemaItem): self.constraint._append_element(column, self) self.constraint._set_parent_with_dispatch(table) table.foreign_keys.add(self) - # set up remote ".column" attribute, or a note to pick it # up when the other Table/Column shows up if isinstance(self._colspec, util.string_types): @@ -2760,7 +2761,7 @@ class ColumnCollectionMixin(object): def __init__(self, *columns, **kw): _autoattach = kw.pop("_autoattach", True) self._column_flag = kw.pop("_column_flag", False) - self.columns = ColumnCollection() + self.columns = DedupeColumnCollection() self._pending_colargs = [ _to_schema_column_or_string(c) for c in columns ] @@ -2885,14 +2886,10 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): return self.columns.contains_column(col) def __iter__(self): - # inlining of - # return iter(self.columns) - # ColumnCollection->OrderedProperties->OrderedDict - ordered_dict = self.columns._data - return (ordered_dict[key] for key in ordered_dict._list) + return iter(self.columns) def __len__(self): - return len(self.columns._data) + return len(self.columns) class CheckConstraint(ColumnCollectionConstraint): @@ -3368,11 +3365,7 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint): table.constraints.add(self) table_pks = [c for c in table.c if c.primary_key] - if ( - self.columns - and table_pks - and set(table_pks) != set(self.columns.values()) - ): + if self.columns and table_pks and set(table_pks) != set(self.columns): util.warn( "Table '%s' specifies columns %s as primary_key=True, " "not matching locally specified columns %s; setting the " @@ -3390,7 +3383,8 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint): for c in self.columns: c.primary_key = True c.nullable = False - self.columns.extend(table_pks) + if table_pks: + self.columns.extend(table_pks) def _reload(self, columns): """repopulate this :class:`.PrimaryKeyConstraint` given diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index c93de8d736..10643c9e46 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -27,10 +27,10 @@ from .base import _from_objects from .base import _generative from .base import ColumnCollection from .base import ColumnSet +from .base import DedupeColumnCollection from .base import Executable from .base import Generative from .base import Immutable -from .base import SeparateKeyColumnCollection from .coercions import _document_text_coercion from .elements import _anonymous_label from .elements import _select_iterables @@ -534,8 +534,9 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable): self._memoized_property.expire_instance(self) def _generate_fromclause_column_proxies(self, fromclause): - for col in self.c: - col._make_proxy(fromclause) + fromclause._columns._populate_separate_keys( + col._make_proxy(fromclause) for col in self.c + ) @property def exported_columns(self): @@ -791,7 +792,9 @@ class Join(FromClause): (c for c in columns if c.primary_key), self.onclause ) ) - self._columns.update((col._key_label, col) for col in columns) + self._columns._populate_separate_keys( + (col._key_label, col) for col in columns + ) self.foreign_keys.update( itertools.chain(*[col.foreign_keys for col in columns]) ) @@ -1861,7 +1864,7 @@ class TableClause(Immutable, FromClause): super(TableClause, self).__init__() self.name = self.fullname = name - self._columns = ColumnCollection() + self._columns = DedupeColumnCollection() self.primary_key = ColumnSet() self.foreign_keys = set() for c in columns: @@ -1881,7 +1884,7 @@ class TableClause(Immutable, FromClause): return self.name.encode("ascii", "backslashreplace") def append_column(self, c): - self._columns[c.key] = c + self._columns.add(c) c.table = self def get_children(self, column_collections=True, **kwargs): @@ -2328,6 +2331,8 @@ class SelectStatementGrouping(GroupedElement, SelectBase): __visit_name__ = "grouping" + _is_select_container = True + def __init__(self, element): # type: (SelectBase) self.element = coercions.expect(roles.SelectStatementRole, element) @@ -2526,6 +2531,7 @@ class GenerativeSelect(SelectBase): FROM clauses to produce a unique set of column names regardless of name conflicts among the individual FROM clauses. + """ self.use_labels = True @@ -4081,6 +4087,8 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect): """ names = set() + cols = _select_iterables(self._raw_columns) + def name_for_col(c): # we use key_label since this name is intended for targeting # within the ColumnCollection only, it's not related to SQL @@ -4090,18 +4098,22 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect): else: name = c._proxy_key if name in names: - name = c.anon_label + if self.use_labels: + name = c._label_anon_label + else: + name = c.anon_label else: names.add(name) return name - return SeparateKeyColumnCollection( - (name_for_col(c), c) - for c in util.unique_list(_select_iterables(self._raw_columns)) + return ColumnCollection( + (name_for_col(c), c) for c in cols ).as_immutable() @_memoized_property def _columns_plus_names(self): + cols = _select_iterables(self._raw_columns) + if self.use_labels: names = set() @@ -4111,23 +4123,18 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect): name = c._label if name in names: - name = c.anon_label + name = c._label_anon_label else: names.add(name) return name, c - return [ - name_for_col(c) - for c in util.unique_list(_select_iterables(self._raw_columns)) - ] + return [name_for_col(c) for c in cols] else: - return [ - (None, c) - for c in util.unique_list(_select_iterables(self._raw_columns)) - ] + return [(None, c) for c in cols] def _generate_fromclause_column_proxies(self, subquery): keys_seen = set() + prox = [] for name, c in self._columns_plus_names: if not hasattr(c, "_make_proxy"): @@ -4137,14 +4144,16 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect): elif self.use_labels: key = c._key_label if key is not None and key in keys_seen: - key = c.anon_label + key = c._label_anon_label keys_seen.add(key) else: key = None - - c._make_proxy( - subquery, key=key, name=name, name_is_truncatable=True + prox.append( + c._make_proxy( + subquery, key=key, name=name, name_is_truncatable=True + ) ) + subquery._columns._populate_separate_keys(prox) def _needs_parens_for_grouping(self): return ( @@ -4397,7 +4406,9 @@ class TextualSelect(SelectBase): .. versionadded:: 1.4 """ - return ColumnCollection(*self.column_args).as_immutable() + return ColumnCollection( + (c.key, c) for c in self.column_args + ).as_immutable() @property def _bind(self): @@ -4408,8 +4419,9 @@ class TextualSelect(SelectBase): self.element = self.element.bindparams(*binds, **bind_as_values) def _generate_fromclause_column_proxies(self, fromclause): - for c in self.column_args: - c._make_proxy(fromclause) + fromclause._columns._populate_separate_keys( + c._make_proxy(fromclause) for c in self.column_args + ) def _copy_internals(self, clone=_clone, **kw): self._reset_memoizations() diff --git a/test/base/test_utils.py b/test/base/test_utils.py index d7e4deb289..4f073ebfed 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -9,7 +9,7 @@ from sqlalchemy import sql from sqlalchemy import testing from sqlalchemy import util from sqlalchemy.sql import column -from sqlalchemy.sql.base import SeparateKeyColumnCollection +from sqlalchemy.sql.base import DedupeColumnCollection from sqlalchemy.testing import assert_raises from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import eq_ @@ -18,6 +18,8 @@ from sqlalchemy.testing import fails_if from sqlalchemy.testing import fixtures from sqlalchemy.testing import in_ from sqlalchemy.testing import is_ +from sqlalchemy.testing import is_false +from sqlalchemy.testing import is_true from sqlalchemy.testing import mock from sqlalchemy.testing import ne_ from sqlalchemy.testing.util import gc_collect @@ -442,60 +444,110 @@ class ToListTest(fixtures.TestBase): ) -class SeparateKeysColumnCollectionTest( - testing.AssertsCompiledSQL, fixtures.TestBase -): - def test_in(self): - cc = SeparateKeyColumnCollection() - cc["kcol1"] = sql.column("col1") - cc["kcol2"] = sql.column("col2") - cc["kcol3"] = sql.column("col3") - assert "col1" not in cc - assert "kcol2" in cc +class ColumnCollectionCommon(testing.AssertsCompiledSQL): + def _assert_collection_integrity(self, coll): + eq_(coll._colset, set(c for k, c in coll._collection)) + d = {} + for k, col in coll._collection: + d.setdefault(k, col) + d.update({idx: col for idx, (k, col) in enumerate(coll._collection)}) + eq_(coll._index, d) + + def test_keys(self): + c1, c2, c3 = sql.column("c1"), sql.column("c2"), sql.column("c3") + c2.key = "foo" + cc = self._column_collection( + columns=[("c1", c1), ("foo", c2), ("c3", c3)] + ) + eq_(cc.keys(), ["c1", "foo", "c3"]) - def test_get(self): - c1, c2 = sql.column("col1"), sql.column("col2") - cc = SeparateKeyColumnCollection([("kcol1", c1), ("kcol2", c2)]) - is_(cc.kcol1, c1) - is_(cc.kcol2, c2) + ci = cc.as_immutable() + eq_(ci.keys(), ["c1", "foo", "c3"]) + + def test_key_index_error(self): + cc = self._column_collection( + columns=[ + ("col1", sql.column("col1")), + ("col2", sql.column("col2")), + ] + ) + assert_raises(KeyError, lambda: cc["foo"]) + assert_raises(KeyError, lambda: cc[object()]) + assert_raises(IndexError, lambda: cc[5]) - def test_all_cols(self): - c1, c2 = sql.column("col1"), sql.column("col2") - cc = SeparateKeyColumnCollection([("kcol1", c1), ("kcol2", c2)]) - eq_(cc._all_columns, [c1, c2]) + def test_contains_column(self): + c1, c2, c3 = sql.column("c1"), sql.column("c2"), sql.column("c3") + cc = self._column_collection(columns=[("c1", c1), ("c2", c2)]) + is_true(cc.contains_column(c1)) + is_false(cc.contains_column(c3)) -class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): def test_in(self): - cc = sql.ColumnCollection() - cc.add(sql.column("col1")) - cc.add(sql.column("col2")) - cc.add(sql.column("col3")) + col1 = sql.column("col1") + cc = self._column_collection( + columns=[ + ("col1", col1), + ("col2", sql.column("col2")), + ("col3", sql.column("col3")), + ] + ) assert "col1" in cc assert "col2" in cc - try: - cc["col1"] in cc - assert False - except exc.ArgumentError as e: - eq_(str(e), "__contains__ requires a string argument") + assert_raises_message( + exc.ArgumentError, + "__contains__ requires a string argument", + lambda: col1 in cc, + ) def test_compare(self): - cc1 = sql.ColumnCollection() - cc2 = sql.ColumnCollection() - cc3 = sql.ColumnCollection() c1 = sql.column("col1") c2 = c1.label("col2") c3 = sql.column("col3") - cc1.add(c1) - cc2.add(c2) - cc3.add(c3) - assert (cc1 == cc2).compare(c1 == c2) - assert not (cc1 == cc3).compare(c2 == c3) - @testing.emits_warning("Column ") + is_true( + self._column_collection( + [("col1", c1), ("col2", c2), ("col3", c3)] + ).compare( + self._column_collection( + [("col1", c1), ("col2", c2), ("col3", c3)] + ) + ) + ) + is_false( + self._column_collection( + [("col1", c1), ("col2", c2), ("col3", c3)] + ).compare(self._column_collection([("col1", c1), ("col2", c2)])) + ) + + +class ColumnCollectionTest(ColumnCollectionCommon, fixtures.TestBase): + def _column_collection(self, columns=None): + return sql.ColumnCollection(columns=columns) + + def test_separate_key_all_cols(self): + c1, c2 = sql.column("col1"), sql.column("col2") + cc = self._column_collection([("kcol1", c1), ("kcol2", c2)]) + eq_(cc._all_columns, [c1, c2]) + + def test_separate_key_get(self): + c1, c2 = sql.column("col1"), sql.column("col2") + cc = self._column_collection([("kcol1", c1), ("kcol2", c2)]) + is_(cc.kcol1, c1) + is_(cc.kcol2, c2) + + def test_separate_key_in(self): + cc = self._column_collection( + columns=[ + ("kcol1", sql.column("col1")), + ("kcol2", sql.column("col2")), + ("kcol3", sql.column("col3")), + ] + ) + assert "col1" not in cc + assert "kcol2" in cc + def test_dupes_add(self): - cc = sql.ColumnCollection() c1, c2a, c3, c2b = ( column("c1"), @@ -504,27 +556,198 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): column("c2"), ) + cc = sql.ColumnCollection() + cc.add(c1) - cc.add(c2a) + cc.add(c2a, "c2") cc.add(c3) cc.add(c2b) eq_(cc._all_columns, [c1, c2a, c3, c2b]) + eq_(list(cc), [c1, c2a, c3, c2b]) + eq_(cc.keys(), ["c1", "c2", "c3", "c2"]) + + assert cc.contains_column(c2a) + assert cc.contains_column(c2b) + + # this is deterministic + is_(cc["c2"], c2a) + + self._assert_collection_integrity(cc) + + ci = cc.as_immutable() + eq_(ci._all_columns, [c1, c2a, c3, c2b]) + eq_(list(ci), [c1, c2a, c3, c2b]) + eq_(ci.keys(), ["c1", "c2", "c3", "c2"]) + + def test_dupes_construct(self): + + c1, c2a, c3, c2b = ( + column("c1"), + column("c2"), + column("c3"), + column("c2"), + ) + + cc = sql.ColumnCollection( + columns=[("c1", c1), ("c2", c2a), ("c3", c3), ("c2", c2b)] + ) + + eq_(cc._all_columns, [c1, c2a, c3, c2b]) + + eq_(list(cc), [c1, c2a, c3, c2b]) + eq_(cc.keys(), ["c1", "c2", "c3", "c2"]) + + assert cc.contains_column(c2a) + assert cc.contains_column(c2b) + + # this is deterministic + is_(cc["c2"], c2a) + + self._assert_collection_integrity(cc) + + ci = cc.as_immutable() + eq_(ci._all_columns, [c1, c2a, c3, c2b]) + eq_(list(ci), [c1, c2a, c3, c2b]) + eq_(ci.keys(), ["c1", "c2", "c3", "c2"]) + + def test_identical_dupe_construct(self): + + c1, c2, c3 = (column("c1"), column("c2"), column("c3")) + + cc = sql.ColumnCollection( + columns=[("c1", c1), ("c2", c2), ("c3", c3), ("c2", c2)] + ) + + eq_(cc._all_columns, [c1, c2, c3, c2]) + # for iter, c2a is replaced by c2b, ordering # is maintained in that way. ideally, iter would be # the same as the "_all_columns" collection. + eq_(list(cc), [c1, c2, c3, c2]) + + assert cc.contains_column(c2) + self._assert_collection_integrity(cc) + + ci = cc.as_immutable() + eq_(ci._all_columns, [c1, c2, c3, c2]) + eq_(list(ci), [c1, c2, c3, c2]) + + +class DedupeColumnCollectionTest(ColumnCollectionCommon, fixtures.TestBase): + def _column_collection(self, columns=None): + return DedupeColumnCollection(columns=columns) + + def test_separate_key_cols(self): + c1, c2 = sql.column("col1"), sql.column("col2") + assert_raises_message( + exc.ArgumentError, + "DedupeColumnCollection requires columns be under " + "the same key as their .key", + self._column_collection, + [("kcol1", c1), ("kcol2", c2)], + ) + + cc = self._column_collection() + assert_raises_message( + exc.ArgumentError, + "DedupeColumnCollection requires columns be under " + "the same key as their .key", + cc.add, + c1, + "kcol1", + ) + + def test_pickle_w_mutation(self): + c1, c2, c3 = sql.column("c1"), sql.column("c2"), sql.column("c3") + + c2.key = "foo" + + cc = self._column_collection(columns=[("c1", c1), ("foo", c2)]) + ci = cc.as_immutable() + + d = {"cc": cc, "ci": ci} + + for loads, dumps in picklers(): + dp = loads(dumps(d)) + + cp = dp["cc"] + cpi = dp["ci"] + self._assert_collection_integrity(cp) + self._assert_collection_integrity(cpi) + + assert cp._colset is cpi._colset + assert cp._index is cpi._index + assert cp._collection is cpi._collection + + cp.add(c3) + + eq_(cp.keys(), ["c1", "foo", "c3"]) + eq_(cpi.keys(), ["c1", "foo", "c3"]) + + assert cp.contains_column(c3) + assert cpi.contains_column(c3) + + def test_keys_after_replace(self): + c1, c2, c3 = sql.column("c1"), sql.column("c2"), sql.column("c3") + c2.key = "foo" + cc = self._column_collection( + columns=[("c1", c1), ("foo", c2), ("c3", c3)] + ) + eq_(cc.keys(), ["c1", "foo", "c3"]) + + c4 = sql.column("c3") + cc.replace(c4) + eq_(cc.keys(), ["c1", "foo", "c3"]) + self._assert_collection_integrity(cc) + + def test_dupes_add_dedupe(self): + cc = DedupeColumnCollection() + + c1, c2a, c3, c2b = ( + column("c1"), + column("c2"), + column("c3"), + column("c2"), + ) + + cc.add(c1) + cc.add(c2a) + cc.add(c3) + cc.add(c2b) + + eq_(cc._all_columns, [c1, c2b, c3]) + eq_(list(cc), [c1, c2b, c3]) - assert cc.contains_column(c2a) + assert not cc.contains_column(c2a) assert cc.contains_column(c2b) + self._assert_collection_integrity(cc) - ci = cc.as_immutable() - eq_(ci._all_columns, [c1, c2a, c3, c2b]) - eq_(list(ci), [c1, c2b, c3]) + def test_dupes_construct_dedupe(self): - def test_identical_dupe_add(self): - cc = sql.ColumnCollection() + c1, c2a, c3, c2b = ( + column("c1"), + column("c2"), + column("c3"), + column("c2"), + ) + + cc = DedupeColumnCollection( + columns=[("c1", c1), ("c2", c2a), ("c3", c3), ("c2", c2b)] + ) + + eq_(cc._all_columns, [c1, c2b, c3]) + + eq_(list(cc), [c1, c2b, c3]) + + assert not cc.contains_column(c2a) + assert cc.contains_column(c2b) + self._assert_collection_integrity(cc) + + def test_identical_dupe_add_dedupes(self): + cc = DedupeColumnCollection() c1, c2, c3 = (column("c1"), column("c2"), column("c3")) @@ -535,27 +758,43 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): eq_(cc._all_columns, [c1, c2, c3]) - self.assert_compile( - cc == [c1, c2, c3], "c1 = c1 AND c2 = c2 AND c3 = c3" - ) - # for iter, c2a is replaced by c2b, ordering # is maintained in that way. ideally, iter would be # the same as the "_all_columns" collection. eq_(list(cc), [c1, c2, c3]) assert cc.contains_column(c2) + self._assert_collection_integrity(cc) ci = cc.as_immutable() eq_(ci._all_columns, [c1, c2, c3]) eq_(list(ci), [c1, c2, c3]) - self.assert_compile( - ci == [c1, c2, c3], "c1 = c1 AND c2 = c2 AND c3 = c3" + def test_identical_dupe_construct_dedupes(self): + + c1, c2, c3 = (column("c1"), column("c2"), column("c3")) + + cc = DedupeColumnCollection( + columns=[("c1", c1), ("c2", c2), ("c3", c3), ("c2", c2)] ) + eq_(cc._all_columns, [c1, c2, c3]) + + # for iter, c2a is replaced by c2b, ordering + # is maintained in that way. ideally, iter would be + # the same as the "_all_columns" collection. + eq_(list(cc), [c1, c2, c3]) + + assert cc.contains_column(c2) + self._assert_collection_integrity(cc) + + ci = cc.as_immutable() + eq_(ci._all_columns, [c1, c2, c3]) + eq_(list(ci), [c1, c2, c3]) + def test_replace(self): - cc = sql.ColumnCollection() + cc = DedupeColumnCollection() + ci = cc.as_immutable() c1, c2a, c3, c2b = ( column("c1"), @@ -572,16 +811,49 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): eq_(cc._all_columns, [c1, c2b, c3]) eq_(list(cc), [c1, c2b, c3]) + is_(cc[1], c2b) assert not cc.contains_column(c2a) assert cc.contains_column(c2b) + self._assert_collection_integrity(cc) + eq_(ci._all_columns, [c1, c2b, c3]) + eq_(list(ci), [c1, c2b, c3]) + is_(ci[1], c2b) + + def test_replace_key_matches_name_of_another(self): + cc = DedupeColumnCollection() ci = cc.as_immutable() + + c1, c2a, c3, c2b = ( + column("c1"), + column("c2"), + column("c3"), + column("c4"), + ) + c2b.key = "c2" + + cc.add(c1) + cc.add(c2a) + cc.add(c3) + + cc.replace(c2b) + + eq_(cc._all_columns, [c1, c2b, c3]) + eq_(list(cc), [c1, c2b, c3]) + is_(cc[1], c2b) + self._assert_collection_integrity(cc) + + assert not cc.contains_column(c2a) + assert cc.contains_column(c2b) + eq_(ci._all_columns, [c1, c2b, c3]) eq_(list(ci), [c1, c2b, c3]) + is_(ci[1], c2b) def test_replace_key_matches(self): - cc = sql.ColumnCollection() + cc = DedupeColumnCollection() + ci = cc.as_immutable() c1, c2a, c3, c2b = ( column("c1"), @@ -599,16 +871,21 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): assert not cc.contains_column(c2a) assert cc.contains_column(c2b) + is_(cc[1], c2b) + assert_raises(IndexError, lambda: cc[3]) + self._assert_collection_integrity(cc) eq_(cc._all_columns, [c1, c2b, c3]) eq_(list(cc), [c1, c2b, c3]) - ci = cc.as_immutable() eq_(ci._all_columns, [c1, c2b, c3]) eq_(list(ci), [c1, c2b, c3]) + is_(ci[1], c2b) + assert_raises(IndexError, lambda: ci[3]) def test_replace_name_matches(self): - cc = sql.ColumnCollection() + cc = DedupeColumnCollection() + ci = cc.as_immutable() c1, c2a, c3, c2b = ( column("c1"), @@ -628,14 +905,19 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): assert cc.contains_column(c2b) eq_(cc._all_columns, [c1, c2b, c3]) - eq_(list(cc), [c1, c3, c2b]) + eq_(list(cc), [c1, c2b, c3]) + eq_(len(cc), 3) + is_(cc[1], c2b) + self._assert_collection_integrity(cc) - ci = cc.as_immutable() eq_(ci._all_columns, [c1, c2b, c3]) - eq_(list(ci), [c1, c3, c2b]) + eq_(list(ci), [c1, c2b, c3]) + eq_(len(ci), 3) + is_(ci[1], c2b) def test_replace_no_match(self): - cc = sql.ColumnCollection() + cc = DedupeColumnCollection() + ci = cc.as_immutable() c1, c2, c3, c4 = column("c1"), column("c2"), column("c3"), column("c4") c4.key = "X" @@ -651,42 +933,102 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): eq_(cc._all_columns, [c1, c2, c3, c4]) eq_(list(cc), [c1, c2, c3, c4]) + is_(cc[3], c4) + self._assert_collection_integrity(cc) - ci = cc.as_immutable() eq_(ci._all_columns, [c1, c2, c3, c4]) eq_(list(ci), [c1, c2, c3, c4]) + is_(ci[3], c4) - def test_dupes_extend(self): - cc = sql.ColumnCollection() + def test_replace_switch_key_name(self): + c1 = column("id") + c2 = column("street") + c3 = column("user_id") - c1, c2a, c3, c2b = ( - column("c1"), - column("c2"), - column("c3"), - column("c2"), + cc = DedupeColumnCollection( + columns=[("id", c1), ("street", c2), ("user_id", c3)] ) - cc.add(c1) - cc.add(c2a) + # for replace col with different key than name, it necessarily + # removes two columns - cc.extend([c3, c2b]) + c4 = column("id") + c4.key = "street" - eq_(cc._all_columns, [c1, c2a, c3, c2b]) + cc.replace(c4) - # for iter, c2a is replaced by c2b, ordering - # is maintained in that way. ideally, iter would be - # the same as the "_all_columns" collection. - eq_(list(cc), [c1, c2b, c3]) + eq_(list(cc), [c4, c3]) + self._assert_collection_integrity(cc) - assert cc.contains_column(c2a) - assert cc.contains_column(c2b) + def test_remove(self): + + c1, c2, c3 = column("c1"), column("c2"), column("c3") + cc = DedupeColumnCollection( + columns=[("c1", c1), ("c2", c2), ("c3", c3)] + ) ci = cc.as_immutable() - eq_(ci._all_columns, [c1, c2a, c3, c2b]) - eq_(list(ci), [c1, c2b, c3]) - def test_dupes_update(self): - cc = sql.ColumnCollection() + eq_(cc._all_columns, [c1, c2, c3]) + eq_(list(cc), [c1, c2, c3]) + assert cc.contains_column(c2) + assert "c2" in cc + + eq_(ci._all_columns, [c1, c2, c3]) + eq_(list(ci), [c1, c2, c3]) + assert ci.contains_column(c2) + assert "c2" in ci + + cc.remove(c2) + + eq_(cc._all_columns, [c1, c3]) + eq_(list(cc), [c1, c3]) + is_(cc[0], c1) + is_(cc[1], c3) + assert not cc.contains_column(c2) + assert "c2" not in cc + self._assert_collection_integrity(cc) + + eq_(ci._all_columns, [c1, c3]) + eq_(list(ci), [c1, c3]) + is_(ci[0], c1) + is_(ci[1], c3) + assert not ci.contains_column(c2) + assert "c2" not in ci + + assert_raises(IndexError, lambda: ci[2]) + + def test_remove_doesnt_change_iteration(self): + + c1, c2, c3, c4, c5 = ( + column("c1"), + column("c2"), + column("c3"), + column("c4"), + column("c5"), + ) + + cc = DedupeColumnCollection( + columns=[ + ("c1", c1), + ("c2", c2), + ("c3", c3), + ("c4", c4), + ("c5", c5), + ] + ) + + for col in cc: + if col.name not in ["c1", "c2"]: + cc.remove(col) + + eq_(cc.keys(), ["c1", "c2"]) + eq_([c.name for c in cc], ["c1", "c2"]) + self._assert_collection_integrity(cc) + + def test_dupes_extend(self): + cc = DedupeColumnCollection() + ci = cc.as_immutable() c1, c2a, c3, c2b = ( column("c1"), @@ -698,20 +1040,29 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): cc.add(c1) cc.add(c2a) - cc.update([(c3.key, c3), (c2b.key, c2b)]) + cc.extend([c3, c2b]) # this should remove c2a - eq_(cc._all_columns, [c1, c2a, c3, c2b]) + eq_(cc._all_columns, [c1, c2b, c3]) + eq_(list(cc), [c1, c2b, c3]) + is_(cc[1], c2b) + is_(cc[2], c3) + assert_raises(IndexError, lambda: cc[3]) + self._assert_collection_integrity(cc) - assert cc.contains_column(c2a) + assert not cc.contains_column(c2a) assert cc.contains_column(c2b) - # for iter, c2a is replaced by c2b, ordering - # is maintained in that way. ideally, iter would be - # the same as the "_all_columns" collection. - eq_(list(cc), [c1, c2b, c3]) + eq_(ci._all_columns, [c1, c2b, c3]) + eq_(list(ci), [c1, c2b, c3]) + is_(ci[1], c2b) + is_(ci[2], c3) + assert_raises(IndexError, lambda: ci[3]) - def test_extend_existing(self): - cc = sql.ColumnCollection() + assert not ci.contains_column(c2a) + assert ci.contains_column(c2b) + + def test_extend_existing_maintains_ordering(self): + cc = DedupeColumnCollection() c1, c2, c3, c4, c5 = ( column("c1"), @@ -723,32 +1074,16 @@ class ColumnCollectionTest(testing.AssertsCompiledSQL, fixtures.TestBase): cc.extend([c1, c2]) eq_(cc._all_columns, [c1, c2]) + self._assert_collection_integrity(cc) cc.extend([c3]) eq_(cc._all_columns, [c1, c2, c3]) - cc.extend([c4, c2, c5]) + self._assert_collection_integrity(cc) - eq_(cc._all_columns, [c1, c2, c3, c4, c5]) - - def test_update_existing(self): - cc = sql.ColumnCollection() - - c1, c2, c3, c4, c5 = ( - column("c1"), - column("c2"), - column("c3"), - column("c4"), - column("c5"), - ) - - cc.update([("c1", c1), ("c2", c2)]) - eq_(cc._all_columns, [c1, c2]) - - cc.update([("c3", c3)]) - eq_(cc._all_columns, [c1, c2, c3]) - cc.update([("c4", c4), ("c2", c2), ("c5", c5)]) + cc.extend([c4, c2, c5]) eq_(cc._all_columns, [c1, c2, c3, c4, c5]) + self._assert_collection_integrity(cc) class LRUTest(fixtures.TestBase): diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py index 1cabf8963c..f6c19047e7 100644 --- a/test/engine/test_reflection.py +++ b/test/engine/test_reflection.py @@ -280,6 +280,7 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): # test against a table which is already reflected meta3 = MetaData(testing.db) foo = Table("foo", meta3, autoload=True) + foo = Table( "foo", meta3, include_columns=["b", "f", "e"], extend_existing=True ) @@ -308,7 +309,7 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): old_y = Column("y", String) old_q = Column("q", Integer) t2 = Table("t", m2, old_z, old_q) - eq_(t2.primary_key.columns, (t2.c.z,)) + eq_(list(t2.primary_key.columns), [t2.c.z]) t2 = Table( "t", m2, @@ -318,7 +319,11 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): autoload_with=testing.db, ) eq_(set(t2.columns.keys()), set(["x", "y", "z", "q", "id"])) - eq_(t2.primary_key.columns, (t2.c.id,)) + + # this has been the actual behavior, the cols are added together, + # however the test wasn't checking this correctly + eq_(list(t2.primary_key.columns), [t2.c.z, t2.c.id]) + assert t2.c.z is not old_z assert t2.c.y is old_y assert t2.c.z.type._type_affinity is Integer @@ -340,7 +345,7 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): old_y = Column("y", String) old_q = Column("q", Integer) t4 = Table("t", m4, old_z, old_q) - eq_(t4.primary_key.columns, (t4.c.z,)) + eq_(list(t4.primary_key.columns), [t4.c.z]) t4 = Table( "t", m4, @@ -351,7 +356,7 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): autoload_with=testing.db, ) eq_(set(t4.columns.keys()), set(["x", "y", "z", "q", "id"])) - eq_(t4.primary_key.columns, (t4.c.id,)) + eq_(list(t4.primary_key.columns), [t4.c.z, t4.c.id]) assert t4.c.z is old_z assert t4.c.y is old_y assert t4.c.z.type._type_affinity is String @@ -770,6 +775,9 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): ), autoload=True, ) + + # for the thing happening here with the column collection, + # see test/base/test_utils.py-> test_replace_switch_key_name. assert u4.join(a4).onclause.compare(u4.c.u_id == a4.c.id) assert list(u4.primary_key) == [u4.c.u_id] assert len(u4.columns) == 2 diff --git a/test/profiles.txt b/test/profiles.txt index abdc79f968..469dac01c3 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -21,20 +21,20 @@ test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_mysql_pymysql_dbapi test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_mysql_pymysql_dbapiunicode_nocextensions 70,70 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_oracle_cx_oracle_dbapiunicode_cextensions 70,70 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 70,70 -test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_postgresql_psycopg2_dbapiunicode_cextensions 70 -test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 70 -test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_sqlite_pysqlite_dbapiunicode_cextensions 70 -test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 70 +test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_postgresql_psycopg2_dbapiunicode_cextensions 69 +test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 69 +test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_sqlite_pysqlite_dbapiunicode_cextensions 69 +test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_mysql_mysqldb_dbapiunicode_cextensions 73,73,73,73 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_mysql_mysqldb_dbapiunicode_nocextensions 73,73,73,73 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_mysql_pymysql_dbapiunicode_cextensions 73,73 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_mysql_pymysql_dbapiunicode_nocextensions 73,73 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_oracle_cx_oracle_dbapiunicode_cextensions 73 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 73 -test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_postgresql_psycopg2_dbapiunicode_cextensions 73 -test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 73 -test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_sqlite_pysqlite_dbapiunicode_cextensions 73 -test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 73 +test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_postgresql_psycopg2_dbapiunicode_cextensions 72 +test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 72 +test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_sqlite_pysqlite_dbapiunicode_cextensions 72 +test.aaa_profiling.test_compiler.CompileTest.test_insert 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 72 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_select @@ -46,20 +46,20 @@ test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_mysql_pymysql_dbapi test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_mysql_pymysql_dbapiunicode_nocextensions 163,163 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_oracle_cx_oracle_dbapiunicode_cextensions 163,161 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 163,161 -test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_postgresql_psycopg2_dbapiunicode_cextensions 169 -test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 169 -test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_sqlite_pysqlite_dbapiunicode_cextensions 169 -test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 169 +test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_postgresql_psycopg2_dbapiunicode_cextensions 165 +test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 165 +test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_sqlite_pysqlite_dbapiunicode_cextensions 165 +test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 165 test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_mysql_mysqldb_dbapiunicode_cextensions 176,176,176,176 test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_mysql_mysqldb_dbapiunicode_nocextensions 176,176,176,176 test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_mysql_pymysql_dbapiunicode_cextensions 176,176 test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_mysql_pymysql_dbapiunicode_nocextensions 176,176 test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_oracle_cx_oracle_dbapiunicode_cextensions 176 test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 176 -test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_postgresql_psycopg2_dbapiunicode_cextensions 182 -test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 182 -test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_sqlite_pysqlite_dbapiunicode_cextensions 182 -test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 182 +test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_postgresql_psycopg2_dbapiunicode_cextensions 177 +test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 177 +test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_sqlite_pysqlite_dbapiunicode_cextensions 177 +test.aaa_profiling.test_compiler.CompileTest.test_select 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 177 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_select_labels @@ -71,20 +71,20 @@ test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_mysql_pymysq test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_mysql_pymysql_dbapiunicode_nocextensions 196,196 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_oracle_cx_oracle_dbapiunicode_cextensions 196,194 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 196,194 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_postgresql_psycopg2_dbapiunicode_cextensions 202 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 202 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_sqlite_pysqlite_dbapiunicode_cextensions 202 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 202 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_postgresql_psycopg2_dbapiunicode_cextensions 198 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 198 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_sqlite_pysqlite_dbapiunicode_cextensions 198 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 198 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_mysql_mysqldb_dbapiunicode_cextensions 209,209,209,209 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_mysql_mysqldb_dbapiunicode_nocextensions 209,209,209,209 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_mysql_pymysql_dbapiunicode_cextensions 209,209 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_mysql_pymysql_dbapiunicode_nocextensions 209,209 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_oracle_cx_oracle_dbapiunicode_cextensions 209 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 209 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_postgresql_psycopg2_dbapiunicode_cextensions 215 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 215 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_sqlite_pysqlite_dbapiunicode_cextensions 215 -test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 215 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_postgresql_psycopg2_dbapiunicode_cextensions 210 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 210 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_sqlite_pysqlite_dbapiunicode_cextensions 210 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 210 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_update @@ -96,20 +96,20 @@ test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_mysql_pymysql_dbapi test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_mysql_pymysql_dbapiunicode_nocextensions 80,80 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_oracle_cx_oracle_dbapiunicode_cextensions 82,80 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 82,80 -test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_postgresql_psycopg2_dbapiunicode_cextensions 82 -test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 82 -test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_sqlite_pysqlite_dbapiunicode_cextensions 82 -test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 82 +test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_postgresql_psycopg2_dbapiunicode_cextensions 81 +test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 81 +test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_sqlite_pysqlite_dbapiunicode_cextensions 81 +test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 81 test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_mysql_mysqldb_dbapiunicode_cextensions 83,81,81,81 test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_mysql_mysqldb_dbapiunicode_nocextensions 83,81,81,81 test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_mysql_pymysql_dbapiunicode_cextensions 81,81 test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_mysql_pymysql_dbapiunicode_nocextensions 81,81 test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_oracle_cx_oracle_dbapiunicode_cextensions 83 test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 83 -test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_postgresql_psycopg2_dbapiunicode_cextensions 83 -test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 83 -test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_sqlite_pysqlite_dbapiunicode_cextensions 83 -test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 83 +test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_postgresql_psycopg2_dbapiunicode_cextensions 82 +test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 82 +test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_sqlite_pysqlite_dbapiunicode_cextensions 82 +test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 82 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause @@ -121,93 +121,99 @@ test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_p test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_pymysql_dbapiunicode_nocextensions 158,158 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_dbapiunicode_cextensions 158,156 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 158,156 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_cextensions 161 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 161 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_cextensions 161 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 161 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_cextensions 160 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 160 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_cextensions 160 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 160 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_mysqldb_dbapiunicode_cextensions 158,158,158,158 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_mysqldb_dbapiunicode_nocextensions 158,158,158,158 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_pymysql_dbapiunicode_cextensions 158,158 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_pymysql_dbapiunicode_nocextensions 158,158 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_oracle_cx_oracle_dbapiunicode_cextensions 158 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 158 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_cextensions 161 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 161 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_cextensions 161 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 161 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_cextensions 160 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 160 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_cextensions 160 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 160 # TEST: test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members -test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 4638 -test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 3.7_sqlite_pysqlite_dbapiunicode_cextensions 942 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1324 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1324 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1324 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1324 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 3.7_postgresql_psycopg2_dbapiunicode_cextensions 924 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 924 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 3.7_sqlite_pysqlite_dbapiunicode_cextensions 924 +test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 924 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_mysql_mysqldb_dbapiunicode_cextensions 51975 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_mysql_mysqldb_dbapiunicode_nocextensions 54975 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_oracle_cx_oracle_dbapiunicode_cextensions 52014 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 49599 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 52599 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 49185 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 52185 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 48598 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 51598 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 48184 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51184 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_mysql_mysqldb_dbapiunicode_cextensions 54378 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_mysql_mysqldb_dbapiunicode_nocextensions 57978 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 57517 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 52502 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 55702 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_sqlite_pysqlite_dbapiunicode_cextensions 51596 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 54796 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 51501 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 54701 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_sqlite_pysqlite_dbapiunicode_cextensions 50995 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 53795 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_mysql_mysqldb_dbapiunicode_cextensions 51972 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_mysql_mysqldb_dbapiunicode_nocextensions 54972 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_oracle_cx_oracle_dbapiunicode_cextensions 51972 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 49572 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 52572 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 49156 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 52156 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 48572 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 51572 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 48156 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51156 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_mysql_mysqldb_dbapiunicode_cextensions 54364 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_mysql_mysqldb_dbapiunicode_nocextensions 57964 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 57464 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 52464 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 55664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_sqlite_pysqlite_dbapiunicode_cextensions 51556 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 54756 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 51464 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 54664 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_sqlite_pysqlite_dbapiunicode_cextensions 50956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 53756 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_mysql_mysqldb_dbapiunicode_cextensions 49677 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_mysql_mysqldb_dbapiunicode_nocextensions 52677 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_oracle_cx_oracle_dbapiunicode_cextensions 49677 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 47277 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 50277 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46861 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49861 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 46277 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 49277 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45861 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48861 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_mysql_mysqldb_dbapiunicode_cextensions 51472 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_mysql_mysqldb_dbapiunicode_nocextensions 55072 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 54572 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 49572 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 52772 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51864 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 48572 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 51772 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48064 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 50864 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_mysql_mysqldb_dbapiunicode_cextensions 49772 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_mysql_mysqldb_dbapiunicode_nocextensions 52772 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_oracle_cx_oracle_dbapiunicode_cextensions 49772 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 47372 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 50372 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46956 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 46372 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 49372 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48956 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_mysql_mysqldb_dbapiunicode_cextensions 51564 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_mysql_mysqldb_dbapiunicode_nocextensions 55164 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 54664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 49664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 52864 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48756 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 48664 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 51864 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48156 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 50956 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle @@ -231,34 +237,34 @@ test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.7_sqlite_pysq test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_mysql_mysqldb_dbapiunicode_cextensions 49677 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_mysql_mysqldb_dbapiunicode_nocextensions 52677 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_oracle_cx_oracle_dbapiunicode_cextensions 49677 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 47277 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 50277 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46861 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49861 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 46277 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 49277 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45861 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48861 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_mysql_mysqldb_dbapiunicode_cextensions 51472 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_mysql_mysqldb_dbapiunicode_nocextensions 55072 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 54572 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 49572 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 52772 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51864 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 48572 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 51772 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48064 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 50864 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_mysql_mysqldb_dbapiunicode_cextensions 49772 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_mysql_mysqldb_dbapiunicode_nocextensions 52772 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_oracle_cx_oracle_dbapiunicode_cextensions 49772 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 47372 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 50372 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46956 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 49956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_cextensions 46372 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 49372 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48956 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_mysql_mysqldb_dbapiunicode_cextensions 51564 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_mysql_mysqldb_dbapiunicode_nocextensions 55164 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 54664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 49664 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 52864 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48756 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 51956 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 48664 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 51864 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 48156 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 50956 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations @@ -274,7 +280,7 @@ test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 31009 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 28709 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 30409 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 28001 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 28401 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 29701 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations @@ -291,7 +297,7 @@ test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 31109 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_cextensions 28809 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 30509 -test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 28101 +test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_cextensions 28501 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 29801 # TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set @@ -388,18 +394,18 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_mysql_mysqldb_dba test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_mysql_mysqldb_dbapiunicode_nocextensions 26204 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_oracle_cx_oracle_dbapiunicode_cextensions 17299 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 44316 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycopg2_dbapiunicode_cextensions 17216 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 26221 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_cextensions 17196 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26201 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycopg2_dbapiunicode_cextensions 17210 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 26215 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_cextensions 17190 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26195 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_mysql_mysqldb_dbapiunicode_cextensions 18218 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_mysql_mysqldb_dbapiunicode_nocextensions 27225 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_oracle_cx_oracle_dbapiunicode_cextensions 18306 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 27313 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_postgresql_psycopg2_dbapiunicode_cextensions 18250 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 27257 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_sqlite_pysqlite_dbapiunicode_cextensions 18223 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 27230 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_postgresql_psycopg2_dbapiunicode_cextensions 18244 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 27251 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_sqlite_pysqlite_dbapiunicode_cextensions 18217 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 27224 # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols @@ -424,62 +430,32 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.7_sqlite_pys # TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mssql_pyodbc_dbapiunicode_cextensions 418033 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mssql_pyodbc_dbapiunicode_nocextensions 418033 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mysql_mysqldb_dbapiunicode_cextensions 419084 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_mysql_mysqldb_dbapiunicode_nocextensions 419094 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_oracle_cx_oracle_dbapiunicode_cextensions 418945 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 418945 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_cextensions 439576 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 439581 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_cextensions 439566 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 439576 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_mysql_mysqldb_dbapiunicode_cextensions 455858 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_mysql_mysqldb_dbapiunicode_nocextensions 455858 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_oracle_cx_oracle_dbapiunicode_cextensions 455708 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 455708 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_postgresql_psycopg2_dbapiunicode_cextensions 476346 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 476346 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_sqlite_pysqlite_dbapiunicode_cextensions 476346 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 476346 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_cextensions 449362 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 449357 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_cextensions 449357 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 449362 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_postgresql_psycopg2_dbapiunicode_cextensions 488504 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 488504 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_sqlite_pysqlite_dbapiunicode_cextensions 488504 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 488504 # TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_mssql_pyodbc_dbapiunicode_cextensions 466544 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_mssql_pyodbc_dbapiunicode_nocextensions 479246 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_mysql_mysqldb_dbapiunicode_cextensions 448590 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_mysql_mysqldb_dbapiunicode_nocextensions 461390 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_oracle_cx_oracle_dbapiunicode_cextensions 553130 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 565832 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_postgresql_psycopg2_dbapiunicode_cextensions 448488 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 461288 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 444802 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 457602 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_mysql_mysqldb_dbapiunicode_cextensions 453303 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_mysql_mysqldb_dbapiunicode_nocextensions 466303 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_oracle_cx_oracle_dbapiunicode_cextensions 557941 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 570941 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_postgresql_psycopg2_dbapiunicode_cextensions 469901 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 482999 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_sqlite_pysqlite_dbapiunicode_cextensions 451115 -test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 464213 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_postgresql_psycopg2_dbapiunicode_cextensions 447788 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 460588 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 444102 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 456902 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_postgresql_psycopg2_dbapiunicode_cextensions 469298 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 482298 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_sqlite_pysqlite_dbapiunicode_cextensions 450512 +test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 463512 # 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_mssql_pyodbc_dbapiunicode_cextensions 21984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mssql_pyodbc_dbapiunicode_nocextensions 21984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_dbapiunicode_cextensions 21984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_dbapiunicode_nocextensions 21984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_oracle_cx_oracle_dbapiunicode_cextensions 21984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 21984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 21984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 21984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 21984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 21984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_mysql_mysqldb_dbapiunicode_cextensions 22984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_mysql_mysqldb_dbapiunicode_nocextensions 22984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_oracle_cx_oracle_dbapiunicode_cextensions 22984 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 22984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_postgresql_psycopg2_dbapiunicode_cextensions 22984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 22984 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.7_sqlite_pysqlite_dbapiunicode_cextensions 22984 @@ -487,45 +463,25 @@ 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 2.7_mssql_pyodbc_dbapiunicode_cextensions 89778 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mssql_pyodbc_dbapiunicode_nocextensions 91530 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_dbapiunicode_cextensions 99964 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_dbapiunicode_nocextensions 101765 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_oracle_cx_oracle_dbapiunicode_cextensions 97720 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 99521 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 91217 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 92969 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 89968 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 91771 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_mysql_mysqldb_dbapiunicode_cextensions 102537 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_mysql_mysqldb_dbapiunicode_nocextensions 104291 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_oracle_cx_oracle_dbapiunicode_cextensions 99793 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 101547 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_postgresql_psycopg2_dbapiunicode_cextensions 94292 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 96046 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_sqlite_pysqlite_dbapiunicode_cextensions 92043 -test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 93797 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_cextensions 91469 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 93221 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 90220 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 91972 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_postgresql_psycopg2_dbapiunicode_cextensions 94544 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 96298 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_sqlite_pysqlite_dbapiunicode_cextensions 92295 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 94049 # 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_mssql_pyodbc_dbapiunicode_cextensions 18454 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mssql_pyodbc_dbapiunicode_nocextensions 18630 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_dbapiunicode_cextensions 18768 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_dbapiunicode_nocextensions 18992 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_oracle_cx_oracle_dbapiunicode_cextensions 19043 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 19316 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_cextensions 18343 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 18567 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_cextensions 18206 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 18430 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_mysql_mysqldb_dbapiunicode_cextensions 19415 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_mysql_mysqldb_dbapiunicode_nocextensions 19659 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_oracle_cx_oracle_dbapiunicode_cextensions 19707 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 19939 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_postgresql_psycopg2_dbapiunicode_cextensions 19014 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 19258 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_sqlite_pysqlite_dbapiunicode_cextensions 18880 -test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 19124 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_cextensions 18297 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 18521 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_cextensions 18262 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 18486 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_postgresql_psycopg2_dbapiunicode_cextensions 19019 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 19263 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_sqlite_pysqlite_dbapiunicode_cextensions 18885 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 19129 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_load @@ -535,18 +491,18 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiuni test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1213 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_oracle_cx_oracle_dbapiunicode_cextensions 1111 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 1128 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1142 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1159 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_cextensions 998 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1015 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1143 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1160 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_cextensions 999 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1016 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_mysql_mysqldb_dbapiunicode_cextensions 1242 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_mysql_mysqldb_dbapiunicode_nocextensions 1261 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_oracle_cx_oracle_dbapiunicode_cextensions 1138 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 1157 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_postgresql_psycopg2_dbapiunicode_cextensions 1162 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 1181 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_sqlite_pysqlite_dbapiunicode_cextensions 1033 -test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 1052 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_postgresql_psycopg2_dbapiunicode_cextensions 1163 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 1182 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_sqlite_pysqlite_dbapiunicode_cextensions 1034 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 1053 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_no_load @@ -577,18 +533,18 @@ test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_mysql_mysqldb_dbapiuni test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_mysql_mysqldb_dbapiunicode_nocextensions 6840 test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_oracle_cx_oracle_dbapiunicode_cextensions 6360 test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 8190 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_postgresql_psycopg2_dbapiunicode_cextensions 6108 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6658 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_cextensions 6052 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6602 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_postgresql_psycopg2_dbapiunicode_cextensions 6100 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6650 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_cextensions 6044 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6594 test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_mysql_mysqldb_dbapiunicode_cextensions 6483 test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_mysql_mysqldb_dbapiunicode_nocextensions 7143 test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_oracle_cx_oracle_dbapiunicode_cextensions 6473 test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 7043 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_postgresql_psycopg2_dbapiunicode_cextensions 6391 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 6961 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_sqlite_pysqlite_dbapiunicode_cextensions 6253 -test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 6823 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_postgresql_psycopg2_dbapiunicode_cextensions 6383 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 6953 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_sqlite_pysqlite_dbapiunicode_cextensions 6335 +test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 6815 # TEST: test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results @@ -598,18 +554,18 @@ test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_my test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_mysql_mysqldb_dbapiunicode_nocextensions 182353 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_oracle_cx_oracle_dbapiunicode_cextensions 188198 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 192504 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_cextensions 168839 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 173243 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 164747 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 169151 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_cextensions 169005 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 173409 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 164913 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 169317 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_mysql_mysqldb_dbapiunicode_cextensions 183039 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_mysql_mysqldb_dbapiunicode_nocextensions 187847 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_oracle_cx_oracle_dbapiunicode_cextensions 192818 test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 197426 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_postgresql_psycopg2_dbapiunicode_cextensions 175514 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 180222 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_sqlite_pysqlite_dbapiunicode_cextensions 170822 -test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 175530 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_postgresql_psycopg2_dbapiunicode_cextensions 175680 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 180388 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_sqlite_pysqlite_dbapiunicode_cextensions 171188 +test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 175696 # TEST: test.aaa_profiling.test_orm.SessionTest.test_expire_lots @@ -619,18 +575,18 @@ test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_mysql_mysqldb_dbapi test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1147 test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_oracle_cx_oracle_dbapiunicode_cextensions 1156 test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 1142 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1143 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 1136 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1146 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1156 +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 1154 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1155 +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.7_mysql_mysqldb_dbapiunicode_cextensions 1256 test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_mysql_mysqldb_dbapiunicode_nocextensions 1258 test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_oracle_cx_oracle_dbapiunicode_cextensions 1257 test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 1242 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_postgresql_psycopg2_dbapiunicode_cextensions 1276 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 1248 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_sqlite_pysqlite_dbapiunicode_cextensions 1265 -test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 1274 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_postgresql_psycopg2_dbapiunicode_cextensions 1258 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 1261 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_sqlite_pysqlite_dbapiunicode_cextensions 1279 +test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 1250 # TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect @@ -830,20 +786,20 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_mysql_pymysql_db test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_mysql_pymysql_dbapiunicode_nocextensions 137498 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_oracle_cx_oracle_dbapiunicode_cextensions 555 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 45577 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_postgresql_psycopg2_dbapiunicode_cextensions 501 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 15503 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_sqlite_pysqlite_dbapiunicode_cextensions 464 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 15466 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_postgresql_psycopg2_dbapiunicode_cextensions 489 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 15491 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_sqlite_pysqlite_dbapiunicode_cextensions 452 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 15454 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_mysql_mysqldb_dbapiunicode_cextensions 530 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_mysql_mysqldb_dbapiunicode_nocextensions 14534 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_mysql_pymysql_dbapiunicode_cextensions 88288 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_mysql_pymysql_dbapiunicode_nocextensions 102292 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_oracle_cx_oracle_dbapiunicode_cextensions 537 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 14541 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_postgresql_psycopg2_dbapiunicode_cextensions 524 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 14528 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_sqlite_pysqlite_dbapiunicode_cextensions 482 -test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 14486 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_postgresql_psycopg2_dbapiunicode_cextensions 511 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 14515 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_sqlite_pysqlite_dbapiunicode_cextensions 469 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 14473 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_unicode @@ -855,31 +811,31 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_mysql_pymysql_d test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_mysql_pymysql_dbapiunicode_nocextensions 137498 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_oracle_cx_oracle_dbapiunicode_cextensions 555 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 45577 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_postgresql_psycopg2_dbapiunicode_cextensions 501 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 15503 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_sqlite_pysqlite_dbapiunicode_cextensions 464 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 15466 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_postgresql_psycopg2_dbapiunicode_cextensions 489 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 15491 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_sqlite_pysqlite_dbapiunicode_cextensions 452 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 15454 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_mysql_mysqldb_dbapiunicode_cextensions 530 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_mysql_mysqldb_dbapiunicode_nocextensions 14534 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_mysql_pymysql_dbapiunicode_cextensions 88288 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_mysql_pymysql_dbapiunicode_nocextensions 102292 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_oracle_cx_oracle_dbapiunicode_cextensions 537 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 14541 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_postgresql_psycopg2_dbapiunicode_cextensions 524 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 14528 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_sqlite_pysqlite_dbapiunicode_cextensions 482 -test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 14486 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_postgresql_psycopg2_dbapiunicode_cextensions 511 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 14515 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_sqlite_pysqlite_dbapiunicode_cextensions 469 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 14473 # TEST: test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation -test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 6473,328,3985,12867,1217,2209,2667 -test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6517,328,4105,14171,1332,2222,2898 -test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 6189,308,3953,12802,1206,2147,2719 -test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 6272,308,4081,14064,1317,2166,2927 +test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 6472,328,3905,12599,1208,2183,2632 +test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6516,328,4025,13903,1323,2196,2863 +test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 6205,309,3865,12511,1193,2118,2684 +test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 6288,309,3993,13773,1304,2137,2892 # TEST: test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation -test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 7045,414,7183,18831,1234,2854 -test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 7136,419,7303,19900,1340,2889 -test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 7054,406,7379,19439,1224,2924 -test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 7143,411,7515,20550,1327,2966 +test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_cextensions 7056,415,7170,18831,1225,2853 +test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 7146,420,7290,19900,1331,2888 +test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_cextensions 7080,408,7366,19439,1211,2923 +test.aaa_profiling.test_zoomark_orm.ZooMarkTest.test_invocation 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 7176,413,7502,20550,1314,2965 diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index ea1a9bd75a..cd462fb779 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -531,8 +531,7 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): ) def test_dupe_columns(self): - """test that deduping is performed against clause - element identity, not rendered result.""" + """as of 1.4, there's no deduping.""" self.assert_compile( select([column("a"), column("a"), column("a")]), @@ -542,13 +541,15 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): c = column("a") self.assert_compile( - select([c, c, c]), "SELECT a", dialect=default.DefaultDialect() + select([c, c, c]), + "SELECT a, a, a", + dialect=default.DefaultDialect(), ) a, b = column("a"), column("b") self.assert_compile( select([a, b, b, b, a, a]), - "SELECT a, b", + "SELECT a, b, b, b, a, a", dialect=default.DefaultDialect(), ) @@ -560,7 +561,7 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): ) self.assert_compile( select([a, b, c, a, b, c]), - "SELECT a, b, c", + "SELECT a, b, c, a, b, c", dialect=default.DefaultDialect(), ) @@ -584,6 +585,18 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): s = s.compile(dialect=default.DefaultDialect(paramstyle="qmark")) eq_(s.positiontup, ["a", "b", "c"]) + def test_dupe_columns_use_labels(self): + """as of 1.4, there's no deduping. + + however the labels will still uniqify themselves... + """ + + t = table("t", column("a"), column("b")) + self.assert_compile( + select([t.c.a, t.c.a, t.c.b]).apply_labels(), + "SELECT t.a AS t_a, t.a AS t_a_1, t.b AS t_b FROM t", + ) + def test_nested_label_targeting(self): """test nested anonymous label generation. @@ -2050,6 +2063,22 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): {"param_1": 10}, ) + def test_dupe_cols_hey_we_can_union(self): + """test the original inspiration for [ticket:4753].""" + + s1 = select([table1, table1.c.myid]).where(table1.c.myid == 5) + s2 = select([table1, table2.c.otherid]).where( + table1.c.myid == table2.c.otherid + ) + self.assert_compile( + union(s1, s2).order_by(s1.selected_columns.myid), + "SELECT mytable.myid, mytable.name, mytable.description, " + "mytable.myid FROM mytable WHERE mytable.myid = :myid_1 " + "UNION SELECT mytable.myid, mytable.name, mytable.description, " + "myothertable.otherid FROM mytable, myothertable " + "WHERE mytable.myid = myothertable.otherid ORDER BY myid", + ) + def test_compound_grouping(self): s = select([column("foo"), column("bar")]).select_from(text("bat")) @@ -4511,7 +4540,8 @@ class ResultMapTest(fixtures.TestBase): t = table("a", column("x"), column("y"), column("z")) l1, l2, l3 = t.c.z.label("a"), t.c.x.label("b"), t.c.x.label("c") - orig = [t.c.x, t.c.y, l1, l2, l3] + + orig = [t.c.x, t.c.y, l1, t.c.y, l2, t.c.x, l3] # create the statement with some duplicate columns. right now # the behavior is that these redundant columns are deduped. @@ -4520,11 +4550,11 @@ class ResultMapTest(fixtures.TestBase): # so the statement has 7 inner columns... eq_(len(list(stmt.inner_columns)), 7) - # but only exposes 5 of them, the other two are dupes of x and y - eq_(len(stmt.subquery().c), 5) + # 7 are exposed as of 1.4, no more deduping + eq_(len(stmt.subquery().c), 7) - # and when it generates a SELECT it will also render only 5 - eq_(len(stmt._columns_plus_names), 5) + # will render 7 as well + eq_(len(stmt._columns_plus_names), 7) wrapped = stmt._generate() wrapped = wrapped.column( @@ -4543,4 +4573,5 @@ class ResultMapTest(fixtures.TestBase): proxied = [obj[0] for (k, n, obj, type_) in compiled._result_columns] for orig_obj, proxied_obj in zip(orig, proxied): + is_(orig_obj, proxied_obj) diff --git a/test/sql/test_cte.py b/test/sql/test_cte.py index ac46e7d5d9..26f367e9f4 100644 --- a/test/sql/test_cte.py +++ b/test/sql/test_cte.py @@ -815,6 +815,7 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL): "regional_sales_1 " "AS anon_2, regional_sales_1 " 'WHERE orders."order" = :3) SELECT regional_sales_2.anon_1, ' + 'regional_sales_2."order", regional_sales_2."order", ' 'regional_sales_2."order" FROM regional_sales_2', checkpositional=("x", "y", "z"), dialect=dialect, @@ -862,8 +863,9 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL): 'regional_sales_1."order" AS "order" ' "FROM orders, regional_sales_1 AS anon_2, regional_sales_1 " "WHERE orders.\"order\" = 'z') " - 'SELECT regional_sales_2.anon_1, regional_sales_2."order" ' - "FROM regional_sales_2", + "SELECT regional_sales_2.anon_1, " + 'regional_sales_2."order", regional_sales_2."order", ' + 'regional_sales_2."order" FROM regional_sales_2', checkpositional=(), dialect=dialect, literal_binds=True, diff --git a/test/sql/test_join_rewriting.py b/test/sql/test_join_rewriting.py index a966af4e49..573455e7db 100644 --- a/test/sql/test_join_rewriting.py +++ b/test/sql/test_join_rewriting.py @@ -7,6 +7,7 @@ from sqlalchemy import Column from sqlalchemy import exists from sqlalchemy import ForeignKey from sqlalchemy import Integer +from sqlalchemy import literal_column from sqlalchemy import MetaData from sqlalchemy import select from sqlalchemy import Table @@ -14,10 +15,11 @@ from sqlalchemy import testing from sqlalchemy import union from sqlalchemy import util from sqlalchemy.engine import default +from sqlalchemy.sql import elements from sqlalchemy.testing import AssertsCompiledSQL +from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures - m = MetaData() @@ -92,11 +94,15 @@ class _JoinRewriteTestBase(AssertsCompiledSQL): compiled = s.compile(dialect=self.__dialect__) - # column name should be in result map, as we never render - # .key in SQL - for key, col in zip([c.name for c in s.subquery().c], s.inner_columns): - key = key % compiled.anon_map - assert col in compiled._create_result_map()[key][1] + for rec, (name, col) in zip( + compiled._result_columns, s._columns_plus_names + ): + assert col in set(rec[2]) + if ( + not isinstance(name, elements._anonymous_label) + and name is not None + ): + eq_(rec[1], name) _a_bkeyselect_bkey = "" @@ -128,6 +134,48 @@ class _JoinRewriteTestBase(AssertsCompiledSQL): self._test(s, self._a_bc) + def test_a_bc_preserve_dupes(self): + j1 = b.join(c) + j2 = a.join(j1) + + s = ( + select( + [a.c.id, b.c.id, b.c.a_id, c, b.c.a_id, c.c.b_id], + use_labels=True, + ) + .select_from(j2) + .where(b.c.id == 2) + .where(c.c.id == 3) + .order_by(a.c.id, b.c.id, c.c.id) + ) + + self._test(s, self._a_bc_wdupes) + + def test_a_bc_preserve_dupes_anon_map(self): + j1 = b.join(c) + j2 = a.join(j1) + + s = ( + select( + [a.c.id, b.c.id, b.c.a_id, c, b.c.a_id, c.c.b_id], + use_labels=True, + ) + .select_from(j2) + .where(b.c.id == 2) + .where(c.c.id == 3) + ) + + # the anon_map needs to be preserved after the transform + # as the labels are going to be referred to outside of the query + subq = s.subquery() + s2 = ( + select([literal_column("1")]) + .select_from(subq) + .where(subq.c[5] == subq.c[6]) + ) + + self._test(s2, self._a_bc_wdupes_anon_map) + def test_a_bkeyassoc(self): j1 = b_key.join(a_to_b_key) j2 = a.join(j1) @@ -311,6 +359,35 @@ class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase): "ORDER BY a.id, anon_1.b_id, anon_1.c_id" ) + _a_bc_wdupes = ( + "SELECT a.id AS a_id, anon_1.b_id AS b_id, anon_1.b_a_id AS b_a_id, " + "anon_1.c_id AS c_id, anon_1.c_b_id AS c_b_id, " + "anon_1.b_a_id AS b_a_id_1, anon_1.c_b_id AS c_b_id_1 " + "FROM a JOIN " + "(SELECT b.id AS b_id, b.a_id AS b_a_id, c.id AS c_id, " + "c.b_id AS c_b_id " + "FROM b JOIN c ON b.id = c.b_id) AS anon_1 ON a.id = anon_1.b_a_id " + "WHERE anon_1.b_id = :id_1 AND anon_1.c_id = :id_2 " + "ORDER BY a.id, anon_1.b_id, anon_1.c_id" + ) + + _a_bc_wdupes_anon_map = ( + "SELECT 1 FROM (SELECT a.id AS a_id, b.id AS b_id, b.a_id AS b_a_id, " + "c.id AS c_id, c.b_id AS c_b_id, b.a_id AS b_a_id_1, " + "c.b_id AS c_b_id_1 " + "FROM a JOIN (b JOIN c ON b.id = c.b_id) ON a.id = b.a_id " + "WHERE b.id = :id_1 AND c.id = :id_2) AS anon_1 " + "WHERE anon_1.b_a_id_1 = anon_1.c_b_id_1" + ) + + _a_bc_wdupes_anon_map = ( + "SELECT 1 FROM (SELECT a.id AS a_id, b.id AS b_id, b.a_id AS b_a_id, " + "c.id AS c_id, c.b_id AS c_b_id, b.a_id AS b_a_id_1, " + "c.b_id AS c_b_id_1 FROM a JOIN (b JOIN c ON b.id = c.b_id) " + "ON a.id = b.a_id WHERE b.id = :id_1 AND c.id = :id_2) AS anon_1 " + "WHERE anon_1.b_a_id_1 = anon_1.c_b_id_1" + ) + _a_bc_comma_a1_selbc = ( "SELECT a.id AS a_id, a_1.id AS a_1_id, anon_1.b_id AS b_id, " "anon_1.b_a_id AS b_a_id, anon_1.c_id AS c_id, " @@ -346,15 +423,14 @@ class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase): ) _a_bkeyselect_bkey = ( - "SELECT a.id AS a_id, anon_2.anon_1_aid AS anon_1_aid, " - "anon_2.anon_1_bid AS anon_1_bid, anon_2.b_key_id AS b_key_id " - "FROM a JOIN (SELECT anon_1.aid AS anon_1_aid, " - "anon_1.bid AS anon_1_bid, " + "SELECT a.id AS a_id, anon_1.b_key_id AS b_key_id " + "FROM a JOIN (SELECT anon_2.aid AS anon_2_aid, " + "anon_2.bid AS anon_2_bid, " "b_key.id AS b_key_id " "FROM (SELECT a_to_b_key.aid AS aid, a_to_b_key.bid AS bid " - "FROM a_to_b_key) AS anon_1 " - "JOIN b_key ON b_key.id = anon_1.bid) AS anon_2 " - "ON a.id = anon_2.anon_1_aid" + "FROM a_to_b_key) AS anon_2 " + "JOIN b_key ON b_key.id = anon_2.bid) AS anon_1 " + "ON a.id = anon_1.anon_2_aid" ) _a_atobalias_balias_c_w_exists = ( @@ -400,8 +476,8 @@ class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase): _b_a_id_double_overlap_annotated = ( "SELECT anon_1.b_id AS anon_1_b_id, anon_1.b_a_id AS anon_1_b_a_id, " - "anon_1.id_1 AS anon_1_id_1 " - "FROM (SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS id_1 " + "anon_1.b_a_id_1 AS anon_1_b_a_id_1 " + "FROM (SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS b_a_id_2 " "FROM b JOIN b_a ON b.id = b_a.id) AS anon_1" ) @@ -433,6 +509,7 @@ class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase): "FROM a_to_b_key) AS anon_1 JOIN b_key ON b_key.id = anon_1.bid) " "ON a.id = anon_1.aid" ) + _a__b_dc = ( "SELECT a.id AS a_id, b.id AS b_id, " "b.a_id AS b_a_id, c.id AS c_id, " @@ -455,6 +532,25 @@ class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase): "ORDER BY a.id, b.id, c.id" ) + _a_bc_wdupes = ( + "SELECT a.id AS a_id, b.id AS b_id, b.a_id AS b_a_id, c.id AS c_id, " + "c.b_id AS c_b_id, b.a_id AS b_a_id_1, c.b_id AS c_b_id_1 " + "FROM a JOIN " + "(b JOIN c ON b.id = c.b_id) " + "ON a.id = b.a_id " + "WHERE b.id = :id_1 AND c.id = :id_2 " + "ORDER BY a.id, b.id, c.id" + ) + + _a_bc_wdupes_anon_map = ( + "SELECT 1 FROM (SELECT a.id AS a_id, b.id AS b_id, b.a_id AS b_a_id, " + "c.id AS c_id, c.b_id AS c_b_id, b.a_id AS b_a_id_1, " + "c.b_id AS c_b_id_1 " + "FROM a JOIN (b JOIN c ON b.id = c.b_id) ON a.id = b.a_id " + "WHERE b.id = :id_1 AND c.id = :id_2) AS anon_1 " + "WHERE anon_1.b_a_id_1 = anon_1.c_b_id_1" + ) + _a_bc_comma_a1_selbc = ( "SELECT a.id AS a_id, a_1.id AS a_1_id, b.id AS b_id, " "b.a_id AS b_a_id, c.id AS c_id, " @@ -517,8 +613,8 @@ class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase): _b_a_id_double_overlap_annotated = ( "SELECT anon_1.b_id AS anon_1_b_id, anon_1.b_a_id AS anon_1_b_a_id, " - "anon_1.id_1 AS anon_1_id_1 FROM " - "(SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS id_1 " + "anon_1.b_a_id_1 AS anon_1_b_a_id_1 FROM " + "(SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS b_a_id_1 " "FROM b JOIN b_a ON b.id = b_a.id) AS anon_1" ) @@ -573,6 +669,24 @@ class JoinNoUseLabelsTest(_JoinRewriteTestBase, fixtures.TestBase): "ORDER BY a.id, b.id, c.id" ) + _a_bc_wdupes = ( + "SELECT a.id, b.id, b.a_id, c.id, c.b_id, b.a_id, c.b_id " + "FROM a JOIN " + "(b JOIN c ON b.id = c.b_id) " + "ON a.id = b.a_id " + "WHERE b.id = :id_1 AND c.id = :id_2 " + "ORDER BY a.id, b.id, c.id" + ) + + _a_bc_wdupes_anon_map = ( + "SELECT 1 FROM (SELECT a.id AS a_id, b.id AS b_id, b.a_id AS b_a_id, " + "c.id AS c_id, c.b_id AS c_b_id, b.a_id AS b_a_id_1, " + "c.b_id AS c_b_id_1 " + "FROM a JOIN (b JOIN c ON b.id = c.b_id) ON a.id = b.a_id " + "WHERE b.id = :id_1 AND c.id = :id_2) AS anon_1 " + "WHERE anon_1.b_a_id_1 = anon_1.c_b_id_1" + ) + _a_bc_comma_a1_selbc = ( "SELECT a.id, a_1.id, b.id, " "b.a_id, c.id, " @@ -626,8 +740,8 @@ class JoinNoUseLabelsTest(_JoinRewriteTestBase, fixtures.TestBase): ) _b_a_id_double_overlap_annotated = ( - "SELECT anon_1.b_id, anon_1.b_a_id, anon_1.id_1 FROM " - "(SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS id_1 " + "SELECT anon_1.b_id, anon_1.b_a_id, anon_1.b_a_id_1 FROM " + "(SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS b_a_id_1 " "FROM b JOIN b_a ON b.id = b_a.id) AS anon_1" ) @@ -650,6 +764,10 @@ class JoinExecTest(_JoinRewriteTestBase, fixtures.TestBase): __backend__ = True _a_bc = ( + _a_bc_wdupes + ) = ( + _a_bc_wdupes_anon_map + ) = ( _a_bc_comma_a1_selbc ) = ( _a__b_dc diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index 5081cfbd2a..f3fa008c59 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -1518,6 +1518,7 @@ class TableTest(fixtures.TestBase, AssertsCompiledSQL): y = Column("y", Integer) t1 = Table("t", m, Column("x", Integer), y) + # note we are testing immutable column collection here t2 = pickle.loads(pickle.dumps(t1)) z = Column("z", Integer) g = Column("g", Integer) @@ -2530,7 +2531,7 @@ class ConstraintTest(fixtures.TestBase): i = Index("i", t.c.x, _table=t) is_(i.table, t) - eq_(i.columns, [t.c.x]) + eq_(list(i.columns), [t.c.x]) def test_inline_decl_columns(self): m = MetaData() diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 485a0e4281..9bcdd0620e 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -656,27 +656,23 @@ class SelectableTest( s2 = select([table2.c.col1, table2.c.col2, table2.c.col3]) u1 = union(s1, s2).subquery() - with testing.expect_warnings("Column 'col1'"): - u1.c - assert ( u1.corresponding_column(s1.selected_columns._all_columns[0]) is u1.c._all_columns[0] ) - # due to the duplicate key, "col1" is now the column at the end - # of the list and the first column is not accessible by key - assert u1.c.col1 is u1.c._all_columns[2] + # col1 is taken by the first "col1" in the list + assert u1.c.col1 is u1.c._all_columns[0] # table2.c.col1 is in two positions in this union, so...currently # it is the replaced one at position 2. assert u1.corresponding_column(table2.c.col1) is u1.c._all_columns[2] - # this is table2.c.col1 in both cases, so this is "right" - assert u1.corresponding_column(s2.selected_columns.col1) is u1.c.col1 + # this is table2.c.col1, which in the first selectable is in position 2 + assert u1.corresponding_column(s2.selected_columns.col1) is u1.c[2] # same - assert u1.corresponding_column(s2.subquery().c.col1) is u1.c.col1 + assert u1.corresponding_column(s2.subquery().c.col1) is u1.c[2] # col2 is working OK assert u1.corresponding_column(s1.selected_columns.col2) is u1.c.col2 @@ -691,8 +687,8 @@ class SelectableTest( ) assert u1.corresponding_column(s2.subquery().c.col2) is u1.c.col2 - # col3 is also "correct" , though confusing - assert u1.corresponding_column(s2.selected_columns.col3) is u1.c.col1 + # col3 is also "correct" + assert u1.corresponding_column(s2.selected_columns.col3) is u1.c[2] assert u1.corresponding_column(table1.c.col1) is u1.c._all_columns[0] assert u1.corresponding_column(table1.c.col2) is u1.c._all_columns[1] @@ -705,22 +701,23 @@ class SelectableTest( s2 = select([table2.c.col1, table2.c.col2, table2.c.col3]).limit(1) u1 = union(s1, s2).subquery() - with testing.expect_warnings("Column 'col1'"): - u1.c + assert ( + u1.corresponding_column(s1.selected_columns._all_columns[0]) + is u1.c._all_columns[0] + ) - # due to the duplicate key, "col1" is now the column at the end - # of the list and the first column is not accessible by key - assert u1.c.col1 is u1.c._all_columns[2] + # col1 is taken by the first "col1" in the list + assert u1.c.col1 is u1.c._all_columns[0] # table2.c.col1 is in two positions in this union, so...currently # it is the replaced one at position 2. assert u1.corresponding_column(table2.c.col1) is u1.c._all_columns[2] - # this is table2.c.col1 in both cases, so this is "right" - assert u1.corresponding_column(s2.selected_columns.col1) is u1.c.col1 + # this is table2.c.col1, which in the first selectable is in position 2 + assert u1.corresponding_column(s2.selected_columns.col1) is u1.c[2] # same - assert u1.corresponding_column(s2.subquery().c.col1) is u1.c.col1 + assert u1.corresponding_column(s2.subquery().c.col1) is u1.c[2] # col2 is working OK assert u1.corresponding_column(s1.selected_columns.col2) is u1.c.col2 @@ -735,8 +732,8 @@ class SelectableTest( ) assert u1.corresponding_column(s2.subquery().c.col2) is u1.c.col2 - # col3 is also "correct" , though confusing - assert u1.corresponding_column(s2.selected_columns.col3) is u1.c.col1 + # col3 is also "correct" + assert u1.corresponding_column(s2.selected_columns.col3) is u1.c[2] assert u1.corresponding_column(table1.c.col1) is u1.c._all_columns[0] assert u1.corresponding_column(table1.c.col2) is u1.c._all_columns[1] @@ -2610,13 +2607,6 @@ class ReprTest(fixtures.TestBase): class WithLabelsTest(fixtures.TestBase): - def _assert_labels_warning(self, s): - assert_raises_message( - exc.SAWarning, - r"replaced by Column.*, which has the same key", - lambda: s.subquery().c, - ) - def _assert_result_keys(self, s, keys): compiled = s.compile() eq_(set(compiled._create_result_map()), set(keys)) @@ -2633,7 +2623,6 @@ class WithLabelsTest(fixtures.TestBase): def test_names_overlap_nolabel(self): sel = self._names_overlap() - self._assert_labels_warning(sel) self._assert_result_keys(sel, ["x"]) def test_names_overlap_label(self): @@ -2675,10 +2664,16 @@ class WithLabelsTest(fixtures.TestBase): def test_labels_overlap_label(self): sel = self._labels_overlap().apply_labels() t2 = sel.froms[1] - eq_(list(sel.selected_columns.keys()), ["t_x_id", t2.c.id.anon_label]) - eq_(list(sel.subquery().c.keys()), ["t_x_id", t2.c.id.anon_label]) - self._assert_result_keys(sel, ["t_x_id", "id_1"]) - self._assert_subq_result_keys(sel, ["t_x_id", "id_1"]) + eq_( + list(sel.selected_columns.keys()), + ["t_x_id", t2.c.id._label_anon_label], + ) + eq_( + list(sel.subquery().c.keys()), + ["t_x_id", t2.c.id._label_anon_label], + ) + self._assert_result_keys(sel, ["t_x_id", "t_x_id_1"]) + self._assert_subq_result_keys(sel, ["t_x_id", "t_x_id_1"]) def _labels_overlap_keylabels_dont(self): m = MetaData() @@ -2696,7 +2691,7 @@ class WithLabelsTest(fixtures.TestBase): sel = self._labels_overlap_keylabels_dont().apply_labels() eq_(list(sel.selected_columns.keys()), ["t_a", "t_x_b"]) eq_(list(sel.subquery().c.keys()), ["t_a", "t_x_b"]) - self._assert_result_keys(sel, ["t_x_id", "id_1"]) + self._assert_result_keys(sel, ["t_x_id", "t_x_id_1"]) def _keylabels_overlap_labels_dont(self): m = MetaData() @@ -2713,8 +2708,14 @@ class WithLabelsTest(fixtures.TestBase): def test_keylabels_overlap_labels_dont_label(self): sel = self._keylabels_overlap_labels_dont().apply_labels() t2 = sel.froms[1] - eq_(list(sel.selected_columns.keys()), ["t_x_id", t2.c.id.anon_label]) - eq_(list(sel.subquery().c.keys()), ["t_x_id", t2.c.id.anon_label]) + eq_( + list(sel.selected_columns.keys()), + ["t_x_id", t2.c.id._label_anon_label], + ) + eq_( + list(sel.subquery().c.keys()), + ["t_x_id", t2.c.id._label_anon_label], + ) self._assert_result_keys(sel, ["t_a", "t_x_b"]) self._assert_subq_result_keys(sel, ["t_a", "t_x_b"]) @@ -2734,10 +2735,13 @@ class WithLabelsTest(fixtures.TestBase): def test_keylabels_overlap_labels_overlap_label(self): sel = self._keylabels_overlap_labels_overlap().apply_labels() t2 = sel.froms[1] - eq_(list(sel.selected_columns.keys()), ["t_x_a", t2.c.a.anon_label]) - eq_(list(sel.subquery().c.keys()), ["t_x_a", t2.c.a.anon_label]) - self._assert_result_keys(sel, ["t_x_id", "id_1"]) - self._assert_subq_result_keys(sel, ["t_x_id", "id_1"]) + eq_( + list(sel.selected_columns.keys()), + ["t_x_a", t2.c.a._label_anon_label], + ) + eq_(list(sel.subquery().c.keys()), ["t_x_a", t2.c.a._label_anon_label]) + self._assert_result_keys(sel, ["t_x_id", "t_x_id_1"]) + self._assert_subq_result_keys(sel, ["t_x_id", "t_x_id_1"]) def _keys_overlap_names_dont(self): m = MetaData() @@ -2747,7 +2751,6 @@ class WithLabelsTest(fixtures.TestBase): def test_keys_overlap_names_dont_nolabel(self): sel = self._keys_overlap_names_dont() - self._assert_labels_warning(sel) self._assert_result_keys(sel, ["a", "b"]) def test_keys_overlap_names_dont_label(self):