67 continue |
67 continue |
68 if stinfo['selected'] and var.valuable_references() == 1+bool(stinfo['constnode']): |
68 if stinfo['selected'] and var.valuable_references() == 1+bool(stinfo['constnode']): |
69 # "Any X", "Any X, Y WHERE X attr Y" |
69 # "Any X", "Any X, Y WHERE X attr Y" |
70 stinfo['invariant'] = False |
70 stinfo['invariant'] = False |
71 continue |
71 continue |
72 joins = set() |
72 joins = set() |
73 invariant = False |
73 invariant = False |
74 for ref in var.references(): |
74 for ref in var.references(): |
75 rel = ref.relation() |
75 rel = ref.relation() |
76 if rel is None or rel.is_types_restriction(): |
76 if rel is None or rel.is_types_restriction(): |
77 continue |
77 continue |
78 lhs, rhs = rel.get_parts() |
78 lhs, rhs = rel.get_parts() |
79 onlhs = ref is lhs |
79 onlhs = ref is lhs |
80 if rel.r_type == 'eid': |
80 if rel.r_type == 'eid': |
81 if not (onlhs and len(stinfo['relations']) > 1): |
81 if not (onlhs and len(stinfo['relations']) > 1): |
82 break |
82 break |
83 if not stinfo['constnode']: |
83 if not stinfo['constnode']: |
84 joins.add(rel) |
84 joins.add(rel) |
85 continue |
85 continue |
86 elif rel.r_type == 'identity': |
86 elif rel.r_type == 'identity': |
108 break |
108 break |
109 joins.add(rel) |
109 joins.add(rel) |
110 continue |
110 continue |
111 if not stinfo['constnode']: |
111 if not stinfo['constnode']: |
112 if rschema.inlined and rel.neged(strict=True): |
112 if rschema.inlined and rel.neged(strict=True): |
113 # if relation is inlined, can't be invariant if that |
113 # if relation is inlined, can't be invariant if that |
114 # variable is used anywhere else. |
114 # variable is used anywhere else. |
115 # see 'Any P WHERE NOT N ecrit_par P, N eid 512': |
115 # see 'Any P WHERE NOT N ecrit_par P, N eid 512': |
116 # sql for 'NOT N ecrit_par P' is 'N.ecrit_par is NULL' so P |
116 # sql for 'NOT N ecrit_par P' is 'N.ecrit_par is NULL' so P |
117 # can use N.ecrit_par as principal |
117 # can use N.ecrit_par as principal |
118 if (stinfo['selected'] or len(stinfo['relations']) > 1): |
118 if (stinfo['selected'] or len(stinfo['relations']) > 1): |
119 break |
119 break |
120 elif rschema.symetric and stinfo['selected']: |
120 elif rschema.symetric and stinfo['selected']: |
182 # since introduced duplicates will be removed |
182 # since introduced duplicates will be removed |
183 if sqlscope.stmt.distinct and diffscope_rels: |
183 if sqlscope.stmt.distinct and diffscope_rels: |
184 return iter(_sort(diffscope_rels)).next() |
184 return iter(_sort(diffscope_rels)).next() |
185 # XXX could use a relation for a different scope if it can't generate |
185 # XXX could use a relation for a different scope if it can't generate |
186 # duplicates, so we would have to check cardinality |
186 # duplicates, so we would have to check cardinality |
187 raise CantSelectPrincipal() |
187 raise CantSelectPrincipal() |
188 |
188 |
189 def _select_main_var(relations): |
189 def _select_main_var(relations): |
190 """given a list of rqlst relations, select one which will be used as main |
190 """given a list of rqlst relations, select one which will be used as main |
191 relation for the rhs variable |
191 relation for the rhs variable |
192 """ |
192 """ |
263 if len([rel for rel in var.stinfo['relations'] |
263 if len([rel for rel in var.stinfo['relations'] |
264 if rel.sqlscope is var.sqlscope and rel.r_type == 'has_text']) == 1: |
264 if rel.sqlscope is var.sqlscope and rel.r_type == 'has_text']) == 1: |
265 return False |
265 return False |
266 try: |
266 try: |
267 data = var.stmt._deamb_data |
267 data = var.stmt._deamb_data |
268 except AttributeError: |
268 except AttributeError: |
269 data = var.stmt._deamb_data = IsAmbData(self.schema, self.nfdomain) |
269 data = var.stmt._deamb_data = IsAmbData(self.schema, self.nfdomain) |
270 data.compute(var.stmt) |
270 data.compute(var.stmt) |
271 return data.is_ambiguous(var) |
271 return data.is_ambiguous(var) |
272 |
272 |
273 |
273 |
274 class IsAmbData(object): |
274 class IsAmbData(object): |
275 def __init__(self, schema, nfdomain): |
275 def __init__(self, schema, nfdomain): |
276 self.schema = schema |
276 self.schema = schema |
277 # shortcuts |
277 # shortcuts |
278 self.rschema = schema.rschema |
278 self.rschema = schema.rschema |
286 # remember if a variable has been deambiguified by another to avoid |
286 # remember if a variable has been deambiguified by another to avoid |
287 # doing the opposite |
287 # doing the opposite |
288 self.deambification_map = {} |
288 self.deambification_map = {} |
289 # not invariant variables (access to final.inlined relation) |
289 # not invariant variables (access to final.inlined relation) |
290 self.not_invariants = set() |
290 self.not_invariants = set() |
291 |
291 |
292 def is_ambiguous(self, var): |
292 def is_ambiguous(self, var): |
293 return var in self.ambiguousvars |
293 return var in self.ambiguousvars |
294 |
294 |
295 def restrict(self, var, restricted_domain): |
295 def restrict(self, var, restricted_domain): |
296 self.varsols[var] &= restricted_domain |
296 self.varsols[var] &= restricted_domain |
297 if var in self.ambiguousvars and self.varsols[var] == var.stinfo['possibletypes']: |
297 if var in self.ambiguousvars and self.varsols[var] == var.stinfo['possibletypes']: |
298 self.ambiguousvars.remove(var) |
298 self.ambiguousvars.remove(var) |
299 |
299 |
300 def compute(self, rqlst): |
300 def compute(self, rqlst): |
301 # set domains for each variable |
301 # set domains for each variable |
302 for varname, var in rqlst.defined_vars.iteritems(): |
302 for varname, var in rqlst.defined_vars.iteritems(): |
303 if var.stinfo['uidrels'] or \ |
303 if var.stinfo['uidrels'] or \ |
304 self.eschema(rqlst.solutions[0][varname]).is_final(): |
304 self.eschema(rqlst.solutions[0][varname]).is_final(): |
332 modified = True |
332 modified = True |
333 break |
333 break |
334 except KeyError: |
334 except KeyError: |
335 # no relation to deambiguify |
335 # no relation to deambiguify |
336 continue |
336 continue |
337 |
337 |
338 def _debug_print(self): |
338 def _debug_print(self): |
339 print 'varsols', dict((x, sorted(str(v) for v in values)) |
339 print 'varsols', dict((x, sorted(str(v) for v in values)) |
340 for x, values in self.varsols.iteritems()) |
340 for x, values in self.varsols.iteritems()) |
341 print 'ambiguous vars', sorted(self.ambiguousvars) |
341 print 'ambiguous vars', sorted(self.ambiguousvars) |
342 |
342 |
348 self.restrict(var, frozenset(etypes_func())) |
348 self.restrict(var, frozenset(etypes_func())) |
349 try: |
349 try: |
350 self.maydeambrels[var].add(rel) |
350 self.maydeambrels[var].add(rel) |
351 except KeyError: |
351 except KeyError: |
352 self.maydeambrels[var] = set((rel,)) |
352 self.maydeambrels[var] = set((rel,)) |
353 |
353 |
354 def deambiguifying_relation(self, var, rel): |
354 def deambiguifying_relation(self, var, rel): |
355 lhs, rhs = rel.get_variable_parts() |
355 lhs, rhs = rel.get_variable_parts() |
356 onlhs = var is getattr(lhs, 'variable', None) |
356 onlhs = var is getattr(lhs, 'variable', None) |
357 other = onlhs and rhs or lhs |
357 other = onlhs and rhs or lhs |
358 otheretypes = None |
358 otheretypes = None |