summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2006-07-03 15:55:20 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2006-07-03 15:55:20 +0000
commit61579c9302e1e8e745e01588afe615c1d12aaca7 (patch)
tree30baadbf79349081d1a0bef6c4c74f513d6a42f8 /lib/sqlalchemy
parent433f20d631085cf0e14348b4055e45db080b630f (diff)
downloadsqlalchemy-61579c9302e1e8e745e01588afe615c1d12aaca7.tar.gz
ordering of UPDATE and DELETE statements within groups is now
in order of primary key values, for more deterministic ordering after_insert/delete/update mapper extensions now called per object, not per-object-per-table fixed import in firebird.py
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/databases/firebird.py2
-rw-r--r--lib/sqlalchemy/orm/dependency.py1
-rw-r--r--lib/sqlalchemy/orm/mapper.py47
3 files changed, 40 insertions, 10 deletions
diff --git a/lib/sqlalchemy/databases/firebird.py b/lib/sqlalchemy/databases/firebird.py
index 42779e8ff..0039333d5 100644
--- a/lib/sqlalchemy/databases/firebird.py
+++ b/lib/sqlalchemy/databases/firebird.py
@@ -8,7 +8,7 @@
import sys, StringIO, string, types
import sqlalchemy.engine.default as default
-# import sqlalchemy.sql as sql
+import sqlalchemy.sql as sql
import sqlalchemy.schema as schema
import sqlalchemy.ansisql as ansisql
# from sqlalchemy import *
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py
index 8970dab50..1af368431 100644
--- a/lib/sqlalchemy/orm/dependency.py
+++ b/lib/sqlalchemy/orm/dependency.py
@@ -279,6 +279,7 @@ class ManyToManyDP(DependencyProcessor):
self._synchronize(obj, child, associationrow, False)
secondary_delete.append(associationrow)
if len(secondary_delete):
+ secondary_delete.sort()
# TODO: precompile the delete/insert queries and store them as instance variables
# on the PropertyLoader
statement = self.secondary.delete(sql.and_(*[c == sql.bindparam(c.key) for c in self.secondary.c if c.key in associationrow]))
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index b6c5dc56d..120c5f209 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -742,7 +742,6 @@ class Mapper(object):
def _setattrbycolumn(self, obj, column, value):
self.columntoproperty[column][0].setattr(obj, value)
-
def save_obj(self, objects, uow, postupdate=False):
"""called by a UnitOfWork object to save objects, which involves either an INSERT or
@@ -750,6 +749,16 @@ class Mapper(object):
list."""
#print "SAVE_OBJ MAPPER", self.class_.__name__, objects
connection = uow.transaction.connection(self)
+
+ if not postupdate:
+ for obj in objects:
+ if not hasattr(obj, "_instance_key"):
+ self.extension.before_insert(self, connection, obj)
+ else:
+ self.extension.before_update(self, connection, obj)
+
+ inserted_objects = util.Set()
+ updated_objects = util.Set()
for table in self.tables.sort(reverse=False):
#print "SAVE_OBJ table ", self.class_.__name__, table.name
# looping through our set of tables, which are all "real" tables, as opposed
@@ -857,14 +866,24 @@ class Mapper(object):
statement = table.update(clause)
rows = 0
supports_sane_rowcount = True
+ def comparator(a, b):
+ for col in self.pks_by_table[table]:
+ x = cmp(a[1][col._label],b[1][col._label])
+ if x != 0:
+ return x
+ return 0
+ update.sort(comparator)
for rec in update:
(obj, params) = rec
c = connection.execute(statement, params)
self._postfetch(connection, table, obj, c, c.last_updated_params())
- self.extension.after_update(self, connection, obj)
+
+ updated_objects.add(obj)
rows += c.cursor.rowcount
+
if c.supports_sane_rowcount() and rows != len(update):
raise exceptions.FlushError("ConcurrencyError - updated rowcount %d does not match number of objects updated %d" % (rows, len(update)))
+
if len(insert):
statement = table.insert()
for rec in insert:
@@ -888,7 +907,10 @@ class Mapper(object):
mapper._synchronizer.execute(obj, obj)
sync(self)
- self.extension.after_insert(self, connection, obj)
+ inserted_objects.add(obj)
+ if not postupdate:
+ [self.extension.after_insert(self, connection, obj) for obj in inserted_objects]
+ [self.extension.after_update(self, connection, obj) for obj in updated_objects]
def _postfetch(self, connection, table, obj, resultproxy, params):
"""after an INSERT or UPDATE, asks the returned result if PassiveDefaults fired off on the database side
@@ -917,12 +939,13 @@ class Mapper(object):
DELETE statement for each table used by this mapper, for each object in the list."""
connection = uow.transaction.connection(self)
#print "DELETE_OBJ MAPPER", self.class_.__name__, objects
-
+
+ [self.extension.before_delete(self, connection, obj) for obj in objects]
+ deleted_objects = util.Set()
for table in self.tables.sort(reverse=True):
if not self._has_pks(table):
continue
delete = []
- deleted_objects = []
for obj in objects:
params = {}
if not hasattr(obj, "_instance_key"):
@@ -933,9 +956,15 @@ class Mapper(object):
params[col.key] = self._getattrbycolumn(obj, col)
if self.version_id_col is not None:
params[self.version_id_col.key] = self._getattrbycolumn(obj, self.version_id_col)
- self.extension.before_delete(self, connection, obj)
- deleted_objects.append(obj)
+ deleted_objects.add(obj)
if len(delete):
+ def comparator(a, b):
+ for col in self.pks_by_table[table]:
+ x = cmp(a[col.key],b[col.key])
+ if x != 0:
+ return x
+ return 0
+ delete.sort(comparator)
clause = sql.and_()
for col in self.pks_by_table[table]:
clause.clauses.append(col == sql.bindparam(col.key, type=col.type))
@@ -945,8 +974,8 @@ class Mapper(object):
c = connection.execute(statement, delete)
if c.supports_sane_rowcount() and c.rowcount != len(delete):
raise exceptions.FlushError("ConcurrencyError - updated rowcount %d does not match number of objects updated %d" % (c.cursor.rowcount, len(delete)))
- for obj in deleted_objects:
- self.extension.after_delete(self, connection, obj)
+
+ [self.extension.after_delete(self, connection, obj) for obj in deleted_objects]
def _has_pks(self, table):
try: