[rql2sql] None for attributes in kwargs generate IS NULL, so should be considered in sql cache key. Closes #2116693 stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 12 Dec 2011 12:09:49 +0100
branchstable
changeset 8127 96d343a5e01b
parent 8126 a4d8064bf393
child 8131 a6654712ad50
[rql2sql] None for attributes in kwargs generate IS NULL, so should be considered in sql cache key. Closes #2116693
server/querier.py
server/ssplanner.py
server/test/unittest_querier.py
--- 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()