11 __docformat__ = "restructuredtext en" |
11 __docformat__ = "restructuredtext en" |
12 |
12 |
13 from rql import nodes as n, stmts, TypeResolverException |
13 from rql import nodes as n, stmts, TypeResolverException |
14 |
14 |
15 from logilab.common.compat import any |
15 from logilab.common.compat import any |
|
16 from logilab.common.graph import has_path |
16 |
17 |
17 from cubicweb import Unauthorized, typed_eid |
18 from cubicweb import Unauthorized, typed_eid |
18 |
19 |
19 |
20 |
20 def add_types_restriction(schema, rqlst, newroot=None, solutions=None): |
21 def add_types_restriction(schema, rqlst, newroot=None, solutions=None): |
132 except TypeResolverException: |
133 except TypeResolverException: |
133 raise Unsupported(str(self.select)) |
134 raise Unsupported(str(self.select)) |
134 if len(self.select.solutions) < len(self.solutions): |
135 if len(self.select.solutions) < len(self.solutions): |
135 raise Unsupported() |
136 raise Unsupported() |
136 |
137 |
137 def rewrite(self, select, snippets, solutions, kwargs): |
138 def rewrite(self, select, snippets, solutions, kwargs, existingvars=None): |
138 """ |
139 """ |
139 snippets: (varmap, list of rql expression) |
140 snippets: (varmap, list of rql expression) |
140 with varmap a *tuple* (select var, snippet var) |
141 with varmap a *tuple* (select var, snippet var) |
141 """ |
142 """ |
142 self.select = self.insert_scope = select |
143 self.select = self.insert_scope = select |
144 self.kwargs = kwargs |
145 self.kwargs = kwargs |
145 self.u_varname = None |
146 self.u_varname = None |
146 self.removing_ambiguity = False |
147 self.removing_ambiguity = False |
147 self.exists_snippet = {} |
148 self.exists_snippet = {} |
148 self.pending_keys = [] |
149 self.pending_keys = [] |
|
150 self.existingvars = existingvars |
149 # we have to annotate the rqlst before inserting snippets, even though |
151 # we have to annotate the rqlst before inserting snippets, even though |
150 # we'll have to redo it latter |
152 # we'll have to redo it latter |
151 self.annotate(select) |
153 self.annotate(select) |
152 self.insert_snippets(snippets) |
154 self.insert_snippets(snippets) |
153 if not self.exists_snippet and self.u_varname: |
155 if not self.exists_snippet and self.u_varname: |
211 # no rql expression found matching rql solutions. User has no access right |
213 # no rql expression found matching rql solutions. User has no access right |
212 raise Unauthorized() |
214 raise Unauthorized() |
213 |
215 |
214 def insert_snippet(self, varmap, snippetrqlst, parent=None): |
216 def insert_snippet(self, varmap, snippetrqlst, parent=None): |
215 new = snippetrqlst.where.accept(self) |
217 new = snippetrqlst.where.accept(self) |
|
218 existing = self.existingvars |
|
219 self.existingvars = None |
|
220 try: |
|
221 return self._insert_snippet(varmap, parent, new) |
|
222 finally: |
|
223 self.existingvars = existing |
|
224 |
|
225 def _insert_snippet(self, varmap, parent, new): |
216 if new is not None: |
226 if new is not None: |
217 if self.varinfo.get('stinfo', {}).get('optrelations'): |
227 if self.varinfo.get('stinfo', {}).get('optrelations'): |
218 assert parent is None |
228 assert parent is None |
219 self.insert_scope = self.snippet_subquery(varmap, new) |
229 self.insert_scope = self.snippet_subquery(varmap, new) |
220 self.insert_pending() |
230 self.insert_pending() |
476 return self._visit_unary(node, n.Not) |
486 return self._visit_unary(node, n.Not) |
477 |
487 |
478 def visit_exists(self, node): |
488 def visit_exists(self, node): |
479 return self._visit_unary(node, n.Exists) |
489 return self._visit_unary(node, n.Exists) |
480 |
490 |
|
491 def keep_var(self, varname): |
|
492 if varname in 'SO': |
|
493 return varname in self.existingvars |
|
494 if varname == 'U': |
|
495 return True |
|
496 vargraph = self.current_expr.vargraph |
|
497 for existingvar in self.existingvars: |
|
498 #path = has_path(vargraph, varname, existingvar) |
|
499 if has_path(vargraph, varname, existingvar): |
|
500 return True |
|
501 # no path from this variable to an existing variable |
|
502 return False |
|
503 |
481 def visit_relation(self, node): |
504 def visit_relation(self, node): |
482 lhs, rhs = node.get_variable_parts() |
505 lhs, rhs = node.get_variable_parts() |
|
506 # remove relations where an unexistant variable and or a variable linked |
|
507 # to an unexistant variable is used. |
|
508 if self.existingvars: |
|
509 if not self.keep_var(lhs.name): |
|
510 return |
483 if node.r_type in ('has_add_permission', 'has_update_permission', |
511 if node.r_type in ('has_add_permission', 'has_update_permission', |
484 'has_delete_permission', 'has_read_permission'): |
512 'has_delete_permission', 'has_read_permission'): |
485 assert lhs.name == 'U' |
513 assert lhs.name == 'U' |
486 action = node.r_type.split('_')[1] |
514 action = node.r_type.split('_')[1] |
487 key = (self.current_expr, self.varmap, rhs.name) |
515 key = (self.current_expr, self.varmap, rhs.name) |
488 self.pending_keys.append( (key, action) ) |
516 self.pending_keys.append( (key, action) ) |
489 return |
517 return |
490 if isinstance(rhs, n.VariableRef): |
518 if isinstance(rhs, n.VariableRef): |
|
519 if self.existingvars and not self.keep_var(rhs.name): |
|
520 return |
491 if lhs.name in self.revvarmap and rhs.name != 'U': |
521 if lhs.name in self.revvarmap and rhs.name != 'U': |
492 orel = self._may_be_shared_with(node, 'object', lhs.name) |
522 orel = self._may_be_shared_with(node, 'object', lhs.name) |
493 if orel is not None: |
523 if orel is not None: |
494 self._use_orig_term(rhs.name, orel.children[1].children[0]) |
524 self._use_orig_term(rhs.name, orel.children[1].children[0]) |
495 return |
525 return |