]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- SingletonConnectionPool must use the "threadlocal" pooling behavior
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 24 Oct 2006 22:19:31 +0000 (22:19 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 24 Oct 2006 22:19:31 +0000 (22:19 +0000)
- 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().

CHANGES
doc/build/content/adv_datamapping.txt
lib/sqlalchemy/orm/dependency.py
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/pool.py

diff --git a/CHANGES b/CHANGES
index ba5bafc575a74bab5e4850533c49d1e25b6e1f6c..b19142f92bc7a6b6d65939938a2a76584e00875e 100644 (file)
--- 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:
index ccbadc30eb7edaedf46ac2ae89c91aca39de57fc..0a0274c46aacec1bde41a78841e70ec8b2083a64 100644 (file)
@@ -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}
 
index 8bf5a489d9b389ef0a5941fde65d43c618e3f3bf..0e74a3873cae1623d7c7f3401689440f3abd3f92 100644 (file)
@@ -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()
index 5019039833e1ff852a64dfac601c809caf27f571..a810e7e96b2eddea96d35bcd5db6d627c15161b7 100644 (file)
@@ -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)
index 79fc22927c73234f13b6850a663770230fca92d0..cd58c103130f654d126487ea77f65a683600a242 100644 (file)
@@ -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