129 |
129 |
130 def remove_unused_solutions(rqlst, solutions, varmap, schema): |
130 def remove_unused_solutions(rqlst, solutions, varmap, schema): |
131 """cleanup solutions: remove solutions where invariant variables are taking |
131 """cleanup solutions: remove solutions where invariant variables are taking |
132 different types |
132 different types |
133 """ |
133 """ |
134 newsolutions = _new_solutions(rqlst, solutions) |
134 newsols = _new_solutions(rqlst, solutions) |
135 existssols = {} |
135 existssols = {} |
136 unstable = set() |
136 unstable = set() |
|
137 invariants = {} |
137 for vname, var in rqlst.defined_vars.iteritems(): |
138 for vname, var in rqlst.defined_vars.iteritems(): |
138 vtype = newsolutions[0][vname] |
139 vtype = newsols[0][vname] |
139 if var._q_invariant or vname in varmap: |
140 if var._q_invariant or vname in varmap: |
140 for i in xrange(len(newsolutions)-1, 0, -1): |
141 # remove invariant variable from solutions to remove duplicates |
141 if vtype != newsolutions[i][vname]: |
142 # later, then reinserting a type for the variable even later |
142 newsolutions.pop(i) |
143 for sol in newsols: |
143 elif not var.scope is rqlst: |
144 invariants.setdefault(id(sol), {})[vname] = sol.pop(vname) |
|
145 elif var.scope is not rqlst: |
144 # move appart variables which are in a EXISTS scope and are variating |
146 # move appart variables which are in a EXISTS scope and are variating |
145 try: |
147 try: |
146 thisexistssols, thisexistsvars = existssols[var.scope] |
148 thisexistssols, thisexistsvars = existssols[var.scope] |
147 except KeyError: |
149 except KeyError: |
148 thisexistssols = [newsolutions[0]] |
150 thisexistssols = [newsols[0]] |
149 thisexistsvars = set() |
151 thisexistsvars = set() |
150 existssols[var.scope] = thisexistssols, thisexistsvars |
152 existssols[var.scope] = thisexistssols, thisexistsvars |
151 for i in xrange(len(newsolutions)-1, 0, -1): |
153 for i in xrange(len(newsols)-1, 0, -1): |
152 if vtype != newsolutions[i][vname]: |
154 if vtype != newsols[i][vname]: |
153 thisexistssols.append(newsolutions.pop(i)) |
155 thisexistssols.append(newsols.pop(i)) |
154 thisexistsvars.add(vname) |
156 thisexistsvars.add(vname) |
155 else: |
157 else: |
156 # remember unstable variables |
158 # remember unstable variables |
157 for i in xrange(1, len(newsolutions)): |
159 for i in xrange(1, len(newsols)): |
158 if vtype != newsolutions[i][vname]: |
160 if vtype != newsols[i][vname]: |
159 unstable.add(vname) |
161 unstable.add(vname) |
160 if len(newsolutions) > 1: |
162 if invariants: |
161 if rewrite_unstable_outer_join(rqlst, newsolutions, unstable, schema): |
163 # filter out duplicates |
|
164 newsols_ = [] |
|
165 for sol in newsols: |
|
166 if not sol in newsols_: |
|
167 newsols_.append(sol) |
|
168 newsols = newsols_ |
|
169 # reinsert solutions for invariants |
|
170 for sol in newsols: |
|
171 for invvar, vartype in invariants[id(sol)].iteritems(): |
|
172 sol[invvar] = vartype |
|
173 for sol in existssols: |
|
174 for invvar, vartype in invariants[id(sol)].iteritems(): |
|
175 sol[invvar] = vartype |
|
176 if len(newsols) > 1: |
|
177 if rewrite_unstable_outer_join(rqlst, newsols, unstable, schema): |
162 # remove variables extracted to subqueries from solutions |
178 # remove variables extracted to subqueries from solutions |
163 newsolutions = _new_solutions(rqlst, newsolutions) |
179 newsols = _new_solutions(rqlst, newsols) |
164 return newsolutions, existssols, unstable |
180 return newsols, existssols, unstable |
165 |
181 |
166 def relation_info(relation): |
182 def relation_info(relation): |
167 lhs, rhs = relation.get_variable_parts() |
183 lhs, rhs = relation.get_variable_parts() |
168 try: |
184 try: |
169 lhs = lhs.variable |
185 lhs = lhs.variable |