147 # XXX if constant term are used to define sort, their value |
147 # XXX if constant term are used to define sort, their value |
148 # may necessite a decay |
148 # may necessite a decay |
149 select.append_selected(vref.copy(select)) |
149 select.append_selected(vref.copy(select)) |
150 if select.groupby and not vref in select.groupby: |
150 if select.groupby and not vref in select.groupby: |
151 select.add_group_var(vref.copy(select)) |
151 select.add_group_var(vref.copy(select)) |
152 |
152 |
|
153 # XXX move to rql |
|
154 def is_ancestor(n1, n2): |
|
155 p = n1.parent |
|
156 while p is not None: |
|
157 if p is n2: |
|
158 return True |
|
159 p = p.parent |
|
160 return False |
153 |
161 |
154 class PartPlanInformation(object): |
162 class PartPlanInformation(object): |
155 """regroups necessary information to execute some part of a "global" rql |
163 """regroups necessary information to execute some part of a "global" rql |
156 query ("global" means as received by the querier, which may result in |
164 query ("global" means as received by the querier, which may result in |
157 several internal queries, e.g. parts, due to security insertions) |
165 several internal queries, e.g. parts, due to security insertions) |
192 for k2, v2 in v.iteritems(): |
200 for k2, v2 in v.iteritems(): |
193 self.sourcesvars[k][k2] = v2.copy() |
201 self.sourcesvars[k][k2] = v2.copy() |
194 self._inputmaps = {} |
202 self._inputmaps = {} |
195 if rqlhelper is not None: # else test |
203 if rqlhelper is not None: # else test |
196 self._insert_identity_variable = rqlhelper._annotator.rewrite_shared_optional |
204 self._insert_identity_variable = rqlhelper._annotator.rewrite_shared_optional |
197 |
205 |
198 def copy_solutions(self, solindices): |
206 def copy_solutions(self, solindices): |
199 return [self._solutions[solidx].copy() for solidx in solindices] |
207 return [self._solutions[solidx].copy() for solidx in solindices] |
200 |
208 |
201 @property |
209 @property |
202 @cached |
210 @cached |
429 for ovar, rel in self._linkedvars.get(var, ()): |
437 for ovar, rel in self._linkedvars.get(var, ()): |
430 if not var.scope is ovar.scope and rel.scope.neged(strict=True): |
438 if not var.scope is ovar.scope and rel.scope.neged(strict=True): |
431 # can't get information from relation inside a NOT exists |
439 # can't get information from relation inside a NOT exists |
432 # where variables don't belong to the same scope |
440 # where variables don't belong to the same scope |
433 continue |
441 continue |
434 if not (var.scope is rel.scope and ovar.scope is rel.scope) and rel.ored(): |
442 need_ancestor_scope = False |
435 continue |
443 if not (var.scope is rel.scope and ovar.scope is rel.scope): |
|
444 if rel.ored(): |
|
445 continue |
|
446 if rel.ored(traverse_scope=True): |
|
447 # if relation has some OR as parent, constraints should only |
|
448 # propagate from parent scope to child scope, nothing else |
|
449 need_ancestor_scope = True |
436 relsources = self._session.repo.rel_type_sources(rel.r_type) |
450 relsources = self._session.repo.rel_type_sources(rel.r_type) |
437 if rel.neged(strict=True) and ( |
451 if rel.neged(strict=True) and ( |
438 len(relsources) < 2 |
452 len(relsources) < 2 |
439 or not isinstance(ovar, Variable) |
453 or not isinstance(ovar, Variable) |
440 or ovar.valuable_references() != 1 |
454 or ovar.valuable_references() != 1 |
446 # on a multisource relation for a variable only used by this relation |
460 # on a multisource relation for a variable only used by this relation |
447 # (eg "Any X WHERE NOT X multisource_rel Y" and over is Y), iif |
461 # (eg "Any X WHERE NOT X multisource_rel Y" and over is Y), iif |
448 continue |
462 continue |
449 norelsup = self._norel_support_set(rel) |
463 norelsup = self._norel_support_set(rel) |
450 # compute invalid sources for variables and remove them |
464 # compute invalid sources for variables and remove them |
451 self._remove_var_sources(var, norelsup, ovar, vsources) |
465 if not need_ancestor_scope or is_ancestor(var.scope, ovar.scope): |
452 self._remove_var_sources(ovar, norelsup, var, vsources) |
466 self._remove_var_sources(var, norelsup, ovar, vsources) |
|
467 if not need_ancestor_scope or is_ancestor(ovar.scope, var.scope): |
|
468 self._remove_var_sources(ovar, norelsup, var, vsources) |
453 |
469 |
454 def _remove_var_sources(self, var, norelsup, ovar, vsources): |
470 def _remove_var_sources(self, var, norelsup, ovar, vsources): |
455 """remove invalid sources for var according to ovar's sources and the |
471 """remove invalid sources for var according to ovar's sources and the |
456 relation between those two variables. |
472 relation between those two variables. |
457 """ |
473 """ |