[ms, entity metas] add 'actual source' to entities table / base entity metadata cache. Closes #1767090
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 21 Jun 2011 10:57:25 +0200
changeset 7543 570522300e22
parent 7542 86e9632a4e9c
child 7547 3d654a7df823
[ms, entity metas] add 'actual source' to entities table / base entity metadata cache. Closes #1767090 this is needed since for entities from 'copy based sources' such as datafeed, we want entity.cw_metainformation() to return as 'source' the datafeed source, not the system source (ie the source where the entity is actually stored). For both performance and bootstraping reasons, we should store this information in the `entities` table and in the _type_source cache.
__pkginfo__.py
dbapi.py
entity.py
hooks/metadata.py
misc/migration/bootstrapmigration_repository.py
req.py
server/repository.py
server/schemaserial.py
server/session.py
server/sources/native.py
server/test/unittest_datafeed.py
server/test/unittest_msplanner.py
server/test/unittest_repository.py
--- a/__pkginfo__.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/__pkginfo__.py	Tue Jun 21 10:57:25 2011 +0200
@@ -22,7 +22,7 @@
 
 modname = distname = "cubicweb"
 
-numversion = (3, 13, 0)
+numversion = (3, 13, 1)
 version = '.'.join(str(num) for num in numversion)
 
 description = "a repository of entities / relations for knowledge management"
--- a/dbapi.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/dbapi.py	Tue Jun 21 10:57:25 2011 +0200
@@ -346,9 +346,9 @@
 
     # server session compat layer #############################################
 
-    def describe(self, eid):
+    def describe(self, eid, asdict=False):
         """return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
-        return self.cnx.describe(eid)
+        return self.cnx.describe(eid, asdict)
 
     def source_defs(self):
         """return the definition of sources used by the repository."""
@@ -674,8 +674,16 @@
         return self._repo.get_option_value(option, foreid)
 
     @check_not_closed
-    def describe(self, eid):
-        return self._repo.describe(self.sessionid, eid, **self._txid())
+    def describe(self, eid, asdict=False):
+        metas = self._repo.describe(self.sessionid, eid, **self._txid())
+        if asdict:
+            if len(metas) == 3:
+                d = dict(zip(('type', 'source', 'extid'), metas))
+                d['asource'] = d['source']
+                return d
+            return dict(zip(('type', 'source', 'extid', 'asource'), metas))
+        # XXX :-1 for cw compat, use asdict=True for full information
+        return metas[:-1]
 
     # db-api like interface ####################################################
 
--- a/entity.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/entity.py	Tue Jun 21 10:57:25 2011 +0200
@@ -395,8 +395,10 @@
 
     @cached
     def cw_metainformation(self):
-        res = dict(zip(('type', 'source', 'extid'), self._cw.describe(self.eid)))
-        res['source'] = self._cw.source_defs()[res['source']]
+        res = self._cw.describe(self.eid, asdict=True)
+        # use 'asource' and not 'source' since this is the actual source,
+        # while 'source' is the physical source (where it's stored)
+        res['source'] = self._cw.source_defs()[res.pop('asource')]
         return res
 
     def cw_check_perm(self, action):
--- a/hooks/metadata.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/hooks/metadata.py	Tue Jun 21 10:57:25 2011 +0200
@@ -154,7 +154,7 @@
         entity = self.entity
         extid = entity.cw_metainformation()['extid']
         repo._type_source_cache[entity.eid] = (
-            entity.__regid__, self.newsource.uri, None)
+            entity.__regid__, self.newsource.uri, None, self.newsource.uri)
         if self.oldsource.copy_based_source:
             uri = 'system'
         else:
@@ -177,6 +177,7 @@
         schange = self._cw.transaction_data.setdefault('cw_source_change', {})
         schange[self.eidfrom] = self.eidto
 
+
 class ChangeEntitySourceAddHook(MetaDataHook):
     __regid__ = 'cw.metadata.source-change'
     __select__ = MetaDataHook.__select__ & hook.match_rtype('cw_source')
@@ -204,10 +205,12 @@
             # source='system'. External source will then have consider case
             # where `extid2eid` return a negative eid as 'this entity was known
             # but has been moved, ignore it'.
-            self._cw.system_sql('UPDATE entities SET eid=-eid,source=%(source)s WHERE eid=%(eid)s',
+            self._cw.system_sql('UPDATE entities SET eid=-eid,source=%(source)s '
+                                'WHERE eid=%(eid)s',
                                 {'eid': self.eidfrom, 'source': newsource.name})
             attrs = {'type': entity.__regid__, 'eid': entity.eid, 'extid': None,
-                     'source': 'system', 'mtime': datetime.now()}
+                     'source': 'system', 'asource': 'system',
+                     'mtime': datetime.now()}
             self._cw.system_sql(syssource.sqlgen.insert('entities', attrs), attrs)
             # register an operation to update repository/sources caches
             ChangeEntityUpdateCaches(self._cw, entity=entity,
--- a/misc/migration/bootstrapmigration_repository.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/misc/migration/bootstrapmigration_repository.py	Tue Jun 21 10:57:25 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -35,6 +35,12 @@
     ss.execschemarql(rql, rdef, ss.rdef2rql(rdef, CSTRMAP, groupmap=None))
     commit(ask_confirm=False)
 
+if applcubicwebversion == (3, 13, 0) and cubicwebversion >= (3, 13, 1):
+    sql('ALTER TABLE entities ADD COLUMN asource VARCHAR(64)')
+    sql('INSERT INTO entities(asource) '
+        'SELECT cw_name FROM cw_CWSource, cw_source_relation '
+        'WHERE entities.eid=cw_source_relation.eid_from AND cw_source_relation.eid_to=cw_CWSource.cw_eid')
+
 if applcubicwebversion == (3, 6, 0) and cubicwebversion >= (3, 6, 0):
     CSTRMAP = dict(rql('Any T, X WHERE X is CWConstraintType, X name T',
                        ask_confirm=False))
--- a/req.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/req.py	Tue Jun 21 10:57:25 2011 +0200
@@ -409,7 +409,7 @@
 
     # abstract methods to override according to the web front-end #############
 
-    def describe(self, eid):
+    def describe(self, eid, asdict=False):
         """return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
         raise NotImplementedError
 
