[rql annotation] fix has_text_query detection (if coming from sub-query and if has_text on a column aliases. Closes #2275322

authorSylvain Thénault <sylvain.thenault@logilab.fr>
changeset7a5271182ef0
branchstable
phasepublic
hiddenno
parent revision#af813e7d5daa [etwist] fix static directory serving; closes #2174797
child revision#6bd8db130476 Fix a Python 2.5 regression introduced by previous commit
files modified by this revision
server/querier.py
server/rqlannotation.py
server/test/unittest_querier.py
server/test/unittest_rqlannotation.py
test/unittest_rqlrewrite.py
# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1332756708 -7200
# Mon Mar 26 12:11:48 2012 +0200
# Branch stable
# Node ID 7a5271182ef0ae9acdd5b7f0a9d943ff92b99074
# Parent af813e7d5daa597307fbeec44f7602a8ed8a91d6
[rql annotation] fix has_text_query detection (if coming from sub-query and if has_text on a column aliases. Closes #2275322

diff --git a/server/querier.py b/server/querier.py
@@ -1,6 +1,6 @@
1 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
3  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
4  #
5  # This file is part of CubicWeb.
6  #
7  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -721,11 +721,11 @@
8              # bother modifying it. This is not necessary on write queries since
9              # a new syntax tree is built from them.
10              rqlst = rqlst.copy()
11              self._annotate(rqlst)
12              if args:
13 -                 # different SQL generated when some argument is None or not (IS
14 +                # different SQL generated when some argument is None or not (IS
15                  # NULL). This should be considered when computing sql cache key
16                  cachekey += tuple(sorted([k for k,v in args.iteritems()
17                                            if v is None]))
18          # make an execution plan
19          plan = self.plan_factory(rqlst, args, session)
diff --git a/server/rqlannotation.py b/server/rqlannotation.py
@@ -1,6 +1,6 @@
20 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
21 +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
22  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
23  #
24  # This file is part of CubicWeb.
25  #
26  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -26,16 +26,17 @@
27  from rql import BadRQLQuery
28  from rql.nodes import Relation, VariableRef, Constant, Variable, Or, Exists
29  from rql.utils import common_parent
30 
31  def _annotate_select(annotator, rqlst):
32 +    has_text_query = False
33      for subquery in rqlst.with_:
34 -        annotator._annotate_union(subquery.query)
35 +        if annotator._annotate_union(subquery.query):
36 +            has_text_query = True
37      #if server.DEBUG:
38      #    print '-------- sql annotate', repr(rqlst)
39      getrschema = annotator.schema.rschema
40 -    has_text_query = False
41      need_distinct = rqlst.distinct
42      for rel in rqlst.iget_nodes(Relation):
43          if getrschema(rel.r_type).symmetric and not isinstance(rel.parent, Exists):
44              for vref in rel.iget_nodes(VariableRef):
45                  stinfo = vref.variable.stinfo
@@ -152,10 +153,15 @@
46                      # rhs variable's scope (since it's retrieved from lhs's table)
47                      sstinfo = principal.children[0].variable.stinfo
48                      sstinfo['scope'] = common_parent(sstinfo['scope'], stinfo['scope']).scope
49              except CantSelectPrincipal:
50                  stinfo['invariant'] = False
51 +    # see unittest_rqlannotation. test_has_text_security_cache_bug
52 +    # XXX probably more to do, but yet that work without more...
53 +    for col_alias in rqlst.aliases.itervalues():
54 +        if col_alias.stinfo.get('ftirels'):
55 +            has_text_query = True
56      rqlst.need_distinct = need_distinct
57      return has_text_query
58 
59 
60 
@@ -270,12 +276,11 @@
61          rqlst.has_text_query = self._annotate_union(rqlst)
62 
63      def _annotate_union(self, union):
64          has_text_query = False
65          for select in union.children:
66 -            htq = _annotate_select(self, select)
67 -            if htq:
68 +            if _annotate_select(self, select):
69                  has_text_query = True
70          return has_text_query
71 
72      def is_ambiguous(self, var):
73          # ignore has_text relation when we know it will be used as principal.
diff --git a/server/test/unittest_querier.py b/server/test/unittest_querier.py
@@ -1,7 +1,7 @@
74  # -*- coding: iso-8859-1 -*-
75 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
76 +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
77  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
78  #
79  # This file is part of CubicWeb.
80  #
81  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -26,11 +26,11 @@
82  from cubicweb import QueryError, Unauthorized, Binary
83  from cubicweb.server.sqlutils import SQL_PREFIX
84  from cubicweb.server.utils import crypt_password
85  from cubicweb.server.sources.native import make_schema
86  from cubicweb.devtools import get_test_db_handler, TestServerConfiguration
87 -
88 +from cubicweb.devtools.testlib import CubicWebTC
89  from cubicweb.devtools.repotest import tuplify, BaseQuerierTC
90  from unittest_session import Variable
91 
92  class FixedOffset(tzinfo):
93      def __init__(self, hours=0):
@@ -1499,7 +1499,19 @@
94      def test_nonregr_sql_cache(self):
95          # different SQL generated when 'name' is None or not (IS NULL).
96          self.assertFalse(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': None}))
97          self.assertTrue(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': 'CWEType'}))
98 
99 +class NonRegressionTC(CubicWebTC):
100 +    def test_has_text_security_cache_bug(self):
101 +        self.create_user('user', ('users',))
102 +        req = self.request()
103 +        aff1 = req.create_entity('Societe', nom=u'aff1')
104 +        aff2 = req.create_entity('Societe', nom=u'aff2')
105 +        self.commit()
106 +        with self.login('user', password='user'):
107 +            res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff1'})
108 +            self.assertEqual(res.rows, [[aff1.eid]])
109 +            res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'})
110 +            self.assertEqual(res.rows, [[aff2.eid]])
111  if __name__ == '__main__':
112      unittest_main()
diff --git a/server/test/unittest_rqlannotation.py b/server/test/unittest_rqlannotation.py
@@ -1,7 +1,7 @@
113  # -*- coding: iso-8859-1 -*-
114 -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
115 +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
116  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
117  #
118  # This file is part of CubicWeb.
119  #
120  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -348,8 +348,14 @@
121      def test_remove_from_deleted_source_2(self):
122          rqlst = self._prepare('Note X WHERE X eid IN (999998, 999999), NOT X cw_source Y')
123          self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
124          self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
125 
126 +
127 +    def test_has_text_security_cache_bug(self):
128 +        rqlst = self._prepare('Any X WHERE X has_text "toto" WITH X BEING '
129 +                              '(Any C WHERE C is Societe, C nom CS)')
130 +        self.assertTrue(rqlst.parent.has_text_query)
131 +
132  if __name__ == '__main__':
133      from logilab.common.testlib import unittest_main
134      unittest_main()
diff --git a/test/unittest_rqlrewrite.py b/test/unittest_rqlrewrite.py
@@ -1,6 +1,6 @@
135 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
136 +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
137  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
138  #
139  # This file is part of CubicWeb.
140  #
141  # CubicWeb is free software: you can redistribute it and/or modify it under the