in some cases (eg ambiguous neged relations), INTERSECT should be used instead of DISTINCT
--- a/server/rqlannotation.py Tue Jan 06 12:53:47 2009 -0800
+++ b/server/rqlannotation.py Wed Jan 07 09:47:56 2009 +0100
@@ -20,7 +20,7 @@
#if server.DEBUG:
# print '-------- sql annotate', repr(rqlst)
getrschema = annotator.schema.rschema
- has_text_query = False
+ has_text_query = need_intersect = False
need_distinct = rqlst.distinct
for rel in rqlst.iget_nodes(Relation):
if rel.neged(strict=True):
@@ -28,14 +28,23 @@
need_distinct = True
else:
rschema = getrschema(rel.r_type)
- if rschema.inlined:
- try:
- var = rel.children[1].children[0].variable
- except AttributeError:
- pass # rewritten variable
+ if not rschema.is_final():
+ # if one of the relation's variable is ambiguous, an intersection
+ # will be necessary
+ for vref in rel.get_nodes(VariableRef):
+ var = vref.variable
+ if not var.stinfo['selected'] and len(var.stinfo['possibletypes']) > 1:
+ need_intersect = True
+ break
else:
- if not var.stinfo['constnode']:
- need_distinct = True
+ if rschema.inlined:
+ try:
+ var = rel.children[1].children[0].variable
+ except AttributeError:
+ pass # rewritten variable
+ else:
+ if not var.stinfo['constnode']:
+ need_distinct = True
elif getrschema(rel.r_type).symetric:
for vref in rel.iget_nodes(VariableRef):
stinfo = vref.variable.stinfo
@@ -139,6 +148,7 @@
except CantSelectPrincipal:
stinfo['invariant'] = False
rqlst.need_distinct = need_distinct
+ rqlst.need_intersect = need_intersect
return has_text_query
--- a/server/sources/rql2sql.py Tue Jan 06 12:53:47 2009 -0800
+++ b/server/sources/rql2sql.py Wed Jan 07 09:47:56 2009 +0100
@@ -76,7 +76,7 @@
unstable.remove(varname)
torewrite.add(var)
newselect = Select()
- newselect.need_distinct = False
+ newselect.need_distinct = newselect.need_intersect = False
myunion = Union()
myunion.append(newselect)
# extract aliases / selection
@@ -487,7 +487,9 @@
elif self._state.restrictions and self.dbms_helper.needs_from_clause:
sql.insert(1, 'FROM (SELECT 1) AS _T')
sqls.append('\n'.join(sql))
- if distinct:
+ if select.need_intersect:
+ return '\nINTERSECT\n'.join(sqls)
+ elif distinct:
return '\nUNION\n'.join(sqls)
else:
return '\nUNION ALL\n'.join(sqls)
--- a/server/test/unittest_rql2sql.py Tue Jan 06 12:53:47 2009 -0800
+++ b/server/test/unittest_rql2sql.py Wed Jan 07 09:47:56 2009 +0100
@@ -745,6 +745,14 @@
FROM EProperty AS P
WHERE P.for_user IS NULL'''),
+ ('Any S WHERE NOT X in_state S, X is IN(Affaire, EUser)',
+ '''SELECT S.eid
+FROM Affaire AS X, State AS S
+WHERE (X.in_state IS NULL OR X.in_state!=S.eid)
+INTERSECT
+SELECT S.eid
+FROM EUser AS X, State AS S
+WHERE (X.in_state IS NULL OR X.in_state!=S.eid)'''),
]
OUTER_JOIN = [