--- a/server/repository.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/repository.py	Tue Jun 21 10:57:25 2011 +0200
@@ -154,7 +154,7 @@
         self.sources_by_uri = {'system': self.system_source}
         # querier helper, need to be created after sources initialization
         self.querier = querier.QuerierHelper(self, self.schema)
-        # cache eid -> (type, source, extid)
+        # cache eid -> (type, physical source, extid, actual source)
         self._type_source_cache = {}
         # cache (extid, source uri) -> eid
         self._extid_cache = {}
@@ -534,7 +534,7 @@
         # XXX we may want to check we don't give sensible information
         if foreid is None:
             return self.config[option]
-        _, sourceuri, extid = self.type_and_source_from_eid(foreid)
+        _, sourceuri, extid, _ = self.type_and_source_from_eid(foreid)
         if sourceuri == 'system':
             return self.config[option]
         cnxset = self._get_cnxset()
@@ -749,7 +749,9 @@
             session.free_cnxset()
 
     def describe(self, sessionid, eid, txid=None):
-        """return a tuple (type, source, extid) for the entity with id <eid>"""
+        """return a tuple `(type, physical source uri, extid, actual source
+        uri)` for the entity of the given `eid`
+        """
         session = self._get_session(sessionid, setcnxset=True, txid=txid)
         try:
             return self.type_and_source_from_eid(eid, session)
@@ -954,7 +956,9 @@
     # * correspondance between eid and local id (i.e. specific to a given source)
 
     def type_and_source_from_eid(self, eid, session=None):
-        """return a tuple (type, source, extid) for the entity with id <eid>"""
+        """return a tuple `(type, physical source uri, extid, actual source
+        uri)` for the entity of the given `eid`
+        """
         try:
             eid = typed_eid(eid)
         except ValueError:
@@ -968,15 +972,15 @@
             else:
                 free_cnxset = False
             try:
-                etype, uri, extid = self.system_source.eid_type_source(session,
-                                                                       eid)
+                etype, uri, extid, auri = self.system_source.eid_type_source(
+                    session, eid)
             finally:
                 if free_cnxset:
                     session.free_cnxset()
-        self._type_source_cache[eid] = (etype, uri, extid)
-        if uri != 'system':
-            self._extid_cache[(extid, uri)] = eid
-        return etype, uri, extid
+            self._type_source_cache[eid] = (etype, uri, extid, auri)
+            if uri != 'system':
+                self._extid_cache[(extid, uri)] = eid
+            return etype, uri, extid, auri
 
     def clear_caches(self, eids):
         etcache = self._type_source_cache
@@ -984,7 +988,7 @@
         rqlcache = self.querier._rql_cache
         for eid in eids:
             try:
-                etype, uri, extid = etcache.pop(typed_eid(eid)) # may be a string in some cases
+                etype, uri, extid, auri = etcache.pop(typed_eid(eid)) # may be a string in some cases
                 rqlcache.pop('%s X WHERE X eid %s' % (etype, eid), None)
                 extidcache.pop((extid, uri), None)
             except KeyError:
@@ -1018,7 +1022,7 @@
 
     def eid2extid(self, source, eid, session=None):
         """get local id from an eid"""
-        etype, uri, extid = self.type_and_source_from_eid(eid, session)
+        etype, uri, extid, _ = self.type_and_source_from_eid(eid, session)
         if source.uri != uri:
             # eid not from the given source
             raise UnknownEid(eid)
@@ -1061,7 +1065,7 @@
         eid = self.system_source.extid2eid(session, uri, extid)
         if eid is not None:
             self._extid_cache[cachekey] = eid
-            self._type_source_cache[eid] = (etype, uri, extid)
+            self._type_source_cache[eid] = (etype, uri, extid, source.uri)
             if free_cnxset:
                 session.free_cnxset()
             return eid
@@ -1079,7 +1083,7 @@
         try:
             eid = self.system_source.create_eid(session)
             self._extid_cache[cachekey] = eid
