--- a/server/msplanner.py Wed Apr 06 16:00:56 2011 +0200
+++ b/server/msplanner.py Wed Apr 06 22:52:39 2011 +0200
@@ -1223,11 +1223,22 @@
def build_non_final_part(self, select, solindices, sources, insertedvars,
table):
"""non final step, will have to store results in a temporary table"""
+ inputmapkey = tuple(sorted(solindices))
solutions = [self._solutions[i] for i in solindices]
- rqlst = self.plan.finalize(select, solutions, insertedvars)
- step = FetchStep(self.plan, rqlst, sources, table, False)
+ # XXX be smarter vs rql comparison
+ idx_key = (select.as_string(), inputmapkey,
+ tuple(sorted(sources)), tuple(sorted(insertedvars)))
+ try:
+ # if a similar step has already been process, simply backport its
+ # input map
+ step = self.plan.ms_steps_idx[idx_key]
+ except KeyError:
+ # processing needed
+ rqlst = self.plan.finalize(select, solutions, insertedvars)
+ step = FetchStep(self.plan, rqlst, sources, table, False)
+ self.plan.ms_steps_idx[idx_key] = step
+ self.plan.add_step(step)
# update input map for following steps, according to processed solutions
- inputmapkey = tuple(sorted(solindices))
inputmap = self._inputmaps.setdefault(inputmapkey, {})
for varname, mapping in step.outputmap.iteritems():
if varname in inputmap and not '.' in varname and \
@@ -1235,7 +1246,6 @@
self._schema.eschema(solutions[0][varname]).final):
self._conflicts.append((varname, inputmap[varname]))
inputmap.update(step.outputmap)
- self.plan.add_step(step)
class MSPlanner(SSPlanner):
@@ -1259,6 +1269,7 @@
print 'PLANNING', rqlst
ppis = [PartPlanInformation(plan, select, self.rqlhelper)
for select in rqlst.children]
+ plan.ms_steps_idx = {}
steps = self._union_plan(plan, ppis)
if server.DEBUG & server.DBG_MS:
from pprint import pprint
--- a/server/test/unittest_msplanner.py Wed Apr 06 16:00:56 2011 +0200
+++ b/server/test/unittest_msplanner.py Wed Apr 06 22:52:39 2011 +0200
@@ -2383,6 +2383,56 @@
None, None, [self.system], {}, [])],
{'x': 999999, 'u': 999998})
+ def test_nonregr_similar_subquery(self):
+ repo._type_source_cache[999999] = ('Personne', 'system', 999999)
+ self._test('Any T,TD,U,T,UL WITH T,TD,U,UL BEING ('
+ '(Any T,TD,U,UL WHERE X eid %(x)s, T comments X, T content TD, T created_by U?, U login UL)'
+ ' UNION '
+ '(Any T,TD,U,UL WHERE X eid %(x)s, X connait P, T comments P, T content TD, T created_by U?, U login UL))',
+ # XXX optimization: use a OneFetchStep with a UNION of both queries
+ [('FetchStep', [('Any U,UL WHERE U login UL, U is CWUser',
+ [{'U': 'CWUser', 'UL': 'String'}])],
+ [self.ldap, self.system], None,
+ {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+ []),
+ ('UnionFetchStep',
+ [('FetchStep',
+ [('Any T,TD,U,UL WHERE T comments 999999, T content TD, T created_by U?, U login UL, T is Comment, U is CWUser',
+ [{'T': 'Comment', 'TD': 'String', 'U': 'CWUser', 'UL': 'String'}])],
+ [self.system],
+ {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+ {'T': 'table1.C0',
+ 'T.content': 'table1.C1',
+ 'TD': 'table1.C1',
+ 'U': 'table1.C2',
+ 'U.login': 'table1.C3',
+ 'UL': 'table1.C3'},
+ []),
+ ('FetchStep',
+ [('Any T,TD,U,UL WHERE 999999 connait P, T comments P, T content TD, T created_by U?, U login UL, P is Personne, T is Comment, U is CWUser',
+ [{'P': 'Personne',
+ 'T': 'Comment',
+ 'TD': 'String',
+ 'U': 'CWUser',
+ 'UL': 'String'}])],
+ [self.system],
+ {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+ {'T': 'table1.C0',
+ 'T.content': 'table1.C1',
+ 'TD': 'table1.C1',
+ 'U': 'table1.C2',
+ 'U.login': 'table1.C3',
+ 'UL': 'table1.C3'},
+ [])]),
+ ('OneFetchStep',
+ [('Any T,TD,U,T,UL',
+ [{'T': 'Comment', 'TD': 'String', 'U': 'CWUser', 'UL': 'String'}])],
+ None, None,
+ [self.system],
+ {'T': 'table1.C0', 'TD': 'table1.C1', 'U': 'table1.C2', 'UL': 'table1.C3'},
+ [])],
+ {'x': 999999})
+
class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
"""test planner related feature on a 3-sources repository: