backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 10 Jun 2010 10:16:59 +0200
changeset 5707 3586d36d2a45
parent 5705 30b94973bc67 (current diff)
parent 5706 c2e8290bc7b7 (diff)
child 5708 277c8a8eab21
backport stable
__pkginfo__.py
debian/control
schema.py
server/session.py
server/test/unittest_querier.py
--- a/__pkginfo__.py	Wed Jun 09 16:16:54 2010 +0200
+++ b/__pkginfo__.py	Thu Jun 10 10:16:59 2010 +0200
@@ -42,8 +42,13 @@
 __depends__ = {
     'logilab-common': '>= 0.50.2',
     'logilab-mtconverter': '>= 0.6.0',
+<<<<<<< /home/syt/src/fcubicweb/cubicweb/__pkginfo__.py
     'rql': '>= 0.26.0',
     'yams': '>= 0.30.0',
+=======
+    'rql': '>= 0.26.2',
+    'yams': '>= 0.28.1',
+>>>>>>> /tmp/__pkginfo__.py~other.ZMqgs5
     'docutils': '>= 0.6',
     #gettext                    # for xgettext, msgcat, etc...
     # web dependancies
--- a/debian/control	Wed Jun 09 16:16:54 2010 +0200
+++ b/debian/control	Thu Jun 10 10:16:59 2010 +0200
@@ -97,7 +97,7 @@
 Package: cubicweb-common
 Architecture: all
 XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.6.0), python-logilab-common (>= 0.50.2), python-yams (>= 0.30.0), python-rql (>= 0.26.1), python-lxml
+Depends: ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.6.0), python-logilab-common (>= 0.50.2), python-yams (>= 0.30.0), python-rql (>= 0.26.2), python-lxml
 Recommends: python-simpletal (>= 4.0), python-crypto
 Conflicts: cubicweb-core
 Replaces: cubicweb-core
--- a/rqlrewrite.py	Wed Jun 09 16:16:54 2010 +0200
+++ b/rqlrewrite.py	Thu Jun 10 10:16:59 2010 +0200
@@ -353,7 +353,7 @@
         if need_null_test:
             snippetrqlst = n.Or(
                 n.make_relation(subselectvar, 'is', (None, None), n.Constant,
-                                operator='IS'),
+                                operator='='),
                 snippetrqlst)
         subselect.add_restriction(snippetrqlst)
         if self.u_varname:
--- a/schema.py	Wed Jun 09 16:16:54 2010 +0200
+++ b/schema.py	Thu Jun 10 10:16:59 2010 +0200
@@ -852,11 +852,9 @@
             except KeyError:
                 pass
         rql, has_perm_defs, keyarg = self.transform_has_permission()
-        if creating:
-            # when creating an entity, consider has_*_permission satisfied
-            if has_perm_defs:
-                return True
-            return False
+        # when creating an entity, expression related to X satisfied
+        if creating and 'X' in self.rqlst.defined_vars:
+            return True
         if keyarg is None:
             kwargs.setdefault('u', session.user.eid)
             try:
--- a/server/session.py	Wed Jun 09 16:16:54 2010 +0200
+++ b/server/session.py	Thu Jun 10 10:16:59 2010 +0200
@@ -15,9 +15,8 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""Repository users' and internal' sessions.
+"""Repository users' and internal' sessions."""
 
-"""
 from __future__ import with_statement
 
 __docformat__ = "restructuredtext en"
@@ -29,7 +28,7 @@
 from warnings import warn
 
 from logilab.common.deprecation import deprecated
-from rql.nodes import VariableRef, Function, ETYPE_PYOBJ_MAP, etype_from_pyobj
+from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj
 from yams import BASE_TYPES
 
 from cubicweb import Binary, UnknownEid, schema
@@ -49,17 +48,6 @@
 NO_UNDO_TYPES.add('is_instance_of')
 # XXX rememberme,forgotpwd,apycot,vcsfile
 
-def is_final(rqlst, variable, args):
-    # try to find if this is a final var or not
-    for select in rqlst.children:
-        for sol in select.solutions:
-            etype = variable.get_type(sol, args)
-            if etype is None:
-                continue
-            if etype in BASE_TYPES:
-                return True
-            return False
-
 def _make_description(selected, args, solution):
     """return a description for a result set"""
     description = []
@@ -861,32 +849,37 @@
         """
         # not so easy, looks for variable which changes from one solution
         # to another
-        unstables = rqlst.get_variable_variables()
-        basedescription = []
+        unstables = rqlst.get_variable_indices()
+        basedescr = []
         todetermine = []
-        selected = rqlst.children[0].selection # sample selection
-        for i, term in enumerate(selected):
-            if isinstance(term, Function) and term.descr().rtype is not None:
-                basedescription.append(term.get_type(term.descr().rtype, args))
-                continue
-            for vref in term.get_nodes(VariableRef):
-                if vref.name in unstables:
-                    basedescription.append(None)
-                    todetermine.append( (i, is_final(rqlst, vref.variable, args)) )
-                    break
+        sampleselect = rqlst.children[0]
+        samplesols = sampleselect.solutions[0]
+        for i, term in enumerate(sampleselect.selection):
+            try:
+                ttype = term.get_type(samplesols, args)
+            except CoercionError:
+                ttype = None
+                isfinal = True
             else:
