--- a/test/unittest_rqlrewrite.py Thu Jul 04 09:26:59 2013 +0200
+++ b/test/unittest_rqlrewrite.py Tue Jul 30 20:31:57 2013 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -23,7 +23,7 @@
from cubicweb import Unauthorized, rqlrewrite
from cubicweb.schema import RRQLExpression, ERQLExpression
-from cubicweb.devtools import repotest, TestServerConfiguration
+from cubicweb.devtools import repotest, TestServerConfiguration, BaseApptestConfiguration
def setUpModule(*args):
@@ -46,7 +46,8 @@
def eid_func_map(eid):
return {1: 'CWUser',
- 2: 'Card'}[eid]
+ 2: 'Card',
+ 3: 'Affaire'}[eid]
def rewrite(rqlst, snippets_map, kwargs, existingvars=None):
class FakeVReg:
@@ -72,9 +73,7 @@
for snippet in exprs]
snippets.append((dict([v]), rqlexprs))
rqlhelper.compute_solutions(rqlst.children[0], {'eid': eid_func_map}, kwargs=kwargs)
- solutions = rqlst.children[0].solutions
- rewriter.rewrite(rqlst.children[0], snippets, solutions, kwargs,
- existingvars)
+ rewriter.rewrite(rqlst.children[0], snippets, kwargs, existingvars)
test_vrefs(rqlst.children[0])
return rewriter.rewritten
@@ -202,6 +201,17 @@
'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), '
'B eid %(D)s, LA is Affaire)')
+
+ def test_ambiguous_optional_same_exprs(self):
+ """See #3013535"""
+ # see test of the same name in RewriteFullTC: original problem is
+ # unreproducible here because it actually lies in
+ # RQLRewriter.insert_local_checks
+ rqlst = parse('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date CD')
+ rewrite(rqlst, {('X', 'X'): ('X created_by U',),}, {'a': 3})
+ self.assertEqual(rqlst.as_string(),
+ u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))')
+
def test_optional_var_inlined(self):
c1 = ('X require_permission P')
c2 = ('X inlined_card O, O require_permission P')
@@ -292,6 +302,7 @@
self.assertEqual(rqlst.as_string(),
"Any C WHERE C in_state STATE, C is Card, "
"EXISTS(STATE name 'hop'), STATE is State")
+
def test_relation_optimization_3_rhs(self):
snippet = ('TW? subworkflow_exit X, TW name "hop"')
rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT')
@@ -308,6 +319,7 @@
self.assertEqual(rqlst.as_string(),
"Any C WHERE C in_state STATE?, C is Card, "
"EXISTS(C in_state A, A name 'hop', A is State), STATE is State")
+
def test_relation_non_optimization_1_rhs(self):
snippet = ('TW subworkflow_exit X, TW name "hop"')
rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
@@ -317,6 +329,21 @@
"EXISTS(A subworkflow_exit EXIT, A name 'hop', A is WorkflowTransition), "
"C is WorkflowTransition")
+ def test_relation_non_optimization_2(self):
+ """See #3024730"""
+ # 'X inlined_note N' must not be shared with 'C inlined_note N'
+ # previously inserted, else this may introduce duplicated results, as N
+ # will then be shared by multiple EXISTS and so at SQL generation time,
+ # the table will be in the FROM clause of the outermost query
+ rqlst = parse('Any A,C WHERE A inlined_card C')
+ rewrite(rqlst, {('A', 'X'): ('X inlined_card C, C inlined_note N, N owned_by U',),
+ ('C', 'X'): ('X inlined_note N, N owned_by U',)}, {})
+ self.assertEqual(rqlst.as_string(),
+ 'Any A,C WHERE A inlined_card C, D eid %(E)s, '
+ 'EXISTS(C inlined_note B, B owned_by D, B is Note), '
+ 'EXISTS(C inlined_note F, F owned_by D, F is Note), '
+ 'A is Affaire, C is Card')
+
def test_unsupported_constraint_1(self):
# CWUser doesn't have require_permission
trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
@@ -459,5 +486,55 @@
rqlst = parse('Any A, R WHERE A ref R, S is Affaire')
rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {})
+
+from cubicweb.devtools.testlib import CubicWebTC
+from logilab.common.decorators import classproperty
+
+class RewriteFullTC(CubicWebTC):
+ @classproperty
+ def config(cls):
+ return BaseApptestConfiguration(apphome=cls.datapath('rewrite'))
+
+ def process(self, rql, args=None):
+ if args is None:
+ args = {}
+ querier = self.repo.querier
+ union = querier.parse(rql)
+ querier.solutions(self.session, union, args)
+ querier._annotate(union)
+ plan = querier.plan_factory(union, args, self.session)
+ plan.preprocess(union)
+ return union
+
+ def test_ambiguous_optional_same_exprs(self):
+ """See #3013535"""
+ edef1 = self.schema['Societe']
+ edef2 = self.schema['Division']
+ edef3 = self.schema['Note']
+ with self.temporary_permissions((edef1, {'read': (ERQLExpression('X owned_by U'),)}),
+ (edef2, {'read': (ERQLExpression('X owned_by U'),)}),
+ (edef3, {'read': (ERQLExpression('X owned_by U'),)})):
+ union = self.process('Any A,AR,X,CD WHERE A concerne X?, A ref AR, X creation_date CD')
+ self.assertEqual('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A is Affaire '
+ 'WITH X,CD BEING (Any X,CD WHERE X creation_date CD, '
+ 'EXISTS(X owned_by %(A)s), X is IN(Division, Note, Societe))',
+ union.as_string())
+
+
+ def test_xxxx(self):
+ edef1 = self.schema['Societe']
+ edef2 = self.schema['Division']
+ read_expr = ERQLExpression('X responsable E, U has_read_permission E')
+ with self.temporary_permissions((edef1, {'read': (read_expr,)}),
+ (edef2, {'read': (read_expr,)})):
+ union = self.process('Any X,AA,AC,AD ORDERBY AD DESC '
+ 'WHERE X responsable E, X nom AA, '
+ 'X responsable AC?, AC modification_date AD')
+ self.assertEqual('Any X,AA,AC,AD ORDERBY AD DESC '
+ 'WHERE X responsable E, X nom AA, '
+ 'X responsable AC?, AC modification_date AD, '
+ 'AC is CWUser, E is CWUser, X is IN(Division, Societe)',
+ union.as_string())
+
if __name__ == '__main__':
unittest_main()