# HG changeset patch # User Sylvain Thénault # Date 1308232325 -7200 # Node ID f6856231cc518aa73b3e8c2762d708bd2d3c9355 # Parent 6f6b334a14b7c9245f382a5fc7530594ad357525 [rql annotation] fix bad invariant variable w/ has_text relation: this is only true when has_text will be used as principal (though we don't know that yet) diff -r 6f6b334a14b7 -r f6856231cc51 server/rqlannotation.py --- a/server/rqlannotation.py Thu Jun 16 15:16:58 2011 +0200 +++ b/server/rqlannotation.py Thu Jun 16 15:52:05 2011 +0200 @@ -271,9 +271,17 @@ return has_text_query def is_ambiguous(self, var): - # ignore has_text relation - if len([rel for rel in var.stinfo['relations'] - if rel.scope is var.scope and rel.r_type == 'has_text']) == 1: + # ignore has_text relation when we know it will be used as principal. + # This is expected by the rql2sql generator which will use the `entities` + # table to filter out by type if necessary, This optimisation is very + # interesting in multi-sources cases, as it may avoid a costly query + # on sources to get all entities of a given type to achieve this, while + # we have all the necessary information. + root = var.stmt.root # Union node + # rel.scope -> Select or Exists node, so add .parent to get Union from + # Select node + rels = [rel for rel in var.stinfo['relations'] if rel.scope.parent is root] + if len(rels) == 1 and rels[0].r_type == 'has_text': return False try: data = var.stmt._deamb_data diff -r 6f6b334a14b7 -r f6856231cc51 server/test/unittest_querier.py --- a/server/test/unittest_querier.py Thu Jun 16 15:16:58 2011 +0200 +++ b/server/test/unittest_querier.py Thu Jun 16 15:52:05 2011 +0200 @@ -1443,5 +1443,14 @@ rset = self.execute('Any X,Y WHERE X nom XD, Y nom XD, X eid Z, Y eid > Z') self.assertEqual(rset.rows, [[peid1, peid2]]) + def test_nonregr_has_text_ambiguity_1(self): + peid = self.execute("INSERT CWUser X: X login 'bidule', X upassword 'bidule', X in_group G WHERE G name 'users'")[0][0] + aeid = self.execute("INSERT Affaire X: X ref 'bidule'")[0][0] + self.commit() + rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule"') + self.assertEqual(rset.rows, [[peid]]) + 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]]) + if __name__ == '__main__': unittest_main() diff -r 6f6b334a14b7 -r f6856231cc51 server/test/unittest_rqlannotation.py --- a/server/test/unittest_rqlannotation.py Thu Jun 16 15:16:58 2011 +0200 +++ b/server/test/unittest_rqlannotation.py Thu Jun 16 15:52:05 2011 +0200 @@ -333,6 +333,13 @@ self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) self.assertEqual(rqlst.defined_vars['F']._q_invariant, True) + def test_nonregr_ambiguity_2(self): + rqlst = self._prepare('Any S,SN WHERE X has_text "tot", X in_state S, S name SN, X is CWUser') + # X use has_text but should not be invariant as ambiguous, and has_text + # may not be its principal + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) + if __name__ == '__main__': from logilab.common.testlib import unittest_main unittest_main()