fix wrong type analysis with 'NOT identity' (closes #80799)
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
Tue, 25 Oct 2011 17:56:34 +0200
changeset 671 8c2612f53bf6
parent 670 3daa0b5c31c5
child 672 1965eda264bd
fix wrong type analysis with 'NOT identity' (closes #80799)
ChangeLog
analyze.py
test/unittest_analyze.py
--- a/ChangeLog	Tue Oct 25 11:11:30 2011 +0200
+++ b/ChangeLog	Tue Oct 25 17:56:34 2011 +0200
@@ -4,6 +4,7 @@
 --
     * #78681: don't crash on column aliases used in outer join
     * #81394: HAVING support in write queries (INSERT,SET,DELETE)
+    * #80799: fix wrong type analysis with 'NOT identity'
     * when possible, use entity type as translation context of relation
       (break cw < 3.13.10 compat)
 
--- a/analyze.py	Tue Oct 25 11:11:30 2011 +0200
+++ b/analyze.py	Tue Oct 25 17:56:34 2011 +0200
@@ -469,9 +469,11 @@
         """extract constraints for an relation according to it's  type"""
         if relation.is_types_restriction():
             self.visit_type_restriction(relation, constraints)
-            return True
+            return None
         rtype = relation.r_type
         lhs, rhs = relation.get_parts()
+        if rtype == 'identity' and relation.neged(strict=True):
+            return None
         if rtype in self.uid_func_mapping:
             if isinstance(relation.parent, nodes.Not) or relation.operator() != '=':
                 # non final entity types
@@ -480,22 +482,22 @@
                 etypes = self._uid_node_types(rhs)
             if etypes:
                 constraints.var_has_types( lhs.name, etypes )
-                return True
+                return None
         if isinstance(rhs, nodes.Comparison):
             rhs = rhs.children[0]
         rschema = self.schema.rschema(rtype)
         if isinstance(lhs, nodes.Constant): # lhs is a constant node (simplified tree)
             if not isinstance(rhs, nodes.VariableRef):
-                return True
+                return None
             self._extract_constraint(constraints, rhs.name, lhs, rschema.objects)
         elif isinstance(rhs, nodes.Constant) and not rschema.final:
             # rhs.type is None <-> NULL
             if not isinstance(lhs, nodes.VariableRef) or rhs.type is None:
-                return True
+                return None
             self._extract_constraint(constraints, lhs.name, rhs, rschema.subjects)
         elif not isinstance(lhs, nodes.VariableRef):
             # XXX: check relation is valid
-            return True
+            return None
         elif isinstance(rhs, nodes.VariableRef):
             lhsvar = lhs.name
             rhsvar = rhs.name
@@ -520,7 +522,7 @@
             ptypes = [str(subj) for subj in rschema.subjects()
                       if subj in lhsdomain]
             constraints.var_has_types( lhs.name, ptypes )
-        return True
+        return None
 
     def visit_type_restriction(self, relation, constraints):
         lhs, rhs = relation.get_parts()
--- a/test/unittest_analyze.py	Tue Oct 25 11:11:30 2011 +0200
+++ b/test/unittest_analyze.py	Tue Oct 25 17:56:34 2011 +0200
@@ -300,6 +300,7 @@
                                 {'X': 'Person', 'T': 'Eetype'},
                                 {'X': 'Student', 'T': 'Eetype'}])
 
+
     def test_not(self):
         node = self.helper.parse('Any X WHERE NOT X is Person')
         self.helper.compute_solutions(node, debug=DEBUG)
@@ -308,6 +309,15 @@
         expected.remove({'X': 'Person'})
         self.assertEqual(sols, expected)
 
+    def test_not_identity(self):
+        node = self.helper.parse('Any X WHERE X located A, P is Person, NOT X identity P')
+        self.helper.compute_solutions(node, debug=DEBUG)
+        sols = sorted(node.children[0].solutions)
+        self.assertEqual(sols, [{'X': 'Company', 'A': 'Address', 'P': 'Person'},
+                                {'X': 'Person', 'A': 'Address', 'P': 'Person'},
+                                {'X': 'Student', 'A': 'Address', 'P': 'Person'},
+                                ])
+
     def test_uid_func_mapping(self):
         h = self.helper
         def type_from_uid(name):