Use a moved_entities table to record external entities moved to the system source
Instead of using a negative eid in the entities table, move the record
to a new table so we don't have an interval with a missing eid in
entities.
Related to #4846892
--- a/hooks/metadata.py Fri Jan 16 12:43:32 2015 +0100
+++ b/hooks/metadata.py Fri Jan 16 12:35:46 2015 +0100
@@ -199,17 +199,15 @@
oldsource = self._cw.entity_from_eid(schange[self.eidfrom])
entity = self._cw.entity_from_eid(self.eidfrom)
# we don't want the moved entity to be reimported later. To
- # distinguish this state, the trick is to change the associated
- # record in the 'entities' system table with eid=-eid while leaving
- # other fields unchanged, and to add a new record with eid=eid,
- # 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 WHERE eid=%(eid)s',
- {'eid': self.eidfrom})
+ # distinguish this state, move the record from the 'entities' table
+ # to 'moved_entities'. External source will then have consider
+ # case where `extid2eid` returns a negative eid as 'this entity was
+ # known but has been moved, ignore it'.
+ attrs = {'eid': entity.eid, 'extid': self._cw.entity_metas(entity.eid)['extid']}
+ self._cw.system_sql(syssource.sqlgen.insert('moved_entities', attrs), attrs)
attrs = {'type': entity.cw_etype, 'eid': entity.eid, 'extid': None,
'asource': 'system'}
- self._cw.system_sql(syssource.sqlgen.insert('entities', attrs), attrs)
+ self._cw.system_sql(syssource.sqlgen.update('entities', attrs, ['eid']), attrs)
# register an operation to update repository/sources caches
ChangeEntitySourceUpdateCaches(self._cw, entity=entity,
oldsource=oldsource.repo_source,
--- a/misc/migration/3.21.0_Any.py Fri Jan 16 12:43:32 2015 +0100
+++ b/misc/migration/3.21.0_Any.py Fri Jan 16 12:35:46 2015 +0100
@@ -2,4 +2,18 @@
helper = repo.system_source.dbhelper
sql('DROP INDEX entities_extid_idx')
sql(helper.sql_create_index('entities', 'extid', True))
+
+sql('''
+CREATE TABLE moved_entities (
+ eid INTEGER PRIMARY KEY NOT NULL,
+ extid VARCHAR(256) UNIQUE
+)
+''')
+
+moved_entities = sql('SELECT -eid, extid FROM entities WHERE eid < 0')
+cu = session.cnxset.cu
+cu.executemany('INSERT INTO moved_entities (eid, extid) VALUES (%s, %s)',
+ moved_entities)
+sql('DELETE FROM entities WHERE eid < 0')
+
commit()
--- a/server/sources/native.py Fri Jan 16 12:43:32 2015 +0100
+++ b/server/sources/native.py Fri Jan 16 12:35:46 2015 +0100
@@ -868,9 +868,10 @@
def extid2eid(self, cnx, extid):
"""get eid from an external id. Return None if no record found."""
assert isinstance(extid, str)
+ args = {'x': b64encode(extid)}
cursor = self.doexec(cnx,
'SELECT eid FROM entities WHERE extid=%(x)s',
- {'x': b64encode(extid)})
+ args)
# XXX testing rowcount cause strange bug with sqlite, results are there
# but rowcount is 0
#if cursor.rowcount > 0:
@@ -880,6 +881,17 @@
return result[0]
except Exception:
pass
+ cursor = self.doexec(cnx,
+ 'SELECT eid FROM moved_entities WHERE extid=%(x)s',
+ args)
+ try:
+ result = cursor.fetchone()
+ if result:
+ # entity was moved to the system source, return negative
+ # number to tell the external source to ignore it
+ return -result[0]
+ except Exception:
+ pass
return None
def _handle_is_relation_sql(self, cnx, sql, attrs):
@@ -1390,6 +1402,10 @@
extid VARCHAR(256) UNIQUE
);;
CREATE INDEX entities_type_idx ON entities(type);;
+CREATE TABLE moved_entities (
+ eid INTEGER PRIMARY KEY NOT NULL,
+ extid VARCHAR(256) UNIQUE
+);;
CREATE TABLE transactions (
tx_uuid CHAR(32) PRIMARY KEY NOT NULL,