Index: Connection.py
===================================================================
RCS file: /cvs-repository/Packages/ZODB/Attic/Connection.py,v
retrieving revision 1.98.4.11
diff -u -r1.98.4.11 Connection.py
--- Connection.py	2 May 2005 20:30:27 -0000	1.98.4.11
+++ Connection.py	2 Jun 2005 15:34:50 -0000
@@ -120,6 +120,10 @@
         # Transaction.abort() calls, so there's not much choice.
         self._object_registered = False
 
+        self.SETSTATE_QUEUE = []
+        self.OID_BACK = {}
+        self.OID_ID = {}
+
     def getTransaction(self):
         t = self._transaction
         if t is None:
@@ -203,6 +207,9 @@
         __traceback_info__=oid
 
         if type(oid) is tt:
+            if self.SETSTATE_QUEUE:
+                self.SETSTATE_QUEUE[-1][oid[0]] = None
+
             # Quick instance reference.  We know all we need to know
             # to create the instance wo hitting the db, so go for it!
             oid, klass = oid
@@ -228,6 +235,9 @@
 
             return object
 
+        if self.SETSTATE_QUEUE:
+            self.SETSTATE_QUEUE[-1][oid] = None
+
         obj = self._cache.get(oid, None)
         if obj is not None:
             return obj
@@ -587,6 +597,7 @@
             raise RuntimeError(msg)
 
         try:
+            self.SETSTATE_QUEUE.append({})
             # Avoid reading data from a transaction that committed
             # after the current transaction started, as that might
             # lead to mixing of cached data from earlier transactions
@@ -602,12 +613,39 @@
             if invalid:
                 self._handle_independent(obj)
         except ConflictError:
+            self.SETSTATE_QUEUE.pop()
             raise
         except:
             LOG('ZODB', ERROR,
                 "Couldn't load state for %s" % oid_repr(oid),
                 error=sys.exc_info())
+            self.SETSTATE_QUEUE.pop()
             raise
+
+        # Store backpointers
+        suboids = self.SETSTATE_QUEUE.pop().keys()
+        for suboid in suboids:
+            # assume only one reference per object
+            self.OID_BACK[suboid] = oid
+
+        # Store id and class name
+        dict = getattr(obj, '__dict__', {})
+        klass = obj.__class__
+        id = (dict.get('id') or dict.get('__name__')
+              or getattr(klass, 'id', None))
+        self.OID_ID[oid] = (id, klass.__name__)
+
+        #print 'loading %s: %s' % (oid_repr(oid), self._oid_path(oid))
+
+    def _oid_path(self, oid):
+        if oid in ('\0\0\0\0\0\0\0\0', '\0\0\0\0\0\0\0\1', None):
+            return ''
+        id, clsname = self.OID_ID.get(oid, ('', '?'))
+        if not id:
+            id = '(%s %s)' % (clsname, oid_repr(oid))
+        back_oid = self.OID_BACK.get(oid)
+        path = self._oid_path(back_oid)+'/'+id
+        return path
 
     def _is_invalidated(self, obj):
         # Helper method for setstate() covers three cases:
Index: POSException.py
===================================================================
RCS file: /cvs-repository/Packages/ZODB/Attic/POSException.py,v
retrieving revision 1.20.4.5
diff -u -r1.20.4.5 POSException.py
--- POSException.py	9 Sep 2004 18:18:19 -0000	1.20.4.5
+++ POSException.py	2 Jun 2005 15:34:50 -0000
@@ -67,10 +67,12 @@
         if object is None:
             self.oid = None
             self.class_name = None
+            self.path = ''
         else:
             self.oid = object._p_oid
             klass = object.__class__
             self.class_name = klass.__module__ + "." + klass.__name__
+            self.path = object._p_jar._oid_path(self.oid)
 
         if oid is not None:
             assert self.oid is None
@@ -90,6 +92,8 @@
                           readable_tid_repr(old))
             extras.append("serial currently committed %s" %
                           readable_tid_repr(current))
+        if self.path:
+            extras.append("path %s" % self.path)
         if extras:
             return "%s (%s)" % (self.message, ", ".join(extras))
         else:
