# HG changeset patch # User Sylvain Thénault # Date 1308916949 -7200 # Node ID c3bf459268d71a35f37e9a81e64b985b5a1f5db2 # Parent 2d4ba5b984dc13cf114c2bc23d15a965ccbb64f7 [rqlrewrite] closes #1772135: 1. don't try to reuse a relation from another statement (eg because a subquery has been introduced) 2. _use_orig_term should consider the current statement diff -r 2d4ba5b984dc -r c3bf459268d7 rqlrewrite.py --- a/rqlrewrite.py Wed Jun 22 18:24:56 2011 +0200 +++ b/rqlrewrite.py Fri Jun 24 14:02:29 2011 +0200 @@ -467,6 +467,7 @@ original query, return that relation node """ rschema = self.schema.rschema(sniprel.r_type) + stmt = self.current_statement() for vi in self.varinfos: try: if target == 'object': @@ -482,6 +483,9 @@ except KeyError: # may be raised by vi['xhs_rels'][sniprel.r_type] return None + # don't share if relation's statement is not the current statement + if orel.stmt is not stmt: + return None # can't share neged relation or relations with different outer join if (orel.neged(strict=True) or sniprel.neged(strict=True) or (orel.optional and orel.optional != sniprel.optional)): @@ -498,9 +502,10 @@ def _use_orig_term(self, snippet_varname, term): key = (self.current_expr, self.varmap, snippet_varname) if key in self.rewritten: - insertedvar = self.select.defined_vars.pop(self.rewritten[key]) + stmt = self.current_statement() + insertedvar = stmt.defined_vars.pop(self.rewritten[key]) for inserted_vref in insertedvar.references(): - inserted_vref.parent.replace(inserted_vref, term.copy(self.select)) + inserted_vref.parent.replace(inserted_vref, term.copy(stmt)) self.rewritten[key] = term.name def _get_varname_or_term(self, vname): diff -r 2d4ba5b984dc -r c3bf459268d7 test/data/rewrite/schema.py --- a/test/data/rewrite/schema.py Wed Jun 22 18:24:56 2011 +0200 +++ b/test/data/rewrite/schema.py Fri Jun 24 14:02:29 2011 +0200 @@ -27,8 +27,8 @@ 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')), } ref = String(fulltextindexed=True, indexed=True, maxsize=16) - documented_by = SubjectRelation('Card') - concerne = SubjectRelation(('Societe', 'Note')) + documented_by = SubjectRelation('Card', cardinality='1*') + concerne = SubjectRelation(('Societe', 'Note'), cardinality='1*') class Societe(EntityType): diff -r 2d4ba5b984dc -r c3bf459268d7 test/unittest_rqlrewrite.py --- a/test/unittest_rqlrewrite.py Wed Jun 22 18:24:56 2011 +0200 +++ b/test/unittest_rqlrewrite.py Fri Jun 24 14:02:29 2011 +0200 @@ -33,7 +33,8 @@ config.bootstrap_cubes() schema = config.load_schema() from yams.buildobjs import RelationDefinition - schema.add_relation_def(RelationDefinition(subject='Card', name='in_state', object='State', cardinality='1*')) + schema.add_relation_def(RelationDefinition(subject='Card', name='in_state', + object='State', cardinality='1*')) rqlhelper = RQLHelper(schema, special_relations={'eid': 'uid', 'has_text': 'fti'}) @@ -78,12 +79,21 @@ return rewriter.rewritten def test_vrefs(node): - vrefmap = {} + vrefmaps = {} + selects = [] for vref in node.iget_nodes(nodes.VariableRef): - vrefmap.setdefault(vref.name, set()).add(vref) - for var in node.defined_vars.itervalues(): - assert var.stinfo['references'] - assert not (var.stinfo['references'] ^ vrefmap[var.name]), (node.as_string(), var.stinfo['references'], vrefmap[var.name]) + stmt = vref.stmt + try: + vrefmaps[stmt].setdefault(vref.name, set()).add(vref) + except KeyError: + vrefmaps[stmt] = {vref.name: set( (vref,) )} + selects.append(stmt) + assert node in selects + for stmt in selects: + for var in stmt.defined_vars.itervalues(): + assert var.stinfo['references'] + vrefmap = vrefmaps[stmt] + assert not (var.stinfo['references'] ^ vrefmap[var.name]), (node.as_string(), var, var.stinfo['references'], vrefmap[var.name]) class RQLRewriteTC(TestCase): @@ -140,7 +150,7 @@ "EXISTS(2 in_state A, B in_group D, E require_state A, " "E name 'read', E require_group D, A is State, D is CWGroup, E is CWPermission)") - def test_optional_var_base_1(self): + def test_optional_var_1(self): constraint = ('X in_state S, U in_group G, P require_state S,' 'P name "read", P require_group G') rqlst = parse('Any A,C WHERE A documented_by C?') @@ -151,7 +161,7 @@ "(Any C WHERE EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', " "G require_group F), D eid %(A)s, C is Card)") - def test_optional_var_base_2(self): + def test_optional_var_2(self): constraint = ('X in_state S, U in_group G, P require_state S,' 'P name "read", P require_group G') rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T') @@ -163,7 +173,7 @@ "G require_state B, G name 'read', G require_group F), " "D eid %(A)s, C is Card)") - def test_optional_var_base_3(self): + def test_optional_var_3(self): constraint1 = ('X in_state S, U in_group G, P require_state S,' 'P name "read", P require_group G') constraint2 = 'X in_state S, S name "public"' @@ -176,6 +186,21 @@ "D eid %(A)s, C is Card, " "EXISTS(C in_state E, E name 'public'))") + def test_optional_var_4(self): + constraint1 = 'A created_by U, X documented_by A' + constraint2 = 'A created_by U, X concerne A' + constraint3 = 'X created_by U' + rqlst = parse('Any X,LA,Y WHERE LA? documented_by X, LA concerne Y') + rewrite(rqlst, {('LA', 'X'): (constraint1, constraint2), + ('X', 'X'): (constraint3,), + ('Y', 'X'): (constraint3,)}, {}) + self.failUnlessEqual(rqlst.as_string(), + u'Any X,LA,Y WHERE LA? documented_by X, LA concerne Y, B eid %(C)s, ' + 'EXISTS(X created_by B), EXISTS(Y created_by B), ' + 'X is Card, Y is IN(Division, Note, Societe) ' + 'WITH LA BEING (Any LA WHERE EXISTS(A created_by B, LA documented_by A), ' + 'B eid %(D)s, LA is Affaire, EXISTS(E created_by B, LA concerne E))') + def test_optional_var_inlined(self): c1 = ('X require_permission P') c2 = ('X inlined_card O, O require_permission P')