[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
--- 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
--- 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(
--- 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):