-                # sample etype
-                etype = rqlst.children[0].solutions[0]
-                basedescription.append(term.get_type(etype, args))
+                if ttype is None or ttype == 'Any':
+                    ttype = None
+                    isfinal = True
+                else:
+                    isfinal = ttype in BASE_TYPES
+            if ttype is None or i in unstables:
+                basedescr.append(None)
+                todetermine.append( (i, isfinal) )
+            else:
+                basedescr.append(ttype)
         if not todetermine:
-            return RepeatList(len(result), tuple(basedescription))
-        return self._build_descr(result, basedescription, todetermine)
+            return RepeatList(len(result), tuple(basedescr))
+        return self._build_descr(result, basedescr, todetermine)
 
     def _build_descr(self, result, basedescription, todetermine):
         description = []
         etype_from_eid = self.describe
         for row in result:
-            row_descr = basedescription
+            row_descr = basedescription[:]
             for index, isfinal in todetermine:
                 value = row[index]
                 if value is None:
@@ -899,7 +892,8 @@
                     try:
                         row_descr[index] = etype_from_eid(value)[0]
                     except UnknownEid:
-                        self.critical('wrong eid %s in repository, should check database' % value)
+                        self.critical('wrong eid %s in repository, you should '
+                                      'db-check the database' % value)
                         row_descr[index] = row[index] = None
             description.append(tuple(row_descr))
         return description
--- a/server/sources/rql2sql.py	Wed Jun 09 16:16:54 2010 +0200
+++ b/server/sources/rql2sql.py	Thu Jun 10 10:16:59 2010 +0200
@@ -742,29 +742,29 @@
                 else:
                     # no variables in the RHS
                     sql = self._visit_attribute_relation(relation)
+        elif (rtype == 'is' and isinstance(rhs.children[0], Constant)
+              and rhs.children[0].eval(self._args) is None):
+            # special case "C is NULL"
+            if lhs.name in self._varmap:
+                lhssql = self._varmap[lhs.name]
+            else:
+                lhssql = lhs.accept(self)
+            return '%s%s' % (lhssql, rhs.accept(self))
+        elif '%s.%s' % (lhs, relation.r_type) in self._varmap:
+            # relation has already been processed by a previous step
+            return ''
+        elif relation.optional:
+            # check it has not already been treaten (to get necessary
+            # information to add an outer join condition)
+            if relation in self._state.done:
+                return ''
+            # OPTIONAL relation, generate a left|right outer join
+            sql = self._visit_outer_join_relation(relation, rschema)
+        elif rschema.inlined:
+            sql = self._visit_inlined_relation(relation)
         else:
-            if rtype == 'is' and rhs.operator == 'IS':
-                # special case "C is NULL"
-                if lhs.name in self._varmap:
-                    lhssql = self._varmap[lhs.name]
-                else:
-                    lhssql = lhs.accept(self)
-                return '%s%s' % (lhssql, rhs.accept(self))
-            if '%s.%s' % (lhs, relation.r_type) in self._varmap:
-                # relation has already been processed by a previous step
-                return
-            if relation.optional:
-                # check it has not already been treaten (to get necessary
-                # information to add an outer join condition)
-                if relation in self._state.done:
-                    return
-                # OPTIONAL relation, generate a left|right outer join
-                sql = self._visit_outer_join_relation(relation, rschema)
-            elif rschema.inlined:
-                sql = self._visit_inlined_relation(relation)
-            else:
-                # regular (non final) relation
-                sql = self._visit_relation(relation, rschema)
+            # regular (non final) relation
+            sql = self._visit_relation(relation, rschema)
         return sql
 
     def _visit_inlined_relation(self, relation):
@@ -1026,7 +1026,7 @@
             lhs = None
             rhs = cmp.children[0]
         operator = cmp.operator
-        if operator in ('IS', 'LIKE', 'ILIKE'):
+        if operator in ('LIKE', 'ILIKE'):
             if operator == 'ILIKE' and not self.dbhelper.ilike_support:
                 operator = ' LIKE '
             else:
--- a/server/test/unittest_querier.py	Wed Jun 09 16:16:54 2010 +0200
+++ b/server/test/unittest_querier.py	Thu Jun 10 10:16:59 2010 +0200
@@ -789,6 +789,15 @@
                            'end', 'finie', 'markasdone', 'pitetre', 'redoit',
                            'start', 'todo'])
 
+    def test_select_union_description_diff_var(self):
+        eid1 = self.execute('CWGroup X WHERE X name "managers"')[0][0]
+        eid2 = self.execute('CWUser X WHERE X login "admin"')[0][0]
+        rset = self.execute('(Any X WHERE X eid %(x)s)'
+                            ' UNION '
+                            '(Any Y WHERE Y eid %(y)s)',
+                            {'x': eid1, 'y': eid2})
+        self.assertEquals(rset.description[:], [('CWGroup',), ('CWUser',)])
+
     def test_exists(self):
         geid = self.execute("INSERT CWGroup X: X name 'lulufanclub'")[0][0]
         self.execute("SET U in_group G WHERE G name 'lulufanclub'")