# HG changeset patch # User Sylvain Thenault # Date 1231318076 -3600 # Node ID c0a0ce6c042876f10abe4d664af5dda35f419fba # Parent 25aae8a1553200052ac1a05b312ce6017dcfbe0d in some cases (eg ambiguous neged relations), INTERSECT should be used instead of DISTINCT diff -r 25aae8a15532 -r c0a0ce6c0428 server/rqlannotation.py --- 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 diff -r 25aae8a15532 -r c0a0ce6c0428 server/sources/rql2sql.py --- 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) diff -r 25aae8a15532 -r c0a0ce6c0428 server/test/unittest_rql2sql.py --- 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 = [