fix bug in multisource planner, w/ inlined relation stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 09 Jun 2009 18:04:31 +0200
branchstable
changeset 2075 933ccfce6e91
parent 2074 9e268cb6202e
child 2076 65cbe891edac
fix bug in multisource planner, w/ inlined relation
server/msplanner.py
server/test/unittest_msplanner.py
--- a/server/msplanner.py	Tue Jun 09 18:03:28 2009 +0200
+++ b/server/msplanner.py	Tue Jun 09 18:04:31 2009 +0200
@@ -158,6 +158,7 @@
 # XXX move functions below to rql ##############################################
 
 def is_ancestor(n1, n2):
+    """return True if n2 is a parent scope of n1"""
     p = n1.parent
     while p is not None:
         if p is n2:
@@ -171,17 +172,14 @@
         newnode.append(part)
     return newnode
 
-def same_scope(var):
-    """return true if the variable is always used in the same scope"""
-    try:
-        return var.stinfo['samescope']
-    except KeyError:
-        for rel in var.stinfo['relations']:
-            if not rel.scope is var.scope:
-                var.stinfo['samescope'] = False
-                return False
-        var.stinfo['samescope'] = True
-        return True
+def used_in_outer_scope(var, scope):
+    """return true if the variable is used in an outer scope of the given scope
+    """
+    for rel in var.stinfo['relations']:
+        rscope = rel.scope
+        if not rscope is scope and is_ancestor(scope, rscope):
+            return True
+    return False
 
 ################################################################################
 
@@ -1227,6 +1225,7 @@
         self.mayneedvar, self.hasvar = {}, {}
         self.use_only_defined = False
         self.scopes = {rqlst: newroot}
+        self.current_scope = rqlst
         if rqlst.where:
             rqlst = self._rqlst_accept(rqlst, rqlst.where, newroot, terms,
                                        newroot.set_where)
@@ -1397,7 +1396,7 @@
             return False
         if var.name in self.extneedsel or var.stinfo['selected']:
             return False
-        if not same_scope(var):
+        if not var in terms or used_in_outer_scope(var, self.current_scope):
             return False
         if any(v for v, _ in var.stinfo['attrvars'] if not v in terms):
             return False
--- a/server/test/unittest_msplanner.py	Tue Jun 09 18:03:28 2009 +0200
+++ b/server/test/unittest_msplanner.py	Tue Jun 09 18:04:31 2009 +0200
@@ -2073,6 +2073,44 @@
                    {'x': 999999})
 
 
+
+class FakeVCSSource(AbstractSource):
+    uri = 'ccc'
+    support_entities = {'Card': True, 'Note': True}
+    support_relations = {'multisource_inlined_rel': True,
+                         'multisource_rel': True}
+    #dont_cross_relations = set(('fiche', 'in_state'))
+    #cross_relations = set(('multisource_crossed_rel',))
+
+    def syntax_tree_search(self, *args, **kwargs):
+        return []
+
+class MSPlannerVCSSource(BasePlannerTC):
+    repo = repo
+
+    def setUp(self):
+        self.setup()
+        self.add_source(FakeVCSSource, 'vcs')
+        self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
+    _test = test_plan
+
+    def test_multisource_inlined_rel_skipped(self):
+        self._test('Any MAX(VC) '
+                   'WHERE VC multisource_inlined_rel R2, R para %(branch)s, VC in_state S, S name "published", '
+                   '(EXISTS(R identity R2)) OR (EXISTS(R multisource_rel R2))',
+                   [('FetchStep', [('Any VC WHERE VC multisource_inlined_rel R2, R para "???", (EXISTS(R identity R2)) OR (EXISTS(R multisource_rel R2)), R is Note, R2 is Note, VC is Note',
+                                    [{'R': 'Note', 'R2': 'Note', 'VC': 'Note'}])],
+                     [self.vcs, self.system], None,
+                     {'VC': 'table0.C0'},
+                     []),
+                    ('OneFetchStep', [(u'Any MAX(VC) WHERE VC in_state S, S name "published", S is State, VC is Note',
+                                       [{'S': 'State', 'VC': 'Note'}])],
+                     None, None, [self.system],
+                     {'VC': 'table0.C0'},
+                     [])
+                    ])
+
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()