From d4c60a64a62e5c2542a27918e6d3c9fc26875736 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 14 Jul 2006 21:02:35 +0000 Subject: [PATCH] deferred column load could screw up the connection status in a flush() under some circumstances, this was fixed --- CHANGES | 2 ++ lib/sqlalchemy/engine/base.py | 14 +++++++++----- lib/sqlalchemy/orm/properties.py | 22 +++++++++++----------- test/orm/objectstore.py | 9 +++++++++ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 810f2ec9a9..7fbbe6e015 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,8 @@ this also adds them to activemapper database if you supply a __autoload__ = True attribute in your mapping inner-class. Currently this does not support reflecting any relationships. +- deferred column load could screw up the connection status in +a flush() under some circumstances, this was fixed 0.2.5 - fixed endless loop bug in select_by(), if the traversal hit diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 85e68825f2..048c240098 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -231,11 +231,15 @@ class Connection(Connectable): self.__connection = None del self.__connection def scalar(self, object, parameters=None, **kwargs): - row = self.execute(object, parameters, **kwargs).fetchone() - if row is not None: - return row[0] - else: - return None + result = self.execute(object, parameters, **kwargs) + row = result.fetchone() + try: + if row is not None: + return row[0] + else: + return None + finally: + result.close() def execute(self, object, *multiparams, **params): return Connection.executors[type(object).__mro__[-2]](self, object, *multiparams, **params) def execute_default(self, default, **kwargs): diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 997636b49b..752ea23af1 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -79,16 +79,15 @@ class DeferredColumnProperty(ColumnProperty): if not attr: return None clause.clauses.append(primary_key == attr) - session = sessionlib.object_session(instance) if session is None: raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) - connection = session.connection(self.parent) - - try: - if self.group is not None: - groupcols = [p for p in self.localparent.props.values() if isinstance(p, DeferredColumnProperty) and p.group==self.group] - row = connection.execute(sql.select([g.columns[0] for g in groupcols], clause, use_labels=True), None).fetchone() + + if self.group is not None: + groupcols = [p for p in self.localparent.props.values() if isinstance(p, DeferredColumnProperty) and p.group==self.group] + result = session.execute(self.localparent, sql.select([g.columns[0] for g in groupcols], clause, use_labels=True), None) + try: + row = result.fetchone() for prop in groupcols: if prop is self: continue @@ -97,10 +96,11 @@ class DeferredColumnProperty(ColumnProperty): instance.__dict__[prop.key] = row[prop.columns[0]] sessionlib.attribute_manager.init_instance_attribute(instance, prop.key, uselist=False) return row[self.columns[0]] - else: - return connection.scalar(sql.select([self.columns[0]], clause, use_labels=True),None) - finally: - connection.close() + finally: + result.close() + else: + return session.scalar(self.localparent, sql.select([self.columns[0]], clause, use_labels=True),None) + return lazyload def setup(self, key, statement, **options): pass diff --git a/test/orm/objectstore.py b/test/orm/objectstore.py index 237c4b5545..19e5faccb8 100644 --- a/test/orm/objectstore.py +++ b/test/orm/objectstore.py @@ -612,6 +612,15 @@ class SaveTest(SessionTest): l = AddressUser.mapper.selectone() self.assert_(l.user_id == au.user_id and l.address_id == au.address_id) + def testdeferred(self): + """test that a deferred load within a flush() doesnt screw up the connection""" + mapper(User, users, properties={ + 'user_name':deferred(users.c.user_name) + }) + u = User() + u.user_id=42 + ctx.current.flush() + def testmultitable(self): """tests a save of an object where each instance spans two tables. also tests redefinition of the keynames for the column properties.""" -- 2.47.3