178 # final relation which is supported by multiple sources |
178 # final relation which is supported by multiple sources |
179 self._linkedvars = {} |
179 self._linkedvars = {} |
180 # processing |
180 # processing |
181 self._compute_sourcesvars() |
181 self._compute_sourcesvars() |
182 self._remove_invalid_sources() |
182 self._remove_invalid_sources() |
183 #if server.DEBUG: |
|
184 # print 'planner sources vars', self._sourcesvars |
|
185 self._compute_needsplit() |
183 self._compute_needsplit() |
186 self._inputmaps = {} |
184 self._inputmaps = {} |
187 if rqlhelper is not None: # else test |
185 if rqlhelper is not None: # else test |
188 self._insert_identity_variable = rqlhelper._annotator.rewrite_shared_optional |
186 self._insert_identity_variable = rqlhelper._annotator.rewrite_shared_optional |
189 |
187 |
210 """ |
208 """ |
211 return frozenset((source, solidx) for source in self._session.repo.sources |
209 return frozenset((source, solidx) for source in self._session.repo.sources |
212 for solidx in self._solindices |
210 for solidx in self._solindices |
213 if not (source.support_relation(rtype) |
211 if not (source.support_relation(rtype) |
214 or rtype in source.dont_cross_relations)) |
212 or rtype in source.dont_cross_relations)) |
|
213 |
215 |
214 |
216 def _compute_sourcesvars(self): |
215 def _compute_sourcesvars(self): |
217 """compute for each variable/solution in the rqlst which sources support |
216 """compute for each variable/solution in the rqlst which sources support |
218 them |
217 them |
219 """ |
218 """ |
275 # process non final relations only |
274 # process non final relations only |
276 # note: don't try to get schema for 'is' relation (not available |
275 # note: don't try to get schema for 'is' relation (not available |
277 # during bootstrap) |
276 # during bootstrap) |
278 if not rel.is_types_restriction() and not rschema(rel.r_type).is_final(): |
277 if not rel.is_types_restriction() and not rschema(rel.r_type).is_final(): |
279 # nothing to do if relation is not supported by multiple sources |
278 # nothing to do if relation is not supported by multiple sources |
280 relsources = [source for source in repo.sources |
279 relsources = repo.rel_type_sources(rel.r_type) |
281 if source.support_relation(rel.r_type) |
|
282 or rel.r_type in source.dont_cross_relations] |
|
283 if len(relsources) < 2: |
280 if len(relsources) < 2: |
284 if relsources:# and not relsources[0] in self._sourcesvars: |
281 if relsources: |
285 # this means the relation is using a variable inlined as |
282 # this means the relation is using a variable inlined as |
286 # a constant and another unsupported variable, in which |
283 # a constant and another unsupported variable, in which |
287 # case we put the relation in sourcesvars |
284 # case we put the relation in sourcesvars |
288 self._sourcesvars.setdefault(relsources[0], {})[rel] = set(self._solindices) |
285 self._sourcesvars.setdefault(relsources[0], {})[rel] = set(self._solindices) |
289 continue |
286 continue |
342 elif source in self._sourcesvars: |
339 elif source in self._sourcesvars: |
343 source_scopes = frozenset(v.scope for v in self._sourcesvars[source]) |
340 source_scopes = frozenset(v.scope for v in self._sourcesvars[source]) |
344 for const in vconsts: |
341 for const in vconsts: |
345 if const.scope in source_scopes: |
342 if const.scope in source_scopes: |
346 self._set_source_for_var(source, const) |
343 self._set_source_for_var(source, const) |
347 |
344 |
348 def _extern_term(self, term, vsources, inserted): |
345 def _extern_term(self, term, vsources, inserted): |
349 var = term.variable |
346 var = term.variable |
350 if var.stinfo['constnode']: |
347 if var.stinfo['constnode']: |
351 termv = var.stinfo['constnode'] |
348 termv = var.stinfo['constnode'] |
352 vsources[termv] = self._term_sources(termv) |
349 vsources[termv] = self._term_sources(termv) |
359 if not termv in vsources: |
356 if not termv in vsources: |
360 vsources[termv] = self._term_sources(termv) |
357 vsources[termv] = self._term_sources(termv) |
361 return termv |
358 return termv |
362 |
359 |
363 def _remove_sources_until_stable(self, var, vsources): |
360 def _remove_sources_until_stable(self, var, vsources): |
|
361 sourcesvars = self._sourcesvars |
364 for ovar, rel in self._linkedvars.get(var, ()): |
362 for ovar, rel in self._linkedvars.get(var, ()): |
365 if not var.scope is ovar.scope and rel.scope.neged(strict=True): |
363 if not var.scope is ovar.scope and rel.scope.neged(strict=True): |
366 # can't get information from relation inside a NOT exists |
364 # can't get information from relation inside a NOT exists |
367 # where variables don't belong to the same scope |
365 # where variables don't belong to the same scope |
368 continue |
366 continue |
369 if rel.neged(strict=True): |
367 relsources = self._session.repo.rel_type_sources(rel.r_type) |
370 # neged relation doesn't allow to infer variable sources |
368 if rel.neged(strict=True) and ( |
|
369 len(relsources) < 2 |
|
370 or not isinstance(ovar, Variable) |
|
371 or ovar.valuable_references() != 1 |
|
372 or any(sourcesvars[source][var] != sourcesvars[source][ovar] |
|
373 for source in relsources |
|
374 if var in sourcesvars.get(source, ()) |
|
375 and ovar in sourcesvars.get(source, ()))): |
|
376 # neged relation doesn't allow to infer variable sources unless we're |
|
377 # on a multisource relation for a variable only used by this relation |
|
378 # (eg "Any X WHERE NOT X multisource_rel Y" and over is Y), iif |
371 continue |
379 continue |
372 norelsup = self._norel_support_set(rel.r_type) |
380 norelsup = self._norel_support_set(rel.r_type) |
373 # compute invalid sources for variables and remove them |
381 # compute invalid sources for variables and remove them |
374 self._remove_var_sources(var, norelsup, ovar, vsources) |
382 self._remove_var_sources(var, norelsup, ovar, vsources) |
375 self._remove_var_sources(ovar, norelsup, var, vsources) |
383 self._remove_var_sources(ovar, norelsup, var, vsources) |
896 # finally: join parts, deal with aggregat/group/sorts if necessary |
904 # finally: join parts, deal with aggregat/group/sorts if necessary |
897 if atemptable is not None: |
905 if atemptable is not None: |
898 step = AggrStep(plan, selection, select, atemptable, temptable) |
906 step = AggrStep(plan, selection, select, atemptable, temptable) |
899 step.children = steps |
907 step.children = steps |
900 elif len(steps) > 1: |
908 elif len(steps) > 1: |
901 if temptable: |
909 if select.need_intersect: |
902 step = UnionFetchStep(plan) |
910 if temptable: |
|
911 step = IntersectFetchStep(plan) |
|
912 else: |
|
913 step = IntersectStep(plan) |
903 else: |
914 else: |
904 step = UnionStep(plan) |
915 if temptable: |
|
916 step = UnionFetchStep(plan) |
|
917 else: |
|
918 step = UnionStep(plan) |
905 step.children = steps |
919 step.children = steps |
906 else: |
920 else: |
907 step = steps[0] |
921 step = steps[0] |
908 if select.limit is not None or select.offset: |
922 if select.limit is not None or select.offset: |
909 step.set_limit_offset(select.limit, select.offset) |
923 step.set_limit_offset(select.limit, select.offset) |