17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
18 """Helper classes to execute RQL queries on a set of sources, performing |
18 """Helper classes to execute RQL queries on a set of sources, performing |
19 security checking and data aggregation. |
19 security checking and data aggregation. |
20 """ |
20 """ |
21 import uuid |
21 import uuid |
|
22 import time |
|
23 import traceback |
22 from itertools import repeat |
24 from itertools import repeat |
23 |
25 |
24 from rql import RQLSyntaxError, CoercionError |
26 from rql import RQLSyntaxError, CoercionError |
25 from rql.stmts import Union |
27 from rql.stmts import Union |
26 from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not |
28 from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not |
28 |
30 |
29 from cubicweb import ValidationError, Unauthorized, UnknownEid, QueryError |
31 from cubicweb import ValidationError, Unauthorized, UnknownEid, QueryError |
30 from cubicweb.rqlrewrite import RQLRelationRewriter |
32 from cubicweb.rqlrewrite import RQLRelationRewriter |
31 from cubicweb import Binary, server |
33 from cubicweb import Binary, server |
32 from cubicweb.rset import ResultSet |
34 from cubicweb.rset import ResultSet |
|
35 from cubicweb.debug import emit_to_debug_channel |
33 |
36 |
34 from cubicweb.utils import QueryCache, RepeatList |
37 from cubicweb.utils import QueryCache, RepeatList |
35 from cubicweb.misc.source_highlight import highlight_terminal |
38 from cubicweb.misc.source_highlight import highlight_terminal |
36 from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata |
39 from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata |
37 from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction |
40 from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction |
556 # make an execution plan |
559 # make an execution plan |
557 plan = self.plan_factory(rqlst, args, cnx) |
560 plan = self.plan_factory(rqlst, args, cnx) |
558 plan.cache_key = cachekey |
561 plan.cache_key = cachekey |
559 plan.rql_query_tracing_token = str(uuid.uuid4()) |
562 plan.rql_query_tracing_token = str(uuid.uuid4()) |
560 self._planner.build_plan(plan) |
563 self._planner.build_plan(plan) |
|
564 |
|
565 query_debug_informations = { |
|
566 "rql": rql, |
|
567 "rql_query_tracing_token": plan.rql_query_tracing_token, |
|
568 "args": args, |
|
569 # remove the last part of the stack which is: this line |
|
570 "callstack": "".join(traceback.format_stack()[:-1]), |
|
571 "description": "", |
|
572 } |
|
573 |
|
574 start = time.time() |
|
575 |
561 # execute the plan |
576 # execute the plan |
562 try: |
577 try: |
563 results = plan.execute() |
578 results = plan.execute() |
564 except (Unauthorized, ValidationError): |
579 except (Unauthorized, ValidationError): |
565 # getting an Unauthorized/ValidationError exception means the |
580 # getting an Unauthorized/ValidationError exception means the |
571 # * don't rollback if we're in the commit process, will be handled |
586 # * don't rollback if we're in the commit process, will be handled |
572 # by the connection |
587 # by the connection |
573 if cnx.commit_state is None: |
588 if cnx.commit_state is None: |
574 cnx.commit_state = 'uncommitable' |
589 cnx.commit_state = 'uncommitable' |
575 raise |
590 raise |
|
591 |
|
592 query_debug_informations["time"] = ((time.time() - start) * 1000) |
|
593 query_debug_informations["result"] = results |
|
594 |
576 # build a description for the results if necessary |
595 # build a description for the results if necessary |
577 descr = () |
596 descr = () |
578 if build_descr: |
597 if build_descr: |
579 if rqlst.TYPE == 'select': |
598 if rqlst.TYPE == 'select': |
580 # sample selection |
599 # sample selection |
594 basedescr = [None] * len(plan.selected) |
613 basedescr = [None] * len(plan.selected) |
595 todetermine = list(zip(range(len(plan.selected)), repeat(False))) |
614 todetermine = list(zip(range(len(plan.selected)), repeat(False))) |
596 descr = _build_descr(cnx, results, basedescr, todetermine) |
615 descr = _build_descr(cnx, results, basedescr, todetermine) |
597 # FIXME: get number of affected entities / relations on non |
616 # FIXME: get number of affected entities / relations on non |
598 # selection queries ? |
617 # selection queries ? |
|
618 query_debug_informations["description"] = descr |
|
619 |
|
620 emit_to_debug_channel("rql", query_debug_informations) |
|
621 |
599 # return a result set object |
622 # return a result set object |
600 return ResultSet(results, rql, args, descr) |
623 return ResultSet(results, rql, args, descr) |
601 |
624 |
602 # these are overridden by set_log_methods below |
625 # these are overridden by set_log_methods below |
603 # only defining here to prevent pylint from complaining |
626 # only defining here to prevent pylint from complaining |