# HG changeset patch # User Sylvain Thénault # Date 1387525143 -3600 # Node ID 54ead5f372bbaf8fb6826943397c5ddf68e35805 # Parent 3338b2205ea37745bf045b934020c98795ef3ea4 [rql2sql] remove special behaviour of symmetric relation vs DISTINCT 0542a85fe667 replacing SQL OR by hooks for symmetric relations allows that. This involve a single test value change for a border case: when querying a symmetric relation without specifying the subject nor the object, you may get some duplicated result. IMO this is fine to let the user explicitly use DISTINCT or not and to remove the dedicated handling we had which didn't let any choice. Related to #3259713 diff -r 3338b2205ea3 -r 54ead5f372bb server/rqlannotation.py --- a/server/rqlannotation.py Tue Feb 11 11:03:01 2014 +0100 +++ b/server/rqlannotation.py Fri Dec 20 08:39:03 2013 +0100 @@ -35,15 +35,6 @@ #if server.DEBUG: # print '-------- sql annotate', repr(rqlst) getrschema = annotator.schema.rschema - need_distinct = rqlst.distinct - for rel in rqlst.iget_nodes(Relation): - if getrschema(rel.r_type).symmetric and not isinstance(rel.parent, Exists): - for vref in rel.iget_nodes(VariableRef): - stinfo = vref.variable.stinfo - if not stinfo['constnode'] and stinfo['selected']: - need_distinct = True - # XXX could mark as not invariant - break for var in rqlst.defined_vars.itervalues(): stinfo = var.stinfo if stinfo.get('ftirels'): @@ -158,7 +149,6 @@ for col_alias in rqlst.aliases.itervalues(): if col_alias.stinfo.get('ftirels'): has_text_query = True - rqlst.need_distinct = need_distinct return has_text_query diff -r 3338b2205ea3 -r 54ead5f372bb server/sources/rql2sql.py --- a/server/sources/rql2sql.py Tue Feb 11 11:03:01 2014 +0100 +++ b/server/sources/rql2sql.py Fri Dec 20 08:39:03 2013 +0100 @@ -116,7 +116,6 @@ continue unstable.remove(varname) newselect = Select() - newselect.need_distinct = False myunion = Union() myunion.append(newselect) # extract aliases / selection @@ -703,9 +702,6 @@ } if not self.dbhelper.union_parentheses_support: self.union_sql = self.noparen_union_sql - if self.dbhelper.fti_need_distinct: - self.__union_sql = self.union_sql - self.union_sql = self.has_text_need_distinct_union_sql self._lock = threading.Lock() if attrmap is None: attrmap = {} @@ -739,12 +735,6 @@ finally: self._lock.release() - def has_text_need_distinct_union_sql(self, union, needalias=False): - if getattr(union, 'has_text_query', False): - for select in union.children: - select.need_distinct = True - return self.__union_sql(union, needalias) - def union_sql(self, union, needalias=False): # pylint: disable=E0202 if len(union.children) == 1: return self.select_sql(union.children[0], needalias) @@ -772,7 +762,12 @@ :needwrap: boolean telling if the query will be wrapped in an outer query (to deal with aggregat and/or grouping) """ - distinct = selectsortterms = select.need_distinct + if select.distinct: + distinct = True + elif self.dbhelper.fti_need_distinct: + distinct = getattr(select.parent, 'has_text_query', False) + else: + distinct = False sorts = select.orderby groups = select.groupby having = select.having @@ -796,6 +791,7 @@ # selection (union or distinct query) and wrapping (union with groups) needwrap = False sols = select.solutions + selectsortterms = distinct if len(sols) > 1: # remove invariant from solutions sols, existssols, unstable = remove_unused_solutions( diff -r 3338b2205ea3 -r 54ead5f372bb server/test/unittest_querier.py --- a/server/test/unittest_querier.py Tue Feb 11 11:03:01 2014 +0100 +++ b/server/test/unittest_querier.py Fri Dec 20 08:39:03 2013 +0100 @@ -718,17 +718,17 @@ self.execute("INSERT Personne X: X nom 'trucmuche'") self.execute("SET X connait Y WHERE X nom 'chouette', Y nom 'bidule'") self.execute("SET X connait Y WHERE X nom 'machin', Y nom 'chouette'") - rset = self.execute('Any P where P connait P2') - self.assertEqual(len(rset.rows), 3, rset.rows) - rset = self.execute('Any P where NOT P connait P2') + rset = self.execute('Any P WHERE P connait P2') + self.assertEqual(len(rset.rows), 4, rset.rows) + rset = self.execute('Any P WHERE NOT P connait P2') self.assertEqual(len(rset.rows), 1, rset.rows) # trucmuche - rset = self.execute('Any P where P connait P2, P2 nom "bidule"') + rset = self.execute('Any P WHERE P connait P2, P2 nom "bidule"') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('Any P where P2 connait P, P2 nom "bidule"') + rset = self.execute('Any P WHERE P2 connait P, P2 nom "bidule"') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('Any P where P connait P2, P2 nom "chouette"') + rset = self.execute('Any P WHERE P connait P2, P2 nom "chouette"') self.assertEqual(len(rset.rows), 2, rset.rows) - rset = self.execute('Any P where P2 connait P, P2 nom "chouette"') + rset = self.execute('Any P WHERE P2 connait P, P2 nom "chouette"') self.assertEqual(len(rset.rows), 2, rset.rows) def test_select_inline(self):