diff --git a/product/ZSQLCatalog/SQLCatalog.py b/product/ZSQLCatalog/SQLCatalog.py
index fafa193d9fa2b8e08f58f93c94c35ebf068d093d..5a98caebed981d0f81bc1f0f13e5731540ae571f 100755
--- a/product/ZSQLCatalog/SQLCatalog.py
+++ b/product/ZSQLCatalog/SQLCatalog.py
@@ -50,6 +50,10 @@ try:
 except ImportError:
   withCMF = 0
 
+try:
+  import psyco
+except ImportError:
+  psyco = None
 
 UID_BUFFER_SIZE = 900
 MAX_UID_BUFFER_SIZE = 20000
@@ -1033,7 +1037,7 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
         #                                                                   100,str(path))
 
   security.declarePrivate('queueCataloggedObject')
-  def queueCataloggedObject(self, object, **kw):
+  def queueCataloggedObject(self, object, *args, **kw):
     """
       Add an object into the queue for catalogging the object later in a batch form.
     """
@@ -1049,7 +1053,7 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
       self.flushQueuedObjectList()
 
   security.declarePublic('flushQueuedObjectList')
-  def flushQueuedObjectList(self, **kw):
+  def flushQueuedObjectList(self, *args, **kw):
     """
       Flush queued objects.
     """
@@ -1089,6 +1093,8 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
 
       XXX: For now newUid is used to allocated UIDs. Is this good? Is it better to INSERT then SELECT?
     """
+    LOG('catalogObjectList', 0, 'called with %d objects' % len(object_list))
+    
     if withCMF:
       zope_root = getToolByName(self, 'portal_url').getPortalObject().aq_parent
     else:
@@ -1099,13 +1105,57 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
       return
 
     for object in object_list:
-      if getattr(aq_base(object), 'uid', None) is None:
+      if not getattr(aq_base(object), 'uid', None):
         try:
-          object._setUid(self.newUid())
+          object.uid = self.newUid()
         except:
           raise RuntimeError, 'could not set missing uid for %r' % (object,)
+      else:
+        uid = object.uid
+        path = object.getPath()
+        index = self.getUidForPath(path)
+        try:
+          index = int(index)
+        except TypeError:
+          pass
+        if index is not None and index < 0:
+          raise CatalogError, 'A negative uid %d is used for %s. Your catalog is broken. Recreate your catalog.' % (index, path)
+        if index:
+          if uid != index:
+            LOG('SQLCatalog Warning:', 0, 'uid of %r changed from %r to %r !!! This can be fatal. You should reindex the whole site immediately.' % (object, uid, index))
+            uid = index
+            object.uid = uid
+        else:
+          # Make sure no duplicates - ie. if an object with different path has same uid, we need a new uid
+          # This can be very dangerous with relations stored in a category table (CMFCategory)
+          # This is why we recommend completely reindexing subobjects after any change of id
+          catalog_path = self.getPathForUid(uid)
+          #LOG('catalogObject', 0, 'uid = %r, catalog_path = %r' % (uid, catalog_path))
+          if catalog_path == "reserved":
+            # Reserved line in catalog table
+            klass = self.__class__
+            try:
+              klass._reserved_uid_lock.acquire()
+              uid_list = getattr(aq_base(self), '_v_uid_buffer', [])
+              if uid in uid_list:
+                # This is the case where:
+                #   1. The object got an uid.
+                #   2. The catalog was cleared.
+                #   3. The catalog produced the same reserved uid.
+                #   4. The object was reindexed.
+                # In this case, the uid is not reserved any longer, but
+                # SQLCatalog believes that it is still reserved. So it is
+                # necessary to remove the uid from the list explicitly.
+                uid_list.remove(uid)
+                self._v_uid_buffer = uid_list
+            finally:
+              klass._reserved_uid_lock.release()
+          elif catalog_path is not None:
+            # An uid conflict happened... Why?
+            object.uid = self.newUid()
 
     methods = self.sql_catalog_object_list
+    econtext_cache = {}
     for method_name in methods:
       kw = {}
       #LOG('catalogObjectList', 0, 'method_name = %s, self.isMethodFiltered(method_name) = %r, self.filter_dict.has_key(method_name) = %r' % (method_name, self.isMethodFiltered(method_name), self.filter_dict.has_key(method_name)))
@@ -1119,10 +1169,14 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
           # method, if so we may not call this zsqlMethod
           # for this object
           portal_type = object.getPortalType()
-          if portal_type not in type_list:
+          if type_list and portal_type not in type_list:
             continue
           elif expression is not None:
-              econtext = self.getExpressionContext(object)
+              try:
+                econtext = econtext_cache[object.uid]
+              except KeyError:
+                econtext_cache[object.uid] = self.getExpressionContext(object)
+                econtext = econtext_cache[object.uid]
               result = expression(econtext)
               if not result:
                 continue
@@ -1145,9 +1199,11 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
             #LOG('catalog_object_list: object.uid',0,getattr(object,'uid',None))
             #LOG('catalog_object_list: object.path',0,object.getPhysicalPath())
             try:
-              value = getattr(object, arg)
+              value = getattr(object, arg, None)
               if callable(value):
                 value = value()
+              #if arg == 'optimised_roles_and_users':
+              #  LOG('catalogObjectList', 0, 'object = %r, arg = %r, value = %r' % (object, arg, value,))
               append(value)
             except:
               #LOG("SQLCatalog Warning: Callable value could not be called",0,str((path, arg, method_name)))
@@ -1158,6 +1214,7 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
       # Alter/Create row
       try:
         #start_time = DateTime()
+        #LOG('catalogObjectList', 0, 'kw = %r, method_name = %r' % (kw, method_name))
         method(**kw)
         #end_time = DateTime()
         #if method_name not in profile_dict:
@@ -1168,6 +1225,8 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
       except:
         LOG("SQLCatalog Warning: could not catalog objects with method %s" % method_name,100, str(object_list))
         raise
+    
+  if psyco is not None: psyco.bind(catalogObjectList)
 
   def uncatalogObject(self, path):
     """
@@ -1841,10 +1900,13 @@ class Catalog(Folder, Persistent, Acquisition.Implicit, ExtensionClass.Base):
             'here':         ob,
             'container':    aq_parent(aq_inner(ob)),
             'nothing':      None,
-            'root':         ob.getPhysicalRoot(),
-            'request':      getattr( ob, 'REQUEST', None ),
-            'modules':      SecureModuleImporter,
-            'user':         getSecurityManager().getUser(),
+            #'root':         ob.getPhysicalRoot(),
+            #'request':      getattr( ob, 'REQUEST', None ),
+            #'modules':      SecureModuleImporter,
+            #'user':         getSecurityManager().getUser(),
+            'isDelivery':   ob.isDelivery, # XXX
+            'isMovement':   ob.isMovement, # XXX
+            'isPredicate':  ob.isPredicate, # XXX
             }
         return getEngine().getContext(data)