--- a/devtools/testlib.py Wed Mar 24 17:58:05 2010 +0100
+++ b/devtools/testlib.py Wed Mar 24 18:04:59 2010 +0100
@@ -5,6 +5,8 @@
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
+from __future__ import with_statement
+
__docformat__ = "restructuredtext en"
import os
@@ -29,6 +31,7 @@
from cubicweb.dbapi import repo_connect, ConnectionProperties, ProgrammingError
from cubicweb.sobjects import notification
from cubicweb.web import Redirect, application
+from cubicweb.server.session import security_enabled
from cubicweb.devtools import SYSTEM_ENTITIES, SYSTEM_RELATIONS, VIEW_VALIDATORS
from cubicweb.devtools import fake, htmlparser
@@ -764,6 +767,10 @@
"""this method populates the database with `how_many` entities
of each possible type. It also inserts random relations between them
"""
+ with security_enabled(self.session, read=False, write=False):
+ self._auto_populate(how_many)
+
+ def _auto_populate(self, how_many):
cu = self.cursor()
self.custom_populate(how_many, cu)
vreg = self.vreg
--- a/rqlrewrite.py Wed Mar 24 17:58:05 2010 +0100
+++ b/rqlrewrite.py Wed Mar 24 18:04:59 2010 +0100
@@ -41,15 +41,15 @@
except KeyError:
continue
stinfo = var.stinfo
- if stinfo.get('uidrels'):
+ if stinfo.get('uidrel') is not None:
continue # eid specified, no need for additional type specification
try:
- typerels = rqlst.defined_vars[varname].stinfo.get('typerels')
+ typerel = rqlst.defined_vars[varname].stinfo.get('typerel')
except KeyError:
assert varname in rqlst.aliases
continue
- if newroot is rqlst and typerels:
- mytyperel = iter(typerels).next()
+ if newroot is rqlst and typerel is not None:
+ mytyperel = typerel
else:
for vref in newroot.defined_vars[varname].references():
rel = vref.relation()
@@ -80,7 +80,7 @@
# 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['typerel'] = rel
stinfo['possibletypes'] = possibletypes
--- a/server/msplanner.py Wed Mar 24 17:58:05 2010 +0100
+++ b/server/msplanner.py Wed Mar 24 18:04:59 2010 +0100
@@ -309,21 +309,20 @@
# find for each source which variable/solution are supported
for varname, varobj in self.rqlst.defined_vars.items():
# if variable has an eid specified, we can get its source directly
- # NOTE: use uidrels and not constnode to deal with "X eid IN(1,2,3,4)"
- if varobj.stinfo['uidrels']:
- vrels = varobj.stinfo['relations'] - varobj.stinfo['uidrels']
- for rel in varobj.stinfo['uidrels']:
- for const in rel.children[1].get_nodes(Constant):
- eid = const.eval(self.plan.args)
- source = self._session.source_from_eid(eid)
- if vrels and not any(source.support_relation(r.r_type)
- for r in vrels):
- self._set_source_for_term(self.system_source, varobj)
- else:
- self._set_source_for_term(source, varobj)
+ # NOTE: use uidrel and not constnode to deal with "X eid IN(1,2,3,4)"
+ if varobj.stinfo['uidrel'] is not None:
+ rel = varobj.stinfo['uidrel']
+ for const in rel.children[1].get_nodes(Constant):
+ eid = const.eval(self.plan.args)
+ source = self._session.source_from_eid(eid)
+ if vrels and not any(source.support_relation(r.r_type)
+ for r in vrels if not r is rel):
+ self._set_source_for_term(self.system_source, varobj)
+ else:
+ self._set_source_for_term(source, varobj)
continue
rels = varobj.stinfo['relations']
- if not rels and not varobj.stinfo['typerels']:
+ if not rels and varobj.stinfo['typerel'] is None:
# (rare) case where the variable has no type specified nor
# relation accessed ex. "Any MAX(X)"
self._set_source_for_term(self.system_source, varobj)
@@ -700,7 +699,7 @@
for var in select.defined_vars.itervalues():
if not var in terms:
stinfo = var.stinfo
- for ovar, rtype in stinfo['attrvars']:
+ for ovar, rtype in stinfo.get('attrvars', ()):
if ovar in terms:
needsel.add(var.name)
terms.append(var)
@@ -778,20 +777,19 @@
# variable is refed by an outer scope and should be substituted
# using an 'identity' relation (else we'll get a conflict of
# temporary tables)
- if rhsvar in terms and not lhsvar in terms:
+ if rhsvar in terms and not lhsvar in terms and lhsvar.scope is lhsvar.stmt:
self._identity_substitute(rel, lhsvar, terms, needsel)
- elif lhsvar in terms and not rhsvar in terms:
+ elif lhsvar in terms and not rhsvar in terms and rhsvar.scope is rhsvar.stmt:
self._identity_substitute(rel, rhsvar, terms, needsel)
def _identity_substitute(self, relation, var, terms, needsel):
newvar = self._insert_identity_variable(relation.scope, var)
- if newvar is not None:
- # ensure relation is using '=' operator, else we rely on a
- # sqlgenerator side effect (it won't insert an inequality operator
- # in this case)
- relation.children[1].operator = '='
- terms.append(newvar)
- needsel.add(newvar.name)
+ # ensure relation is using '=' operator, else we rely on a
+ # sqlgenerator side effect (it won't insert an inequality operator
+ # in this case)
+ relation.children[1].operator = '='
+ terms.append(newvar)
+ needsel.add(newvar.name)
def _choose_term(self, sourceterms):
"""pick one term among terms supported by a source, which will be used
@@ -1418,7 +1416,7 @@
return False
if not var in terms or used_in_outer_scope(var, self.current_scope):
return False
- if any(v for v, _ in var.stinfo['attrvars'] if not v in terms):
+ if any(v for v, _ in var.stinfo.get('attrvars', ()) if not v in terms):
return False
return True
--- a/server/mssteps.py Wed Mar 24 17:58:05 2010 +0100
+++ b/server/mssteps.py Wed Mar 24 18:04:59 2010 +0100
@@ -61,7 +61,7 @@
if not isinstance(vref, VariableRef):
continue
var = vref.variable
- if var.stinfo['attrvars']:
+ if var.stinfo.get('attrvars'):
for lhsvar, rtype in var.stinfo['attrvars']:
if lhsvar.name in srqlst.defined_vars:
key = '%s.%s' % (lhsvar.name, rtype)
--- a/server/querier.py Wed Mar 24 17:58:05 2010 +0100
+++ b/server/querier.py Wed Mar 24 18:04:59 2010 +0100
@@ -319,16 +319,9 @@
varkwargs = {}
if not session.transaction_data.get('security-rqlst-cache'):
for var in rqlst.defined_vars.itervalues():
- for rel in var.stinfo['uidrels']:
- const = rel.children[1].children[0]
- try:
- varkwargs[var.name] = typed_eid(const.eval(self.args))
- break
- except AttributeError:
- #from rql.nodes import Function
- #assert isinstance(const, Function)
- # X eid IN(...)
- pass
+ if var.stinfo['constnode'] is not None:
+ eid = var.stinfo['constnode'].eval(self.args)
+ varkwargs[var.name] = typed_eid(eid)
# dictionnary of variables restricted for security reason
localchecks = {}
restricted_vars = set()
--- a/server/rqlannotation.py Wed Mar 24 17:58:05 2010 +0100
+++ b/server/rqlannotation.py Wed Mar 24 18:04:59 2010 +0100
@@ -38,7 +38,7 @@
stinfo['invariant'] = False
stinfo['principal'] = _select_main_var(stinfo['rhsrelations'])
continue
- if not stinfo['relations'] and not stinfo['typerels']:
+ if not stinfo['relations'] and stinfo['typerel'] is None:
# Any X, Any MAX(X)...
# those particular queries should be executed using the system
# entities table unless there is some type restriction
@@ -80,7 +80,7 @@
continue
rschema = getrschema(rel.r_type)
if rel.optional:
- if rel in stinfo['optrelations']:
+ if rel in stinfo.get('optrelations', ()):
# optional variable can't be invariant if this is the lhs
# variable of an inlined relation
if not rel in stinfo['rhsrelations'] and rschema.inlined:
@@ -296,7 +296,7 @@
def compute(self, rqlst):
# set domains for each variable
for varname, var in rqlst.defined_vars.iteritems():
- if var.stinfo['uidrels'] or \
+ if var.stinfo['uidrel'] is not None or \
self.eschema(rqlst.solutions[0][varname]).final:
ptypes = var.stinfo['possibletypes']
else:
@@ -339,7 +339,11 @@
def set_rel_constraint(self, term, rel, etypes_func):
if isinstance(term, VariableRef) and self.is_ambiguous(term.variable):
var = term.variable
- if len(var.stinfo['relations'] - var.stinfo['typerels']) == 1 \
+ if var.stinfo['typerel'] is not None:
+ sub = 1
+ else:
+ sub = 0
+ if len(var.stinfo['relations']) - sub == 1 \
or rel.sqlscope is var.sqlscope or rel.r_type == 'identity':
self.restrict(var, frozenset(etypes_func()))
try:
@@ -356,7 +360,7 @@
if isinstance(other, VariableRef) and isinstance(other.variable, Variable):
deambiguifier = other.variable
if not var is self.deambification_map.get(deambiguifier):
- if not var.stinfo['typerels']:
+ if var.stinfo['typerel'] is None:
otheretypes = deambiguifier.stinfo['possibletypes']
elif not self.is_ambiguous(deambiguifier):
otheretypes = self.varsols[deambiguifier]
@@ -364,7 +368,7 @@
# we know variable won't be invariant, try to use
# it to deambguify the current variable
otheretypes = self.varsols[deambiguifier]
- if not deambiguifier.stinfo['typerels']:
+ if deambiguifier.stinfo['typerel'] is None:
# if deambiguifier has no type restriction using 'is',
# don't record it
deambiguifier = None
--- a/server/sources/rql2sql.py Wed Mar 24 17:58:05 2010 +0100
+++ b/server/sources/rql2sql.py Wed Mar 24 18:04:59 2010 +0100
@@ -73,7 +73,7 @@
modified = False
for varname in tuple(unstable):
var = select.defined_vars[varname]
- if not var.stinfo['optrelations']:
+ if not var.stinfo.get('optrelations'):
continue
modified = True
unstable.remove(varname)
@@ -100,13 +100,13 @@
var.stinfo['relations'].remove(rel)
newvar.stinfo['relations'].add(newrel)
if rel.optional in ('left', 'both'):
- newvar.stinfo['optrelations'].add(newrel)
+ newvar.add_optional_relation(newrel)
for vref in newrel.children[1].iget_nodes(VariableRef):
var = vref.variable
var.stinfo['relations'].add(newrel)
var.stinfo['rhsrelations'].add(newrel)
if rel.optional in ('right', 'both'):
- var.stinfo['optrelations'].add(newrel)
+ var.add_optional_relation(newrel)
# extract subquery solutions
mysolutions = [sol.copy() for sol in solutions]
cleanup_solutions(newselect, mysolutions)
@@ -816,7 +816,7 @@
condition = '%s=%s' % (lhssql, rhsconst.accept(self))
if relation.r_type != 'identity':
condition = '(%s OR %s IS NULL)' % (condition, lhssql)
- if not lhsvar.stinfo['optrelations']:
+ if not lhsvar.stinfo.get('optrelations'):
return condition
self.add_outer_join_condition(lhsvar, t1, condition)
return
@@ -909,7 +909,7 @@
sql = '%s%s' % (lhssql, rhssql)
except AttributeError:
sql = '%s%s' % (lhssql, rhssql)
- if lhs.variable.stinfo['optrelations']:
+ if lhs.variable.stinfo.get('optrelations'):
self.add_outer_join_condition(lhs.variable, table, sql)
else:
return sql
@@ -924,7 +924,7 @@
lhsvar = lhs.variable
me_is_principal = lhsvar.stinfo.get('principal') is rel
if me_is_principal:
- if not lhsvar.stinfo['typerels']:
+ if lhsvar.stinfo['typerel'] is None:
# the variable is using the fti table, no join needed
jointo = None
elif not lhsvar.name in self._varmap:
@@ -1053,7 +1053,7 @@
vtablename = '_' + variable.name
self.add_table('entities AS %s' % vtablename, vtablename)
sql = '%s.eid' % vtablename
- if variable.stinfo['typerels']:
+ if variable.stinfo['typerel'] is not None:
# add additional restriction on entities.type column
pts = variable.stinfo['possibletypes']
if len(pts) == 1:
@@ -1207,7 +1207,7 @@
tablealias = self._state.outer_tables[table]
actualtables = self._state.actual_tables[-1]
except KeyError:
- for rel in var.stinfo['optrelations']:
+ for rel in var.stinfo.get('optrelations'):
self.visit_relation(rel)
assert self._state.outer_tables
self.add_outer_join_condition(var, table, condition)
--- a/server/test/unittest_rql2sql.py Wed Mar 24 17:58:05 2010 +0100
+++ b/server/test/unittest_rql2sql.py Wed Mar 24 18:04:59 2010 +0100
@@ -1594,8 +1594,8 @@
class removeUnsusedSolutionsTC(TestCase):
def test_invariant_not_varying(self):
rqlst = mock_object(defined_vars={})
- rqlst.defined_vars['A'] = mock_object(scope=rqlst, stinfo={'optrelations':False}, _q_invariant=True)
- rqlst.defined_vars['B'] = mock_object(scope=rqlst, stinfo={'optrelations':False}, _q_invariant=False)
+ rqlst.defined_vars['A'] = mock_object(scope=rqlst, stinfo={}, _q_invariant=True)
+ rqlst.defined_vars['B'] = mock_object(scope=rqlst, stinfo={}, _q_invariant=False)
self.assertEquals(remove_unused_solutions(rqlst, [{'A': 'RugbyGroup', 'B': 'RugbyTeam'},
{'A': 'FootGroup', 'B': 'FootTeam'}], {}, None),
([{'A': 'RugbyGroup', 'B': 'RugbyTeam'},
@@ -1605,8 +1605,8 @@
def test_invariant_varying(self):
rqlst = mock_object(defined_vars={})
- rqlst.defined_vars['A'] = mock_object(scope=rqlst, stinfo={'optrelations':False}, _q_invariant=True)
- rqlst.defined_vars['B'] = mock_object(scope=rqlst, stinfo={'optrelations':False}, _q_invariant=False)
+ rqlst.defined_vars['A'] = mock_object(scope=rqlst, stinfo={}, _q_invariant=True)
+ rqlst.defined_vars['B'] = mock_object(scope=rqlst, stinfo={}, _q_invariant=False)
self.assertEquals(remove_unused_solutions(rqlst, [{'A': 'RugbyGroup', 'B': 'RugbyTeam'},
{'A': 'FootGroup', 'B': 'RugbyTeam'}], {}, None),
([{'A': 'RugbyGroup', 'B': 'RugbyTeam'}], {}, set())
--- a/web/facet.py Wed Mar 24 17:58:05 2010 +0100
+++ b/web/facet.py Wed Mar 24 18:04:59 2010 +0100
@@ -8,7 +8,6 @@
"""
__docformat__ = "restructuredtext en"
-from itertools import chain
from copy import deepcopy
from datetime import date, datetime, timedelta
@@ -199,7 +198,7 @@
# add attribute variable to selection
rqlst.add_selected(attrvar)
# add is restriction if necessary
- if not mainvar.stinfo['typerels']:
+ if mainvar.stinfo['typerel'] is None:
etypes = frozenset(sol[mainvar.name] for sol in rqlst.solutions)
rqlst.add_type_restriction(mainvar, etypes)
return var
@@ -228,12 +227,16 @@
for ovarname in linkedvars:
vargraph[ovarname].remove(trvarname)
# remove relation using this variable
- for rel in chain(trvar.stinfo['relations'], trvar.stinfo['typerels']):
+ for rel in trvar.stinfo['relations']:
if rel in removed:
# already removed
continue
rqlst.remove_node(rel)
removed.add(rel)
+ rel = trvar.stinfo['typerel']
+ if rel is not None and not rel in removed:
+ rqlst.remove_node(rel)
+ removed.add(rel)
# cleanup groupby clause
if rqlst.groupby:
for vref in rqlst.groupby[:]: