226 vi['rhs_rels'] = dict( (r.r_type, r) for r in sti['rhsrelations']) |
226 vi['rhs_rels'] = dict( (r.r_type, r) for r in sti['rhsrelations']) |
227 vi['lhs_rels'] = dict( (r.r_type, r) for r in sti['relations'] |
227 vi['lhs_rels'] = dict( (r.r_type, r) for r in sti['relations'] |
228 if not r in sti['rhsrelations']) |
228 if not r in sti['rhsrelations']) |
229 else: |
229 else: |
230 vi['rhs_rels'] = vi['lhs_rels'] = {} |
230 vi['rhs_rels'] = vi['lhs_rels'] = {} |
231 parent = None |
231 previous = None |
232 inserted = False |
232 inserted = False |
233 for rqlexpr in rqlexprs: |
233 for rqlexpr in rqlexprs: |
234 self.current_expr = rqlexpr |
234 self.current_expr = rqlexpr |
235 if varexistsmap is None: |
235 if varexistsmap is None: |
236 try: |
236 try: |
237 new = self.insert_snippet(varmap, rqlexpr.snippet_rqlst, parent) |
237 new = self.insert_snippet(varmap, rqlexpr.snippet_rqlst, previous) |
238 except Unsupported: |
238 except Unsupported: |
239 continue |
239 continue |
240 inserted = True |
240 inserted = True |
241 if new is not None and self._insert_scope is None: |
241 if new is not None and self._insert_scope is None: |
242 self.exists_snippet[rqlexpr] = new |
242 self.exists_snippet[rqlexpr] = new |
243 parent = parent or new |
243 previous = previous or new |
244 else: |
244 else: |
245 # called to reintroduce snippet due to ambiguity creation, |
245 # called to reintroduce snippet due to ambiguity creation, |
246 # so skip snippets which are not introducing this ambiguity |
246 # so skip snippets which are not introducing this ambiguity |
247 exists = varexistsmap[varmap] |
247 exists = varexistsmap[varmap] |
248 if self.exists_snippet[rqlexpr] is exists: |
248 if self.exists_snippet[rqlexpr] is exists: |
249 self.insert_snippet(varmap, rqlexpr.snippet_rqlst, exists) |
249 self.insert_snippet(varmap, rqlexpr.snippet_rqlst, exists) |
250 if varexistsmap is None and not inserted: |
250 if varexistsmap is None and not inserted: |
251 # no rql expression found matching rql solutions. User has no access right |
251 # no rql expression found matching rql solutions. User has no access right |
252 raise Unauthorized() # XXX may also be because of bad constraints in schema definition |
252 raise Unauthorized() # XXX may also be because of bad constraints in schema definition |
253 |
253 |
254 def insert_snippet(self, varmap, snippetrqlst, parent=None): |
254 def insert_snippet(self, varmap, snippetrqlst, previous=None): |
255 new = snippetrqlst.where.accept(self) |
255 new = snippetrqlst.where.accept(self) |
256 existing = self.existingvars |
256 existing = self.existingvars |
257 self.existingvars = None |
257 self.existingvars = None |
258 try: |
258 try: |
259 return self._insert_snippet(varmap, parent, new) |
259 return self._insert_snippet(varmap, previous, new) |
260 finally: |
260 finally: |
261 self.existingvars = existing |
261 self.existingvars = existing |
262 |
262 |
263 def _insert_snippet(self, varmap, parent, new): |
263 def _insert_snippet(self, varmap, previous, new): |
|
264 """insert `new` snippet into the syntax tree, which have been rewritten |
|
265 using `varmap`. In cases where an action is protected by several rql |
|
266 expresssion, `previous` will be the first rql expression which has been |
|
267 inserted, and so should be ORed with the following expressions. |
|
268 """ |
264 if new is not None: |
269 if new is not None: |
265 if self._insert_scope is None: |
270 if self._insert_scope is None: |
266 insert_scope = None |
271 insert_scope = None |
267 for vi in self.varinfos: |
272 for vi in self.varinfos: |
268 scope = vi.get('stinfo', {}).get('scope', self.select) |
273 scope = vi.get('stinfo', {}).get('scope', self.select) |
272 insert_scope = common_parent(scope, insert_scope) |
277 insert_scope = common_parent(scope, insert_scope) |
273 else: |
278 else: |
274 insert_scope = self._insert_scope |
279 insert_scope = self._insert_scope |
275 if self._insert_scope is None and any(vi.get('stinfo', {}).get('optrelations') |
280 if self._insert_scope is None and any(vi.get('stinfo', {}).get('optrelations') |
276 for vi in self.varinfos): |
281 for vi in self.varinfos): |
277 assert parent is None |
282 assert previous is None |
278 self._insert_scope = self.snippet_subquery(varmap, new) |
283 self._insert_scope, new = self.snippet_subquery(varmap, new) |
279 self.insert_pending() |
284 self.insert_pending() |
280 #self._insert_scope = None |
285 #self._insert_scope = None |
281 return |
286 return new |
282 if not isinstance(new, (n.Exists, n.Not)): |
287 if not isinstance(new, (n.Exists, n.Not)): |
283 new = n.Exists(new) |
288 new = n.Exists(new) |
284 if parent is None: |
289 if previous is None: |
285 insert_scope.add_restriction(new) |
290 insert_scope.add_restriction(new) |
286 else: |
291 else: |
287 grandpa = parent.parent |
292 grandpa = previous.parent |
288 or_ = n.Or(parent, new) |
293 or_ = n.Or(previous, new) |
289 grandpa.replace(parent, or_) |
294 grandpa.replace(previous, or_) |
290 if not self.removing_ambiguity: |
295 if not self.removing_ambiguity: |
291 try: |
296 try: |
292 self.compute_solutions() |
297 self.compute_solutions() |
293 except Unsupported: |
298 except Unsupported: |
294 # some solutions have been lost, can't apply this rql expr |
299 # some solutions have been lost, can't apply this rql expr |
295 if parent is None: |
300 if previous is None: |
296 self.current_statement().remove_node(new, undefine=True) |
301 self.current_statement().remove_node(new, undefine=True) |
297 else: |
302 else: |
298 grandpa.replace(or_, parent) |
303 grandpa.replace(or_, previous) |
299 self._cleanup_inserted(new) |
304 self._cleanup_inserted(new) |
300 raise |
305 raise |
301 else: |
306 else: |
302 with tempattr(self, '_insert_scope', new): |
307 with tempattr(self, '_insert_scope', new): |
303 self.insert_pending() |
308 self.insert_pending() |
417 self.compute_solutions() |
422 self.compute_solutions() |
418 except Unsupported: |
423 except Unsupported: |
419 # some solutions have been lost, can't apply this rql expr |
424 # some solutions have been lost, can't apply this rql expr |
420 self.select.remove_subquery(self.select.with_[-1]) |
425 self.select.remove_subquery(self.select.with_[-1]) |
421 raise |
426 raise |
422 return subselect |
427 return subselect, snippetrqlst |
423 |
428 |
424 def remove_ambiguities(self, snippets, newsolutions): |
429 def remove_ambiguities(self, snippets, newsolutions): |
425 # the snippet has introduced some ambiguities, we have to resolve them |
430 # the snippet has introduced some ambiguities, we have to resolve them |
426 # "manually" |
431 # "manually" |
427 variantes = self.build_variantes(newsolutions) |
432 variantes = self.build_variantes(newsolutions) |