[Sqlalchemy-commits] sqlalchemy: - Tightened the iterate vs. remove mutex around the
Brought to you by:
zzzeek
From: <co...@sq...> - 2011-03-05 17:28:08
|
details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/3861c784aa8a changeset: 7384:3861c784aa8a user: zzzeek date: Sat Mar 05 12:19:40 2011 -0500 description: - Tightened the iterate vs. remove mutex around the identity map iteration, attempting to reduce the chance of an (extremely rare) reentrant gc operation causing a deadlock. Might remove the mutex in 0.7. [ticket:2087] Subject: sqlalchemy: 0.6.7 changelog message details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/1e50625b8ea3 changeset: 7385:1e50625b8ea3 user: zzzeek date: Sat Mar 05 12:28:16 2011 -0500 description: 0.6.7 changelog message diffstat: .hgignore | 1 + .hgtags | 3 +- CHANGES | 369 ++- LICENSE | 2 +- README.py3k | 14 +- README.unittests | 78 +- doc/build/core/engines.rst | 25 +- doc/build/core/event.rst | 104 + doc/build/core/events.rst | 33 + doc/build/core/expression_api.rst | 10 +- doc/build/core/index.rst | 4 +- doc/build/core/interfaces.rst | 17 +- doc/build/core/pooling.rst | 12 +- doc/build/core/schema.rst | 128 +- doc/build/core/tutorial.rst | 21 +- doc/build/core/types.rst | 32 +- doc/build/dialects/drizzle.rst | 72 + doc/build/dialects/index.rst | 1 + doc/build/dialects/mysql.rst | 5 + doc/build/dialects/postgresql.rst | 2 + doc/build/dialects/sqlite.rst | 2 + doc/build/intro.rst | 8 +- doc/build/orm/events.rst | 49 + doc/build/orm/examples.rst | 6 - doc/build/orm/extensions/hybrid.rst | 16 + doc/build/orm/extensions/index.rst | 7 + doc/build/orm/extensions/mutable.rst | 25 + doc/build/orm/index.rst | 3 +- doc/build/orm/interfaces.rst | 91 +- doc/build/orm/loading.rst | 17 +- doc/build/orm/mapper_config.rst | 179 +- doc/build/orm/session.rst | 16 +- doc/build/orm/tutorial.rst | 32 +- examples/beaker_caching/caching_query.py | 24 +- examples/custom_attributes/custom_management.py | 3 +- examples/custom_attributes/listen_for_events.py | 46 +- examples/derived_attributes/__init__.py | 10 - examples/derived_attributes/attributes.py | 168 - examples/sharding/attribute_shard.py | 24 +- examples/versioning/test_versioning.py | 7 +- examples/vertical/dictlike-polymorphic.py | 64 +- lib/sqlalchemy/__init__.py | 5 +- lib/sqlalchemy/connectors/mxodbc.py | 9 +- lib/sqlalchemy/connectors/mysqldb.py | 150 + lib/sqlalchemy/connectors/pyodbc.py | 3 +- lib/sqlalchemy/connectors/zxJDBC.py | 2 +- lib/sqlalchemy/databases/__init__.py | 2 + lib/sqlalchemy/dialects/__init__.py | 1 + lib/sqlalchemy/dialects/access/base.py | 5 - lib/sqlalchemy/dialects/drizzle/__init__.py | 18 + lib/sqlalchemy/dialects/drizzle/base.py | 582 +++ lib/sqlalchemy/dialects/drizzle/mysqldb.py | 68 + lib/sqlalchemy/dialects/firebird/base.py | 26 +- lib/sqlalchemy/dialects/firebird/kinterbasdb.py | 23 +- lib/sqlalchemy/dialects/informix/informixdb.py | 2 +- lib/sqlalchemy/dialects/maxdb/base.py | 11 +- lib/sqlalchemy/dialects/mssql/adodbapi.py | 3 +- lib/sqlalchemy/dialects/mssql/base.py | 80 +- lib/sqlalchemy/dialects/mssql/information_schema.py | 2 +- lib/sqlalchemy/dialects/mssql/mxodbc.py | 6 +- lib/sqlalchemy/dialects/mssql/pymssql.py | 3 +- lib/sqlalchemy/dialects/mssql/pyodbc.py | 27 +- lib/sqlalchemy/dialects/mysql/__init__.py | 2 +- lib/sqlalchemy/dialects/mysql/base.py | 138 +- lib/sqlalchemy/dialects/mysql/mysqlconnector.py | 2 +- lib/sqlalchemy/dialects/mysql/mysqldb.py | 160 +- lib/sqlalchemy/dialects/mysql/oursql.py | 2 +- lib/sqlalchemy/dialects/mysql/pymysql.py | 38 + lib/sqlalchemy/dialects/oracle/base.py | 37 +- lib/sqlalchemy/dialects/oracle/cx_oracle.py | 21 +- lib/sqlalchemy/dialects/oracle/zxjdbc.py | 2 +- lib/sqlalchemy/dialects/postgresql/base.py | 136 +- lib/sqlalchemy/dialects/postgresql/pg8000.py | 6 +- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 70 +- lib/sqlalchemy/dialects/postgresql/pypostgresql.py | 4 +- lib/sqlalchemy/dialects/sqlite/base.py | 94 +- lib/sqlalchemy/dialects/sqlite/pysqlite.py | 50 +- lib/sqlalchemy/dialects/sybase/base.py | 2 + lib/sqlalchemy/dialects/sybase/pyodbc.py | 2 +- lib/sqlalchemy/dialects/sybase/pysybase.py | 2 +- lib/sqlalchemy/engine/base.py | 761 ++- lib/sqlalchemy/engine/ddl.py | 114 +- lib/sqlalchemy/engine/default.py | 457 +- lib/sqlalchemy/engine/reflection.py | 6 +- lib/sqlalchemy/engine/strategies.py | 39 +- lib/sqlalchemy/engine/threadlocal.py | 10 +- lib/sqlalchemy/event.py | 312 + lib/sqlalchemy/events.py | 379 ++ lib/sqlalchemy/exc.py | 77 +- lib/sqlalchemy/ext/associationproxy.py | 68 +- lib/sqlalchemy/ext/declarative.py | 148 +- lib/sqlalchemy/ext/horizontal_shard.py | 6 +- lib/sqlalchemy/ext/hybrid.py | 425 ++ lib/sqlalchemy/ext/mutable.py | 540 +++ lib/sqlalchemy/ext/sqlsoup.py | 9 +- lib/sqlalchemy/interfaces.py | 103 +- lib/sqlalchemy/log.py | 201 +- lib/sqlalchemy/orm/__init__.py | 205 +- lib/sqlalchemy/orm/attributes.py | 1295 ++----- lib/sqlalchemy/orm/collections.py | 28 +- lib/sqlalchemy/orm/dependency.py | 181 +- lib/sqlalchemy/orm/deprecated_interfaces.py | 583 +++ lib/sqlalchemy/orm/descriptor_props.py | 405 ++ lib/sqlalchemy/orm/dynamic.py | 67 +- lib/sqlalchemy/orm/events.py | 1046 +++++ lib/sqlalchemy/orm/exc.py | 3 + lib/sqlalchemy/orm/identity.py | 166 +- lib/sqlalchemy/orm/instrumentation.py | 691 +++ lib/sqlalchemy/orm/interfaces.py | 538 +-- lib/sqlalchemy/orm/mapper.py | 1008 +++-- lib/sqlalchemy/orm/properties.py | 358 +- lib/sqlalchemy/orm/query.py | 259 +- lib/sqlalchemy/orm/scoping.py | 88 +- lib/sqlalchemy/orm/session.py | 503 +- lib/sqlalchemy/orm/state.py | 256 +- lib/sqlalchemy/orm/strategies.py | 524 +- lib/sqlalchemy/orm/sync.py | 22 +- lib/sqlalchemy/orm/unitofwork.py | 119 +- lib/sqlalchemy/orm/util.py | 185 +- lib/sqlalchemy/pool.py | 295 +- lib/sqlalchemy/queue.py | 191 - lib/sqlalchemy/schema.py | 672 ++- lib/sqlalchemy/sql/__init__.py | 1 + lib/sqlalchemy/sql/compiler.py | 515 +- lib/sqlalchemy/sql/expression.py | 823 +++- lib/sqlalchemy/sql/operators.py | 6 + lib/sqlalchemy/sql/util.py | 14 +- lib/sqlalchemy/test/__init__.py | 33 - lib/sqlalchemy/test/assertsql.py | 300 - lib/sqlalchemy/test/engines.py | 311 - lib/sqlalchemy/test/entities.py | 89 - lib/sqlalchemy/test/orm.py | 117 - lib/sqlalchemy/test/pickleable.py | 81 - lib/sqlalchemy/test/profiling.py | 228 - lib/sqlalchemy/test/requires.py | 333 - lib/sqlalchemy/test/schema.py | 85 - lib/sqlalchemy/test/testing.py | 805 ---- lib/sqlalchemy/test/util.py | 81 - lib/sqlalchemy/topological.py | 83 - lib/sqlalchemy/types.py | 417 +- lib/sqlalchemy/util.py | 1875 ---------- lib/sqlalchemy/util/__init__.py | 32 + lib/sqlalchemy/util/_collections.py | 897 +++++ lib/sqlalchemy/util/compat.py | 209 + lib/sqlalchemy/util/deprecations.py | 118 + lib/sqlalchemy/util/langhelpers.py | 757 ++++ lib/sqlalchemy/util/queue.py | 191 + lib/sqlalchemy/util/topological.py | 83 + lib/sqlalchemy_nose/config.py | 173 - lib/sqlalchemy_nose/noseplugin.py | 166 - setup.cfg | 3 +- setup.py | 15 +- sqla_nose.py | 18 +- test/aaa_profiling/test_compiler.py | 28 +- test/aaa_profiling/test_memusage.py | 43 +- test/aaa_profiling/test_orm.py | 112 +- test/aaa_profiling/test_pool.py | 10 +- test/aaa_profiling/test_resultset.py | 54 +- test/aaa_profiling/test_zoomark.py | 30 +- test/aaa_profiling/test_zoomark_orm.py | 27 +- test/base/test_dependency.py | 16 +- test/base/test_events.py | 283 + test/base/test_except.py | 33 +- test/base/test_utils.py | 10 +- test/bootstrap/config.py | 167 + test/bootstrap/noseplugin.py | 180 + test/dialect/test_access.py | 2 +- test/dialect/test_firebird.py | 20 +- test/dialect/test_informix.py | 2 +- test/dialect/test_maxdb.py | 8 +- test/dialect/test_mssql.py | 70 +- test/dialect/test_mxodbc.py | 4 +- test/dialect/test_mysql.py | 92 +- test/dialect/test_oracle.py | 63 +- test/dialect/test_postgresql.py | 321 +- test/dialect/test_sqlite.py | 104 +- test/dialect/test_sybase.py | 2 +- test/engine/_base.py | 4 +- test/engine/test_bind.py | 27 +- test/engine/test_ddlevents.py | 266 +- test/engine/test_execute.py | 579 ++- test/engine/test_metadata.py | 435 -- test/engine/test_parseconnect.py | 4 +- test/engine/test_pool.py | 364 +- test/engine/test_reconnect.py | 75 +- test/engine/test_reflection.py | 41 +- test/engine/test_transaction.py | 146 +- test/ex/test_examples.py | 2 +- test/ext/test_associationproxy.py | 171 +- test/ext/test_compiler.py | 7 +- test/ext/test_declarative.py | 312 +- test/ext/test_horizontal_shard.py | 51 +- test/ext/test_hybrid.py | 244 + test/ext/test_mutable.py | 284 + test/ext/test_orderinglist.py | 4 +- test/ext/test_serializer.py | 16 +- test/ext/test_sqlsoup.py | 2 +- test/lib/__init__.py | 27 + test/lib/assertsql.py | 314 + test/lib/engines.py | 297 + test/lib/entities.py | 83 + test/lib/orm.py | 111 + test/lib/pickleable.py | 75 + test/lib/profiling.py | 238 + test/lib/requires.py | 361 ++ test/lib/schema.py | 79 + test/lib/testing.py | 802 ++++ test/lib/util.py | 125 + test/orm/_base.py | 11 +- test/orm/_fixtures.py | 6 +- test/orm/inheritance/test_abc_inheritance.py | 4 +- test/orm/inheritance/test_abc_polymorphic.py | 4 +- test/orm/inheritance/test_basic.py | 188 +- test/orm/inheritance/test_concrete.py | 10 +- test/orm/inheritance/test_magazine.py | 6 +- test/orm/inheritance/test_manytomany.py | 4 +- test/orm/inheritance/test_poly_linked_list.py | 10 +- test/orm/inheritance/test_polymorph.py | 75 +- test/orm/inheritance/test_polymorph2.py | 10 +- test/orm/inheritance/test_productspec.py | 4 +- test/orm/inheritance/test_query.py | 92 +- test/orm/inheritance/test_selects.py | 2 +- test/orm/inheritance/test_single.py | 6 +- test/orm/test_association.py | 6 +- test/orm/test_assorted_eager.py | 82 +- test/orm/test_attributes.py | 1414 ++++--- test/orm/test_backref_mutations.py | 13 +- test/orm/test_bind.py | 8 +- test/orm/test_cascade.py | 1227 +++++- test/orm/test_collection.py | 35 +- test/orm/test_compile.py | 37 +- test/orm/test_composites.py | 243 +- test/orm/test_cycles.py | 8 +- test/orm/test_defaults.py | 16 +- test/orm/test_deprecations.py | 6 +- test/orm/test_descriptor.py | 133 + test/orm/test_dynamic.py | 17 +- test/orm/test_eager_relations.py | 76 +- test/orm/test_evaluator.py | 8 +- test/orm/test_events.py | 1075 ++++++ test/orm/test_expire.py | 10 +- test/orm/test_extendedattr.py | 77 +- test/orm/test_froms.py | 1734 +++++++++ test/orm/test_generative.py | 19 +- test/orm/test_immediate_load.py | 4 +- test/orm/test_instrumentation.py | 241 +- test/orm/test_joins.py | 1711 +++++++++ test/orm/test_lazy_relations.py | 10 +- test/orm/test_legacy_mutable.py | 353 ++ test/orm/test_load_on_fks.py | 6 +- test/orm/test_manytomany.py | 10 +- test/orm/test_mapper.py | 609 +-- test/orm/test_merge.py | 126 +- test/orm/test_naturalpks.py | 10 +- test/orm/test_onetoone.py | 4 +- test/orm/test_pickled.py | 44 +- test/orm/test_query.py | 3347 +----------------- test/orm/test_relationships.py | 128 +- test/orm/test_scoping.py | 182 +- test/orm/test_selectable.py | 35 +- test/orm/test_session.py | 258 +- test/orm/test_subquery_relations.py | 10 +- test/orm/test_transaction.py | 88 +- test/orm/test_unitofwork.py | 372 +- test/orm/test_unitofworkv2.py | 205 +- test/orm/test_utils.py | 46 +- test/orm/test_versioning.py | 122 +- test/perf/README | 17 + test/perf/cascade_speed.py | 93 - test/perf/insertspeed.py | 2 +- test/perf/large_flush.py | 2 +- test/perf/masscreate.py | 39 - test/perf/masscreate2.py | 36 - test/perf/masseagerload.py | 54 - test/perf/massload.py | 63 - test/perf/massload2.py | 70 - test/perf/masssave.py | 54 - test/perf/objselectspeed.py | 4 +- test/perf/objupdatespeed.py | 4 +- test/perf/orm2010.py | 186 + test/perf/ormsession.py | 4 +- test/perf/poolload.py | 37 - test/perf/sessions.py | 4 +- test/perf/stress_all.py | 2 +- test/perf/wsgi.py | 52 - test/sql/test_case_statement.py | 5 +- test/sql/test_columns.py | 95 - test/sql/test_compiler.py | 154 +- test/sql/test_constraints.py | 78 +- test/sql/test_defaults.py | 470 ++- test/sql/test_functions.py | 19 +- test/sql/test_generative.py | 55 +- test/sql/test_labels.py | 4 +- test/sql/test_metadata.py | 753 ++++ test/sql/test_query.py | 118 +- test/sql/test_quote.py | 8 +- test/sql/test_returning.py | 6 +- test/sql/test_rowcount.py | 2 +- test/sql/test_selectable.py | 4 +- test/sql/test_types.py | 195 +- test/sql/test_unicode.py | 4 +- test/zblog/blog.py | 35 - test/zblog/mappers.py | 135 - test/zblog/tables.py | 53 - test/zblog/test_zblog.py | 116 - test/zblog/user.py | 41 - 306 files changed, 30983 insertions(+), 19642 deletions(-) diffs (truncated from 67296 to 300 lines): diff -r 3898c13f6e7c -r 1e50625b8ea3 .hgignore --- a/.hgignore Sat Feb 19 12:59:12 2011 -0500 +++ b/.hgignore Sat Mar 05 12:28:16 2011 -0500 @@ -5,6 +5,7 @@ .orig$ .egg-info .*,cover +.un~ \.coverage \.DS_Store test.cfg diff -r 3898c13f6e7c -r 1e50625b8ea3 .hgtags --- a/.hgtags Sat Feb 19 12:59:12 2011 -0500 +++ b/.hgtags Sat Mar 05 12:28:16 2011 -0500 @@ -76,4 +76,5 @@ 1db7766705b70f5326b614699b7c06d46168d19d rel_0_6_3 2db46b7f51c1e64f06d9c31c49ff6e15be98e9ca rel_0_6_4 ff12fe7cac947ce9e28be4e8b4473df2c0adaa04 rel_0_6_5 -3ef75b251d060573ccd994598d03f3c30f0e012c rel_0_6_6 +92a08c9934aa8e4d080386102d76235ee1897829 rel_0_7b1 +e08d40f2b46cdaffc1af0c4950151963efa6e3f1 rel_0_7b2 diff -r 3898c13f6e7c -r 1e50625b8ea3 CHANGES --- a/CHANGES Sat Feb 19 12:59:12 2011 -0500 +++ b/CHANGES Sat Mar 05 12:28:16 2011 -0500 @@ -3,9 +3,372 @@ ======= CHANGES ======= +0.7.0b3 +======= +- orm + - some changes to the identity map regarding + rare weakref callbacks during iterations. + The mutex has been removed as it apparently + can cause a reentrant (i.e. in one thread) deadlock, + perhaps when gc collects objects at the point of + iteration in order to gain more memory. It is hoped + that "dictionary changed during iteration" will + be exceedingly rare as iteration methods internally + acquire the full list of objects in a single values() + call. [ticket:2087] + +- sql + - Added a fully descriptive error message for the + case where Column is subclassed and _make_proxy() + fails to make a copy due to TypeError on the + constructor. The method _constructor should + be implemented in this case. + +0.7.0b2 +======== +- orm + - Fixed bug whereby Session.merge() would call the + load() event with one too few arguments. + [ticket:2053] + + - Added logic which prevents the generation of + events from a MapperExtension or SessionExtension + from generating do-nothing events for all the methods + not overridden. [ticket:2052] + +- sql + - Renamed the EngineEvents event class to + ConnectionEvents. As these classes are never + accessed directly by end-user code, this strictly + is a documentation change for end users. Also + simplified how events get linked to engines + and connections internally. [ticket:2059] + + - The Sequence() construct, when passed a MetaData() + object via its 'metadata' argument, will be + included in CREATE/DROP statements within + metadata.create_all() and metadata.drop_all(), + including "checkfirst" logic. [ticket:2055] + + - The Column.references() method now returns True + if it has a foreign key referencing the + given column exactly, not just it's parent + table. [ticket:2064] + +- postgresql + - Fixed regression from 0.6 where SMALLINT and + BIGINT types would both generate SERIAL + on an integer PK column, instead of + SMALLINT and BIGSERIAL [ticket:2065] + +- ext + - Association proxy now has correct behavior for + any(), has(), and contains() when proxying + a many-to-one scalar attribute to a one-to-many + collection (i.e. the reverse of the 'typical' + association proxy use case) [ticket:2054] + +- examples + - Beaker example now takes into account 'limit' + and 'offset', bind params within embedded + FROM clauses (like when you use union() or + from_self()) when generating a cache key. + +- declarative + - Fixed regression whereby composite() with + Column objects placed inline would fail + to initialize. The Column objects can now + be inline with the composite() or external + and pulled in via name or object ref. + [ticket:2058] + + - the dictionary at the end of the __table_args__ + tuple is now optional. [ticket:1468] + +0.7.0b1 +======= +- Detailed descriptions of each change below are + described at: + http://www.sqlalchemy.org/trac/wiki/07Migration + +- general + - New event system, supercedes all extensions, listeners, + etc. [ticket:1902] + + - Logging enhancements + [ticket:1926] + + - Setup no longer installs a Nose plugin + [ticket:1949] + + - The "sqlalchemy.exceptions" alias in sys.modules + has been removed. Base SQLA exceptions are + available via "from sqlalchemy import exc". + The "exceptions" alias for "exc" remains in + "sqlalchemy" for now, it's just not patched into + sys.modules. + +- orm + - More succinct form of query.join(target, onclause) + [ticket:1923] + + - Hybrid Attributes, implements/supercedes synonym() + [ticket:1903] + + - Rewrite of composites [ticket:2008] + + - Mutation Event Extension, supercedes "mutable=True" + + - PickleType and ARRAY mutability turned off by default + [ticket:1980] + + - Simplified polymorphic_on assignment + [ticket:1895] + + - Flushing of Orphans that have no parent is allowed + [ticket:1912] + + - Adjusted flush accounting step to occur before + the commit in the case of autocommit=True. This allows + autocommit=True to work appropriately with + expire_on_commit=True, and also allows post-flush session + hooks to operate in the same transactional context + as when autocommit=False. [ticket:2041] + + - Warnings generated when collection members, scalar referents + not part of the flush + [ticket:1973] + + - Non-`Table`-derived constructs can be mapped + [ticket:1876] + + - Tuple label names in Query Improved + [ticket:1942] + + - Mapped column attributes reference the most specific + column first + [ticket:1892] + + - Mapping to joins with two or more same-named columns + requires explicit declaration + [ticket:1896] + + - Mapper requires that polymorphic_on column be present + in the mapped selectable + [ticket:1875] + + - compile_mappers() renamed configure_mappers(), simplified + configuration internals + [ticket:1966] + + - the aliased() function, if passed a SQL FromClause element + (i.e. not a mapped class), will return element.alias() + instead of raising an error on AliasedClass. [ticket:2018] + + - Session.merge() will check the version id of the incoming + state against that of the database, assuming the mapping + uses version ids and incoming state has a version_id + assigned, and raise StaleDataError if they don't + match. [ticket:2027] + + - Session.connection(), Session.execute() accept 'bind', + to allow execute/connection operations to participate + in the open transaction of an engine explicitly. + [ticket:1996] + + - Query.join(), Query.outerjoin(), eagerload(), + eagerload_all(), others no longer allow lists + of attributes as arguments (i.e. option([x, y, z]) + form, deprecated since 0.5) + + - ScopedSession.mapper is removed (deprecated since 0.5). + + - Horizontal shard query places 'shard_id' in + context.attributes where it's accessible by the + "load()" event. [ticket:2031] + + - A single contains_eager() call across + multiple entities will indicate all collections + along that path should load, instead of requiring + distinct contains_eager() calls for each endpoint + (which was never correctly documented). + [ticket:2032] + + - The "name" field used in orm.aliased() now renders + in the resulting SQL statement. + + - Session weak_instance_dict=False is deprecated. + [ticket:1473] + + - An exception is raised in the unusual case that an + append or similar event on a collection occurs after + the parent object has been dereferenced, which + prevents the parent from being marked as "dirty" + in the session. Was a warning in 0.6.6. + [ticket:2046] + + - Query.distinct() now accepts column expressions + as *args, interpreted by the Postgresql dialect + as DISTINCT ON (<expr>). [ticket:1069] + + - Additional tuning to "many-to-one" relationship + loads during a flush(). A change in version 0.6.6 + ([ticket:2002]) required that more "unnecessary" m2o + loads during a flush could occur. Extra loading modes have + been added so that the SQL emitted in this + specific use case is trimmed back, while still + retrieving the information the flush needs in order + to not miss anything. [ticket:2049] + + - the value of "passive" as passed to + attributes.get_history() should be one of the + constants defined in the attributes package. Sending + True or False is deprecated. + +- sql + - Added over() function, method to FunctionElement + classes, produces the _Over() construct which + in turn generates "window functions", i.e. + "<window function> OVER (PARTITION BY <partition by>, + ORDER BY <order by>)". + [ticket:1844] + + - LIMIT/OFFSET clauses now use bind parameters + [ticket:805] + + - select.distinct() now accepts column expressions + as *args, interpreted by the Postgresql dialect + as DISTINCT ON (<expr>). Note this was already + available via passing a list to the `distinct` + keyword argument to select(). [ticket:1069] + + - select.prefix_with() accepts multiple expressions + (i.e. *expr), 'prefix' keyword argument to select() + accepts a list or tuple. + + - Passing a string to the `distinct` keyword argument + of `select()` for the purpose of emitting special + MySQL keywords (DISTINCTROW etc.) is deprecated - + use `prefix_with()` for this. + + - TypeDecorator works with primary key columns + [ticket:2005] [ticket:2006] + + - DDL() constructs now escape percent signs + [ticket:1897] + + - Table.c / MetaData.tables refined a bit, don't allow direct + mutation [ticket:1893] [ticket:1917] + + - Callables passed to `bindparam()` don't get evaluated + [ticket:1950] + + - types.type_map is now private, types._type_map + [ticket:1870] + + - Non-public Pool methods underscored + [ticket:1982] + + - Added NULLS FIRST and NULLS LAST support. It's implemented + as an extension to the asc() and desc() operators, called + nullsfirst() and nullslast(). [ticket:723] + + - The Index() construct can be created inline with a Table + definition, using strings as column names, as an alternative |