summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-04-07 12:49:29 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2011-04-07 12:49:29 -0400
commit708a25e76a3cb9528c65d45ad37fc562cf178e44 (patch)
tree8671a00c4dda81b921183f7f1193ebcaa39e469e /lib
parented5783772dff7bdef9de381dd0fb5c70adc89995 (diff)
downloadsqlalchemy-708a25e76a3cb9528c65d45ad37fc562cf178e44.tar.gz
- Some fixes to "evaulate" and "fetch" evaluation
when query.update(), query.delete() are called. The retrieval of records is done after autoflush in all cases, and before update/delete is emitted, guarding against unflushed data present as well as expired objects failing during the evaluation. [ticket:2122]
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/query.py77
1 files changed, 42 insertions, 35 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index dcfbf3b32..53478c9c6 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -2138,6 +2138,9 @@ class Query(object):
session = self.session
+ if self._autoflush:
+ session._autoflush()
+
if synchronize_session == 'evaluate':
try:
evaluator_compiler = evaluator.EvaluatorCompiler()
@@ -2154,9 +2157,16 @@ class Query(object):
"Specify 'fetch' or False for the synchronize_session "
"parameter.")
- delete_stmt = sql.delete(primary_table, context.whereclause)
+ target_cls = self._mapper_zero().class_
+
+ #TODO: detect when the where clause is a trivial primary key match
+ objs_to_expunge = [
+ obj for (cls, pk),obj in
+ session.identity_map.iteritems()
+ if issubclass(cls, target_cls) and
+ eval_condition(obj)]
- if synchronize_session == 'fetch':
+ elif synchronize_session == 'fetch':
#TODO: use RETURNING when available
select_stmt = context.statement.with_only_columns(
primary_table.primary_key)
@@ -2164,19 +2174,11 @@ class Query(object):
select_stmt,
params=self._params).fetchall()
- if self._autoflush:
- session._autoflush()
+ delete_stmt = sql.delete(primary_table, context.whereclause)
+
result = session.execute(delete_stmt, params=self._params)
if synchronize_session == 'evaluate':
- target_cls = self._mapper_zero().class_
-
- #TODO: detect when the where clause is a trivial primary key match
- objs_to_expunge = [
- obj for (cls, pk),obj in
- session.identity_map.iteritems()
- if issubclass(cls, target_cls) and
- eval_condition(obj)]
for obj in objs_to_expunge:
session._remove_newly_deleted(attributes.instance_state(obj))
elif synchronize_session == 'fetch':
@@ -2271,6 +2273,9 @@ class Query(object):
session = self.session
+ if self._autoflush:
+ session._autoflush()
+
if synchronize_session == 'evaluate':
try:
evaluator_compiler = evaluator.EvaluatorCompiler()
@@ -2291,43 +2296,45 @@ class Query(object):
"Could not evaluate current criteria in Python. "
"Specify 'fetch' or False for the "
"synchronize_session parameter.")
+ target_cls = self._mapper_zero().class_
+ matched_objects = []
+ for (cls, pk),obj in session.identity_map.iteritems():
+ evaluated_keys = value_evaluators.keys()
- update_stmt = sql.update(primary_table, context.whereclause, values)
+ if issubclass(cls, target_cls) and eval_condition(obj):
+ matched_objects.append(obj)
- if synchronize_session == 'fetch':
+ elif synchronize_session == 'fetch':
select_stmt = context.statement.with_only_columns(
primary_table.primary_key)
matched_rows = session.execute(
select_stmt,
params=self._params).fetchall()
- if self._autoflush:
- session._autoflush()
+ update_stmt = sql.update(primary_table, context.whereclause, values)
+
result = session.execute(update_stmt, params=self._params)
if synchronize_session == 'evaluate':
target_cls = self._mapper_zero().class_
- for (cls, pk),obj in session.identity_map.iteritems():
- evaluated_keys = value_evaluators.keys()
+ for obj in matched_objects:
+ state, dict_ = attributes.instance_state(obj),\
+ attributes.instance_dict(obj)
- if issubclass(cls, target_cls) and eval_condition(obj):
- state, dict_ = attributes.instance_state(obj),\
- attributes.instance_dict(obj)
-
- # only evaluate unmodified attributes
- to_evaluate = state.unmodified.intersection(
- evaluated_keys)
- for key in to_evaluate:
- dict_[key] = value_evaluators[key](obj)
-
- state.commit(dict_, list(to_evaluate))
-
- # expire attributes with pending changes
- # (there was no autoflush, so they are overwritten)
- state.expire_attributes(dict_,
- set(evaluated_keys).
- difference(to_evaluate))
+ # only evaluate unmodified attributes
+ to_evaluate = state.unmodified.intersection(
+ evaluated_keys)
+ for key in to_evaluate:
+ dict_[key] = value_evaluators[key](obj)
+
+ state.commit(dict_, list(to_evaluate))
+
+ # expire attributes with pending changes
+ # (there was no autoflush, so they are overwritten)
+ state.expire_attributes(dict_,
+ set(evaluated_keys).
+ difference(to_evaluate))
elif synchronize_session == 'fetch':
target_mapper = self._mapper_zero()