diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-01-05 21:38:19 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-01-05 21:38:19 -0500 |
| commit | 57f684b4b4a661c78de0b5953603984714f01e0b (patch) | |
| tree | e545152a6249dcbb7e80a09da70d0c0f60dea57c /lib/sqlalchemy/orm | |
| parent | 145d0151515d8119931eb2c79425a4e38eb6cae4 (diff) | |
| download | sqlalchemy-57f684b4b4a661c78de0b5953603984714f01e0b.tar.gz | |
- Fixed bug where if an exception were thrown at the start of a
:class:`.Query` before it fetched results, particularly when
row processors can't be formed, the cursor would stay open with
results pending and not actually be closed. This is typically only
an issue on an interpreter like Pypy where the cursor isn't
immediately GC'ed, and can in some circumstances lead to transactions/
locks being open longer than is desirable.
fixes #3285
Diffstat (limited to 'lib/sqlalchemy/orm')
| -rw-r--r-- | lib/sqlalchemy/orm/loading.py | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index 380afcdc7..fdc787545 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -42,41 +42,45 @@ def instances(query, cursor, context): def filter_fn(row): return tuple(fn(x) for x, fn in zip(row, filter_fns)) - (process, labels) = \ - list(zip(*[ - query_entity.row_processor(query, - context, cursor) - for query_entity in query._entities - ])) - - if not single_entity: - keyed_tuple = util.lightweight_named_tuple('result', labels) - - while True: - context.partials = {} - - if query._yield_per: - fetch = cursor.fetchmany(query._yield_per) - if not fetch: - break - else: - fetch = cursor.fetchall() + try: + (process, labels) = \ + list(zip(*[ + query_entity.row_processor(query, + context, cursor) + for query_entity in query._entities + ])) + + if not single_entity: + keyed_tuple = util.lightweight_named_tuple('result', labels) + + while True: + context.partials = {} + + if query._yield_per: + fetch = cursor.fetchmany(query._yield_per) + if not fetch: + break + else: + fetch = cursor.fetchall() - if single_entity: - proc = process[0] - rows = [proc(row) for row in fetch] - else: - rows = [keyed_tuple([proc(row) for proc in process]) - for row in fetch] + if single_entity: + proc = process[0] + rows = [proc(row) for row in fetch] + else: + rows = [keyed_tuple([proc(row) for proc in process]) + for row in fetch] - if filtered: - rows = util.unique_list(rows, filter_fn) + if filtered: + rows = util.unique_list(rows, filter_fn) - for row in rows: - yield row + for row in rows: + yield row - if not query._yield_per: - break + if not query._yield_per: + break + except Exception as err: + cursor.close() + util.raise_from_cause(err) @util.dependencies("sqlalchemy.orm.query") |
