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.get(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) |
474 del variante[key] |
479 del variante[key] |
475 return variantes |
480 return variantes |
476 |
481 |
477 def _cleanup_inserted(self, node): |
482 def _cleanup_inserted(self, node): |
478 # cleanup inserted variable references |
483 # cleanup inserted variable references |
|
484 removed = set() |
479 for vref in node.iget_nodes(n.VariableRef): |
485 for vref in node.iget_nodes(n.VariableRef): |
480 vref.unregister_reference() |
486 vref.unregister_reference() |
481 if not vref.variable.stinfo['references']: |
487 if not vref.variable.stinfo['references']: |
482 # no more references, undefine the variable |
488 # no more references, undefine the variable |
483 del self.select.defined_vars[vref.name] |
489 del self.select.defined_vars[vref.name] |
|
490 removed.add(vref.name) |
|
491 for key, newvar in self.rewritten.items(): # I mean items we alter it |
|
492 if newvar in removed: |
|
493 del self.rewritten[key] |
|
494 |
484 |
495 |
485 def _may_be_shared_with(self, sniprel, target): |
496 def _may_be_shared_with(self, sniprel, target): |
486 """if the snippet relation can be skipped to use a relation from the |
497 """if the snippet relation can be skipped to use a relation from the |
487 original query, return that relation node |
498 original query, return that relation node |
488 """ |
499 """ |