backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 09 Sep 2010 10:10:19 +0200
changeset 581 b40a38e34bed
parent 574 b5a69faac4ea (current diff)
parent 580 6405b59a8355 (diff)
child 588 ede0c8b7d83b
backport stable
--- a/ChangeLog	Wed Jul 28 12:09:37 2010 +0200
+++ b/ChangeLog	Thu Sep 09 10:10:19 2010 +0200
@@ -1,6 +1,24 @@
 ChangeLog for RQL
 =================
 
+--
+    * enhance bad rql query detection with ordered distinct (can't use distinct
+      if an attribute is selected and we sort on another attribute)
+
+    * add constraint package to dependencies  so we've fallback opportunity if
+      gecode is not installed
+
+    * fix subquery_selection_index responsability mess-up: it wasn't doing what
+      it should have done (see cw.rset related_entity implementation)
+
+    * consider subquery aliases in Select.clean_solutions
+
+
+2010-08-02  --  0.26.5
+    * fix solutions computation crash with some query using sub-queries (closes #37423)
+
+
+
 2010-07-28  --  0.26.4
     * fix re-annotation pb: some stinfo keys were not properly reinitialized
       which may cause pb later (at sql generation time for instance)
--- a/__pkginfo__.py	Wed Jul 28 12:09:37 2010 +0200
+++ b/__pkginfo__.py	Thu Sep 09 10:10:19 2010 +0200
@@ -20,7 +20,7 @@
 __docformat__ = "restructuredtext en"
 
 modname = "rql"
-numversion = (0, 26, 4)
+numversion = (0, 26, 5)
 version = '.'.join(str(num) for num in numversion)
 
 license = 'LGPL'
@@ -83,6 +83,7 @@
     'logilab-common >= 0.47.0',
     'logilab-database',
     'yapps2 >= 2.1.1',
+    'constraint', # fallback if the gecode compiled module is missing
     ]
 
 # links to download yapps2 package that is not (yet) registered in pypi
--- a/analyze.py	Wed Jul 28 12:09:37 2010 +0200
+++ b/analyze.py	Thu Sep 09 10:10:19 2010 +0200
@@ -377,8 +377,8 @@
                     alltypes.add(targettypes)
         else:
             alltypes = get_target_types()
-
-        constraints.var_has_types( var, [ str(t) for t in alltypes] )
+        domain = constraints.domains[var]
+        constraints.var_has_types( var, [str(t) for t in alltypes if t in domain] )
 
     def visit(self, node, uid_func_mapping=None, kwargs=None, debug=False):
         # FIXME: not thread safe
@@ -509,18 +509,26 @@
                         samevar = True
                     else:
                         rhsvars.append(v.name)
+            lhsdomain = constraints.domains[lhsvar]
             if rhsvars:
                 s2 = '=='.join(rhsvars)
+                # filter according to domain necessary for column aliases
+                rhsdomain = constraints.domains[rhsvars[0]]
                 res = []
                 for fromtype, totypes in rschema.associations():
-                    res.append( [ ( [lhsvar], [str(fromtype)]), (rhsvars, [ str(t) for t in totypes]) ] )
+                    if not fromtype in lhsdomain:
+                        continue
+                    ptypes = [str(t) for t in totypes if t in rhsdomain]
+                    res.append( [ ( [lhsvar], [str(fromtype)]), (rhsvars, ptypes) ] )
                 constraints.or_and( res )
             else:
-                constraints.var_has_types( lhsvar, [ str(subj) for subj in rschema.subjects()] )
+                ptypes = [str(subj) for subj in rschema.subjects()
+                          if subj in lhsdomain]
+                constraints.var_has_types( lhsvar, ptypes )
             if samevar:
                 res = []
                 for fromtype, totypes in rschema.associations():
-                    if not fromtype in totypes:
+                    if not (fromtype in totypes and fromtype in lhsdomain):
                         continue
                     res.append(str(fromtype))
                 constraints.var_has_types( lhsvar, res )
