From: Mike Bayer Date: Tue, 24 Oct 2006 22:19:31 +0000 (+0000) Subject: - SingletonConnectionPool must use the "threadlocal" pooling behavior X-Git-Tag: rel_0_3_1~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7d1d6deab0716ac49b5cb25656f3ce895b6775a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - SingletonConnectionPool must use the "threadlocal" pooling behavior - the "delete" cascade will load in all child objects, if they were not loaded already. this can be turned off (i.e. the old behavior) by setting passive_deletes=True on a relation(). --- diff --git a/CHANGES b/CHANGES index ba5bafc575..b19142f92b 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ - adjustments to reworked eager query generation - some new Pool utility classes, updated docs - "use_threadlocal" on Pool defaults to False (same as create_engine) +- the "delete" cascade will load in all child objects, if they were not +loaded already. this can be turned off (i.e. the old behavior) by setting +passive_deletes=True on a relation(). 0.3.0 - General: diff --git a/doc/build/content/adv_datamapping.txt b/doc/build/content/adv_datamapping.txt index ccbadc30eb..0a0274c46a 100644 --- a/doc/build/content/adv_datamapping.txt +++ b/doc/build/content/adv_datamapping.txt @@ -269,6 +269,7 @@ Keyword options to the `relation` function include: * post_update - this indicates that the relationship should be handled by a second UPDATE statement after an INSERT, or before a DELETE. using this flag essentially means the relationship will not incur any "dependency" between parent and child item, as the particular foreign key relationship between them is handled by a second statement. use this flag when a particular mapping arrangement will incur two rows that are dependent on each other, such as a table that has a one-to-many relationship to a set of child rows, and also has a column that references a single child row within that list (i.e. both tables contain a foreign key to each other). If a flush() operation returns an error that a "cyclical dependency" was detected, this is a cue that you might want to use post_update. * viewonly=(True|False) - when set to True, the relation is used only for loading objects within the relationship, and has no effect on the unit-of-work flush process. relations with viewonly can specify any kind of join conditions to provide additional views of related objects onto a parent object. * collection_class = None - a class or function that returns a new list-holding object. will be used in place of a plain list for storing elements. +* passive_deletes = False - if False, child instances will be loaded from the database into the current session when a parent instance is deleted so that delete cascade can be processed on those child instances, even if they were not loaded already. When set to True, lazy loaders will not be fired off in order to process a "delete" cascade, which is appropriate if "ON DELETE" rules have been set up on the database tables themselves. ### Controlling Ordering {@name=orderby} diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 8bf5a489d9..0e74a3873c 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -36,6 +36,7 @@ class DependencyProcessor(object): self.is_backref = prop.is_backref self.post_update = prop.post_update self.foreignkey = prop.foreignkey + self.passive_deletes = prop.passive_deletes self.key = prop.key self._compile_synchronizers() diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 5019039833..a810e7e96b 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -72,7 +72,7 @@ mapper.ColumnProperty = ColumnProperty class PropertyLoader(StrategizedProperty): """describes an object property that holds a single item or list of items that correspond to a related database table.""" - def __init__(self, argument, secondary, primaryjoin, secondaryjoin, foreignkey=None, uselist=None, private=False, association=None, order_by=False, attributeext=None, backref=None, is_backref=False, post_update=False, cascade=None, viewonly=False, lazy=True, collection_class=None): + def __init__(self, argument, secondary, primaryjoin, secondaryjoin, foreignkey=None, uselist=None, private=False, association=None, order_by=False, attributeext=None, backref=None, is_backref=False, post_update=False, cascade=None, viewonly=False, lazy=True, collection_class=None, passive_deletes=False): self.uselist = uselist self.argument = argument self.secondary = secondary @@ -84,7 +84,8 @@ class PropertyLoader(StrategizedProperty): self.lazy = lazy self.foreignkey = util.to_set(foreignkey) self.collection_class = collection_class - + self.passive_deletes = passive_deletes + if cascade is not None: self.cascade = mapperutil.CascadeOptions(cascade) else: @@ -124,7 +125,8 @@ class PropertyLoader(StrategizedProperty): def cascade_iterator(self, type, object, recursive): if not type in self.cascade: return - childlist = sessionlib.attribute_manager.get_history(object, self.key, passive=True) + passive = type != 'delete' or self.passive_deletes + childlist = sessionlib.attribute_manager.get_history(object, self.key, passive=passive) if childlist is None: return mapper = self.mapper.primary_mapper() @@ -140,7 +142,8 @@ class PropertyLoader(StrategizedProperty): return mapper = self.mapper.primary_mapper() - for c in sessionlib.attribute_manager.get_as_list(object, self.key, passive=True): + passive = type != 'delete' or self.passive_deletes + for c in sessionlib.attribute_manager.get_as_list(object, self.key, passive=passive): if c is not None and c not in recursive: recursive.add(c) callable_(c, mapper.entity_name) diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py index 79fc22927c..cd58c10313 100644 --- a/lib/sqlalchemy/pool.py +++ b/lib/sqlalchemy/pool.py @@ -26,6 +26,8 @@ except: proxies = {} +ERROR_ON_RETURN = False + def manage(module, **params): """given a DBAPI2 module and pool management parameters, returns a proxy for the module that will automatically pool connections, creating new connection pools for each @@ -244,6 +246,11 @@ class _ConnectionFairy(object): # damn mysql -- (todo look for NotSupportedError) pass if self._connection_record is not None: + global ERROR_ON_RETURN + if ERROR_ON_RETURN: + ERROR_ON_RETURN=False + raise "hi" + if self.__pool.echo: self.__pool.log("Connection %s being returned to pool" % repr(self.connection)) self.__pool.return_conn(self) @@ -273,6 +280,7 @@ class SingletonThreadPool(Pool): pool_size=5 - the number of threads in which to maintain connections at once.""" def __init__(self, creator, pool_size=5, **params): + params['use_threadlocal'] = True Pool.__init__(self, creator, **params) self._conns = {} self.size = pool_size