[ms planning] raise BadRQLQuery when two variables related by a non-crossable relation should come from two different sources (closes #1973767) stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 29 Sep 2011 13:53:34 +0200
branchstable
changeset 7886 b1c913a6d9f0
parent 7885 9454b7ef5ae4
child 7887 42a0b7398d31
[ms planning] raise BadRQLQuery when two variables related by a non-crossable relation should come from two different sources (closes #1973767)
server/msplanner.py
server/test/unittest_msplanner.py
--- a/server/msplanner.py	Thu Sep 29 12:55:28 2011 +0200
+++ b/server/msplanner.py	Thu Sep 29 13:53:34 2011 +0200
@@ -291,6 +291,8 @@
         self.sourcesterms = self._sourcesterms = {}
         # source : {relation: set(child variable and constant)}
         self._crossrelations = {}
+        # term : set(sources)
+        self._discarded_sources = {}
         # dictionary of variables and constants which are linked to each other
         # using a non final relation supported by multiple sources (crossed or
         # not).
@@ -539,6 +541,7 @@
                         if invariant and source is self.system_source:
                             continue
                         self._remove_source_term(source, lhs)
+                        self._discarded_sources.setdefault(lhs, set()).add(source)
                     usesys = self.system_source not in sources
                 else:
                     for source, terms in sourcesterms.items():
@@ -546,6 +549,7 @@
                             if invariant and source is self.system_source:
                                 continue
                             self._remove_source_term(source, lhs)
+                            self._discarded_sources.setdefault(lhs, set()).add(source)
                     usesys = self.system_source in sources
                 if rel is None or (len(var.stinfo['relations']) == 2 and
                                    not var.stinfo['selected']):
@@ -697,6 +701,12 @@
                                                     rel in self._crossrelations[s]))
         if invalid_sources:
             self._remove_sources(term, invalid_sources)
+            discarded = self._discarded_sources.get(term)
+            if discarded is not None and not any(x[0] for x in (termsources-invalid_sources)
+                                                 if not x[0] in discarded):
+                raise BadRQLQuery('relation %s cant be crossed but %s and %s should '
+                              'come from difference sources' %
+                              (rel.r_type, term.as_string(), oterm.as_string()))
             # if term is a rewritten const, we can apply the same changes to
             # all other consts inserted from the same original variable
             for const in self._const_vars.get(term, ()):
--- a/server/test/unittest_msplanner.py	Thu Sep 29 12:55:28 2011 +0200
+++ b/server/test/unittest_msplanner.py	Thu Sep 29 13:53:34 2011 +0200
@@ -1806,15 +1806,19 @@
 
     def test_delete_relation3(self):
         repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
-        self._test('DELETE Y multisource_inlined_rel X WHERE X eid %(x)s, NOT (Y cw_source S, S name %(source)s)',
-                   [('DeleteRelationsStep',
-                     [('OneFetchStep',
-                       [('Any Y,999999 WHERE Y multisource_inlined_rel 999999, NOT EXISTS(Y cw_source S, S name "cards"), S is CWSource, Y is IN(Card, Note)',
-                         [{'S': 'CWSource', 'Y': 'Card'}, {'S': 'CWSource', 'Y': 'Note'}])],
-                       None, None, [self.system], {},
-                       [])]
-                     )],
-                   {'x': 999999, 'source': 'cards'})
+        self.assertRaises(
+            BadRQLQuery, self._test,
+            'DELETE Y multisource_inlined_rel X WHERE X eid %(x)s, '
+            'NOT (Y cw_source S, S name %(source)s)', [],
+            {'x': 999999, 'source': 'cards'})
+
+    def test_delete_relation4(self):
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999, 'cards')
+        self.assertRaises(
+            BadRQLQuery, self._test,
+            'DELETE X multisource_inlined_rel Y WHERE Y is Note, X eid %(x)s, '
+            'NOT (Y cw_source S, S name %(source)s)', [],
+            {'x': 999999, 'source': 'cards'})
 
     def test_delete_entity1(self):
         repo._type_source_cache[999999] = ('Note', 'system', 999999, 'system')