[rql2sql] None for attributes in kwargs generate IS NULL, so should be considered in sql cache key. Closes #2116693
--- a/server/querier.py Fri Dec 09 12:57:22 2011 +0100
+++ b/server/querier.py Mon Dec 12 12:09:49 2011 +0100
@@ -668,7 +668,7 @@
print '*'*80
print 'querier input', repr(rql), repr(args)
# parse the query and binds variables
- cachekey = rql
+ cachekey = (rql,)
try:
if args:
# search for named args in query which are eids (hence
@@ -699,7 +699,7 @@
# we want queries such as "Any X WHERE X eid 9999" return an
# empty result instead of raising UnknownEid
return empty_rset(rql, args, rqlst)
- if args and not rql in self._rql_ck_cache:
+ if args and rql not in self._rql_ck_cache:
self._rql_ck_cache[rql] = eidkeys
if eidkeys:
cachekey = self._repo.querier_cache_key(session, rql, args,
@@ -722,6 +722,11 @@
# a new syntax tree is built from them.
rqlst = rqlst.copy()
self._annotate(rqlst)
+ if args:
+ # different SQL generated when some argument is None or not (IS
+ # NULL). This should be considered when computing sql cache key
+ cachekey += tuple(sorted([k for k,v in args.iteritems()
+ if v is None]))
# make an execution plan
plan = self.plan_factory(rqlst, args, session)
plan.cache_key = cachekey
--- a/server/ssplanner.py Fri Dec 09 12:57:22 2011 +0100
+++ b/server/ssplanner.py Mon Dec 12 12:09:49 2011 +0100
@@ -392,7 +392,8 @@
# cachekey
if inputmap or self.plan.cache_key is None:
cachekey = None
- # union may have been splited into subqueries, rebuild a cache key
+ # union may have been splited into subqueries, in which case we can't
+ # use plan.cache_key, rebuild a cache key
elif isinstance(self.plan.cache_key, tuple):
cachekey = list(self.plan.cache_key)
cachekey[0] = union.as_string()
--- a/server/test/unittest_querier.py Fri Dec 09 12:57:22 2011 +0100
+++ b/server/test/unittest_querier.py Mon Dec 12 12:09:49 2011 +0100
@@ -1495,5 +1495,11 @@
rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule", X in_state S, S name SN')
self.assertEqual(rset.rows, [[peid]])
+
+ def test_nonregr_sql_cache(self):
+ # different SQL generated when 'name' is None or not (IS NULL).
+ self.assertFalse(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': None}))
+ self.assertTrue(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': 'CWEType'}))
+
if __name__ == '__main__':
unittest_main()