10 |
10 |
11 from itertools import repeat |
11 from itertools import repeat |
12 |
12 |
13 from logilab.common.cache import Cache |
13 from logilab.common.cache import Cache |
14 from logilab.common.compat import any |
14 from logilab.common.compat import any |
15 from rql import RQLHelper, RQLSyntaxError |
15 from rql import RQLSyntaxError |
16 from rql.stmts import Union, Select |
16 from rql.stmts import Union, Select |
17 from rql.nodes import Relation, VariableRef, Constant, SubQuery |
17 from rql.nodes import Relation, VariableRef, Constant, SubQuery |
18 |
18 |
19 from cubicweb import Unauthorized, QueryError, UnknownEid, typed_eid |
19 from cubicweb import Unauthorized, QueryError, UnknownEid, typed_eid |
20 from cubicweb import server |
20 from cubicweb import server |
24 from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata |
24 from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata |
25 from cubicweb.server.ssplanner import add_types_restriction |
25 from cubicweb.server.ssplanner import add_types_restriction |
26 |
26 |
27 READ_ONLY_RTYPES = set(('eid', 'has_text', 'is', 'is_instance_of', 'identity')) |
27 READ_ONLY_RTYPES = set(('eid', 'has_text', 'is', 'is_instance_of', 'identity')) |
28 |
28 |
29 def empty_rset(session, rql, args, rqlst=None): |
29 def empty_rset(rql, args, rqlst=None): |
30 """build an empty result set object""" |
30 """build an empty result set object""" |
31 return ResultSet([], rql, args, rqlst=rqlst) |
31 return ResultSet([], rql, args, rqlst=rqlst) |
32 |
32 |
33 def update_varmap(varmap, selected, table): |
33 def update_varmap(varmap, selected, table): |
34 """return a sql schema to store RQL query result""" |
34 """return a sql schema to store RQL query result""" |
208 set_qdata(self.schema.rschema, union, noinvariant) |
208 set_qdata(self.schema.rschema, union, noinvariant) |
209 if union.has_text_query: |
209 if union.has_text_query: |
210 self.cache_key = None |
210 self.cache_key = None |
211 |
211 |
212 def _insert_security(self, union, noinvariant): |
212 def _insert_security(self, union, noinvariant): |
213 rh = self.rqlhelper |
|
214 for select in union.children[:]: |
213 for select in union.children[:]: |
215 for subquery in select.with_: |
214 for subquery in select.with_: |
216 self._insert_security(subquery.query, noinvariant) |
215 self._insert_security(subquery.query, noinvariant) |
217 localchecks, restricted = self._check_permissions(select) |
216 localchecks, restricted = self._check_permissions(select) |
218 if any(localchecks): |
217 if any(localchecks): |
570 |
569 |
571 def execute(self, session, rql, args=None, eid_key=None, build_descr=True): |
570 def execute(self, session, rql, args=None, eid_key=None, build_descr=True): |
572 """execute a rql query, return resulting rows and their description in |
571 """execute a rql query, return resulting rows and their description in |
573 a `ResultSet` object |
572 a `ResultSet` object |
574 |
573 |
575 * `rql` should be an unicode string or a plain ascii string |
574 * `rql` should be an Unicode string or a plain ASCII string |
576 * `args` the optional parameters dictionary associated to the query |
575 * `args` the optional parameters dictionary associated to the query |
577 * `build_descr` is a boolean flag indicating if the description should |
576 * `build_descr` is a boolean flag indicating if the description should |
578 be built on select queries (if false, the description will be en empty |
577 be built on select queries (if false, the description will be en empty |
579 list) |
578 list) |
580 * `eid_key` must be both a key in args and a substitution in the rql |
579 * `eid_key` must be both a key in args and a substitution in the rql |
581 query. It should be used to enhance cacheability of rql queries. |
580 query. It should be used to enhance cacheability of rql queries. |
582 It may be a tuple for keys in args. |
581 It may be a tuple for keys in args. |
583 eid_key must be providen in case where a eid substitution is providen |
582 `eid_key` must be provided in cases where a eid substitution is provided |
584 and resolve some ambiguity in the possible solutions infered for each |
583 and resolves ambiguities in the possible solutions inferred for each |
585 variable in the query. |
584 variable in the query. |
586 |
585 |
587 on INSERT queries, there will be on row with the eid of each inserted |
586 on INSERT queries, there will be one row with the eid of each inserted |
588 entity |
587 entity |
589 |
588 |
590 result for DELETE and SET queries is undefined yet |
589 result for DELETE and SET queries is undefined yet |
591 |
590 |
592 to maximize the rql parsing/analyzing cache performance, you should |
591 to maximize the rql parsing/analyzing cache performance, you should |
593 always use substitute arguments in queries (eg avoid query such as |
592 always use substitute arguments in queries (i.e. avoid query such as |
594 'Any X WHERE X eid 123'!) |
593 'Any X WHERE X eid 123'!) |
595 """ |
594 """ |
596 if server.DEBUG & (server.DBG_RQL | server.DBG_SQL): |
595 if server.DEBUG & (server.DBG_RQL | server.DBG_SQL): |
597 if server.DEBUG & (server.DBG_MORE | server.DBG_SQL): |
596 if server.DEBUG & (server.DBG_MORE | server.DBG_SQL): |
598 print '*'*80 |
597 print '*'*80 |
611 raise QueryError('bad cache key %s (value: %r)' % ( |
610 raise QueryError('bad cache key %s (value: %r)' % ( |
612 key, args[key])) |
611 key, args[key])) |
613 except UnknownEid: |
612 except UnknownEid: |
614 # we want queries such as "Any X WHERE X eid 9999" |
613 # we want queries such as "Any X WHERE X eid 9999" |
615 # return an empty result instead of raising UnknownEid |
614 # return an empty result instead of raising UnknownEid |
616 return empty_rset(session, rql, args) |
615 return empty_rset(rql, args) |
617 cachekey.append(etype) |
616 cachekey.append(etype) |
618 # ensure eid is correctly typed in args |
617 # ensure eid is correctly typed in args |
619 args[key] = typed_eid(args[key]) |
618 args[key] = typed_eid(args[key]) |
620 cachekey = tuple(cachekey) |
619 cachekey = tuple(cachekey) |
621 else: |
620 else: |
629 try: |
628 try: |
630 self.solutions(session, rqlst, args) |
629 self.solutions(session, rqlst, args) |
631 except UnknownEid: |
630 except UnknownEid: |
632 # we want queries such as "Any X WHERE X eid 9999" |
631 # we want queries such as "Any X WHERE X eid 9999" |
633 # return an empty result instead of raising UnknownEid |
632 # return an empty result instead of raising UnknownEid |
634 return empty_rset(session, rql, args, rqlst) |
633 return empty_rset(rql, args, rqlst) |
635 self._rql_cache[cachekey] = rqlst |
634 self._rql_cache[cachekey] = rqlst |
636 orig_rqlst = rqlst |
635 orig_rqlst = rqlst |
637 if not rqlst.TYPE == 'select': |
636 if not rqlst.TYPE == 'select': |
638 if not session.is_super_session: |
637 if not session.is_super_session: |
639 check_no_password_selected(rqlst) |
638 check_no_password_selected(rqlst) |