-            self._type_source_cache[eid] = (etype, uri, extid)
+            self._type_source_cache[eid] = (etype, uri, extid, source.uri)
             entity = source.before_entity_insertion(
                 session, extid, etype, eid, sourceparams)
             if source.should_call_hooks:
@@ -1215,7 +1219,8 @@
                 suri = 'system'
             extid = source.get_extid(entity)
             self._extid_cache[(str(extid), suri)] = entity.eid
-        self._type_source_cache[entity.eid] = (entity.__regid__, suri, extid)
+        self._type_source_cache[entity.eid] = (entity.__regid__, suri, extid,
+                                               source.uri)
         return extid
 
     def glob_add_entity(self, session, edited):
@@ -1376,7 +1381,7 @@
         # in setdefault, this should not be changed without profiling.
 
         for eid in eids:
-            etype, sourceuri, extid = self.type_and_source_from_eid(eid, session)
+            etype, sourceuri, extid, _ = self.type_and_source_from_eid(eid, session)
             # XXX should cache entity's cw_metainformation
             entity = session.entity_from_eid(eid, etype)
             try:
--- a/server/schemaserial.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/schemaserial.py	Tue Jun 21 10:57:25 2011 +0200
@@ -138,8 +138,8 @@
             except:
                 pass
             tocleanup = [eid]
-            tocleanup += (eid for eid, (eidetype, uri, extid) in repo._type_source_cache.items()
-                          if etype == eidetype)
+            tocleanup += (eid for eid, cached in repo._type_source_cache.iteritems()
+                          if etype == cached[0])
             repo.clear_caches(tocleanup)
             session.commit(False)
             if needcopy:
--- a/server/session.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/session.py	Tue Jun 21 10:57:25 2011 +0200
@@ -870,9 +870,13 @@
     def source_defs(self):
         return self.repo.source_defs()
 
