28 from rql import RQLSyntaxError, CoercionError |
28 from rql import RQLSyntaxError, CoercionError |
29 from rql.stmts import Union |
29 from rql.stmts import Union |
30 from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not |
30 from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not |
31 from yams import BASE_TYPES |
31 from yams import BASE_TYPES |
32 |
32 |
33 from cubicweb import ValidationError, Unauthorized, UnknownEid |
33 from cubicweb import ValidationError, Unauthorized, UnknownEid, QueryError |
34 from cubicweb.rqlrewrite import RQLRelationRewriter |
34 from cubicweb.rqlrewrite import RQLRelationRewriter |
35 from cubicweb import Binary, server |
35 from cubicweb import Binary, server |
36 from cubicweb.rset import ResultSet |
36 from cubicweb.rset import ResultSet |
37 |
37 |
38 from cubicweb.utils import QueryCache, RepeatList |
38 from cubicweb.utils import QueryCache, RepeatList |
544 eidkeys = self._rql_ck_cache[rql] |
544 eidkeys = self._rql_ck_cache[rql] |
545 if eidkeys: |
545 if eidkeys: |
546 # if there are some, we need a better cache key, eg (rql + |
546 # if there are some, we need a better cache key, eg (rql + |
547 # entity type of each eid) |
547 # entity type of each eid) |
548 try: |
548 try: |
549 cachekey = self._repo.querier_cache_key(cnx, rql, |
549 cachekey = _rql_cache_key(cnx, rql, args, eidkeys) |
550 args, eidkeys) |
|
551 except UnknownEid: |
550 except UnknownEid: |
552 # we want queries such as "Any X WHERE X eid 9999" |
551 # we want queries such as "Any X WHERE X eid 9999" |
553 # return an empty result instead of raising UnknownEid |
552 # return an empty result instead of raising UnknownEid |
554 return empty_rset(rql, args) |
553 return empty_rset(rql, args) |
555 rqlst = self._rql_cache[cachekey] |
554 rqlst = self._rql_cache[cachekey] |
570 # empty result instead of raising UnknownEid |
569 # empty result instead of raising UnknownEid |
571 return empty_rset(rql, args) |
570 return empty_rset(rql, args) |
572 if args and rql not in self._rql_ck_cache: |
571 if args and rql not in self._rql_ck_cache: |
573 self._rql_ck_cache[rql] = eidkeys |
572 self._rql_ck_cache[rql] = eidkeys |
574 if eidkeys: |
573 if eidkeys: |
575 cachekey = self._repo.querier_cache_key(cnx, rql, args, |
574 cachekey = _rql_cache_key(cnx, rql, args, eidkeys) |
576 eidkeys) |
|
577 self._rql_cache[cachekey] = rqlst |
575 self._rql_cache[cachekey] = rqlst |
578 if rqlst.TYPE != 'select': |
576 if rqlst.TYPE != 'select': |
579 if cnx.read_security: |
577 if cnx.read_security: |
580 check_no_password_selected(rqlst) |
578 check_no_password_selected(rqlst) |
581 cachekey = None |
579 cachekey = None |
644 |
642 |
645 # these are overridden by set_log_methods below |
643 # these are overridden by set_log_methods below |
646 # only defining here to prevent pylint from complaining |
644 # only defining here to prevent pylint from complaining |
647 info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None |
645 info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None |
648 |
646 |
|
647 |
|
648 def _rql_cache_key(cnx, rql, args, eidkeys): |
|
649 cachekey = [rql] |
|
650 type_from_eid = cnx.repo.type_from_eid |
|
651 for key in sorted(eidkeys): |
|
652 try: |
|
653 etype = type_from_eid(args[key], cnx) |
|
654 except KeyError: |
|
655 raise QueryError('bad cache key %s (no value)' % key) |
|
656 except TypeError: |
|
657 raise QueryError('bad cache key %s (value: %r)' % ( |
|
658 key, args[key])) |
|
659 cachekey.append(etype) |
|
660 # ensure eid is correctly typed in args |
|
661 args[key] = int(args[key]) |
|
662 return tuple(cachekey) |
|
663 |
|
664 |
649 from logging import getLogger |
665 from logging import getLogger |
650 from cubicweb import set_log_methods |
666 from cubicweb import set_log_methods |
651 LOGGER = getLogger('cubicweb.querier') |
667 LOGGER = getLogger('cubicweb.querier') |
652 set_log_methods(QuerierHelper, LOGGER) |
668 set_log_methods(QuerierHelper, LOGGER) |
653 |
669 |