summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 03e7b9b)
raw | patch | inline | side by side (parent: 03e7b9b)
author | schlatterbeck <schlatterbeck@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Sat, 16 Apr 2011 11:02:01 +0000 (11:02 +0000) | ||
committer | schlatterbeck <schlatterbeck@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Sat, 16 Apr 2011 11:02:01 +0000 (11:02 +0000) |
this would result in duplicate multilinks to the same node. We're now
going the safe route and doing lazy evaluation only for read-only
access, whenever updates are done we fetch everything.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4599 57a73879-2fb5-44c3-a270-3262357dd7e2
going the safe route and doing lazy evaluation only for read-only
access, whenever updates are done we fetch everything.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4599 57a73879-2fb5-44c3-a270-3262357dd7e2
CHANGES.txt | patch | blob | history | |
roundup/backends/rdbms_common.py | patch | blob | history | |
test/db_test_base.py | patch | blob | history |
diff --git a/CHANGES.txt b/CHANGES.txt
index 3a071349d5f1762e9dddd241c7be30f0eccd6525..c5ea367346d54433d90c26ea51c789e89e7b72d5 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
parameter for binding to all interfaces now (still left in for
compatibility). Thanks to Toni Mueller for providing the first version
of this patch and discussing implementations.
+- Fixed bug in filter_iter refactoring (lazy multilinks), in rare cases
+ this would result in duplicate multilinks to the same node. We're now
+ going the safe route and doing lazy evaluation only for read-only
+ access, whenever updates are done we fetch everything.
2010-10-08 1.4.16 (r4541)
index 5798c8d646e1ab223a16db221e06f52cf47a05e2..3a4d6f5c276ee9c7fe5a226a5bdd7bc5f9edbf38 100644 (file)
raise ValueError('%r is not a hyperdb property class' % propklass)
- def getnode(self, classname, nodeid):
+ def _materialize_multilink(self, classname, nodeid, node, propname):
+ """ evaluation of single Multilink (lazy eval may have skipped this)
+ """
+ if propname not in node:
+ sql = 'select linkid from %s_%s where nodeid=%s'%(classname,
+ propname, self.arg)
+ self.sql(sql, (nodeid,))
+ # extract the first column from the result
+ # XXX numeric ids
+ items = [int(x[0]) for x in self.cursor.fetchall()]
+ items.sort ()
+ node[propname] = [str(x) for x in items]
+
+ def _materialize_multilinks(self, classname, nodeid, node, props=None):
+ """ get all Multilinks of a node (lazy eval may have skipped this)
+ """
+ cl = self.classes[classname]
+ props = props or [pn for (pn, p) in cl.properties.iteritems()
+ if isinstance(p, Multilink)]
+ for propname in props:
+ if propname not in node:
+ self._materialize_multilink(classname, nodeid, node, propname)
+
+ def getnode(self, classname, nodeid, fetch_multilinks=True):
""" Get a node from the database.
+ For optimisation optionally we don't fetch multilinks
+ (lazy Multilinks).
+ But for internal database operations we need them.
"""
# see if we have this node cached
key = (classname, nodeid)
if __debug__:
self.stats['cache_hits'] += 1
# return the cached information
+ if fetch_multilinks:
+ self._materialize_multilinks(classname, nodeid, self.cache[key])
return self.cache[key]
if __debug__:
value = self.to_hyperdb_value(props[name].__class__)(value)
node[name] = value
+ if fetch_multilinks and mls:
+ self._materialize_multilinks(classname, nodeid, node, mls)
+
# save off in the cache
key = (classname, nodeid)
self._cache_save(key, node)
return nodeid
# get the node's dict
- d = self.db.getnode(self.classname, nodeid)
+ d = self.db.getnode(self.classname, nodeid, fetch_multilinks=False)
# handle common case -- that property is in dict -- first
# if None and one of creator/creation actor/activity return None
if propname in d:
# lazy evaluation of Multilink
if propname not in d and isinstance(prop, Multilink):
- sql = 'select linkid from %s_%s where nodeid=%s'%(self.classname,
- propname, self.db.arg)
- self.db.sql(sql, (nodeid,))
- # extract the first column from the result
- # XXX numeric ids
- items = [int(x[0]) for x in self.db.cursor.fetchall()]
- items.sort ()
- d[propname] = [str(x) for x in items]
+ self.db._materialize_multilink(self.classname, nodeid, d, propname)
# handle there being no value in the table for the property
if propname not in d or d[propname] is None:
diff --git a/test/db_test_base.py b/test/db_test_base.py
index fe35b5d86b30577cc97f2390c094346e5da10edb..428bc1d5e6b287eb8066cbd397386b57ee766777 100644 (file)
--- a/test/db_test_base.py
+++ b/test/db_test_base.py
if commit: self.db.commit()
self.assertEqual(self.db.issue.get(nid, "nosy"), [])
+ def testMakeSeveralMultilinkedNodes(self):
+ for commit in (0,1):
+ u1 = self.db.user.create(username='foo%s'%commit)
+ u2 = self.db.user.create(username='bar%s'%commit)
+ u3 = self.db.user.create(username='baz%s'%commit)
+ nid = self.db.issue.create(title="spam", nosy=[u1])
+ if commit: self.db.commit()
+ self.assertEqual(self.db.issue.get(nid, "nosy"), [u1])
+ self.db.issue.set(nid, deadline=date.Date('.'))
+ self.db.issue.set(nid, nosy=[u1,u2], title='ta%s'%commit)
+ if commit: self.db.commit()
+ self.assertEqual(self.db.issue.get(nid, "nosy"), [u1,u2])
+ self.db.issue.set(nid, deadline=date.Date('.'))
+ self.db.issue.set(nid, nosy=[u1,u2,u3], title='tb%s'%commit)
+ if commit: self.db.commit()
+ self.assertEqual(self.db.issue.get(nid, "nosy"), [u1,u2,u3])
+
def testMultilinkChangeIterable(self):
for commit in (0,1):
# invalid nosy value assertion