--- a/rqlrewrite.py Wed Sep 23 08:16:06 2009 +0200
+++ b/rqlrewrite.py Wed Sep 23 15:29:31 2009 +0200
@@ -14,8 +14,74 @@
from logilab.common.compat import any
-from cubicweb import Unauthorized, server, typed_eid
-from cubicweb.server.ssplanner import add_types_restriction
+from cubicweb import Unauthorized, typed_eid
+
+
+def add_types_restriction(schema, rqlst, newroot=None, solutions=None):
+ if newroot is None:
+ assert solutions is None
+ if hasattr(rqlst, '_types_restr_added'):
+ return
+ solutions = rqlst.solutions
+ newroot = rqlst
+ rqlst._types_restr_added = True
+ else:
+ assert solutions is not None
+ rqlst = rqlst.stmt
+ eschema = schema.eschema
+ allpossibletypes = {}
+ for solution in solutions:
+ for varname, etype in solution.iteritems():
+ if not varname in newroot.defined_vars or eschema(etype).is_final():
+ continue
+ allpossibletypes.setdefault(varname, set()).add(etype)
+ for varname in sorted(allpossibletypes):
+ try:
+ var = newroot.defined_vars[varname]
+ except KeyError:
+ continue
+ stinfo = var.stinfo
+ if stinfo.get('uidrels'):
+ continue # eid specified, no need for additional type specification
+ try:
+ typerels = rqlst.defined_vars[varname].stinfo.get('typerels')
+ except KeyError:
+ assert varname in rqlst.aliases
+ continue
+ if newroot is rqlst and typerels:
+ mytyperel = iter(typerels).next()
+ else:
+ for vref in newroot.defined_vars[varname].references():
+ rel = vref.relation()
+ if rel and rel.is_types_restriction():
+ mytyperel = rel
+ break
+ else:
+ mytyperel = None
+ possibletypes = allpossibletypes[varname]
+ if mytyperel is not None:
+ # variable as already some types restriction. new possible types
+ # can only be a subset of existing ones, so only remove no more
+ # possible types
+ for cst in mytyperel.get_nodes(n.Constant):
+ if not cst.value in possibletypes:
+ cst.parent.remove(cst)
+ try:
+ stinfo['possibletypes'].remove(cst.value)
+ except KeyError:
+ # restriction on a type not used by this query, may
+ # occurs with X is IN(...)
+ pass
+ else:
+ # we have to add types restriction
+ if stinfo.get('scope') is not None:
+ rel = var.scope.add_type_restriction(var, possibletypes)
+ else:
+ # tree is not annotated yet, no scope set so add the restriction
+ # to the root
+ rel = newroot.add_type_restriction(var, possibletypes)
+ stinfo['typerels'] = frozenset((rel,))
+ stinfo['possibletypes'] = possibletypes
def remove_solutions(origsolutions, solutions, defined):
@@ -73,8 +139,6 @@
snippets: (varmap, list of rql expression)
with varmap a *tuple* (select var, snippet var)
"""
- if server.DEBUG:
- print '---- rewrite', select, snippets, solutions
self.select = self.insert_scope = select
self.solutions = solutions
self.kwargs = kwargs
@@ -102,8 +166,6 @@
newsolutions = self.remove_ambiguities(snippets, newsolutions)
select.solutions = newsolutions
add_types_restriction(self.schema, select)
- if server.DEBUG:
- print '---- rewriten', select
def insert_snippets(self, snippets, varexistsmap=None):
self.rewritten = {}
--- a/server/ssplanner.py Wed Sep 23 08:16:06 2009 +0200
+++ b/server/ssplanner.py Wed Sep 23 15:29:31 2009 +0200
@@ -14,72 +14,8 @@
from cubicweb import QueryError, typed_eid
from cubicweb.schema import VIRTUAL_RTYPES
+from cubicweb.rqlrewrite import add_types_restriction
-def add_types_restriction(schema, rqlst, newroot=None, solutions=None):
- if newroot is None:
- assert solutions is None
- if hasattr(rqlst, '_types_restr_added'):
- return
- solutions = rqlst.solutions
- newroot = rqlst
- rqlst._types_restr_added = True
- else:
- assert solutions is not None
- rqlst = rqlst.stmt
- eschema = schema.eschema
- allpossibletypes = {}
- for solution in solutions:
- for varname, etype in solution.iteritems():
- if not varname in newroot.defined_vars or eschema(etype).is_final():
- continue
- allpossibletypes.setdefault(varname, set()).add(etype)
- for varname in sorted(allpossibletypes):
- try:
- var = newroot.defined_vars[varname]
- except KeyError:
- continue
- stinfo = var.stinfo
- if stinfo.get('uidrels'):
- continue # eid specified, no need for additional type specification
- try:
- typerels = rqlst.defined_vars[varname].stinfo.get('typerels')
- except KeyError:
- assert varname in rqlst.aliases
- continue
- if newroot is rqlst and typerels:
- mytyperel = iter(typerels).next()
- else:
- for vref in newroot.defined_vars[varname].references():
- rel = vref.relation()
- if rel and rel.is_types_restriction():
- mytyperel = rel
- break
- else:
- mytyperel = None
- possibletypes = allpossibletypes[varname]
- if mytyperel is not None:
- # variable as already some types restriction. new possible types
- # can only be a subset of existing ones, so only remove no more
- # possible types
- for cst in mytyperel.get_nodes(Constant):
- if not cst.value in possibletypes:
- cst.parent.remove(cst)
- try:
- stinfo['possibletypes'].remove(cst.value)
- except KeyError:
- # restriction on a type not used by this query, may
- # occurs with X is IN(...)
- pass
- else:
- # we have to add types restriction
- if stinfo.get('scope') is not None:
- rel = var.scope.add_type_restriction(var, possibletypes)
- else:
- # tree is not annotated yet, no scope set so add the restriction
- # to the root
- rel = newroot.add_type_restriction(var, possibletypes)
- stinfo['typerels'] = frozenset((rel,))
- stinfo['possibletypes'] = possibletypes
class SSPlanner(object):
"""SingleSourcePlanner: build execution plan for rql queries