# HG changeset patch # User Sylvain Thénault # Date 1317297214 -7200 # Node ID b1c913a6d9f0924d8d1b962932d57e3162f3428d # Parent 9454b7ef5ae48f2c46b9ac1a998918e09974232c [ms planning] raise BadRQLQuery when two variables related by a non-crossable relation should come from two different sources (closes #1973767) diff -r 9454b7ef5ae4 -r b1c913a6d9f0 server/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, ()): diff -r 9454b7ef5ae4 -r b1c913a6d9f0 server/test/unittest_msplanner.py --- 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')