cubicweb/server/querier.py
author Denis Laxalde <denis.laxalde@logilab.fr>
Thu, 30 Nov 2017 11:55:35 +0100
changeset 12242 68ca7fe0ca29
parent 12241 06deb43c23c3
child 12495 23081860ea60
permissions -rw-r--r--
[ssplanner] Prevent execution of write queries involving computed relations Previously, setting a computed relation upon entity creation or modification (using the ORM or an RQL query) would usually fail with an operational error in the backend ("no such table"). However, under some mysterious circumstances (like passing a string as value in cw_set for a computed relation), the RQL to SQL transformation would simply drop the clause. To prevent this to happen, we add a check for computed relation before adding a relation to an execution plan. This check raises a QueryError. It happens in several places: * in querier.InsertPlan.add_relation_def() (called from several places in ssplanner steps) for INSERT queries, * in ssplanner.UpdateStep.execute() for SET queries and, * in ssplanner.SSplanner.build_delete_plan() for DELETE queries. Tests added to unittest_querier.py because unittest_sslplanner.py looked inappropriate (it has only unit tests) and the former already had a NonRegressionTC class.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11767
432f87a63057 flake8 and all
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11765
diff changeset
     1
# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5419
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    18
"""Helper classes to execute RQL queries on a set of sources, performing
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    19
security checking and data aggregation.
5726
c3b99606644d [json] fix json serialization for recent simplejson implementation, and test encoding of entities
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5657
diff changeset
    20
"""
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
    21
from __future__ import print_function
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
    22
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    23
from itertools import repeat
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    24
10675
e0db937f5add [py3k] unicode → six.text_type
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10663
diff changeset
    25
from six import text_type, string_types, integer_types
12062
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
    26
from six.moves import range, zip
10609
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10589
diff changeset
    27
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    28
from rql import RQLSyntaxError, CoercionError
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
    29
from rql.stmts import Union
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
    30
from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    31
from yams import BASE_TYPES
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    32
12051
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
    33
