144 |
144 |
145 |
145 |
146 |
146 |
147 class CantSelectPrincipal(Exception): pass |
147 class CantSelectPrincipal(Exception): pass |
148 |
148 |
149 def _select_principal(sqlscope, relations): |
149 def _select_principal(sqlscope, relations, _sort=lambda x:x): |
150 """given a list of rqlst relations, select one which will be used to |
150 """given a list of rqlst relations, select one which will be used to |
151 represent an invariant variable (e.g. using on extremity of the relation |
151 represent an invariant variable (e.g. using on extremity of the relation |
152 instead of the variable's type table |
152 instead of the variable's type table |
153 """ |
153 """ |
|
154 # _sort argument is there for test |
154 diffscope_rels = {} |
155 diffscope_rels = {} |
155 has_same_scope_rel = False |
156 has_same_scope_rel = False |
156 ored_rels = set() |
157 ored_rels = set() |
157 diffscope_rels = set() |
158 diffscope_rels = set() |
158 for rel in relations: |
159 for rel in _sort(relations): |
159 # note: only eid and has_text among all final relations may be there |
160 # note: only eid and has_text among all final relations may be there |
160 if rel.r_type in ('eid', 'identity'): |
161 if rel.r_type in ('eid', 'identity'): |
161 has_same_scope_rel = rel.sqlscope is sqlscope |
162 has_same_scope_rel = rel.sqlscope is sqlscope |
162 continue |
163 continue |
163 if rel.ored(traverse_scope=True): |
164 if rel.ored(traverse_scope=True): |
173 if rel1 is rel2: |
174 if rel1 is rel2: |
174 continue |
175 continue |
175 if isinstance(common_parent(rel1, rel2), Or): |
176 if isinstance(common_parent(rel1, rel2), Or): |
176 ored_rels.discard(rel1) |
177 ored_rels.discard(rel1) |
177 ored_rels.discard(rel2) |
178 ored_rels.discard(rel2) |
178 for rel in ored_rels: |
179 for rel in _sort(ored_rels): |
179 if rel.sqlscope is sqlscope: |
180 if rel.sqlscope is sqlscope: |
180 return rel |
181 return rel |
181 diffscope_rels.add(rel) |
182 diffscope_rels.add(rel) |
182 # if DISTINCT query, can use variable from a different scope as principal |
183 # if DISTINCT query, can use variable from a different scope as principal |
183 # since introduced duplicates will be removed |
184 # since introduced duplicates will be removed |
184 if sqlscope.stmt.distinct and diffscope_rels: |
185 if sqlscope.stmt.distinct and diffscope_rels: |
185 return iter(diffscope_rels).next() |
186 return iter(_sort(diffscope_rels)).next() |
186 # XXX could use a relation for a different scope if it can't generate |
187 # XXX could use a relation for a different scope if it can't generate |
187 # duplicates, so we would have to check cardinality |
188 # duplicates, so we would have to check cardinality |
188 raise CantSelectPrincipal() |
189 raise CantSelectPrincipal() |
189 |
|
190 |
190 |
191 def _select_main_var(relations): |
191 def _select_main_var(relations): |
192 """given a list of rqlst relations, select one which will be used as main |
192 """given a list of rqlst relations, select one which will be used as main |
193 relation for the rhs variable |
193 relation for the rhs variable |
194 """ |
194 """ |