# HG changeset patch # User Sylvain Thénault # Date 1296224114 -3600 # Node ID 99eb71b311e4719979d0f502587c4c7a6abe74f2 # Parent 5be96d9cbedc8f88206766dbb3729ac24536de2b [rset] fix entity building for some result set with UNION and subqueries diff -r 5be96d9cbedc -r 99eb71b311e4 rset.py --- a/rset.py Fri Jan 28 15:12:13 2011 +0100 +++ b/rset.py Fri Jan 28 15:15:14 2011 +0100 @@ -487,24 +487,21 @@ select = rqlst # take care, due to outer join support, we may find None # values for non final relation - for i, attr, role in attr_desc_iterator(select, col): - outerselidx = rqlst.subquery_selection_index(select, i) - if outerselidx is None: - continue + for i, attr, role in attr_desc_iterator(select, col, entity.cw_col): if role == 'subject': rschema = eschema.subjrels[attr] if rschema.final: if attr == 'eid': - entity.eid = rowvalues[outerselidx] + entity.eid = rowvalues[i] else: - entity.cw_attr_cache[attr] = rowvalues[outerselidx] + entity.cw_attr_cache[attr] = rowvalues[i] continue else: rschema = eschema.objrels[attr] rdef = eschema.rdef(attr, role) # only keep value if it can't be multivalued if rdef.role_cardinality(role) in '1?': - if rowvalues[outerselidx] is None: + if rowvalues[i] is None: if role == 'subject': rql = 'Any Y WHERE X %s Y, X eid %s' else: @@ -512,7 +509,7 @@ rrset = ResultSet([], rql % (attr, entity.eid)) rrset.req = req else: - rrset = self._build_entity(row, outerselidx).as_rset() + rrset = self._build_entity(row, i).as_rset() entity.cw_set_relation_cache(attr, role, rrset) return entity @@ -650,8 +647,13 @@ return rhs.eval(self.args) return None +def _get_variable(term): + # XXX rewritten const + # use iget_nodes for (hack) case where we have things like MAX(V) + for vref in term.iget_nodes(nodes.VariableRef): + return vref.variable -def attr_desc_iterator(rqlst, index=0): +def attr_desc_iterator(select, selectidx, rootidx): """return an iterator on a list of 2-uple (index, attr_relation) localizing attribute relations of the main variable in a result's row @@ -662,25 +664,33 @@ a generator on (index, relation, target) describing column being attribute of the main variable """ - main = rqlst.selection[index] - for i, term in enumerate(rqlst.selection): - if i == index: + rootselect = select + while rootselect.parent.parent is not None: + rootselect = rootselect.parent.parent.parent + rootmain = rootselect.selection[selectidx] + rootmainvar = _get_variable(rootmain) + assert rootmainvar + root = rootselect.parent + selectmain = select.selection[selectidx] + for i, term in enumerate(rootselect.selection): + rootvar = _get_variable(term) + if rootvar is None: continue - # XXX rewritten const - # use iget_nodes for (hack) case where we have things like MAX(V) - for vref in term.iget_nodes(nodes.VariableRef): - var = vref.variable - break - else: + if rootvar.name == rootmainvar.name: + continue + if select is not rootselect: + term = select.selection[root.subquery_selection_index(select, i)] + var = _get_variable(term) + if var is None: continue for ref in var.references(): rel = ref.relation() if rel is None or rel.is_types_restriction(): continue lhs, rhs = rel.get_variable_parts() - if main.is_equivalent(lhs): + if selectmain.is_equivalent(lhs): if rhs.is_equivalent(term): yield (i, rel.r_type, 'subject') - elif main.is_equivalent(rhs): + elif selectmain.is_equivalent(rhs): if lhs.is_equivalent(term): yield (i, rel.r_type, 'object') diff -r 5be96d9cbedc -r 99eb71b311e4 test/unittest_rset.py --- a/test/unittest_rset.py Fri Jan 28 15:12:13 2011 +0100 +++ b/test/unittest_rset.py Fri Jan 28 15:15:14 2011 +0100 @@ -49,7 +49,7 @@ 'Any C where C is Company, C employs P' : [], } for rql, relations in queries.items(): - result = list(attr_desc_iterator(parse(rql).children[0])) + result = list(attr_desc_iterator(parse(rql).children[0], 0, 0)) self.assertEqual((rql, result), (rql, relations)) def test_relations_description_indexed(self): @@ -59,8 +59,8 @@ {0: [(2,'employs', 'subject')], 1: [(3,'login', 'subject'), (4,'mail', 'subject')]}, } for rql, results in queries.items(): - for var_index, relations in results.items(): - result = list(attr_desc_iterator(parse(rql).children[0], var_index)) + for idx, relations in results.items(): + result = list(attr_desc_iterator(parse(rql).children[0], idx, idx)) self.assertEqual(result, relations) @@ -328,7 +328,7 @@ self.assertEqual(entity, None) self.assertEqual(rtype, None) - def test_related_entity_union_subquery(self): + def test_related_entity_union_subquery_1(self): e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path') rset = self.execute('Any X,N ORDERBY N WITH X,N BEING ' '((Any X,N WHERE X is CWGroup, X name N)' @@ -337,10 +337,14 @@ entity, rtype = rset.related_entity(0, 1) self.assertEqual(entity.eid, e.eid) self.assertEqual(rtype, 'title') + self.assertEqual(entity.title, 'aaaa') entity, rtype = rset.related_entity(1, 1) self.assertEqual(entity.__regid__, 'CWGroup') self.assertEqual(rtype, 'name') - # + self.assertEqual(entity.name, 'guests') + + def test_related_entity_union_subquery_2(self): + e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path') rset = self.execute('Any X,N ORDERBY N WHERE X is Bookmark WITH X,N BEING ' '((Any X,N WHERE X is CWGroup, X name N)' ' UNION ' @@ -348,7 +352,10 @@ entity, rtype = rset.related_entity(0, 1) self.assertEqual(entity.eid, e.eid) self.assertEqual(rtype, 'title') - # + self.assertEqual(entity.title, 'aaaa') + + def test_related_entity_union_subquery_3(self): + e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path') rset = self.execute('Any X,N ORDERBY N WITH N,X BEING ' '((Any N,X WHERE X is CWGroup, X name N)' ' UNION ' @@ -356,6 +363,18 @@ entity, rtype = rset.related_entity(0, 1) self.assertEqual(entity.eid, e.eid) self.assertEqual(rtype, 'title') + self.assertEqual(entity.title, 'aaaa') + + def test_related_entity_union_subquery_4(self): + e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path') + rset = self.execute('Any X,X, N ORDERBY N WITH X,N BEING ' + '((Any X,N WHERE X is CWGroup, X name N)' + ' UNION ' + ' (Any X,N WHERE X is Bookmark, X title N))') + entity, rtype = rset.related_entity(0, 2) + self.assertEqual(entity.eid, e.eid) + self.assertEqual(rtype, 'title') + self.assertEqual(entity.title, 'aaaa') def test_related_entity_trap_subquery(self): req = self.request()