from cubicweb import ValidationError, Unauthorized, UnknownEid, QueryError
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    34
from cubicweb.rqlrewrite import RQLRelationRewriter
8748
f5027f8d2478 drop typed_eid() in favour of int() (closes #2742462)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8697
diff changeset
    35
from cubicweb import Binary, server
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    36
from cubicweb.rset import ResultSet
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    37
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    38
from cubicweb.utils import QueryCache, RepeatList
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    39
from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata
7118
e094b3d4eb95 [server] move EditedEntity class to its own module, to avoid cyclic dependency when needed from e.g. session.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7083
diff changeset
    40
from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction
e094b3d4eb95 [server] move EditedEntity class to its own module, to avoid cyclic dependency when needed from e.g. session.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7083
diff changeset
    41
from cubicweb.server.edition import EditedEntity
9448
3e7cad3967c5 [multi-sources-removal] Drop the "true" multi-sources planner
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9286
diff changeset
    42
from cubicweb.server.ssplanner import SSPlanner
10477
ee21c559f94f implement a simple statsd logger (closes #5488711)
David Douard <david.douard@logilab.fr>
parents: 10366
diff changeset
    43
from cubicweb.statsd_logger import statsd_timeit, statsd_c
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    44
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    45
ETYPE_PYOBJ_MAP[Binary] = 'Bytes'
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    46
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
    47
4722
9c13d5db03d9 pylint suggested refactorings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4719
diff changeset
    48
def empty_rset(rql, args, rqlst=None):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    49
    """build an empty result set object"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    50
    return ResultSet([], rql, args, rqlst=rqlst)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    51
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    52
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    53
# permission utilities ########################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    54
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    55
def check_no_password_selected(rqlst):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    56
    """check that Password entities are not selected"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    57
    for solution in rqlst.solutions:
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10613
diff changeset
    58
        for var, etype in solution.items():
8863
98c107bd6cd0 [querier] improve 'Password selection not allowed' error message
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8697
diff changeset
    59
            if etype == 'Password':
98c107bd6cd0 [querier] improve 'Password selection not allowed' error message
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8697
diff changeset
    60
                raise Unauthorized('Password selection is not allowed (%s)' % var)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    61
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
    62
def term_etype(cnx, term, solution, args):
5419
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    63
    """return the entity type for the given term (a VariableRef or a Constant
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    64
    node)
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    65
    """
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    66
    try:
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    67
        return solution[term.name]
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    68
    except AttributeError:
11765
9cb215e833b0 [cnx] Use entity_type instead of entity_metas()['type']
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11237
diff changeset
    69
        return cnx.entity_type(term.eval(args))
5419
0b7805928a27 [repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5168
diff changeset
    70
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    71
def check_relations_read_access(cnx, select, args):
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    72
    """Raise :exc:`Unauthorized` if the given user doesn't have credentials to
10555
d8df2c7cff1a [server] typo fix
Julien Cristau <julien.cristau@logilab.fr>
parents: 10477
diff changeset
    73
    read relations used in the given syntax tree
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    74
    """
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    75
    # use `term_etype` since we've to deal with rewritten constants here,
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    76
    # when used as an external source by another repository.
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    77
    # XXX what about local read security w/ those rewritten constants...
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    78
    # XXX constants can also happen in some queries generated by req.find()
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    79
    DBG = (server.DEBUG & server.DBG_SEC) and 'read' in server._SECURITY_CAPS
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    80
    schema = cnx.repo.schema
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    81
    user = cnx.user
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    82
    if select.where is not None:
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    83
        for rel in select.where.iget_nodes(Relation):
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    84
            for solution in select.solutions:
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    85
                # XXX has_text may have specific perm ?
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    86
                if rel.r_type in READ_ONLY_RTYPES:
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    87
                    continue
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    88
                rschema = schema.rschema(rel.r_type)
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    89
                if rschema.final:
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    90
                    eschema = schema.eschema(term_etype(cnx, rel.children[0],
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    91
                                             solution, args))
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    92
                    rdef = eschema.rdef(rschema)
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    93
                else:
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    94
                    rdef = rschema.rdef(term_etype(cnx, rel.children[0],
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    95
                                                   solution, args),
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    96
                                        term_etype(cnx, rel.children[1].children[0],
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    97
                                                   solution, args))
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    98
                if not user.matching_groups(rdef.get_groups('read')):
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
    99
                    if DBG:
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   100
                        print('check_read_access: %s %s does not match %s' %
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   101
                              (rdef, user.groups, rdef.get_groups('read')))
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   102
                    # XXX rqlexpr not allowed
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   103
                    raise Unauthorized('read', rel.r_type)
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   104
                if DBG:
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   105
                    print('check_read_access: %s %s matches %s' %
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   106
                          (rdef, user.groups, rdef.get_groups('read')))
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   107
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   108
def get_local_checks(cnx, rqlst, solution):
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   109
    """Check that the given user has credentials to access data read by the
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   110
    query and return a dict defining necessary "local checks" (i.e. rql
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   111
    expression in read permission defined in the schema) where no group grants
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   112
    him the permission.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   113
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   114
    Returned dictionary's keys are variable names and values the rql expressions
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   115
    for this variable (with the given solution).
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   116
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   117
    Raise :exc:`Unauthorized` if access is known to be defined, i.e. if there is
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   118
    no matching group and no local permissions.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   119
    """
9286
02a491f6fa92 [querier/security] instrument a bit the querier read security checks
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9267
diff changeset
   120
    DBG = (server.DEBUG & server.DBG_SEC) and 'read' in server._SECURITY_CAPS
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   121
    schema = cnx.repo.schema
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   122
    user = cnx.user
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   123
    localchecks = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   124
    # iterate on defined_vars and not on solutions to ignore column aliases
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   125
    for varname in rqlst.defined_vars:
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   126
        eschema = schema.eschema(solution[varname])
3877
7ca53fc72a0a reldefsecurity branch :
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3689
diff changeset
   127
        if eschema.final:
7ca53fc72a0a reldefsecurity branch :
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3689
diff changeset
   128
            continue
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   129
        if not user.matching_groups(eschema.get_groups('read')):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   130
            erqlexprs = eschema.get_rqlexprs('read')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   131
            if not erqlexprs:
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   132
                ex = Unauthorized('read', solution[varname])
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   133
                ex.var = varname
9286
02a491f6fa92 [querier/security] instrument a bit the querier read security checks
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9267
diff changeset
   134
                if DBG:
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   135
                    print('check_read_access: %s %s %s %s' %
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   136
                          (varname, eschema, user.groups, eschema.get_groups('read')))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   137
                raise ex
5888
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   138
            # don't insert security on variable only referenced by 'NOT X relation Y' or
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   139
            # 'NOT EXISTS(X relation Y)'
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   140
            varinfo = rqlst.defined_vars[varname].stinfo
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   141
            if varinfo['selected'] or (
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   142
                len([r for r in varinfo['relations']
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   143
                     if (not schema.rschema(r.r_type).final
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   144
                         and ((isinstance(r.parent, Exists) and r.parent.neged(strict=True))
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   145
                              or isinstance(r.parent, Not)))])
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   146
                !=
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   147
                len(varinfo['relations'])):
5888
3ee80d487f11 [security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5726
diff changeset
   148
                localchecks[varname] = erqlexprs
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   149
    return localchecks
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   150
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   151
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   152
# Plans #######################################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   153
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   154
class ExecutionPlan(object):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   155
    """the execution model of a rql query, composed of querier steps"""
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   156
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   157
    def __init__(self, querier, rqlst, args, cnx):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   158
        # original rql syntax tree
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   159
        self.rqlst = rqlst
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   160
        self.args = args or {}
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   161
        # cnx executing the query
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   162
        self.cnx = cnx
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   163
        # quick reference to the system source
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   164
        self.syssource = cnx.repo.system_source
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   165
        # execution steps
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   166
        self.steps = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   167
        # various resource accesors
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   168
        self.querier = querier
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   169
        self.schema = querier.schema
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   170
        self.sqlannotate = querier.sqlgen_annotate
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   171
        self.rqlhelper = cnx.vreg.rqlhelper
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   172
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   173
    def annotate_rqlst(self):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   174
        if not self.rqlst.annotated:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   175
            self.rqlhelper.annotate(self.rqlst)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   176
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   177
    def add_step(self, step):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   178
        """add a step to the plan"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   179
        self.steps.append(step)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   180
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   181
    def sqlexec(self, sql, args=None):
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   182
        return self.syssource.sqlexec(self.cnx, sql, args)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   183
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   184
    def execute(self):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   185
        """execute a plan and return resulting rows"""
9467
ad66d7b3fd48 [multi-sources-removal] Drop no more used federated ('true') multi-sources related code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9463
diff changeset
   186
        for step in self.steps:
ad66d7b3fd48 [multi-sources-removal] Drop no more used federated ('true') multi-sources related code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9463
diff changeset
   187
            result = step.execute()
ad66d7b3fd48 [multi-sources-removal] Drop no more used federated ('true') multi-sources related code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9463
diff changeset
   188
        # the latest executed step contains the full query result
ad66d7b3fd48 [multi-sources-removal] Drop no more used federated ('true') multi-sources related code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9463
diff changeset
   189
        return result
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   190
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   191
    def preprocess(self, union, security=True):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   192
        """insert security when necessary then annotate rql st for sql generation
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   193
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   194
        return rqlst to actually execute
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   195
        """
4954
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   196
        cached = None
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   197
        if security and self.cnx.read_security:
4835
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4764
diff changeset
   198
            # ensure security is turned of when security is inserted,
13b0b96d7982 [repo] enhanced security handling: deprecates unsafe_execute, in favor of explicit read/write security control using the `enabled_security` context manager. Also code executed on the repository side is now unsafe by default.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4764
diff changeset
   199
            # else we may loop for ever...
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   200
            if self.cnx.transaction_data.get('security-rqlst-cache'):
4954
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   201
                key = self.cache_key
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   202
            else:
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   203
                key = None
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   204
            if key is not None and key in self.cnx.transaction_data:
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   205
                cachedunion, args = self.cnx.transaction_data[key]
4954
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   206
                union.children[:] = []
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   207
                for select in cachedunion.children:
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   208
                    union.append(select)
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   209
                union.has_text_query = cachedunion.has_text_query
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   210
                args.update(self.args)
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   211
                self.args = args
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   212
                cached = True
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   213
            else:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   214
                with self.cnx.security_enabled(read=False):
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   215
                    noinvariant = self._insert_security(union)
4954
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   216
                if key is not None:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   217
                    self.cnx.transaction_data[key] = (union, self.args)
4954
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   218
        else:
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   219
            noinvariant = ()
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   220
        if cached is None:
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   221
            self.rqlhelper.simplify(union)
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   222
            self.sqlannotate(union)
96f67c5be0e6 [security] experimental rqlst cache for read security: to activate using a 'security-rqlst-cache' flag in transaction data when you'll issue a lot of identic queries with only kwargs varying
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4953
diff changeset
   223
            set_qdata(self.schema.rschema, union, noinvariant)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   224
        if union.has_text_query:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   225
            self.cache_key = None
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   226
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   227
    def _insert_security(self, union):
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   228
        noinvariant = set()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   229
        for select in union.children[:]:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   230
            for subquery in select.with_:
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   231
                self._insert_security(subquery.query)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   232
            localchecks, restricted = self._check_permissions(select)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   233
            if any(localchecks):
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   234
                self.cnx.rql_rewriter.insert_local_checks(
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   235
                    select, self.args, localchecks, restricted, noinvariant)
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   236
        return noinvariant
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   237
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   238
    def _check_permissions(self, rqlst):
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   239
        """Return a dict defining "local checks", i.e. RQLExpression defined in
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   240
        the schema that should be inserted in the original query, together with
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   241
        a set of variable names which requires some security to be inserted.
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   242
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   243
        Solutions where a variable has a type which the user can't definitly
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   244
        read are removed, else if the user *may* read it (i.e. if an rql
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   245
        expression is defined for the "read" permission of the related type),
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   246
        the local checks dict is updated.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   247
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   248
        The local checks dict has entries for each different local check
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   249
        necessary, with associated solutions as value, a local check being
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   250
        defined by a list of 2-uple (variable name, rql expressions) for each
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   251
        variable which has to be checked. Solutions which don't require local
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   252
        checks will be associated to the empty tuple key.
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   253
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   254
        Note rqlst should not have been simplified at this point.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   255
        """
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   256
        cnx = self.cnx
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   257
        msgs = []
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   258
        # dict(varname: eid), allowing to check rql expression for variables
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   259
        # which have a known eid
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   260
        varkwargs = {}
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   261
        if not cnx.transaction_data.get('security-rqlst-cache'):
10663
54b8a1f249fb [py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
   262
            for var in rqlst.defined_vars.values():
5004
4cc020ee70e2 le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4957
diff changeset
   263
                if var.stinfo['constnode'] is not None:
4cc020ee70e2 le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4957
diff changeset
   264
                    eid = var.stinfo['constnode'].eval(self.args)
8748
f5027f8d2478 drop typed_eid() in favour of int() (closes #2742462)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8697
diff changeset
   265
                    varkwargs[var.name] = int(eid)
8238
087bb529035c [spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8127
diff changeset
   266
        # dictionary of variables restricted for security reason
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   267
        localchecks = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   268
        restricted_vars = set()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   269
        newsolutions = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   270
        for solution in rqlst.solutions:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   271
            try:
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   272
                localcheck = get_local_checks(cnx, rqlst, solution)
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8694
diff changeset
   273
            except Unauthorized as ex:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   274
                msg = 'remove %s from solutions since %s has no %s access to %s'
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   275
                msg %= (solution, cnx.user.login, ex.args[0], ex.args[1])
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   276
                msgs.append(msg)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   277
                LOGGER.info(msg)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   278
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   279
                newsolutions.append(solution)
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   280
                # try to benefit of rqlexpr.check cache for entities which
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   281
                # are specified by eid in query'args
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10613
diff changeset
   282
                for varname, eid in varkwargs.items():
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   283
                    try:
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   284
                        rqlexprs = localcheck.pop(varname)
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   285
                    except KeyError:
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   286
                        continue
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   287
                    # if entity has been added in the current transaction, the
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   288
                    # user can read it whatever rql expressions are associated
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   289
                    # to its type
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   290
                    if cnx.added_in_transaction(eid):
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   291
                        continue
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   292
                    for rqlexpr in rqlexprs:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   293
                        if rqlexpr.check(cnx, eid):
4953
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   294
                            break
c8c0e10dbd97 [read security] minor optimizations
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4843
diff changeset
   295
                    else:
12172
8bb323eb6859 [querier] Fix typo in Unauthorized message exception
Philippe Pepiot <philippe.pepiot@logilab.fr>
parents: 12062
diff changeset
   296
                        raise Unauthorized('No read access on %r with eid %i.' % (var, eid))
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   297
                # mark variables protected by an rql expression
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   298
                restricted_vars.update(localcheck)
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   299
                # turn local check into a dict key
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10613
diff changeset
   300
                localcheck = tuple(sorted(localcheck.items()))
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   301
                localchecks.setdefault(localcheck, []).append(solution)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   302
        # raise Unautorized exception if the user can't access to any solution
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   303
        if not newsolutions:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   304
            raise Unauthorized('\n'.join(msgs))
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   305
        # if there is some message, solutions have been modified and must be
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8867
diff changeset
   306
        # reconsidered by the syntax treee
6128
fbb8398f80dc cleanups
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5989
diff changeset
   307
        if msgs:
fbb8398f80dc cleanups
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5989
diff changeset
   308
            rqlst.set_possible_types(newsolutions)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   309
        return localchecks, restricted_vars
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   310
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   311
    def finalize(self, select, solutions, insertedvars):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   312
        rqlst = Union()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   313
        rqlst.append(select)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   314
        for mainvarname, rschema, newvarname in insertedvars:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   315
            nvartype = str(rschema.objects(solutions[0][mainvarname])[0])
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   316
            for sol in solutions:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   317
                sol[newvarname] = nvartype
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   318
        select.clean_solutions(solutions)
6129
fea746b60093 [ms] fix two planner bugs: one occuring query such as X created_by U where X in a external source and U may come from an ldap source. The other being that when we've to merge input maps, we were modifying the same tree/solutions while a copy were needed. Also, ensure we add type restrictions, necessary for pyro source
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6128
diff changeset
   319
        add_types_restriction(self.schema, select)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   320
        self.rqlhelper.annotate(rqlst)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   321
        self.preprocess(rqlst, security=False)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   322
        return rqlst
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   323
4759
af2e6c377c71 cleanups
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4722
diff changeset
   324
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   325
class InsertPlan(ExecutionPlan):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   326
    """an execution model specific to the INSERT rql query
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   327
    """
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   328
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   329
    def __init__(self, querier, rqlst, args, cnx):
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   330
        ExecutionPlan.__init__(self, querier, rqlst, args, cnx)
10903
da30851f9706 spelling: *aly → *ally
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10759
diff changeset
   331
        # save originally selected variable, we may modify this
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   332
        # dictionary for substitution (query parameters)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   333
        self.selected = rqlst.selection
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   334
        # list of rows of entities definition (ssplanner.EditedEntity)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   335
        self.e_defs = [[]]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   336
        # list of new relation definition (3-uple (from_eid, r_type, to_eid)
5657
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   337
        self.r_defs = set()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   338
        # indexes to track entity definitions bound to relation definitions
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   339
        self._r_subj_index = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   340
        self._r_obj_index = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   341
        self._expanded_r_defs = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   342
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   343
    def add_entity_def(self, edef):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   344
        """add an entity definition to build"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   345
        self.e_defs[-1].append(edef)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   346
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   347
    def add_relation_def(self, rdef):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   348
        """add an relation definition to build"""
12241
06deb43c23c3 [querier] Expand 'rdef' argument in InsertPlan.add_relation_def()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12172
diff changeset
   349
        edef, rtype, value = rdef
12242
68ca7fe0ca29 [ssplanner] Prevent execution of write queries involving computed relations
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12241
diff changeset
   350
        if self.schema[rtype].rule:
68ca7fe0ca29 [ssplanner] Prevent execution of write queries involving computed relations
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12241
diff changeset
   351
            raise QueryError("'%s' is a computed relation" % rtype)
5657
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   352
        self.r_defs.add(rdef)
12241
06deb43c23c3 [querier] Expand 'rdef' argument in InsertPlan.add_relation_def()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12172
diff changeset
   353
        if not isinstance(edef, int):
06deb43c23c3 [querier] Expand 'rdef' argument in InsertPlan.add_relation_def()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12172
diff changeset
   354
            self._r_subj_index.setdefault(edef, []).append(rdef)
06deb43c23c3 [querier] Expand 'rdef' argument in InsertPlan.add_relation_def()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12172
diff changeset
   355
        if not isinstance(value, int):
06deb43c23c3 [querier] Expand 'rdef' argument in InsertPlan.add_relation_def()
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 12172
diff changeset
   356
            self._r_obj_index.setdefault(value, []).append(rdef)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   357
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   358
    def substitute_entity_def(self, edef, edefs):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   359
        """substitute an incomplete entity definition by a list of complete
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   360
        equivalents
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   361
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   362
        e.g. on queries such as ::
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   363
          INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   364
          WHERE U login 'admin', U login N
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   365
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   366
        X will be inserted as many times as U exists, and so the X travaille Y
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   367
        relations as to be added as many time as X is inserted
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   368
        """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   369
        if not edefs or not self.e_defs:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   370
            # no result, no entity will be created
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   371
            self.e_defs = ()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   372
            return
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   373
        # first remove the incomplete entity definition
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   374
        colidx = self.e_defs[0].index(edef)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   375
        for i, row in enumerate(self.e_defs[:]):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   376
            self.e_defs[i][colidx] = edefs[0]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   377
            samplerow = self.e_defs[i]
5657
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   378
            for edef_ in edefs[1:]:
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   379
                row = [ed.clone() for i, ed in enumerate(samplerow)
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   380
                       if i != colidx]
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   381
                row.insert(colidx, edef_)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   382
                self.e_defs.append(row)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   383
        # now, see if this entity def is referenced as subject in some relation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   384
        # definition
8697
574bb05e40a4 [toward py3k] rewrite has_key() (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8696
diff changeset
   385
        if edef in self._r_subj_index:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   386
            for rdef in self._r_subj_index[edef]:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   387
                expanded = self._expanded(rdef)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   388
                result = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   389
                for exp_rdef in expanded:
5657
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   390
                    for edef_ in edefs:
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   391
                        result.append( (edef_, exp_rdef[1], exp_rdef[2]) )
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   392
                self._expanded_r_defs[rdef] = result
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   393
        # and finally, see if this entity def is referenced as object in some
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   394
        # relation definition
8697
574bb05e40a4 [toward py3k] rewrite has_key() (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8696
diff changeset
   395
        if edef in self._r_obj_index:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   396
            for rdef in self._r_obj_index[edef]:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   397
                expanded = self._expanded(rdef)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   398
                result = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   399
                for exp_rdef in expanded:
5657
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   400
                    for edef_ in edefs:
8f56691f01de [querier] test and fix potential bug in insertion query with multiple relations inside, caused by a name conflict. Also fix another bug non reproduced by using a set instead of a list (list may leads to compare entity instances which isn't allowed).
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5596
diff changeset
   401
                        result.append( (exp_rdef[0], exp_rdef[1], edef_) )
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   402
                self._expanded_r_defs[rdef] = result
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   403
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   404
    def _expanded(self, rdef):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   405
        """return expanded value for the given relation definition"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   406
        try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   407
            return self._expanded_r_defs[rdef]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   408
        except KeyError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   409
            self.r_defs.remove(rdef)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   410
            return [rdef]
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   411
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   412
    def relation_defs(self):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   413
        """return the list for relation definitions to insert"""
10663
54b8a1f249fb [py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
   414
        for rdefs in self._expanded_r_defs.values():
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   415
            for rdef in rdefs:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   416
                yield rdef
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   417
        for rdef in self.r_defs:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   418
            yield rdef
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   419
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   420
    def insert_entity_defs(self):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   421
        """return eids of inserted entities in a suitable form for the resulting
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   422
        result set, e.g.:
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   423
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   424
        e.g. on queries such as ::
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   425
          INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   426
          WHERE U login 'admin', U login N
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   427
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   428
        if there is two entities matching U, the result set will look like
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   429
        [(eidX1, eidY1), (eidX2, eidY2)]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   430
        """
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   431
        cnx = self.cnx
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   432
        repo = cnx.repo
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   433
        results = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   434
        for row in self.e_defs:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   435
            results.append([repo.glob_add_entity(cnx, edef)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   436
                            for edef in row])
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   437
        return results
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   438
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   439
    def insert_relation_defs(self):
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   440
        cnx = self.cnx
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   441
        repo = cnx.repo
7237
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   442
        edited_entities = {}
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   443
        relations = {}
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   444
        for subj, rtype, obj in self.relation_defs():
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   445
            # if a string is given into args instead of an int, we get it here
10612
84468b90e9c1 [py3k] basestring → six.string_types
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10609
diff changeset
   446
            if isinstance(subj, string_types):
8748
f5027f8d2478 drop typed_eid() in favour of int() (closes #2742462)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8697
diff changeset
   447
                subj = int(subj)
10613
8d9fe02387e3 [py3k] six.integer_types
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10612
diff changeset
   448
            elif not isinstance(subj, integer_types):
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   449
                subj = subj.entity.eid
10612
84468b90e9c1 [py3k] basestring → six.string_types
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10609
diff changeset
   450
            if isinstance(obj, string_types):
8748
f5027f8d2478 drop typed_eid() in favour of int() (closes #2742462)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8697
diff changeset
   451
                obj = int(obj)
10613
8d9fe02387e3 [py3k] six.integer_types
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10612
diff changeset
   452
            elif not isinstance(obj, integer_types):
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   453
                obj = obj.entity.eid
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   454
            if repo.schema.rschema(rtype).inlined:
7237
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   455
                if subj not in edited_entities:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   456
                    entity = cnx.entity_from_eid(subj)
7237
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   457
                    edited = EditedEntity(entity)
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   458
                    edited_entities[subj] = edited
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   459
                else:
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   460
                    edited = edited_entities[subj]
6142
8bc6eac1fac1 [session] cleanup hook / operation / entity edition api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   461
                edited.edited_attribute(rtype, obj)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   462
            else:
7237
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   463
                if rtype in relations:
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   464
                    relations[rtype].append((subj, obj))
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   465
                else:
9f619715665b [server] improve the speed of setting relations between entities (closes #1625257)
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7139
diff changeset
   466
                    relations[rtype] = [(subj, obj)]
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   467
        repo.glob_add_relations(cnx, relations)
10663
54b8a1f249fb [py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
   468
        for edited in edited_entities.values():
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   469
            repo.glob_update_entity(cnx, edited)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   470
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   471
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   472
class QuerierHelper(object):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   473
    """helper class to execute rql queries, putting all things together"""
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   474
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   475
    def __init__(self, repo, schema):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   476
        # system info helper
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   477
        self._repo = repo
2476
1294a6bdf3bf application -> instance where it makes sense
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2101
diff changeset
   478
        # instance schema
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   479
        self.set_schema(schema)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   480
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   481
    def set_schema(self, schema):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   482
        self.schema = schema
12062
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   483
        self.clear_caches()
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   484
        rqlhelper = self._repo.vreg.rqlhelper
5174
78438ad513ca #759035: Automate addition of eid cachekey in RQL analysis
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5082
diff changeset
   485
        self._annotate = rqlhelper.annotate
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   486
        # rql planner
9448
3e7cad3967c5 [multi-sources-removal] Drop the "true" multi-sources planner
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9286
diff changeset
   487
        self._planner = SSPlanner(schema, rqlhelper)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   488
        # sql generation annotator
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   489
        self.sqlgen_annotate = SQLGenAnnotator(schema).annotate
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   490
12062
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   491
    def clear_caches(self, eids=None, etypes=None):
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   492
        if eids is None:
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   493
            self.rql_cache = RQLCache(self._repo, self.schema)
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   494
        else:
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   495
            cache = self.rql_cache
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   496
            for eid, etype in zip(eids, etypes):
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   497
                cache.pop(('Any X WHERE X eid %s' % eid,), None)
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   498
                if etype is not None:
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   499
                    cache.pop(('%s X WHERE X eid %s' % (etype, eid),), None)
601d65193619 [repo] Introduce a clear_caches method on the Querier class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12060
diff changeset
   500
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   501
    def plan_factory(self, rqlst, args, cnx):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   502
        """create an execution plan for an INSERT RQL query"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   503
        if rqlst.TYPE == 'insert':
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   504
            return InsertPlan(self, rqlst, args, cnx)
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   505
        return ExecutionPlan(self, rqlst, args, cnx)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   506
10477
ee21c559f94f implement a simple statsd logger (closes #5488711)
David Douard <david.douard@logilab.fr>
parents: 10366
diff changeset
   507
    @statsd_timeit
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   508
    def execute(self, cnx, rql, args=None, build_descr=True):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   509
        """execute a rql query, return resulting rows and their description in
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   510
        a `ResultSet` object
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   511
9701
46c8d8701240 an unicode string -> a unicode string
Rémi Cardona <remi.cardona@logilab.fr>
parents: 9286
diff changeset
   512
        * `rql` should be a Unicode string or a plain ASCII string
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   513
        * `args` the optional parameters dictionary associated to the query
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   514
        * `build_descr` is a boolean flag indicating if the description should
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   515
          be built on select queries (if false, the description will be en empty
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   516
          list)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   517
4654
717310b3d576 docstring improvement
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 4533
diff changeset
   518
        on INSERT queries, there will be one row with the eid of each inserted
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   519
        entity
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1133
diff changeset
   520
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   521
        result for DELETE and SET queries is undefined yet
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   522
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   523
        to maximize the rql parsing/analyzing cache performance, you should
4654
717310b3d576 docstring improvement
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 4533
diff changeset
   524
        always use substitute arguments in queries (i.e. avoid query such as
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   525
        'Any X WHERE X eid 123'!)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   526
        """
2621
1b9d08840a0e R [querier] debugging tweaks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2601
diff changeset
   527
        if server.DEBUG & (server.DBG_RQL | server.DBG_SQL):
2629
0d445c2171e4 R [querier] debugging tweaks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2621
diff changeset
   528
            if server.DEBUG & (server.DBG_MORE | server.DBG_SQL):
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   529
                print('*'*80)
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10555
diff changeset
   530
            print('querier input', repr(rql), repr(args))
5174
78438ad513ca #759035: Automate addition of eid cachekey in RQL analysis
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5082
diff changeset
   531
        try:
12060
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   532
            rqlst, cachekey = self.rql_cache.get(cnx, rql, args)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   533
        except UnknownEid:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   534
            # we want queries such as "Any X WHERE X eid 9999"
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   535
            # return an empty result instead of raising UnknownEid
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   536
            return empty_rset(rql, args)
5072
072ae171aeb0 [cleanup] style fixes, add nodes, 0.2 cents refactorings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4957
diff changeset
   537
        if rqlst.TYPE != 'select':
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   538
            if cnx.read_security:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   539
                check_no_password_selected(rqlst)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   540
            cachekey = None
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   541
        else:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   542
            if cnx.read_security:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   543
                for select in rqlst.children:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   544
                    check_no_password_selected(select)
9954
79d34ba48612 [CWEP002] refactor rql read security checking
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9892
diff changeset
   545
                    check_relations_read_access(cnx, select, args)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   546
            # on select query, always copy the cached rqlst so we don't have to
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   547
            # bother modifying it. This is not necessary on write queries since
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   548
            # a new syntax tree is built from them.
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   549
            rqlst = rqlst.copy()
9955
60a9cd1b3a4b [CWEP002] Plug the computed relation rewriter in the querier
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 9954
diff changeset
   550
            # Rewrite computed relations
60a9cd1b3a4b [CWEP002] Plug the computed relation rewriter in the querier
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 9954
diff changeset
   551
            rewriter = RQLRelationRewriter(cnx)
60a9cd1b3a4b [CWEP002] Plug the computed relation rewriter in the querier
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 9954
diff changeset
   552
            rewriter.rewrite(rqlst, args)
3240
8604a15995d1 refactor so that rql rewriter may be used outside the server. Enhance it to be usable for RRQLExpression as well
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3171
diff changeset
   553
            self._annotate(rqlst)
8127
96d343a5e01b [rql2sql] None for attributes in kwargs generate IS NULL, so should be considered in sql cache key. Closes #2116693
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7954
diff changeset
   554
            if args:
8342
7a5271182ef0 [rql annotation] fix has_text_query detection (if coming from sub-query and if has_text on a column aliases. Closes #2275322
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8333
diff changeset
   555
                # different SQL generated when some argument is None or not (IS
8127
96d343a5e01b [rql2sql] None for attributes in kwargs generate IS NULL, so should be considered in sql cache key. Closes #2116693
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7954
diff changeset
   556
                # NULL). This should be considered when computing sql cache key
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10613
diff changeset
   557
                cachekey += tuple(sorted([k for k, v in args.items()
8127
96d343a5e01b [rql2sql] None for attributes in kwargs generate IS NULL, so should be considered in sql cache key. Closes #2116693
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7954
diff changeset
   558
                                          if v is None]))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   559
        # make an execution plan
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   560
        plan = self.plan_factory(rqlst, args, cnx)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   561
        plan.cache_key = cachekey
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   562
        self._planner.build_plan(plan)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   563
        # execute the plan
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   564
        try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   565
            results = plan.execute()
6361
843684a50e48 [transaction] to avoid potential db corruption, we should rollback systematically in case of ValidationError
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   566
        except (Unauthorized, ValidationError):
843684a50e48 [transaction] to avoid potential db corruption, we should rollback systematically in case of ValidationError
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6129
diff changeset
   567
            # getting an Unauthorized/ValidationError exception means the
9267
24d9b86dfa54 spelling: rollbacked -> rolled back
Rémi Cardona <remi.cardona@logilab.fr>
parents: 9167
diff changeset
   568
            # transaction must be rolled back
4532
85116e75f561 fix auto-rollback on unauthorized error:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   569
            #
85116e75f561 fix auto-rollback on unauthorized error:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   570
            # notes:
7398
26695dd703d8 [repository api] definitly kill usage of word 'pool' to refer to connections set used by a session
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7237
diff changeset
   571
            # * we should not reset the connections set here, since we don't want the
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   572
            #   connection to loose it during processing
4532
85116e75f561 fix auto-rollback on unauthorized error:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   573
            # * don't rollback if we're in the commit process, will be handled
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   574
            #   by the connection
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   575
            if cnx.commit_state is None:
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   576
                cnx.commit_state = 'uncommitable'
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   577
            raise
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   578
        # build a description for the results if necessary
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   579
        descr = ()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   580
        if build_descr:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   581
            if rqlst.TYPE == 'select':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   582
                # sample selection
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   583
                if len(rqlst.children) == 1 and len(rqlst.children[0].solutions) == 1:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   584
                    # easy, all lines are identical
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   585
                    selected = rqlst.children[0].selection
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   586
                    solution = rqlst.children[0].solutions[0]
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   587
                    description = _make_description(selected, args, solution)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   588
                    descr = RepeatList(len(results), tuple(description))
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   589
                else:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   590
                    # hard, delegate the work :o)
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   591
                    descr = manual_build_descr(cnx, rqlst, args, results)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   592
            elif rqlst.TYPE == 'insert':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   593
                # on insert plan, some entities may have been auto-casted,
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   594
                # so compute description manually even if there is only
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   595
                # one solution
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   596
                basedescr = [None] * len(plan.selected)
10759
774b53f7dc3a [py3k] fix building rset description for INSERT queries
Julien Cristau <julien.cristau@logilab.fr>
parents: 10675
diff changeset
   597
                todetermine = list(zip(range(len(plan.selected)), repeat(False)))
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   598
                descr = _build_descr(cnx, results, basedescr, todetermine)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   599
            # FIXME: get number of affected entities / relations on non
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   600
            # selection queries ?
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   601
        # return a result set object
10087
ed0b076c119b [rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 9990
diff changeset
   602
        return ResultSet(results, rql, args, descr)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   603
7083
b8e35cde46e9 help pylint by explicitely defining some attributes
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7027
diff changeset
   604
    # these are overridden by set_log_methods below
b8e35cde46e9 help pylint by explicitely defining some attributes
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7027
diff changeset
   605
    # only defining here to prevent pylint from complaining
b8e35cde46e9 help pylint by explicitely defining some attributes
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7027
diff changeset
   606
    info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
b8e35cde46e9 help pylint by explicitely defining some attributes
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7027
diff changeset
   607
12051
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   608
12060
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   609
class RQLCache(object):
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   610
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   611
    def __init__(self, repo, schema):
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   612
        # rql st and solution cache.
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   613
        self._cache = QueryCache(repo.config['rql-cache-size'])
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   614
        # rql cache key cache. Don't bother using a Cache instance: we should
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   615
        # have a limited number of queries in there, since there are no entries
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   616
        # in this cache for user queries (which have no args)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   617
        self._ck_cache = {}
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   618
        # some cache usage stats
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   619
        self.cache_hit, self.cache_miss = 0, 0
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   620
        # rql parsing / analysing helper
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   621
        self.solutions = repo.vreg.solutions
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   622
        rqlhelper = repo.vreg.rqlhelper
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   623
        # set backend on the rql helper, will be used for function checking
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   624
        rqlhelper.backend = repo.config.system_source_config['db-driver']
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   625
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   626
        def parse(rql, annotate=False, parse=rqlhelper.parse):
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   627
            """Return a freshly parsed syntax tree for the given RQL."""
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   628
            try:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   629
                return parse(text_type(rql), annotate=annotate)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   630
            except UnicodeError:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   631
                raise RQLSyntaxError(rql)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   632
        self._parse = parse
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   633
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   634
    def __len__(self):
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   635
        return len(self._cache)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   636
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   637
    def get(self, cnx, rql, args):
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   638
        """Return syntax tree and cache key for the given RQL.
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   639
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   640
        Returned syntax tree is cached and must not be modified
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   641
        """
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   642
        # parse the query and binds variables
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   643
        cachekey = (rql,)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   644
        try:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   645
            if args:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   646
                # search for named args in query which are eids (hence
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   647
                # influencing query's solutions)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   648
                eidkeys = self._ck_cache[rql]
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   649
                if eidkeys:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   650
                    # if there are some, we need a better cache key, eg (rql +
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   651
                    # entity type of each eid)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   652
                    cachekey = _rql_cache_key(cnx, rql, args, eidkeys)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   653
            rqlst = self._cache[cachekey]
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   654
            self.cache_hit += 1
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   655
            statsd_c('cache_hit')
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   656
        except KeyError:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   657
            self.cache_miss += 1
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   658
            statsd_c('cache_miss')
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   659
            rqlst = self._parse(rql)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   660
            # compute solutions for rqlst and return named args in query
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   661
            # which are eids. Notice that if you may not need `eidkeys`, we
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   662
            # have to compute solutions anyway (kept as annotation on the
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   663
            # tree)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   664
            eidkeys = self.solutions(cnx, rqlst, args)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   665
            if args and rql not in self._ck_cache:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   666
                self._ck_cache[rql] = eidkeys
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   667
                if eidkeys:
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   668
                    cachekey = _rql_cache_key(cnx, rql, args, eidkeys)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   669
            self._cache[cachekey] = rqlst
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   670
        return rqlst, cachekey
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   671
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   672
    def pop(self, key, *args):
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   673
        """Pop a key from the cache."""
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   674
        self._cache.pop(key, *args)
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   675
0cdf5fafd234 [repo] Extract rql cache handling to a dedicated class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 12051
diff changeset
   676
12051
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   677
def _rql_cache_key(cnx, rql, args, eidkeys):
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   678
    cachekey = [rql]
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   679
    type_from_eid = cnx.repo.type_from_eid
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   680
    for key in sorted(eidkeys):
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   681
        try:
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   682
            etype = type_from_eid(args[key], cnx)
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   683
        except KeyError:
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   684
            raise QueryError('bad cache key %s (no value)' % key)
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   685
        except TypeError:
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   686
            raise QueryError('bad cache key %s (value: %r)' % (
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   687
                key, args[key]))
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   688
        cachekey.append(etype)
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   689
        # ensure eid is correctly typed in args
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   690
        args[key] = int(args[key])
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   691
    return tuple(cachekey)
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   692
bff3be6eebed [querier] Turn repo.querier_cache_key into a private function
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11767
diff changeset
   693
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   694
from logging import getLogger
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   695
from cubicweb import set_log_methods
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   696
LOGGER = getLogger('cubicweb.querier')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   697
set_log_methods(QuerierHelper, LOGGER)
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   698
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   699
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   700
def manual_build_descr(cnx, rqlst, args, result):
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   701
    """build a description for a given result by analysing each row
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   702
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   703
    XXX could probably be done more efficiently during execution of query
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   704
    """
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   705
    # not so easy, looks for variable which changes from one solution
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   706
    # to another
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   707
    unstables = rqlst.get_variable_indices()
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   708
    basedescr = []
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   709
    todetermine = []
10609
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10589
diff changeset
   710
    for i in range(len(rqlst.children[0].selection)):
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   711
        ttype = _selection_idx_type(i, rqlst, args)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   712
        if ttype is None or ttype == 'Any':
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   713
            ttype = None
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   714
            isfinal = True
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   715
        else:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   716
            isfinal = ttype in BASE_TYPES
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   717
        if ttype is None or i in unstables:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   718
            basedescr.append(None)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   719
            todetermine.append( (i, isfinal) )
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   720
        else:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   721
            basedescr.append(ttype)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   722
    if not todetermine:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   723
        return RepeatList(len(result), tuple(basedescr))
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   724
    return _build_descr(cnx, result, basedescr, todetermine)
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   725
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   726
def _build_descr(cnx, result, basedescription, todetermine):
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   727
    description = []
11765
9cb215e833b0 [cnx] Use entity_type instead of entity_metas()['type']
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11237
diff changeset
   728
    entity_type = cnx.entity_type
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   729
    todel = []
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   730
    for i, row in enumerate(result):
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   731
        row_descr = basedescription[:]
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   732
        for index, isfinal in todetermine:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   733
            value = row[index]
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   734
            if value is None:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   735
                # None value inserted by an outer join, no type
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   736
                row_descr[index] = None
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   737
                continue
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   738
            if isfinal:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   739
                row_descr[index] = etype_from_pyobj(value)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   740
            else:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   741
                try:
11765
9cb215e833b0 [cnx] Use entity_type instead of entity_metas()['type']
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11237
diff changeset
   742
                    row_descr[index] = entity_type(value)
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   743
                except UnknownEid:
9508
1263f1258796 [server] rename session to cnx in querier and plan
Julien Cristau <julien.cristau@logilab.fr>
parents: 9469
diff changeset
   744
                    cnx.error('wrong eid %s in repository, you should '
8542
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   745
                             'db-check the database' % value)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   746
                    todel.append(i)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   747
                    break
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   748
        else:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   749
            description.append(tuple(row_descr))
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   750
    for i in reversed(todel):
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   751
        del result[i]
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   752
    return description
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   753
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   754
def _make_description(selected, args, solution):
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   755
    """return a description for a result set"""
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   756
    description = []
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   757
    for term in selected:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   758
        description.append(term.get_type(solution, args))
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   759
    return description
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   760
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   761
def _selection_idx_type(i, rqlst, args):
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   762
    """try to return type of term at index `i` of the rqlst's selection"""
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   763
    for select in rqlst.children:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   764
        term = select.selection[i]
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   765
        for solution in select.solutions:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   766
            try:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   767
                ttype = term.get_type(solution, args)
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   768
                if ttype is not None:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   769
                    return ttype
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   770
            except CoercionError:
7e264ce34cd4 [session / querier] reorganize code to building result set descriptions
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8342
diff changeset
   771
                return None