-    def describe(self, eid):
+    def describe(self, eid, asdict=False):
         """return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
-        return self.repo.type_and_source_from_eid(eid, self)
+        metas = self.repo.type_and_source_from_eid(eid, self)
+        if asdict:
+            return dict(zip(('type', 'source', 'extid', 'asource'), metas)) 
+       # XXX :-1 for cw compat, use asdict=True for full information
+        return metas[:-1]
 
     # db-api like interface ###################################################
 
--- a/server/sources/native.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/sources/native.py	Tue Jun 21 10:57:25 2011 +0200
@@ -411,6 +411,10 @@
 
     def init(self, activated, source_entity):
         self.init_creating(source_entity._cw.cnxset)
+        try:
+            source_entity._cw.system_sql('SELECT COUNT(asource) FROM entities')
+        except Exception, ex:
+            self.eid_type_source = self.eid_type_source_pre_131
 
     def shutdown(self):
         if self._eid_creation_cnx:
@@ -677,7 +681,7 @@
             for subject, object in subj_obj_list:
                 self._record_tx_action(session, 'tx_relation_actions', 'A',
                                        eid_from=subject, rtype=rtype, eid_to=object)
-                
+
     def _add_relations(self, session, rtype, subj_obj_list, inlined=False):
         """add a relation to the source"""
         sql = []
@@ -846,6 +850,22 @@
 
     def eid_type_source(self, session, eid):
         """return a tuple (type, source, extid) for the entity with id <eid>"""
+        sql = 'SELECT type, source, extid, asource FROM entities WHERE eid=%s' % eid
+        try:
+            res = self.doexec(session, sql).fetchone()
+        except:
+            assert session.cnxset, 'session has no connections set'
+            raise UnknownEid(eid)
+        if res is None:
+            raise UnknownEid(eid)
+        if res[-2] is not None:
+            if not isinstance(res, list):
+                res = list(res)
+            res[-2] = b64decode(res[-2])
+        return res
+
+    def eid_type_source_pre_131(self, session, eid):
+        """return a tuple (type, source, extid) for the entity with id <eid>"""
         sql = 'SELECT type, source, extid FROM entities WHERE eid=%s' % eid
         try:
             res = self.doexec(session, sql).fetchone()
@@ -854,10 +874,11 @@
             raise UnknownEid(eid)
         if res is None:
             raise UnknownEid(eid)
+        if not isinstance(res, list):
+            res = list(res)
         if res[-1] is not None:
-            if not isinstance(res, list):
-                res = list(res)
             res[-1] = b64decode(res[-1])
+        res.append(res[1])
         return res
 
     def extid2eid(self, session, source_uri, extid):
@@ -946,7 +967,7 @@
             extid = b64encode(extid)
         uri = 'system' if source.copy_based_source else source.uri
         attrs = {'type': entity.__regid__, 'eid': entity.eid, 'extid': extid,
-                 'source': uri, 'mtime': datetime.now()}
+                 'source': uri, 'asource': source.uri, 'mtime': datetime.now()}
         self.doexec(session, self.sqlgen.insert('entities', attrs), attrs)
         # insert core relations: is, is_instance_of and cw_source
         try:
@@ -1434,6 +1455,7 @@
   eid INTEGER PRIMARY KEY NOT NULL,
   type VARCHAR(64) NOT NULL,
   source VARCHAR(64) NOT NULL,
+  asource VARCHAR(64) NOT NULL,
   mtime %s NOT NULL,
   extid VARCHAR(256)
 );;
--- a/server/test/unittest_datafeed.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/test/unittest_datafeed.py	Tue Jun 21 10:57:25 2011 +0200
@@ -64,12 +64,12 @@
             self.assertEqual(entity.cw_source[0].name, 'myfeed')
             self.assertEqual(entity.cw_metainformation(),
                              {'type': 'Card',
-                              'source': {'uri': 'system', 'type': 'native'},
+                              'source': {'uri': 'myfeed', 'type': 'datafeed'},
                               'extid': 'http://www.cubicweb.org/'}
                              )
             # test repo cache keys
             self.assertEqual(self.repo._type_source_cache[entity.eid],
-                             ('Card', 'system', 'http://www.cubicweb.org/'))
+                             ('Card', 'system', 'http://www.cubicweb.org/', 'myfeed'))
             self.assertEqual(self.repo._extid_cache[('http://www.cubicweb.org/', 'system')],
                              entity.eid)
             # test repull
@@ -83,7 +83,7 @@
             self.assertEqual(stats['created'], set())
             self.assertEqual(stats['updated'], set((entity.eid,)))
             self.assertEqual(self.repo._type_source_cache[entity.eid],
-                             ('Card', 'system', 'http://www.cubicweb.org/'))
+                             ('Card', 'system', 'http://www.cubicweb.org/', 'myfeed'))
             self.assertEqual(self.repo._extid_cache[('http://www.cubicweb.org/', 'system')],
                              entity.eid)
 
--- a/server/test/unittest_msplanner.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/test/unittest_msplanner.py	Tue Jun 21 10:57:25 2011 +0200
@@ -296,7 +296,7 @@
                    True)
 
     def test_not_relation_no_split_external(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         # similar to the above test but with an eid coming from the external source.
         # the same plan may be used, since we won't find any record in the system source
         # linking 9999999 to a state
@@ -313,7 +313,7 @@
                    True)
 
     def test_simplified_var(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any U WHERE U in_group G, (G name IN ("managers", "logilab") OR (X require_permission P?, P name "bla", P require_group G)), X eid %(x)s, U eid %(u)s',
                    {'x': 999999, 'u': self.session.user.eid},
                    {self.system: {'P': s[0], 'G': s[0], 'X': s[0],
@@ -329,7 +329,7 @@
                    False)
 
     def test_crossed_relation_eid_1_needattr(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         ueid = self.session.user.eid
         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
                    {'x': 999999,},
@@ -337,14 +337,14 @@
                    True)
 
     def test_crossed_relation_eid_1_invariant(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
                    {'x': 999999},
                    {self.system: {'Y': s[0], 'x': s[0]}},
                    False)
 
     def test_crossed_relation_eid_2_invariant(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
                    {'x': 999999,},
                    {self.cards: {'Y': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]},
@@ -352,7 +352,7 @@
                    False)
 
     def test_version_crossed_depends_on_1(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
                    {'x': 999999},
                    {self.cards: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]},
@@ -360,7 +360,7 @@
                    True)
 
     def test_version_crossed_depends_on_2(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
                    {'x': 999999},
                    {self.cards: {'X': s[0], 'AD': s[0]},
@@ -368,8 +368,8 @@
                     True)
 
     def test_simplified_var_3(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('State', 'cards', 999998)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('State', 'cards', 999998, 'cards')
         self._test('Any S,T WHERE S eid %(s)s, N eid %(n)s, N type T, N is Note, S is State',
                    {'n': 999999, 's': 999998},
                    {self.cards: {'s': s[0], 'N': s[0]}}, False)
@@ -1266,7 +1266,7 @@
                    {'x': ueid})
 
     def test_not_relation_no_split_external(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         # similar to the above test but with an eid coming from the external source.
         # the same plan may be used, since we won't find any record in the system source
         # linking 9999999 to a state
@@ -1297,7 +1297,7 @@
                      )])
 
     def test_external_attributes_and_relation(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any A,B,C,D WHERE A eid %(x)s,A creation_date B,A modification_date C, A todo_by D?',
                    [('FetchStep', [('Any A,B,C WHERE A eid 999999, A creation_date B, A modification_date C, A is Note',
                                     [{'A': 'Note', 'C': 'Datetime', 'B': 'Datetime'}])],
@@ -1314,7 +1314,7 @@
 
     def test_simplified_var(self):
         ueid = self.session.user.eid
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any U WHERE U in_group G, (G name IN ("managers", "logilab") OR (X require_permission P?, P name "bla", P require_group G)), X eid %(x)s, U eid %(u)s',
                    [('OneFetchStep', [('Any %s WHERE %s in_group G, (G name IN("managers", "logilab")) OR (X require_permission P?, P name "bla", P require_group G), X eid 999999' % (ueid, ueid),
                                        [{'X': 'Note', 'G': 'CWGroup', 'P': 'CWPermission'}])],
@@ -1529,7 +1529,7 @@
                    {'E': ueid})
 
     def test_eid_dont_cross_relation_1(self):
-        repo._type_source_cache[999999] = ('Personne', 'system', 999999)
+        repo._type_source_cache[999999] = ('Personne', 'system', 999999, 'system')
         self._test('Any Y,YT WHERE X eid %(x)s, X fiche Y, Y title YT',
                    [('OneFetchStep', [('Any Y,YT WHERE X eid 999999, X fiche Y, Y title YT',
                                        [{'X': 'Personne', 'Y': 'Card', 'YT': 'String'}])],
@@ -1537,7 +1537,7 @@
                    {'x': 999999})
 
     def test_eid_dont_cross_relation_2(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self.cards.dont_cross_relations.add('concerne')
         try:
             self._test('Any Y,S,YT,X WHERE Y concerne X, Y in_state S, X eid 999999, Y ref YT',
@@ -1552,7 +1552,7 @@
     # external source w/ .cross_relations == ['multisource_crossed_rel'] ######
 
     def test_crossed_relation_eid_1_invariant(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
                    [('OneFetchStep', [('Any Y WHERE 999999 multisource_crossed_rel Y', [{u'Y': 'Note'}])],
                       None, None, [self.system], {}, [])
@@ -1560,7 +1560,7 @@
                    {'x': 999999,})
 
     def test_crossed_relation_eid_1_needattr(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
                    [('FetchStep', [('Any Y,T WHERE Y type T, Y is Note', [{'T': 'String', 'Y': 'Note'}])],
                      [self.cards, self.system], None,
@@ -1573,7 +1573,7 @@
                    {'x': 999999,})
 
     def test_crossed_relation_eid_2_invariant(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
                    [('OneFetchStep', [('Any Y WHERE 999999 multisource_crossed_rel Y, Y is Note', [{'Y': 'Note'}])],
                       None, None, [self.cards, self.system], {}, [])
@@ -1581,7 +1581,7 @@
                    {'x': 999999,})
 
     def test_crossed_relation_eid_2_needattr(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
                    [('OneFetchStep', [('Any Y,T WHERE 999999 multisource_crossed_rel Y, Y type T, Y is Note',
                                        [{'T': 'String', 'Y': 'Note'}])],
@@ -1591,7 +1591,7 @@
                    {'x': 999999,})
 
     def test_crossed_relation_eid_not_1(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any Y WHERE X eid %(x)s, NOT X multisource_crossed_rel Y',
                    [('FetchStep', [('Any Y WHERE Y is Note', [{'Y': 'Note'}])],
                      [self.cards, self.system], None, {'Y': 'table0.C0'}, []),
@@ -1608,7 +1608,7 @@
 #                    {'x': 999999,})
 
     def test_crossed_relation_base_XXXFIXME(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any X,Y,T WHERE X multisource_crossed_rel Y, Y type T, X type T',
                    [('FetchStep', [('Any X,T WHERE X type T, X is Note', [{'T': 'String', 'X': 'Note'}])],
                      [self.cards, self.system], None,
@@ -1697,8 +1697,8 @@
     # edition queries tests ###################################################
 
     def test_insert_simplified_var_1(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('State', 'system', None)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('State', 'system', None, 'system')
         self._test('INSERT Note X: X in_state S, X type T WHERE S eid %(s)s, N eid %(n)s, N type T',
                    [('InsertStep',
                      [('InsertRelationsStep',
@@ -1710,8 +1710,8 @@
                    {'n': 999999, 's': 999998})
 
     def test_insert_simplified_var_2(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('State', 'system', None)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('State', 'system', None, 'system')
         self._test('INSERT Note X: X in_state S, X type T, X migrated_from N WHERE S eid %(s)s, N eid %(n)s, N type T',
                    [('InsertStep',
                      [('InsertRelationsStep',
@@ -1724,8 +1724,8 @@
                    {'n': 999999, 's': 999998})
 
     def test_insert_simplified_var_3(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('State', 'cards', 999998)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('State', 'cards', 999998, 'cards')
         self._test('INSERT Note X: X in_state S, X type T WHERE S eid %(s)s, N eid %(n)s, N type T',
                    [('InsertStep',
                      [('InsertRelationsStep',
@@ -1737,8 +1737,8 @@
                    {'n': 999999, 's': 999998})
 
     def test_insert_simplified_var_4(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('State', 'system', None)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('State', 'system', None, 'system')
         self._test('INSERT Note X: X in_state S, X type "bla", X migrated_from N WHERE S eid %(s)s, N eid %(n)s',
                    [('InsertStep',
                       [('InsertRelationsStep', [])]
@@ -1746,8 +1746,8 @@
                    {'n': 999999, 's': 999998})
 
     def test_insert_simplified_var_5(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('State', 'system', None)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('State', 'system', None, 'system')
         self._test('INSERT Note X: X in_state S, X type "bla", X migrated_from N WHERE S eid %(s)s, N eid %(n)s, A concerne N',
                    [('InsertStep',
                      [('InsertRelationsStep',
@@ -1784,7 +1784,7 @@
                    {'x': ueid, 'y': ueid})
 
     def test_delete_relation3(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('DELETE Y multisource_inlined_rel X WHERE X eid %(x)s, NOT (Y cw_source S, S name %(source)s)',
                    [('DeleteRelationsStep',
                      [('OneFetchStep',
@@ -1796,7 +1796,7 @@
                    {'x': 999999, 'source': 'cards'})
 
     def test_delete_entity1(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('DELETE Note X WHERE X eid %(x)s, NOT Y multisource_rel X',
                    [('DeleteEntitiesStep',
                      [('OneFetchStep', [('Any 999999 WHERE NOT EXISTS(Y multisource_rel 999999), Y is IN(Card, Note)',
@@ -1807,7 +1807,7 @@
                    {'x': 999999})
 
     def test_delete_entity2(self):
-        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('DELETE Note X WHERE X eid %(x)s, NOT X multisource_inlined_rel Y',
                    [('DeleteEntitiesStep',
                      [('OneFetchStep', [('Any X WHERE X eid 999999, NOT X multisource_inlined_rel Y, X is Note, Y is IN(Affaire, Note)',
@@ -1872,7 +1872,7 @@
 #                     ])
 
     def test_ldap_user_related_to_invariant_and_dont_cross_rel(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self.cards.dont_cross_relations.add('created_by')
         try:
             self._test('Any X,XL WHERE E eid %(x)s, E created_by X, X login XL',
@@ -1893,7 +1893,7 @@
             self.cards.dont_cross_relations.remove('created_by')
 
     def test_ambigous_cross_relation(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self.cards.support_relations['see_also'] = True
         self.cards.cross_relations.add('see_also')
         try:
@@ -2044,7 +2044,7 @@
                     ])
 
     def test_source_conflict_1(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         with self.assertRaises(BadRQLQuery) as cm:
             self._test('Any X WHERE X cw_source S, S name "system", X eid %(x)s',
                        [], {'x': 999999})
@@ -2067,7 +2067,7 @@
 
 
     def test_ambigous_cross_relation_source_specified(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self.cards.support_relations['see_also'] = True
         self.cards.cross_relations.add('see_also')
         try:
@@ -2198,7 +2198,7 @@
                     ])
 
     def test_nonregr7(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any S,SUM(DUR),SUM(I),(SUM(I) - SUM(DUR)),MIN(DI),MAX(DI) GROUPBY S ORDERBY S WHERE A is Affaire, A duration DUR, A invoiced I, A modification_date DI, A in_state S, S name SN, (EXISTS(A concerne WP, W multisource_rel WP)) OR (EXISTS(A concerne W)), W eid %(n)s',
                    [('FetchStep', [('Any WP WHERE 999999 multisource_rel WP, WP is Note', [{'WP': 'Note'}])],
                      [self.cards], None, {'WP': u'table0.C0'}, []),
@@ -2208,7 +2208,7 @@
                    {'n': 999999})
 
     def test_nonregr8(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X,Z WHERE X eid %(x)s, X multisource_rel Y, Z concerne X',
                    [('FetchStep', [('Any 999999 WHERE 999999 multisource_rel Y, Y is Note',
                                     [{'Y': 'Note'}])],
@@ -2223,8 +2223,8 @@
                    {'x': 999999})
 
     def test_nonregr9(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        repo._type_source_cache[999998] = ('Note', 'cards', 999998)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        repo._type_source_cache[999998] = ('Note', 'cards', 999998, 'cards')
         self._test('SET X migrated_from Y WHERE X eid %(x)s, Y multisource_rel Z, Z eid %(z)s, Y migrated_from Z',
                    [('FetchStep', [('Any Y WHERE Y multisource_rel 999998, Y is Note', [{'Y': 'Note'}])],
                      [self.cards], None, {'Y': u'table0.C0'}, []),
@@ -2236,7 +2236,7 @@
                    {'x': 999999, 'z': 999998})
 
     def test_nonregr10(self):
-        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999999)
+        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999999, 'ldap')
         self._test('Any X,AA,AB ORDERBY AA WHERE E eid %(x)s, E owned_by X, X login AA, X modification_date AB',
                    [('FetchStep',
                      [('Any X,AA,AB WHERE X login AA, X modification_date AB, X is CWUser',
@@ -2254,7 +2254,7 @@
                    {'x': 999999})
 
     def test_nonregr11(self):
-        repo._type_source_cache[999999] = ('Bookmark', 'system', 999999)
+        repo._type_source_cache[999999] = ('Bookmark', 'system', 999999, 'system')
         self._test('SET X bookmarked_by Y WHERE X eid %(x)s, Y login "hop"',
                    [('UpdateStep',
                      [('OneFetchStep', [('DISTINCT Any Y WHERE Y login "hop", Y is CWUser', [{'Y': 'CWUser'}])],
@@ -2263,7 +2263,7 @@
                    {'x': 999999})
 
     def test_nonregr12(self):
-        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X ORDERBY Z DESC WHERE X modification_date Z, E eid %(x)s, E see_also X',
                    [('FetchStep', [('Any X,Z WHERE X modification_date Z, X is Note',
                                     [{'X': 'Note', 'Z': 'Datetime'}])],
@@ -2347,38 +2347,38 @@
                    {'x': self.session.user.eid})
 
     def test_nonregr14_1(self):
-        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999999)
+        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999999, 'ldap')
         self._test('Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s',
                    [('OneFetchStep', [('Any 999999 WHERE 999999 owned_by 999999', [{}])],
                      None, None, [self.system], {}, [])],
                    {'x': 999999, 'u': 999999})
 
     def test_nonregr14_2(self):
-        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999999)
-        repo._type_source_cache[999998] = ('Note', 'system', 999998)
+        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999999, 'ldap')
+        repo._type_source_cache[999998] = ('Note', 'system', 999998, 'system')
         self._test('Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s',
                    [('OneFetchStep', [('Any 999998 WHERE 999998 owned_by 999999', [{}])],
                      None, None, [self.system], {}, [])],
                    {'x': 999998, 'u': 999999})
 
     def test_nonregr14_3(self):
-        repo._type_source_cache[999999] = ('CWUser', 'system', 999999)
-        repo._type_source_cache[999998] = ('CWUser', 'ldap', 999998)
+        repo._type_source_cache[999999] = ('CWUser', 'system', 999999, 'system')
+        repo._type_source_cache[999998] = ('CWUser', 'ldap', 999998, 'ldap')
         self._test('Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s',
                    [('OneFetchStep', [('Any 999998 WHERE 999998 owned_by 999999', [{}])],
                      None, None, [self.system], {}, [])],
                    {'x': 999998, 'u': 999999})
 
     def test_nonregr_identity_no_source_access_1(self):
-        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999998)
+        repo._type_source_cache[999999] = ('CWUser', 'ldap', 999998, 'ldap')
         self._test('Any S WHERE S identity U, S eid %(s)s, U eid %(u)s',
                    [('OneFetchStep', [('Any 999999 WHERE 999999 identity 999999', [{}])],
                      None, None, [self.system], {}, [])],
                    {'s': 999999, 'u': 999999})
 
     def test_nonregr_identity_no_source_access_2(self):
-        repo._type_source_cache[999999] = ('EmailAddress', 'system', 999999)
-        repo._type_source_cache[999998] = ('CWUser', 'ldap', 999998)
+        repo._type_source_cache[999999] = ('EmailAddress', 'system', 999999, 'system')
+        repo._type_source_cache[999998] = ('CWUser', 'ldap', 999998, 'ldap')
         self._test('Any X WHERE O use_email X, ((EXISTS(O identity U)) OR (EXISTS(O in_group G, G name IN("managers", "staff")))) OR (EXISTS(O in_group G2, U in_group G2, NOT G2 name "users")), X eid %(x)s, U eid %(u)s',
                    [('OneFetchStep', [('Any 999999 WHERE O use_email 999999, ((EXISTS(O identity 999998)) OR (EXISTS(O in_group G, G name IN("managers", "staff")))) OR (EXISTS(O in_group G2, 999998 in_group G2, NOT G2 name "users"))',
                                        [{'G': 'CWGroup', 'G2': 'CWGroup', 'O': 'CWUser'}])],
@@ -2386,7 +2386,7 @@
                    {'x': 999999, 'u': 999998})
 
     def test_nonregr_similar_subquery(self):
-        repo._type_source_cache[999999] = ('Personne', 'system', 999999)
+        repo._type_source_cache[999999] = ('Personne', 'system', 999999, 'system')
         self._test('Any T,TD,U,T,UL WITH T,TD,U,UL BEING ('
                    '(Any T,TD,U,UL WHERE X eid %(x)s, T comments X, T content TD, T created_by U?, U login UL)'
                    ' UNION '
@@ -2456,7 +2456,7 @@
 
 
     def test_linked_external_entities(self):
-        repo._type_source_cache[999999] = ('Tag', 'system', 999999)
+        repo._type_source_cache[999999] = ('Tag', 'system', 999999, 'system')
         self._test('Any X,XT WHERE X is Card, X title XT, T tags X, T eid %(t)s',
                    [('FetchStep',
                      [('Any X,XT WHERE X title XT, X is Card', [{'X': 'Card', 'XT': 'String'}])],
@@ -2472,7 +2472,7 @@
                    {'t': 999999})
 
     def test_version_depends_on(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X,AD,AE WHERE E eid %(x)s, E migrated_from X, X in_state AD, AD name AE',
                    [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
                                     [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
@@ -2488,7 +2488,7 @@
                    {'x': 999999})
 
     def test_version_crossed_depends_on_1(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
                    [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
                                     [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
@@ -2511,7 +2511,7 @@
                    {'x': 999999})
 
     def test_version_crossed_depends_on_2(self):
-        self.repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')
         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
                    [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
                                     [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
@@ -2587,7 +2587,7 @@
                        )
 
     def test_nonregr_dont_cross_rel_source_filtering_1(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any S WHERE E eid %(x)s, E in_state S, NOT S name "moved"',
                    [('OneFetchStep', [('Any S WHERE 999999 in_state S, NOT S name "moved", S is State',
                                        [{'S': 'State'}])],
@@ -2596,7 +2596,7 @@
                    {'x': 999999})
 
     def test_nonregr_dont_cross_rel_source_filtering_2(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X,AA,AB WHERE E eid %(x)s, E in_state X, X name AA, X modification_date AB',
                    [('OneFetchStep', [('Any X,AA,AB WHERE 999999 in_state X, X name AA, X modification_date AB, X is State',
                                        [{'AA': 'String', 'AB': 'Datetime', 'X': 'State'}])],
@@ -2605,7 +2605,7 @@
                    {'x': 999999})
 
     def test_nonregr_eid_query(self):
-        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
         self._test('Any X WHERE X eid 999999',
                    [('OneFetchStep', [('Any 999999', [{}])],
                      None, None, [self.system], {}, []
@@ -2707,17 +2707,17 @@
                     ])
 
     def test_fully_simplified_extsource(self):
-        self.repo._type_source_cache[999998] = ('Note', 'vcs', 999998)
-        self.repo._type_source_cache[999999] = ('Note', 'vcs', 999999)
+        self.repo._type_source_cache[999998] = ('Note', 'vcs', 999998, 'vcs')
+        self.repo._type_source_cache[999999] = ('Note', 'vcs', 999999, 'vcs')
         self._test('Any X, Y WHERE NOT X multisource_rel Y, X eid 999998, Y eid 999999',
                    [('OneFetchStep', [('Any 999998,999999 WHERE NOT EXISTS(999998 multisource_rel 999999)', [{}])],
                      None, None, [self.vcs], {}, [])
                     ])
 
     def test_nonregr_fully_simplified_extsource(self):
-        self.repo._type_source_cache[999998] = ('Note', 'vcs', 999998)
-        self.repo._type_source_cache[999999] = ('Note', 'vcs', 999999)
-        self.repo._type_source_cache[1000000] = ('Note', 'system', 1000000)
+        self.repo._type_source_cache[999998] = ('Note', 'vcs', 999998, 'vcs')
+        self.repo._type_source_cache[999999] = ('Note', 'vcs', 999999, 'vcs')
+        self.repo._type_source_cache[1000000] = ('Note', 'system', 1000000, 'system')
         self._test('DISTINCT Any T,FALSE,L,M WHERE L eid 1000000, M eid 999999, T eid 999998',
                    [('OneFetchStep', [('DISTINCT Any 999998,FALSE,1000000,999999', [{}])],
                      None, None, [self.system], {}, [])
--- a/server/test/unittest_repository.py	Mon Jun 20 14:52:19 2011 +0200
+++ b/server/test/unittest_repository.py	Tue Jun 21 10:57:25 2011 +0200
@@ -385,7 +385,7 @@
         cnxid = repo.connect(self.admlogin, password=self.admpassword)
         session = repo._get_session(cnxid, setcnxset=True)
         self.assertEqual(repo.type_and_source_from_eid(2, session),
-                         ('CWGroup', 'system', None))
+                         ('CWGroup', 'system', None, 'system'))
         self.assertEqual(repo.type_from_eid(2, session), 'CWGroup')
         self.assertEqual(repo.source_from_eid(2, session).uri, 'system')
         self.assertEqual(repo.eid2extid(repo.system_source, 2, session), None)
@@ -403,7 +403,7 @@
         repo = self.repo
         cnxid = repo.connect(self.admlogin, password=self.admpassword)
         self.assertEqual(repo.user_info(cnxid), (6, 'admin', set([u'managers']), {}))
-        self.assertEqual(repo.describe(cnxid, 2), (u'CWGroup', u'system', None))
+        self.assertEqual(repo.describe(cnxid, 2), (u'CWGroup', u'system', None, 'system'))
         repo.close(cnxid)
         self.assertRaises(BadConnectionId, repo.user_info, cnxid)
         self.assertRaises(BadConnectionId, repo.describe, cnxid, 1)
@@ -548,10 +548,11 @@
         self.repo.add_info(self.session, entity, self.repo.system_source)
         cu = self.session.system_sql('SELECT * FROM entities WHERE eid = -1')
         data = cu.fetchall()
-        self.assertIsInstance(data[0][3], datetime)
+        self.assertIsInstance(data[0][4], datetime)
         data[0] = list(data[0])
-        data[0][3] = None
-        self.assertEqual(tuplify(data), [(-1, 'Personne', 'system', None, None)])
+        data[0][4] = None
+        self.assertEqual(tuplify(data), [(-1, 'Personne', 'system', 'system',
+                                          None, None)])
         self.repo.delete_info(self.session, entity, 'system', None)
         #self.repo.commit()
         cu = self.session.system_sql('SELECT * FROM entities WHERE eid = -1')
@@ -813,6 +814,7 @@
         req.cnx.commit()
         t1 = time.time()
         self.info('add relations: %.2gs', t1-t0)
+
     def test_session_add_relation_inlined(self):
         """ to be compared with test_session_add_relations"""
         req = self.request()