diff options
30 files changed, 597 insertions, 74 deletions
diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 211668867..82e65272b 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -7,6 +7,57 @@ :version: 0.8.2 .. change:: + :tags: bug, mysql + :tickets: 2721 + + The ``deferrable`` keyword argument on :class:`.ForeignKey` and + :class:`.ForeignKeyConstraint` will not render the ``DEFERRABLE`` keyword + on the MySQL dialect. For a long time we left this in place because + a non-deferrable foreign key would act very differently than a deferrable + one, but some environments just disable FKs on MySQL, so we'll be less + opinionated here. + + .. change:: + :tags: bug, ext, orm + :tickets: 2730 + + Fixed bug where :class:`.MutableDict` didn't report a change event + when ``clear()`` was called. + + .. change:: + :tags: bug, sql + :tickets: 2738 + + Fixed bug whereby joining a select() of a table "A" with multiple + foreign key paths to a table "B", to that table "B", would fail + to produce the "ambiguous join condition" error that would be + reported if you join table "A" directly to "B"; it would instead + produce a join condition with multiple criteria. + + .. change:: + :tags: bug, sql, reflection + :tickets: 2728 + + Fixed bug whereby using :meth:`.MetaData.reflect` across a remote + schema as well as a local schema could produce wrong results + in the case where both schemas had a table of the same name. + + .. change:: + :tags: bug, sql + :tickets: 2726 + + Removed the "not implemented" ``__iter__()`` call from the base + :class:`.ColumnOperators` class, while this was introduced + in 0.8.0 to prevent an endless, memory-growing loop when one also + implements a ``__getitem__()`` method on a custom + operator and then calls erroneously ``list()`` on that object, + it had the effect of causing column elements to report that they + were in fact iterable types which then throw an error when you try + to iterate. There's no real way to have both sides here so we + stick with Python best practices. Careful with implementing + ``__getitem__()`` on your custom operators! + + .. change:: :tags: feature, orm :tickets: 2736 diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index baddf7e2a..c5ee84a7b 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -7,6 +7,78 @@ :version: 0.9.0 .. change:: + :tags: bug, mysql + :tickets: 2721 + + The ``deferrable`` keyword argument on :class:`.ForeignKey` and + :class:`.ForeignKeyConstraint` will not render the ``DEFERRABLE`` keyword + on the MySQL dialect. For a long time we left this in place because + a non-deferrable foreign key would act very differently than a deferrable + one, but some environments just disable FKs on MySQL, so we'll be less + opinionated here. Also in 0.8.2. + + .. change:: + :tags: bug, ext, orm + :tickets: 2730 + + Fixed bug where :class:`.MutableDict` didn't report a change event + when ``clear()`` was called. Also in 0.8.2 + + .. change:: + :tags: bug, sql + :tickets: 2738 + + Fixed bug whereby joining a select() of a table "A" with multiple + foreign key paths to a table "B", to that table "B", would fail + to produce the "ambiguous join condition" error that would be + reported if you join table "A" directly to "B"; it would instead + produce a join condition with multiple criteria. Also in 0.8.2. + + .. change:: + :tags: bug, sql, reflection + :tickets: 2728 + + Fixed bug whereby using :meth:`.MetaData.reflect` across a remote + schema as well as a local schema could produce wrong results + in the case where both schemas had a table of the same name. + Also in 0.8.2. + + .. change:: + :tags: bug, sql + :tickets: 2726 + + Removed the "not implemented" ``__iter__()`` call from the base + :class:`.ColumnOperators` class, while this was introduced + in 0.8.0 to prevent an endless, memory-growing loop when one also + implements a ``__getitem__()`` method on a custom + operator and then calls erroneously ``list()`` on that object, + it had the effect of causing column elements to report that they + were in fact iterable types which then throw an error when you try + to iterate. There's no real way to have both sides here so we + stick with Python best practices. Careful with implementing + ``__getitem__()`` on your custom operators! Also in 0.8.2. + + .. change:: + :tags: feature, sql + :tickets: 1068 + + A :class:`.Label` construct will now render as its name alone + in an ``ORDER BY`` clause, if that label is also referred to + in the columns clause of the select, instead of rewriting the + full expression. This gives the database a better chance to + optimize the evaulation of the same expression in two different + contexts. + + .. change:: + :tags: feature, firebird + :tickets: 2504 + + The ``fdb`` dialect is now the default dialect when + specified without a dialect qualifier, i.e. ``firebird://``, + per the Firebird project publishing ``fdb`` as their + official Python driver. + + .. change:: :tags: feature, general :tickets: 2671 diff --git a/doc/build/changelog/migration_09.rst b/doc/build/changelog/migration_09.rst index 969bfb624..03c84d8d9 100644 --- a/doc/build/changelog/migration_09.rst +++ b/doc/build/changelog/migration_09.rst @@ -124,4 +124,58 @@ to 0.9 without issue. :ticket:`2736` +Behavioral Improvements +======================= + +Improvements that should produce no compatibility issues, but are good +to be aware of in case there are unexpected issues. + +Label constructs can now render as their name alone in an ORDER BY +------------------------------------------------------------------ + +For the case where a :class:`.Label` is used in both the columns clause +as well as the ORDER BY clause of a SELECT, the label will render as +just it's name in the ORDER BY clause, assuming the underlying dialect +reports support of this feature. + +E.g. an example like:: + + from sqlalchemy.sql import table, column, select, func + + t = table('t', column('c1'), column('c2')) + expr = (func.foo(t.c.c1) + t.c.c2).label("expr") + + stmt = select([expr]).order_by(expr) + + print stmt + +Prior to 0.9 would render as:: + + SELECT foo(t.c1) + t.c2 AS expr + FROM t ORDER BY foo(t.c1) + t.c2 + +And now renders as:: + + SELECT foo(t.c1) + t.c2 AS expr + FROM t ORDER BY expr + +The ORDER BY only renders the label if the label isn't further embedded into an expression within the ORDER BY, other than a simple ``ASC`` or ``DESC``. + +The above format works on all databases tested, but might have compatibility issues with older database versions (MySQL 4? Oracle 8? etc.). Based on user reports we can add rules +that will disable the feature based on database version detection. + +:ticket:`1068` + +Dialect Changes +=============== + +Firebird ``fdb`` is now the default Firebird dialect. +----------------------------------------------------- + +The ``fdb`` dialect is now used if an engine is created without a dialect +specifier, i.e. ``firebird://``. ``fdb`` is a ``kinterbasdb`` compatible +DBAPI which per the Firebird project is now their official Python driver. + +:ticket:`2504` + diff --git a/doc/build/dialects/firebird.rst b/doc/build/dialects/firebird.rst index d5b6b2ffd..d6e9726af 100644 --- a/doc/build/dialects/firebird.rst +++ b/doc/build/dialects/firebird.rst @@ -5,12 +5,12 @@ Firebird .. automodule:: sqlalchemy.dialects.firebird.base -kinterbasdb ------------ - -.. automodule:: sqlalchemy.dialects.firebird.kinterbasdb - fdb --- .. automodule:: sqlalchemy.dialects.firebird.fdb + +kinterbasdb +----------- + +.. automodule:: sqlalchemy.dialects.firebird.kinterbasdb diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py index 784344b82..6b4e3036d 100644 --- a/lib/sqlalchemy/connectors/pyodbc.py +++ b/lib/sqlalchemy/connectors/pyodbc.py @@ -16,9 +16,12 @@ class PyODBCConnector(Connector): driver = 'pyodbc' supports_sane_multi_rowcount = False - # PyODBC unicode is broken on UCS-4 builds - supports_unicode = sys.maxunicode == 65535 - supports_unicode_statements = supports_unicode + + if util.py2k: + # PyODBC unicode is broken on UCS-4 builds + supports_unicode = sys.maxunicode == 65535 + supports_unicode_statements = supports_unicode + supports_native_decimal = True default_paramstyle = 'named' @@ -121,15 +124,19 @@ class PyODBCConnector(Connector): self.freetds_driver_version = dbapi_con.getinfo( pyodbc.SQL_DRIVER_VER) - if not util.py3k: - self.supports_unicode_statements = ( - not self.freetds and not self.easysoft) - if self._user_supports_unicode_binds is not None: - self.supports_unicode_binds = self._user_supports_unicode_binds - else: - self.supports_unicode_binds = ( - not self.freetds or self.freetds_driver_version >= '0.91' - ) and not self.easysoft + self.supports_unicode_statements = ( + not util.py2k or + (not self.freetds and not self.easysoft) + ) + + if self._user_supports_unicode_binds is not None: + self.supports_unicode_binds = self._user_supports_unicode_binds + elif util.py2k: + self.supports_unicode_binds = ( + not self.freetds or self.freetds_driver_version >= '0.91' + ) and not self.easysoft + else: + self.supports_unicode_binds = True # run other initialization which asks for user name, etc. super(PyODBCConnector, self).initialize(connection) diff --git a/lib/sqlalchemy/dialects/firebird/__init__.py b/lib/sqlalchemy/dialects/firebird/__init__.py index 0f4853bfb..e57457a39 100644 --- a/lib/sqlalchemy/dialects/firebird/__init__.py +++ b/lib/sqlalchemy/dialects/firebird/__init__.py @@ -6,7 +6,7 @@ from sqlalchemy.dialects.firebird import base, kinterbasdb, fdb -base.dialect = kinterbasdb.dialect +base.dialect = fdb.dialect from sqlalchemy.dialects.firebird.base import \ SMALLINT, BIGINT, FLOAT, FLOAT, DATE, TIME, \ diff --git a/lib/sqlalchemy/dialects/firebird/fdb.py b/lib/sqlalchemy/dialects/firebird/fdb.py index 292f15c72..8d0bd3d78 100644 --- a/lib/sqlalchemy/dialects/firebird/fdb.py +++ b/lib/sqlalchemy/dialects/firebird/fdb.py @@ -15,11 +15,11 @@ .. versionadded:: 0.8 - Support for the fdb Firebird driver. -Status ------- - -The fdb dialect is new and not yet tested (can't get fdb to build). + .. versionchanged:: 0.9 - The fdb dialect is now the default dialect + under the ``firebird://`` URL space, as ``fdb`` is now the official + Python driver for Firebird. +The dialect currently accepts the same arguments as the Kinterbasdb driver. """ diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index a5d789be1..3c329fe5e 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -1172,6 +1172,7 @@ class MSDialect(default.DefaultDialect): columns = ischema.columns whereclause = self._unicode_cast(columns.c.table_name) == tablename + if owner: whereclause = sql.and_(whereclause, columns.c.table_schema == owner) diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index ad4650f6d..03827edb7 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1567,6 +1567,8 @@ class MySQLDDLCompiler(compiler.DDLCompiler): (self.preparer.format_table(constraint.table), qual, const) + def define_constraint_deferrability(self, constraint): + return "" class MySQLTypeCompiler(compiler.GenericTypeCompiler): def _extend_numeric(self, type_, spec): diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 7d558f5ff..2ad7002c4 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -54,6 +54,8 @@ class DefaultDialect(interfaces.Dialect): supports_native_enum = False supports_native_boolean = False + supports_simple_order_by_label = True + # if the NUMERIC type # returns decimal.Decimal. # *not* the FLOAT type however. diff --git a/lib/sqlalchemy/ext/mutable.py b/lib/sqlalchemy/ext/mutable.py index b1b851f72..ca27f172f 100644 --- a/lib/sqlalchemy/ext/mutable.py +++ b/lib/sqlalchemy/ext/mutable.py @@ -616,6 +616,10 @@ class MutableDict(Mutable, dict): dict.__delitem__(self, key) self.changed() + def clear(self): + dict.clear(self) + self.changed() + @classmethod def coerce(cls, key, value): """Convert plain dictionary to MutableDict.""" diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 3a74cbd59..94df6751c 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -1134,7 +1134,8 @@ class Column(SchemaItem, expression.ColumnClause): information is not transferred. """ - fk = [ForeignKey(f.column) for f in self.foreign_keys] + fk = [ForeignKey(f.column, _constraint=f.constraint) + for f in self.foreign_keys] if name is None and self.name is None: raise exc.InvalidRequestError("Cannot initialize a sub-selectable" " with this Column object until it's 'name' has " @@ -2711,13 +2712,22 @@ class MetaData(SchemaItem): bind.dialect.get_view_names(conn, schema) ) + if schema is not None: + available_w_schema = util.OrderedSet(["%s.%s" % (schema, name) + for name in available]) + else: + available_w_schema = available + current = set(self.tables) if only is None: - load = [name for name in available if name not in current] + load = [name for name, schname in + zip(available, available_w_schema) + if schname not in current] elif util.callable(only): - load = [name for name in available - if name not in current and only(name, self)] + load = [name for name, schname in + zip(available, available_w_schema) + if schname not in current and only(name, self)] else: missing = [name for name in only if name not in available] if missing: diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index c29b45450..dd2a6e08c 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -387,16 +387,22 @@ class SQLCompiler(engine.Compiled): def visit_label(self, label, add_to_result_map=None, within_label_clause=False, - within_columns_clause=False, **kw): + within_columns_clause=False, + render_label_as_label=None, + **kw): # only render labels within the columns clause # or ORDER BY clause of a select. dialect-specific compilers # can modify this behavior. - if within_columns_clause and not within_label_clause: + render_label_with_as = within_columns_clause and not within_label_clause + render_label_only = render_label_as_label is label + + if render_label_only or render_label_with_as: if isinstance(label.name, sql._truncated_label): labelname = self._truncated_identifier("colident", label.name) else: labelname = label.name + if render_label_with_as: if add_to_result_map is not None: add_to_result_map( labelname, @@ -411,6 +417,8 @@ class SQLCompiler(engine.Compiled): **kw) + \ OPERATORS[operators.as_] + \ self.preparer.format_label(label, labelname) + elif render_label_only: + return labelname else: return label.element._compiler_dispatch(self, within_columns_clause=False, @@ -506,7 +514,11 @@ class SQLCompiler(engine.Compiled): def visit_false(self, expr, **kw): return 'false' - def visit_clauselist(self, clauselist, **kwargs): + def visit_clauselist(self, clauselist, order_by_select=None, **kw): + if order_by_select is not None: + return self._order_by_clauselist( + clauselist, order_by_select, **kw) + sep = clauselist.operator if sep is None: sep = " " @@ -514,8 +526,32 @@ class SQLCompiler(engine.Compiled): sep = OPERATORS[clauselist.operator] return sep.join( s for s in - (c._compiler_dispatch(self, **kwargs) - for c in clauselist.clauses) + ( + c._compiler_dispatch(self, **kw) + for c in clauselist.clauses) + if s) + + def _order_by_clauselist(self, clauselist, order_by_select, **kw): + # look through raw columns collection for labels. + # note that its OK we aren't expanding tables and other selectables + # here; we can only add a label in the ORDER BY for an individual + # label expression in the columns clause. + + raw_col = set(l._order_by_label_element.name + for l in order_by_select._raw_columns + if l._order_by_label_element is not None) + + return ", ".join( + s for s in + ( + c._compiler_dispatch(self, + render_label_as_label= + c._order_by_label_element if + c._order_by_label_element is not None and + c._order_by_label_element.name in raw_col + else None, + **kw) + for c in clauselist.clauses) if s) def visit_case(self, clause, **kwargs): @@ -1284,7 +1320,13 @@ class SQLCompiler(engine.Compiled): text += " \nHAVING " + t if select._order_by_clause.clauses: - text += self.order_by_clause(select, **kwargs) + if self.dialect.supports_simple_order_by_label: + order_by_select = select + else: + order_by_select = None + + text += self.order_by_clause(select, + order_by_select=order_by_select, **kwargs) if select._limit is not None or select._offset is not None: text += self.limit_clause(select) if select.for_update: diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index e7ef3cb72..f0c6134e5 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1659,6 +1659,8 @@ class ClauseElement(Visitable): is_selectable = False is_clause_element = True + _order_by_label_element = None + def _clone(self): """Create a shallow copy of this ClauseElement. @@ -3679,6 +3681,13 @@ class UnaryExpression(ColumnElement): self.type = sqltypes.to_instance(type_) self.negate = negate + @util.memoized_property + def _order_by_label_element(self): + if self.modifier in (operators.desc_op, operators.asc_op): + return self.element._order_by_label_element + else: + return None + @property def _from_objects(self): return self.element._from_objects @@ -4327,6 +4336,10 @@ class Label(ColumnElement): self._proxies = [element] @util.memoized_property + def _order_by_label_element(self): + return self + + @util.memoized_property def type(self): return sqltypes.to_instance( self._type or getattr(self._element, 'type', None) diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index 4afb3db48..128442158 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -313,11 +313,6 @@ class ColumnOperators(Operators): """ return self.operate(neg) - def __iter__(self): - """Block calls to list() from calling __getitem__() endlessly.""" - - raise NotImplementedError("Class %s is not iterable" % self.__class__) - def __getitem__(self, index): """Implement the [] operator. diff --git a/lib/sqlalchemy/testing/engines.py b/lib/sqlalchemy/testing/engines.py index efc0103f2..d8c1709e7 100644 --- a/lib/sqlalchemy/testing/engines.py +++ b/lib/sqlalchemy/testing/engines.py @@ -47,13 +47,13 @@ class ConnectionKiller(object): self._safe(rec._close) def _after_test_ctx(self): - pass # this can cause a deadlock with pg8000 - pg8000 acquires # prepared statment lock inside of rollback() - if async gc # is collecting in finalize_fairy, deadlock. - # not sure if this should be if pypy/jython only - #for conn in self.conns: - # self._safe(conn.rollback) + # not sure if this should be if pypy/jython only. + # note that firebird/fdb definitely needs this though + for conn in self.conns: + self._safe(conn.rollback) def _stop_test_ctx(self): if config.options.low_connections: diff --git a/lib/sqlalchemy/testing/suite/__init__.py b/lib/sqlalchemy/testing/suite/__init__.py index f65dd1a34..780aa40aa 100644 --- a/lib/sqlalchemy/testing/suite/__init__.py +++ b/lib/sqlalchemy/testing/suite/__init__.py @@ -2,6 +2,7 @@ from sqlalchemy.testing.suite.test_ddl import * from sqlalchemy.testing.suite.test_insert import * from sqlalchemy.testing.suite.test_sequence import * +from sqlalchemy.testing.suite.test_select import * from sqlalchemy.testing.suite.test_results import * from sqlalchemy.testing.suite.test_update_delete import * from sqlalchemy.testing.suite.test_reflection import * diff --git a/lib/sqlalchemy/testing/suite/test_select.py b/lib/sqlalchemy/testing/suite/test_select.py new file mode 100644 index 000000000..b040c8f25 --- /dev/null +++ b/lib/sqlalchemy/testing/suite/test_select.py @@ -0,0 +1,83 @@ +from .. import fixtures, config +from ..assertions import eq_ + +from sqlalchemy import Integer, String, select, func + +from ..schema import Table, Column + + +class OrderByLabelTest(fixtures.TablesTest): + """Test the dialect sends appropriate ORDER BY expressions when + labels are used. + + This essentially exercises the "supports_simple_order_by_label" + setting. + + """ + @classmethod + def define_tables(cls, metadata): + Table("some_table", metadata, + Column('id', Integer, primary_key=True), + Column('x', Integer), + Column('y', Integer), + Column('q', String(50)), + Column('p', String(50)) + ) + + @classmethod + def insert_data(cls): + config.db.execute( + cls.tables.some_table.insert(), + [ + {"id": 1, "x": 1, "y": 2, "q": "q1", "p": "p3"}, + {"id": 2, "x": 2, "y": 3, "q": "q2", "p": "p2"}, + {"id": 3, "x": 3, "y": 4, "q": "q3", "p": "p1"}, + ] + ) + + def _assert_result(self, select, result): + eq_( + config.db.execute(select).fetchall(), + result + ) + + def test_plain(self): + table = self.tables.some_table + lx = table.c.x.label('lx') + self._assert_result( + select([lx]).order_by(lx), + [(1, ), (2, ), (3, )] + ) + + def test_composed_int(self): + table = self.tables.some_table + lx = (table.c.x + table.c.y).label('lx') + self._assert_result( + select([lx]).order_by(lx), + [(3, ), (5, ), (7, )] + ) + + def test_composed_multiple(self): + table = self.tables.some_table + lx = (table.c.x + table.c.y).label('lx') + ly = (func.lower(table.c.q) + table.c.p).label('ly') + self._assert_result( + select([lx, ly]).order_by(lx, ly.desc()), + [(3, u'q1p3'), (5, u'q2p2'), (7, u'q3p1')] + ) + + def test_plain_desc(self): + table = self.tables.some_table + lx = table.c.x.label('lx') + self._assert_result( + select([lx]).order_by(lx.desc()), + [(3, ), (2, ), (1, )] + ) + + def test_composed_int_desc(self): + table = self.tables.some_table + lx = (table.c.x + table.c.y).label('lx') + self._assert_result( + select([lx]).order_by(lx.desc()), + [(7, ), (5, ), (3, )] + ) @@ -32,6 +32,7 @@ pg8000=postgresql+pg8000://scott:tiger@127.0.0.1:5432/test postgresql_jython=postgresql+zxjdbc://scott:tiger@127.0.0.1:5432/test mysql_jython=mysql+zxjdbc://scott:tiger@127.0.0.1:5432/test mysql=mysql://scott:tiger@127.0.0.1:3306/test +mssql=mssql+pyodbc://scott:tiger@ms_2005 oursql=mysql+oursql://scott:tiger@127.0.0.1:3306/test pymysql=mysql+pymysql://scott:tiger@127.0.0.1:3306/test?use_unicode=0&charset=utf8 oracle=oracle://scott:tiger@127.0.0.1:1521 diff --git a/test/dialect/test_mysql.py b/test/dialect/test_mysql.py index 728098d3a..2c459dead 100644 --- a/test/dialect/test_mysql.py +++ b/test/dialect/test_mysql.py @@ -82,6 +82,19 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "PRIMARY KEY (data) USING btree)", dialect=mysql.dialect()) + def test_skip_deferrable_kw(self): + m = MetaData() + t1 = Table('t1', m, Column('id', Integer, primary_key=True)) + t2 = Table('t2', m, Column('id', Integer, + ForeignKey('t1.id', deferrable=True), + primary_key=True)) + + self.assert_compile( + schema.CreateTable(t2), + "CREATE TABLE t2 (id INTEGER NOT NULL, " + "PRIMARY KEY (id), FOREIGN KEY(id) REFERENCES t1 (id))" + ) + class DialectTest(fixtures.TestBase): __only_on__ = 'mysql' diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py index a562ef73b..ac0fa5153 100644 --- a/test/engine/test_reflection.py +++ b/test/engine/test_reflection.py @@ -1146,15 +1146,13 @@ class UnicodeReflectionTest(fixtures.TestBase): class SchemaTest(fixtures.TestBase): @testing.requires.schemas - @testing.fails_on_everything_except("postgresql", "unimplemented feature") + @testing.requires.cross_schema_fk_reflection def test_has_schema(self): eq_(testing.db.dialect.has_schema(testing.db, 'test_schema'), True) eq_(testing.db.dialect.has_schema(testing.db, 'sa_fake_schema_123'), False) - @testing.crashes('firebird', 'No schema support') + @testing.requires.schemas @testing.fails_on('sqlite', 'FIXME: unknown') - # fixme: revisit these below. - @testing.fails_on('access', 'FIXME: unknown') @testing.fails_on('sybase', 'FIXME: unknown') def test_explicit_default_schema(self): engine = testing.db @@ -1193,9 +1191,7 @@ class SchemaTest(fixtures.TestBase): finally: metadata.drop_all() - @testing.crashes('firebird', 'No schema support') - # fixme: revisit these below. - @testing.fails_on('access', 'FIXME: unknown') + @testing.requires.schemas @testing.fails_on('sybase', 'FIXME: unknown') def test_explicit_default_schema_metadata(self): engine = testing.db @@ -1245,6 +1241,31 @@ class SchemaTest(fixtures.TestBase): 'test_schema.email_addresses']) ) + @testing.requires.schemas + @testing.requires.cross_schema_fk_reflection + @testing.provide_metadata + def test_reflect_all_schemas_default_overlap(self): + t1 = Table('t', self.metadata, + Column('id', Integer, primary_key=True)) + + t2 = Table('t', self.metadata, + Column('id1', sa.ForeignKey('t.id')), + schema="test_schema" + ) + + self.metadata.create_all() + m2 = MetaData() + m2.reflect(testing.db, schema="test_schema") + + m3 = MetaData() + m3.reflect(testing.db) + m3.reflect(testing.db, schema="test_schema") + + eq_( + set((t.name, t.schema) for t in m2.tables.values()), + set((t.name, t.schema) for t in m3.tables.values()) + ) + diff --git a/test/ext/test_mutable.py b/test/ext/test_mutable.py index 4516e3ac2..bda9e5382 100644 --- a/test/ext/test_mutable.py +++ b/test/ext/test_mutable.py @@ -74,6 +74,18 @@ class _MutableDictTestBase(object): eq_(f1.data, {'a': 'c'}) + def test_clear(self): + sess = Session() + + f1 = Foo(data={'a': 'b'}) + sess.add(f1) + sess.commit() + + f1.data.clear() + sess.commit() + + eq_(f1.data, {}) + def test_replace(self): sess = Session() f1 = Foo(data={'a': 'b'}) diff --git a/test/orm/test_eager_relations.py b/test/orm/test_eager_relations.py index d59d515f4..52f45a2d4 100644 --- a/test/orm/test_eager_relations.py +++ b/test/orm/test_eager_relations.py @@ -1386,8 +1386,7 @@ class SubqueryAliasingTest(fixtures.MappedTest, testing.AssertsCompiledSQL): "AS anon_1_a_id, b_1.id AS b_1_id, b_1.a_id AS " "b_1_a_id, b_1.value AS b_1_value FROM (SELECT " "(SELECT sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) " - "AS anon_2, a.id AS a_id FROM a ORDER BY (SELECT " - "sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) " + "AS anon_2, a.id AS a_id FROM a ORDER BY anon_2 " "LIMIT :param_1) AS anon_1 LEFT OUTER JOIN b AS b_1 ON " "anon_1.a_id = b_1.a_id ORDER BY anon_1.anon_2" ) @@ -1409,8 +1408,7 @@ class SubqueryAliasingTest(fixtures.MappedTest, testing.AssertsCompiledSQL): "AS anon_1_a_id, b_1.id AS b_1_id, b_1.a_id AS " "b_1_a_id, b_1.value AS b_1_value FROM (SELECT " "(SELECT sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) " - "AS anon_2, a.id AS a_id FROM a ORDER BY (SELECT " - "sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) DESC " + "AS anon_2, a.id AS a_id FROM a ORDER BY anon_2 DESC " "LIMIT :param_1) AS anon_1 LEFT OUTER JOIN b AS b_1 ON " "anon_1.a_id = b_1.a_id ORDER BY anon_1.anon_2 DESC" ) @@ -1433,8 +1431,7 @@ class SubqueryAliasingTest(fixtures.MappedTest, testing.AssertsCompiledSQL): "AS anon_1_a_id, b_1.id AS b_1_id, b_1.a_id AS " "b_1_a_id, b_1.value AS b_1_value FROM (SELECT " "(SELECT sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) " - "AS anon_2, a.id AS a_id FROM a ORDER BY (SELECT " - "sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) " + "AS anon_2, a.id AS a_id FROM a ORDER BY anon_2 " "LIMIT :param_1) AS anon_1 LEFT OUTER JOIN b AS b_1 ON " "anon_1.a_id = b_1.a_id ORDER BY anon_1.anon_2" ) @@ -1479,8 +1476,7 @@ class SubqueryAliasingTest(fixtures.MappedTest, testing.AssertsCompiledSQL): "AS anon_1_foo, b_1.id AS b_1_id, b_1.a_id AS " "b_1_a_id, b_1.value AS b_1_value FROM (SELECT a.id " "AS a_id, (SELECT sum(b.value) AS sum_1 FROM b WHERE " - "b.a_id = a.id) AS foo FROM a ORDER BY (SELECT " - "sum(b.value) AS sum_1 FROM b WHERE b.a_id = a.id) " + "b.a_id = a.id) AS foo FROM a ORDER BY foo " "LIMIT :param_1) AS anon_1 LEFT OUTER JOIN b AS b_1 " "ON anon_1.a_id = b_1.a_id ORDER BY " "anon_1.foo" diff --git a/test/profiles.txt b/test/profiles.txt index 74c61a07e..4d8964639 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -1,27 +1,29 @@ -# /Users/classic/dev/sqlalchemy/test/profiles.txt +# /mnt/hgfs/classic/dev/sqlalchemy/test/profiles.txt # This file is written out on a per-environment basis. -# For each test in aaa_profiling, the corresponding function and +# For each test in aaa_profiling, the corresponding function and # environment is located within this file. If it doesn't exist, # the test is skipped. -# If a callcount does exist, it is compared to what we received. +# If a callcount does exist, it is compared to what we received. # assertions are raised if the counts do not match. -# -# To add a new callcount test, apply the function_call_count -# decorator and re-run the tests using the --write-profiles +# +# To add a new callcount test, apply the function_call_count +# decorator and re-run the tests using the --write-profiles # option - this file will be rewritten including the new count. -# +# # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert test.aaa_profiling.test_compiler.CompileTest.test_insert 2.6_sqlite_pysqlite_nocextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_mysql_mysqldb_cextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_mysql_mysqldb_nocextensions 67 +test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_oracle_cx_oracle_nocextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_postgresql_psycopg2_cextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_postgresql_psycopg2_nocextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_sqlite_pysqlite_cextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 2.7_sqlite_pysqlite_nocextensions 67 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.2_postgresql_psycopg2_nocextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.2_sqlite_pysqlite_nocextensions 69 +test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_oracle_cx_oracle_nocextensions 71 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_postgresql_psycopg2_nocextensions 69 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_sqlite_pysqlite_nocextensions 69 @@ -30,12 +32,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_sqlite_pysqlite_noc test.aaa_profiling.test_compiler.CompileTest.test_select 2.6_sqlite_pysqlite_nocextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_mysql_mysqldb_cextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_mysql_mysqldb_nocextensions 141 +test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_oracle_cx_oracle_nocextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_postgresql_psycopg2_cextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_postgresql_psycopg2_nocextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_sqlite_pysqlite_cextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 2.7_sqlite_pysqlite_nocextensions 141 test.aaa_profiling.test_compiler.CompileTest.test_select 3.2_postgresql_psycopg2_nocextensions 151 test.aaa_profiling.test_compiler.CompileTest.test_select 3.2_sqlite_pysqlite_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_oracle_cx_oracle_nocextensions 153 test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_postgresql_psycopg2_nocextensions 151 test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_sqlite_pysqlite_nocextensions 151 @@ -44,12 +48,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_sqlite_pysqlite_noc test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.6_sqlite_pysqlite_nocextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_mysql_mysqldb_cextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_mysql_mysqldb_nocextensions 175 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_oracle_cx_oracle_nocextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_postgresql_psycopg2_cextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_postgresql_psycopg2_nocextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_sqlite_pysqlite_cextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 2.7_sqlite_pysqlite_nocextensions 175 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.2_postgresql_psycopg2_nocextensions 185 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.2_sqlite_pysqlite_nocextensions 185 +test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_oracle_cx_oracle_nocextensions 187 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_postgresql_psycopg2_nocextensions 185 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_sqlite_pysqlite_nocextensions 185 @@ -58,12 +64,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_sqlite_pysql test.aaa_profiling.test_compiler.CompileTest.test_update 2.6_sqlite_pysqlite_nocextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_mysql_mysqldb_cextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_mysql_mysqldb_nocextensions 70 +test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_oracle_cx_oracle_nocextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_postgresql_psycopg2_cextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_postgresql_psycopg2_nocextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_sqlite_pysqlite_cextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 2.7_sqlite_pysqlite_nocextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 3.2_postgresql_psycopg2_nocextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 3.2_sqlite_pysqlite_nocextensions 70 +test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_oracle_cx_oracle_nocextensions 72 test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_postgresql_psycopg2_nocextensions 70 test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_sqlite_pysqlite_nocextensions 70 @@ -72,12 +80,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_sqlite_pysqlite_noc test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.6_sqlite_pysqlite_nocextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_mysqldb_cextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_mysqldb_nocextensions 137 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_nocextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_cextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_nocextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_cextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_nocextensions 137 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.2_postgresql_psycopg2_nocextensions 136 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.2_sqlite_pysqlite_nocextensions 136 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_oracle_cx_oracle_nocextensions 138 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_postgresql_psycopg2_nocextensions 136 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_sqlite_pysqlite_nocextensions 136 @@ -86,12 +96,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_sqlite_ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.6_sqlite_pysqlite_nocextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_cextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_mysql_mysqldb_nocextensions 17987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_oracle_cx_oracle_nocextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_cextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_postgresql_psycopg2_nocextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_cextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 2.7_sqlite_pysqlite_nocextensions 17987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.2_postgresql_psycopg2_nocextensions 18987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.2_sqlite_pysqlite_nocextensions 18987 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_oracle_cx_oracle_nocextensions 18987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_postgresql_psycopg2_nocextensions 18987 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_sqlite_pysqlite_nocextensions 18987 @@ -100,12 +112,14 @@ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.6_sqlite_pysqlite_nocextensions 154319 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_cextensions 124069 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_mysql_mysqldb_nocextensions 126819 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_oracle_cx_oracle_nocextensions 128319 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_cextensions 116569 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_postgresql_psycopg2_nocextensions 119319 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_cextensions 151569 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_nocextensions 154319 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.2_postgresql_psycopg2_nocextensions 121790 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.2_sqlite_pysqlite_nocextensions 121822 +test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.3_oracle_cx_oracle_nocextensions 130792 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.3_postgresql_psycopg2_nocextensions 121822 # TEST: test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks @@ -113,11 +127,13 @@ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_ test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.6_sqlite_pysqlite_nocextensions 21744 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_cextensions 19838 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_mysql_mysqldb_nocextensions 20098 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_oracle_cx_oracle_nocextensions 20152 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_cextensions 19237 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_postgresql_psycopg2_nocextensions 19467 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_cextensions 21530 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_nocextensions 21790 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.2_postgresql_psycopg2_nocextensions 20424 +test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.3_oracle_cx_oracle_nocextensions 21244 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.3_postgresql_psycopg2_nocextensions 20344 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_load @@ -125,11 +141,13 @@ test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3. test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.6_sqlite_pysqlite_nocextensions 1521 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_cextensions 1388 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_nocextensions 1413 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_oracle_cx_oracle_nocextensions 1349 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_cextensions 1296 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_nocextensions 1321 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_cextensions 1496 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_nocextensions 1521 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.2_postgresql_psycopg2_nocextensions 1332 +test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.3_oracle_cx_oracle_nocextensions 1366 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.3_postgresql_psycopg2_nocextensions 1357 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_no_load @@ -137,12 +155,14 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.3_postgresql_psycopg2_no test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.6_sqlite_pysqlite_nocextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mysql_mysqldb_cextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mysql_mysqldb_nocextensions 122,18 +test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_oracle_cx_oracle_nocextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_postgresql_psycopg2_cextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_postgresql_psycopg2_nocextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_sqlite_pysqlite_cextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_sqlite_pysqlite_nocextensions 122,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.2_postgresql_psycopg2_nocextensions 127,19 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.2_sqlite_pysqlite_nocextensions 127,19 +test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_oracle_cx_oracle_nocextensions 134,19 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_postgresql_psycopg2_nocextensions 127,19 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_nocextensions 127,19 @@ -151,12 +171,14 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_noc test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.6_sqlite_pysqlite_nocextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_mysql_mysqldb_cextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_mysql_mysqldb_nocextensions 82 +test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_oracle_cx_oracle_nocextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_postgresql_psycopg2_cextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_postgresql_psycopg2_nocextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_sqlite_pysqlite_cextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 2.7_sqlite_pysqlite_nocextensions 82 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.2_postgresql_psycopg2_nocextensions 70 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.2_sqlite_pysqlite_nocextensions 70 +test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_oracle_cx_oracle_nocextensions 69 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_postgresql_psycopg2_nocextensions 69 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_sqlite_pysqlite_nocextensions 69 @@ -165,12 +187,14 @@ test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_sqlite_pysqlit test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.6_sqlite_pysqlite_nocextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_mysql_mysqldb_cextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_mysql_mysqldb_nocextensions 29 +test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_oracle_cx_oracle_nocextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_postgresql_psycopg2_cextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_postgresql_psycopg2_nocextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_sqlite_pysqlite_cextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 2.7_sqlite_pysqlite_nocextensions 29 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.2_postgresql_psycopg2_nocextensions 23 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.2_sqlite_pysqlite_nocextensions 23 +test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_oracle_cx_oracle_nocextensions 22 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_postgresql_psycopg2_nocextensions 22 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_sqlite_pysqlite_nocextensions 22 @@ -179,12 +203,14 @@ test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_sqlite_pysqli test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.6_sqlite_pysqlite_nocextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_mysql_mysqldb_cextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_mysql_mysqldb_nocextensions 6 +test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_oracle_cx_oracle_nocextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_postgresql_psycopg2_cextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_postgresql_psycopg2_nocextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_sqlite_pysqlite_cextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 2.7_sqlite_pysqlite_nocextensions 6 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.2_postgresql_psycopg2_nocextensions 7 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.2_sqlite_pysqlite_nocextensions 7 +test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_oracle_cx_oracle_nocextensions 7 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_postgresql_psycopg2_nocextensions 7 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_sqlite_pysqlite_nocextensions 7 @@ -193,12 +219,14 @@ test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_sq test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.6_sqlite_pysqlite_nocextensions 43 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_mysql_mysqldb_cextensions 41 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_mysql_mysqldb_nocextensions 43 +test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_oracle_cx_oracle_nocextensions 43 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_postgresql_psycopg2_cextensions 41 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_postgresql_psycopg2_nocextensions 43 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_sqlite_pysqlite_cextensions 41 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 2.7_sqlite_pysqlite_nocextensions 43 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.2_postgresql_psycopg2_nocextensions 41 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.2_sqlite_pysqlite_nocextensions 41 +test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_oracle_cx_oracle_nocextensions 41 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_postgresql_psycopg2_nocextensions 41 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_sqlite_pysqlite_nocextensions 41 @@ -207,12 +235,14 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.6_sqlite_pysqlite_nocextensions 68 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_mysql_mysqldb_cextensions 66 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_mysql_mysqldb_nocextensions 68 +test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_oracle_cx_oracle_nocextensions 68 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_postgresql_psycopg2_cextensions 66 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_postgresql_psycopg2_nocextensions 68 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_sqlite_pysqlite_cextensions 66 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 2.7_sqlite_pysqlite_nocextensions 68 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.2_postgresql_psycopg2_nocextensions 66 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.2_sqlite_pysqlite_nocextensions 66 +test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_oracle_cx_oracle_nocextensions 66 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_postgresql_psycopg2_nocextensions 66 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_sqlite_pysqlite_nocextensions 66 @@ -221,12 +251,14 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_ test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.6_sqlite_pysqlite_nocextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_cextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_nocextensions 14 +test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_oracle_cx_oracle_nocextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_cextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_nocextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_cextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_nocextensions 14 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.2_postgresql_psycopg2_nocextensions 15 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.2_sqlite_pysqlite_nocextensions 15 +test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_oracle_cx_oracle_nocextensions 15 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_postgresql_psycopg2_nocextensions 15 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_sqlite_pysqlite_nocextensions 15 @@ -235,12 +267,14 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.6_sqlite_pysqlite_nocextensions 15447 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_mysql_mysqldb_cextensions 485 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_mysql_mysqldb_nocextensions 15505 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_oracle_cx_oracle_nocextensions 35582 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_postgresql_psycopg2_cextensions 20471 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_postgresql_psycopg2_nocextensions 35491 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_sqlite_pysqlite_cextensions 427 test.aaa_profiling.test_resultset.ResultSetTest.test_string 2.7_sqlite_pysqlite_nocextensions 15447 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.2_postgresql_psycopg2_nocextensions 14459 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.2_sqlite_pysqlite_nocextensions 14430 +test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_oracle_cx_oracle_nocextensions 14548 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_postgresql_psycopg2_nocextensions 14457 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_sqlite_pysqlite_nocextensions 14430 @@ -249,12 +283,14 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_sqlite_pysqlite_ test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.6_sqlite_pysqlite_nocextensions 15447 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_mysql_mysqldb_cextensions 485 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_mysql_mysqldb_nocextensions 45505 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_oracle_cx_oracle_nocextensions 35572 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_postgresql_psycopg2_cextensions 20471 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_postgresql_psycopg2_nocextensions 35491 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_sqlite_pysqlite_cextensions 427 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 2.7_sqlite_pysqlite_nocextensions 15447 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.2_postgresql_psycopg2_nocextensions 14459 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.2_sqlite_pysqlite_nocextensions 14430 +test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_oracle_cx_oracle_nocextensions 14548 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_postgresql_psycopg2_nocextensions 14457 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_sqlite_pysqlite_nocextensions 14430 diff --git a/test/requirements.py b/test/requirements.py index c09c0df99..78544a396 100644 --- a/test/requirements.py +++ b/test/requirements.py @@ -240,6 +240,13 @@ class DefaultRequirements(SuiteRequirements): "firebird" ], "no schema support") + @property + def cross_schema_fk_reflection(self): + """target system must support reflection of inter-schema foreign keys + """ + return only_on([ + "postgresql" + ]) @property def update_nowait(self): diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 9cb0e6bbe..473a422a2 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -748,6 +748,77 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): 'foo || :param_1') + def test_order_by_labels_enabled(self): + lab1 = (table1.c.myid + 12).label('foo') + lab2 = func.somefunc(table1.c.name).label('bar') + dialect = default.DefaultDialect() + + self.assert_compile(select([lab1, lab2]).order_by(lab1, desc(lab2)), + "SELECT mytable.myid + :myid_1 AS foo, " + "somefunc(mytable.name) AS bar FROM mytable " + "ORDER BY foo, bar DESC", + dialect=dialect + ) + + # the function embedded label renders as the function + self.assert_compile( + select([lab1, lab2]).order_by(func.hoho(lab1), desc(lab2)), + "SELECT mytable.myid + :myid_1 AS foo, " + "somefunc(mytable.name) AS bar FROM mytable " + "ORDER BY hoho(mytable.myid + :myid_1), bar DESC", + dialect=dialect + ) + + # binary expressions render as the expression without labels + self.assert_compile(select([lab1, lab2]).order_by(lab1 + "test"), + "SELECT mytable.myid + :myid_1 AS foo, " + "somefunc(mytable.name) AS bar FROM mytable " + "ORDER BY mytable.myid + :myid_1 + :param_1", + dialect=dialect + ) + + # labels within functions in the columns clause render + # with the expression + self.assert_compile( + select([lab1, func.foo(lab1)]).order_by(lab1, func.foo(lab1)), + "SELECT mytable.myid + :myid_1 AS foo, " + "foo(mytable.myid + :myid_1) AS foo_1 FROM mytable " + "ORDER BY foo, foo(mytable.myid + :myid_1)", + dialect=dialect + ) + + + lx = (table1.c.myid + table1.c.myid).label('lx') + ly = (func.lower(table1.c.name) + table1.c.description).label('ly') + + self.assert_compile( + select([lx, ly]).order_by(lx, ly.desc()), + "SELECT mytable.myid + mytable.myid AS lx, " + "lower(mytable.name) || mytable.description AS ly " + "FROM mytable ORDER BY lx, ly DESC", + dialect=dialect + ) + + def test_order_by_labels_disabled(self): + lab1 = (table1.c.myid + 12).label('foo') + lab2 = func.somefunc(table1.c.name).label('bar') + dialect = default.DefaultDialect() + dialect.supports_simple_order_by_label = False + self.assert_compile(select([lab1, lab2]).order_by(lab1, desc(lab2)), + "SELECT mytable.myid + :myid_1 AS foo, " + "somefunc(mytable.name) AS bar FROM mytable " + "ORDER BY mytable.myid + :myid_1, somefunc(mytable.name) DESC", + dialect=dialect + ) + self.assert_compile( + select([lab1, lab2]).order_by(func.hoho(lab1), desc(lab2)), + "SELECT mytable.myid + :myid_1 AS foo, " + "somefunc(mytable.name) AS bar FROM mytable " + "ORDER BY hoho(mytable.myid + :myid_1), " + "somefunc(mytable.name) DESC", + dialect=dialect + ) + def test_conjunctions(self): a, b, c = 'a', 'b', 'c' x = and_(a, b, c) diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index c0873862d..8f0280765 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -1211,6 +1211,30 @@ class ConstraintTest(fixtures.TestBase): schema.CreateTable(t1).compile ) + def test_constraint_copied_to_proxy_ok(self): + m = MetaData() + t1 = Table('t1', m, Column('id', Integer, primary_key=True)) + t2 = Table('t2', m, Column('id', Integer, ForeignKey('t1.id'), + primary_key=True)) + + s = tsa.select([t2]) + t2fk = list(t2.c.id.foreign_keys)[0] + sfk = list(s.c.id.foreign_keys)[0] + + # the two FKs share the ForeignKeyConstraint + is_( + t2fk.constraint, + sfk.constraint + ) + + # but the ForeignKeyConstraint isn't + # aware of the select's FK + eq_( + t2fk.constraint.elements, + [t2fk] + ) + + class ColumnDefinitionTest(AssertsCompiledSQL, fixtures.TestBase): """Test Column() construction.""" diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py index d1db733e0..b3919d0da 100644 --- a/test/sql/test_operators.py +++ b/test/sql/test_operators.py @@ -15,7 +15,7 @@ from sqlalchemy.dialects import mysql, firebird, postgresql, oracle, \ sqlite, mssql from sqlalchemy import util import datetime - +import collections from sqlalchemy import text, literal_column class LoopOperate(operators.ColumnOperators): @@ -352,17 +352,16 @@ class ExtensionOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): "x -> :x_1" ) - def test_no_endless_list_call(self): + @testing.requires.python26 + def test_op_not_an_iterator(self): + # see [ticket:2726] class MyType(UserDefinedType): class comparator_factory(UserDefinedType.Comparator): def __getitem__(self, index): return self.op("->")(index) - assert_raises_message( - NotImplementedError, - "Class <class 'sqlalchemy.schema.Column'> is not iterable", - list, Column('x', MyType()) - ) + col = Column('x', MyType()) + assert not isinstance(col, collections.Iterable) def test_lshift(self): class MyType(UserDefinedType): diff --git a/test/sql/test_query.py b/test/sql/test_query.py index 3e9045fa5..ae029b11c 100644 --- a/test/sql/test_query.py +++ b/test/sql/test_query.py @@ -708,8 +708,6 @@ class QueryTest(fixtures.TestBase): use_labels=labels), [(3, 'a'), (2, 'b'), (1, None)]) - @testing.fails_on('mssql+pyodbc', - "pyodbc result row doesn't support slicing") def test_column_slices(self): users.insert().execute(user_id=1, user_name='john') users.insert().execute(user_id=2, user_name='jack') diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 2ef952c65..2ac04dce3 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -788,11 +788,16 @@ class JoinConditionTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompi Column('id', Integer), Column('t1id', ForeignKey('t1.id')), Column('t2id', ForeignKey('t2.id'))) - t4 = Table('t4', m, - Column('id', Integer), + t4 = Table('t4', m, Column('id', Integer), Column('t2id', ForeignKey('t2.id'))) + t5 = Table('t5', m, + Column('t1id1', ForeignKey('t1.id')), + Column('t1id2', ForeignKey('t1.id')), + ) + t1t2 = t1.join(t2) t2t3 = t2.join(t3) + for (left, right, a_subset, expected) in [ (t1, t2, None, t1.c.id == t2.c.t1id), (t1t2, t3, t2, t1t2.c.t2_id == t3.c.t2id), @@ -806,12 +811,15 @@ class JoinConditionTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompi assert expected.compare(sql_util.join_condition(left, right, a_subset=a_subset)) + # these are ambiguous, or have no joins for left, right, a_subset in [ (t1t2, t3, None), (t2t3, t1, None), (t1, t4, None), (t1t2, t2t3, None), + (t5, t1, None), + (t5.select(use_labels=True), t1, None) ]: assert_raises( exc.ArgumentError, |
