27 |
27 |
28 from logilab.common.cache import Cache |
28 from logilab.common.cache import Cache |
29 from logilab.common.compat import any |
29 from logilab.common.compat import any |
30 from rql import RQLSyntaxError |
30 from rql import RQLSyntaxError |
31 from rql.stmts import Union, Select |
31 from rql.stmts import Union, Select |
32 from rql.nodes import Relation, VariableRef, Constant, SubQuery, Exists, Not |
32 from rql.nodes import (Relation, VariableRef, Constant, SubQuery, Function, |
|
33 Exists, Not) |
33 |
34 |
34 from cubicweb import Unauthorized, QueryError, UnknownEid, typed_eid |
35 from cubicweb import Unauthorized, QueryError, UnknownEid, typed_eid |
35 from cubicweb import server |
36 from cubicweb import server |
36 from cubicweb.rset import ResultSet |
37 from cubicweb.rset import ResultSet |
37 |
38 |
48 """return a sql schema to store RQL query result""" |
49 """return a sql schema to store RQL query result""" |
49 for i, term in enumerate(selected): |
50 for i, term in enumerate(selected): |
50 key = term.as_string() |
51 key = term.as_string() |
51 value = '%s.C%s' % (table, i) |
52 value = '%s.C%s' % (table, i) |
52 if varmap.get(key, value) != value: |
53 if varmap.get(key, value) != value: |
53 raise Exception('variable name conflict on %s' % key) |
54 raise Exception('variable name conflict on %s: got %s / %s' |
|
55 % (key, value, varmap)) |
54 varmap[key] = value |
56 varmap[key] = value |
55 |
57 |
56 # permission utilities ######################################################## |
58 # permission utilities ######################################################## |
57 |
59 |
58 def check_no_password_selected(rqlst): |
60 def check_no_password_selected(rqlst): |
292 selected = set(vref.name for vref in aliases) |
294 selected = set(vref.name for vref in aliases) |
293 # now copy original selection and groups |
295 # now copy original selection and groups |
294 for term in origselection: |
296 for term in origselection: |
295 newselect.append_selected(term.copy(newselect)) |
297 newselect.append_selected(term.copy(newselect)) |
296 if select.orderby: |
298 if select.orderby: |
297 newselect.set_orderby([s.copy(newselect) for s in select.orderby]) |
299 sortterms = [] |
|
300 for sortterm in select.orderby: |
|
301 sortterms.append(sortterm.copy(newselect)) |
|
302 for fnode in sortterm.get_nodes(Function): |
|
303 if fnode.name == 'FTIRANK': |
|
304 # we've to fetch the has_text relation as well |
|
305 var = fnode.children[0].variable |
|
306 rel = iter(var.stinfo['ftirels']).next() |
|
307 assert not rel.ored(), 'unsupported' |
|
308 newselect.add_restriction(rel.copy(newselect)) |
|
309 # remove relation from the orig select and |
|
310 # cleanup variable stinfo |
|
311 rel.parent.remove(rel) |
|
312 var.stinfo['ftirels'].remove(rel) |
|
313 var.stinfo['relations'].remove(rel) |
|
314 # XXX not properly re-annotated after security insertion? |
|
315 newvar = newselect.get_variable(var.name) |
|
316 newvar.stinfo.setdefault('ftirels', set()).add(rel) |
|
317 newvar.stinfo.setdefault('relations', set()).add(rel) |
|
318 newselect.set_orderby(sortterms) |
298 _expand_selection(select.orderby, selected, aliases, select, newselect) |
319 _expand_selection(select.orderby, selected, aliases, select, newselect) |
299 select.orderby = () # XXX dereference? |
320 select.orderby = () # XXX dereference? |
300 if select.groupby: |
321 if select.groupby: |
301 newselect.set_groupby([g.copy(newselect) for g in select.groupby]) |
322 newselect.set_groupby([g.copy(newselect) for g in select.groupby]) |
302 _expand_selection(select.groupby, selected, aliases, select, newselect) |
323 _expand_selection(select.groupby, selected, aliases, select, newselect) |
337 add_noinvariant(noinvariant, restricted, myrqlst, nbtrees) |
358 add_noinvariant(noinvariant, restricted, myrqlst, nbtrees) |
338 if () in localchecks: |
359 if () in localchecks: |
339 select.set_possible_types(localchecks[()]) |
360 select.set_possible_types(localchecks[()]) |
340 add_types_restriction(self.schema, select) |
361 add_types_restriction(self.schema, select) |
341 add_noinvariant(noinvariant, restricted, select, nbtrees) |
362 add_noinvariant(noinvariant, restricted, select, nbtrees) |
|
363 self.rqlhelper.annotate(union) |
342 |
364 |
343 def _check_permissions(self, rqlst): |
365 def _check_permissions(self, rqlst): |
344 """return a dict defining "local checks", e.g. RQLExpression defined in |
366 """return a dict defining "local checks", e.g. RQLExpression defined in |
345 the schema that should be inserted in the original query |
367 the schema that should be inserted in the original query |
346 |
368 |
569 # some cache usage stats |
591 # some cache usage stats |
570 self.cache_hit, self.cache_miss = 0, 0 |
592 self.cache_hit, self.cache_miss = 0, 0 |
571 # rql parsing / analysing helper |
593 # rql parsing / analysing helper |
572 self.solutions = repo.vreg.solutions |
594 self.solutions = repo.vreg.solutions |
573 rqlhelper = repo.vreg.rqlhelper |
595 rqlhelper = repo.vreg.rqlhelper |
|
596 # set backend on the rql helper, will be used for function checking |
|
597 rqlhelper.backend = repo.config.sources()['system']['db-driver'] |
574 self._parse = rqlhelper.parse |
598 self._parse = rqlhelper.parse |
575 self._annotate = rqlhelper.annotate |
599 self._annotate = rqlhelper.annotate |
576 # rql planner |
600 # rql planner |
577 # note: don't use repo.sources, may not be built yet, and also "admin" |
601 # note: don't use repo.sources, may not be built yet, and also "admin" |
578 # isn't an actual source |
602 # isn't an actual source |