--- a/debian/changelog	Wed Jul 28 12:09:37 2010 +0200
+++ b/debian/changelog	Thu Sep 09 10:10:19 2010 +0200
@@ -1,3 +1,9 @@
+rql (0.26.5-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Mon, 02 Aug 2010 14:22:00 +0200
+
 rql (0.26.4-1) unstable; urgency=low
 
   * new upstream release
--- a/stcheck.py	Wed Jul 28 12:09:37 2010 +0200
+++ b/stcheck.py	Thu Sep 09 10:10:19 2010 +0200
@@ -162,8 +162,9 @@
                 self._check_selected(group, 'group', state)
         if node.distinct and node.orderby:
             # check that variables referenced in the given term are reachable from
-            # a selected variable with only ?1 cardinalityselected
-            selectidx = frozenset(vref.name for term in selected for vref in term.get_nodes(VariableRef))
+            # a selected variable with only ?1 cardinality selected
+            selectidx = frozenset(vref.name for term in selected
+                                  for vref in term.get_nodes(VariableRef))
             schema = self.schema
             for sortterm in node.orderby:
                 for vref in sortterm.term.get_nodes(VariableRef):
@@ -186,20 +187,21 @@
         path = has_path(graph, fromvar, tovar)
         if path is None:
             return False
-        for tovar in path:
+        for var in path:
             try:
-                rtype = graph[(fromvar, tovar)]
+                rtype = graph[(fromvar, var)]
                 cardidx = 0
             except KeyError:
-                rtype = graph[(tovar, fromvar)]
+                rtype = graph[(var, fromvar)]
                 cardidx = 1
             rschema = self.schema.rschema(rtype)
             for rdef in rschema.rdefs.itervalues():
                 # XXX aggregats handling needs much probably some enhancements...
-                if not (tovar in select.aggregated
-                        or rdef.cardinality[cardidx] in '?1'):
+                if not (var in select.aggregated
+                        or (rdef.cardinality[cardidx] in '?1' and
+                            (var == tovar or not rschema.final))):
                     return False
-            fromvar = tovar
+            fromvar = var
         return True
 
 
--- a/stmts.py	Wed Jul 28 12:09:37 2010 +0200
+++ b/stmts.py	Thu Sep 09 10:10:19 2010 +0200
@@ -327,14 +327,16 @@
         return self._subq_cache[(col, etype)]
 
     def subquery_selection_index(self, subselect, col):
-        """given a select sub-query and a column index in this sub-query, return
-        the selection index for this column in the root query
+        """given a select sub-query and a column index in the root query, return
+        the selection index for this column in the sub-query
         """
-        while col is not None and subselect.parent.parent:
+        selectpath = []
+        while subselect.parent.parent is not None:
             subq = subselect.parent.parent
             subselect = subq.parent
-            termvar = subselect.aliases[subq.aliases[col].name]
-            col = termvar.selected_index()
+            selectpath.insert(0, subselect)
+        for select in selectpath:
+            col = select.selection[col].variable.colnum
         return col
 
     # recoverable modification methods ########################################
@@ -624,7 +626,7 @@
             solutions = self.solutions
         # this may occurs with rql optimization, for instance on
         # 'Any X WHERE X eid 12' query
-        if not self.defined_vars:
+        if not (self.defined_vars or self.aliases):
             self.solutions = [{}]
         else:
             newsolutions = []
@@ -632,6 +634,8 @@
                 asol = {}
                 for var in self.defined_vars:
                     asol[var] = origsol[var]
+                for var in self.aliases:
+                    asol[var] = origsol[var]
                 if not asol in newsolutions:
                     newsolutions.append(asol)
             self.solutions = newsolutions
--- a/test/unittest_analyze.py	Wed Jul 28 12:09:37 2010 +0200
+++ b/test/unittest_analyze.py	Thu Sep 09 10:10:19 2010 +0200
@@ -47,7 +47,7 @@
         self.inlined = False
         if card is None:
             if self.final:
-                card = '?*'
+                card = '?1'
             else:
                 card = '**'
         self.card = card
--- a/test/unittest_stcheck.py	Wed Jul 28 12:09:37 2010 +0200
+++ b/test/unittest_stcheck.py	Thu Sep 09 10:10:19 2010 +0200
@@ -52,10 +52,17 @@
 
     'Any X WHERE X name "Toto", P is Person',
 
-    # BAD QUERY cant sort on y
+    "Any X WHERE X eid 0, X eid 1",
+
+    # DISTINCT+ORDERBY tests ###################################################
+    # cant sort on Y, B <- work_for X is multivalued
     'DISTINCT Any X ORDERBY Y WHERE B work_for X, B name Y',
-
-    "Any X WHERE X eid 0, X eid 1"
+    # cant sort on PN, there may be different PF values for the same PN value
+    # XXX untrue if PF or PN is marked as unique
+    'DISTINCT Any PF ORDERBY PN WHERE P firstname PF, P name PN',
+    # cant sort on XN, there may be different PF values for the same PF value
+    'DISTINCT Any PF ORDERBY X WHERE P work_for X, P firstname PF',
+    'DISTINCT Any PF ORDERBY XN WHERE P work_for X, P firstname PF, X name XN',
 
     )
 
@@ -66,12 +73,12 @@
 
     'DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is Person, Y is Company',
 
+    # DISTINCT+ORDERBY tests ###################################################
     # sorting allowed since order variable reachable from a selected
     # variable with only ?1 cardinality
-    'DISTINCT Any B ORDERBY Y WHERE B work_for X, B name Y',
-    'DISTINCT Any B ORDERBY Y WHERE B work_for X, X name Y',
+    'DISTINCT Any P ORDERBY PN WHERE P work_for X, P name PN',
+    'DISTINCT Any P ORDERBY XN WHERE P work_for X, X name XN',
 
-#    'DISTINCT Any X ORDERBY SN WHERE X in_state S, S name SN',
 
 
     )