cubicweb/server/sources/rql2sql.py
author Denis Laxalde <denis.laxalde@logilab.fr>
Fri, 05 Apr 2019 17:58:19 +0200
changeset 12567 26744ad37953
parent 12296 23bc9f385645
child 12828 dadbd4148a44
permissions -rw-r--r--
Drop python2 support This mostly consists in removing the dependency on "six" and updating the code to use only Python3 idioms. Notice that we previously used TemporaryDirectory from cubicweb.devtools.testlib for compatibility with Python2. We now directly import it from tempfile.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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: 5280
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
"""RQL to SQL generator for native sources.
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    19
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    20
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    21
SQL queries optimization
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    22
~~~~~~~~~~~~~~~~~~~~~~~~
1398
5fe84a5f7035 rename internal entity types to have CW prefix instead of E
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
    23
1. CWUser X WHERE X in_group G, G name 'users':
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    24
1398
5fe84a5f7035 rename internal entity types to have CW prefix instead of E
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
    25
   CWUser is the only subject entity type for the in_group relation,
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    26
   which allow us to do ::
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    27
1398
5fe84a5f7035 rename internal entity types to have CW prefix instead of E
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
    28
     SELECT eid_from FROM in_group, CWGroup
5fe84a5f7035 rename internal entity types to have CW prefix instead of E
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
    29
     WHERE in_group.eid_to = CWGroup.eid_from
5fe84a5f7035 rename internal entity types to have CW prefix instead of E
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
    30
     AND CWGroup.name = 'users'
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    31
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    32
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    33
2. Any X WHERE X nonfinal1 Y, Y nonfinal2 Z
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    34
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    35
   -> direct join between nonfinal1 and nonfinal2, whatever X,Y, Z (unless
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    36
      inlined...)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
    37
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    38
      NOT IMPLEMENTED (and quite hard to implement)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    39
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    40
Potential optimization information is collected by the querier, sql generation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    41
is done according to this information
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    42
5280
7e13bb484a19 added note about interesting page about SQL implementation differences
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 5013
diff changeset
    43
cross RDMS note : read `Comparison of different SQL implementations`_
7e13bb484a19 added note about interesting page about SQL implementation differences
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 5013
diff changeset
    44
by Troels Arvin. Features SQL ISO Standard, PG, mysql, Oracle, MS SQL, DB2
7e13bb484a19 added note about interesting page about SQL implementation differences
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 5013
diff changeset
    45
and Informix.
7e13bb484a19 added note about interesting page about SQL implementation differences
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 5013
diff changeset
    46
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
    47
.. _Comparison of different SQL implementations: http://www.troels.arvin.dk/db/rdbms
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
    48
"""
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    49
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    50
import threading
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    51
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    52
from logilab.database import FunctionDescr, SQL_FUNCTIONS_REGISTRY
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    53
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    54
from rql import BadRQLQuery, CoercionError
7672
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
    55
from rql.utils import common_parent
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    56
from rql.stmts import Union, Select
9468
39b7a91a3f4c [repo] pylint cleanup, mainly of imports, with a bit of style
Julien Cristau <julien.cristau@logilab.fr>
parents: 9361
diff changeset
    57
from rql.nodes import (VariableRef, Constant, Function, Variable, Or,
39b7a91a3f4c [repo] pylint cleanup, mainly of imports, with a bit of style
Julien Cristau <julien.cristau@logilab.fr>
parents: 9361
diff changeset
    58
                       Not, Comparison, ColumnAlias, Relation, SubQuery)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    59
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    60
from cubicweb import QueryError
9167
c05652b108ce [rql rewrite] move some code from querier to rqlrewrite where it makes more sense.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8894
diff changeset
    61
from cubicweb.rqlrewrite import cleanup_solutions
1251
af40e615dc89 introduce a 'cw_' prefix on entity table and column names so we don't conflict with sql or DBMS specific keywords
sylvain.thenault@logilab.fr
parents: 1124
diff changeset
    62
from cubicweb.server.sqlutils import SQL_PREFIX
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    63
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    64
get_func_descr = SQL_FUNCTIONS_REGISTRY.get_function
4794
81075b09ebf1 [rql2sql] fix potential crash when testing _q_invariant on a ColumnAlias instead of a Variable by always considering _q_invariant to false for them
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4719
diff changeset
    65
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    66
ColumnAlias._q_invariant = False  # avoid to check for ColumnAlias / Variable
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    67
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    68
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    69
def default_update_cb_stack(self, stack):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    70
    stack.append(self.source_execute)
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    71
FunctionDescr.update_cb_stack = default_update_cb_stack
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    72
FunctionDescr.source_execute = None
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    73
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    74
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    75
def length_source_execute(source, session, value):
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    76
    return len(value.getvalue())
7421
5115daeeb2ff [rql2sql] closes #1697862: ORDERBY SUM(C) cancel GROUPBY by wrongly adding C to grouped variables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7396
diff changeset
    77
5115daeeb2ff [rql2sql] closes #1697862: ORDERBY SUM(C) cancel GROUPBY by wrongly adding C to grouped variables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7396
diff changeset
    78
LENGTH = get_func_descr('LENGTH')
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    79
LENGTH.source_execute = length_source_execute
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
    80
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    81
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
    82
def _new_var(select, varname):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    83
    newvar = select.get_variable(varname)
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    84
    if 'relations' not in newvar.stinfo:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    85
        # not yet initialized
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    86
        newvar.prepare_annotation()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    87
        newvar.stinfo['scope'] = select
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    88
        newvar._q_invariant = False
7252
adb1673efa5f [sql generation] fix crash on outer join + ambiguous inlined relation + attribute selection
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7194
diff changeset
    89
        select.selection.append(VariableRef(newvar))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    90
    return newvar
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    91
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    92
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    93
def _fill_to_wrap_rel(var, newselect, towrap, schema):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    94
    for rel in var.stinfo['relations'] - var.stinfo['rhsrelations']:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    95
        rschema = schema.rschema(rel.r_type)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    96
        if rschema.inlined:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
    97
            towrap.add((var, rel))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    98
            for vref in rel.children[1].iget_nodes(VariableRef):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    99
                newivar = _new_var(newselect, vref.name)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   100
                _fill_to_wrap_rel(vref.variable, newselect, towrap, schema)
3689
deb13e88e037 follow yams 0.25 api changes to improve performance
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3245
diff changeset
   101
        elif rschema.final:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   102
            towrap.add((var, rel))
7252
adb1673efa5f [sql generation] fix crash on outer join + ambiguous inlined relation + attribute selection
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7194
diff changeset
   103
            for vref in rel.children[1].iget_nodes(VariableRef):
adb1673efa5f [sql generation] fix crash on outer join + ambiguous inlined relation + attribute selection
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7194
diff changeset
   104
                newivar = _new_var(newselect, vref.name)
adb1673efa5f [sql generation] fix crash on outer join + ambiguous inlined relation + attribute selection
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7194
diff changeset
   105
                newivar.stinfo['attrvar'] = (var, rel.r_type)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   106
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   107
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   108
def rewrite_unstable_outer_join(select, solutions, unstable, schema):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   109
    """if some optional variables are unstable, they should be selected in a
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   110
    subquery. This function check this and rewrite the rql syntax tree if
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   111
    necessary (in place). Return a boolean telling if the tree has been modified
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   112
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   113
    modified = False
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   114
    for varname in tuple(unstable):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   115
        var = select.defined_vars[varname]
5004
4cc020ee70e2 le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   116
        if not var.stinfo.get('optrelations'):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   117
            continue
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   118
        unstable.remove(varname)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   119
        newselect = Select()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   120
        myunion = Union()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   121
        myunion.append(newselect)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   122
        # extract aliases / selection
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   123
        newvar = _new_var(newselect, var.name)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   124
        newselect.selection = [VariableRef(newvar)]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   125
        towrap_rels = set()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   126
        _fill_to_wrap_rel(var, newselect, towrap_rels, schema)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   127
        # extract relations
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   128
        for var, rel in towrap_rels:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   129
            newrel = rel.copy(newselect)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   130
            newselect.add_restriction(newrel)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   131
            select.remove_node(rel)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   132
            var.stinfo['relations'].remove(rel)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   133
            newvar.stinfo['relations'].add(newrel)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   134
            if rel.optional in ('left', 'both'):
5004
4cc020ee70e2 le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   135
                newvar.add_optional_relation(newrel)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   136
            for vref in newrel.children[1].iget_nodes(VariableRef):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   137
                var = vref.variable
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   138
                var.stinfo['relations'].add(newrel)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   139
                var.stinfo['rhsrelations'].add(newrel)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   140
                if rel.optional in ('right', 'both'):
5004
4cc020ee70e2 le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   141
                    var.add_optional_relation(newrel)
6050
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   142
        if not select.where and not modified:
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   143
            # oops, generated the same thing as the original select....
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   144
            # restore original query, else we'll indefinitly loop
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   145
            for var, rel in towrap_rels:
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   146
                select.add_restriction(rel)
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   147
            continue
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   148
        modified = True
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   149
        # extract subquery solutions
3736
07196bda2456 take care to already existant solutions local variable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3689
diff changeset
   150
        mysolutions = [sol.copy() for sol in solutions]
07196bda2456 take care to already existant solutions local variable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3689
diff changeset
   151
        cleanup_solutions(newselect, mysolutions)
6050
20af96a6fffc [rql2sql] add test for rql bug #37423, which triggered a cw bug fixed by this changeset (infinite loop with some queries...)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6003
diff changeset
   152
        newselect.set_possible_types(mysolutions)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   153
        # full sub-query
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   154
        aliases = [VariableRef(select.get_variable(avar.name, i))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   155
                   for i, avar in enumerate(newselect.selection)]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   156
        select.add_subquery(SubQuery(aliases, myunion), check=False)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   157
    return modified
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   158
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   159
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   160
def _new_solutions(rqlst, solutions):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   161
    """first filter out subqueries variables from solutions"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   162
    newsolutions = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   163
    for origsol in solutions:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   164
        asol = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   165
        for vname in rqlst.defined_vars:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   166
            asol[vname] = origsol[vname]
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   167
        if asol not in newsolutions:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   168
            newsolutions.append(asol)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   169
    return newsolutions
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   170
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   171
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
   172
def remove_unused_solutions(rqlst, solutions, schema):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   173
    """cleanup solutions: remove solutions where invariant variables are taking
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   174
    different types
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   175
    """
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   176
    newsols = _new_solutions(rqlst, solutions)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   177
    existssols = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   178
    unstable = set()
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   179
    invariants = {}
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10652
diff changeset
   180
    for vname, var in rqlst.defined_vars.items():
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   181
        vtype = newsols[0][vname]
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
   182
        if var._q_invariant:
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   183
            # remove invariant variable from solutions to remove duplicates
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   184
            # later, then reinserting a type for the variable even later
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   185
            for sol in newsols:
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   186
                invariants.setdefault(id(sol), {})[vname] = sol.pop(vname)
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   187
        elif var.scope is not rqlst:
10450
c5c9e5b6fde0 [server/rql2sql] fix spelling in comment
Julien Cristau <julien.cristau@logilab.fr>
parents: 9543
diff changeset
   188
            # move apart variables which are in a EXISTS scope and are variating
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   189
            try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   190
                thisexistssols, thisexistsvars = existssols[var.scope]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   191
            except KeyError:
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   192
                # copy to avoid shared dict in newsols and exists sols
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   193
                thisexistssols = [newsols[0].copy()]
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   194
                thisexistsvars = set()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   195
                existssols[var.scope] = thisexistssols, thisexistsvars
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   196
            for i in range(len(newsols) - 1, 0, -1):
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   197
                if vtype != newsols[i][vname]:
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   198
                    thisexistssols.append(newsols.pop(i))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   199
                    thisexistsvars.add(vname)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   200
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   201
            # remember unstable variables
10609
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10522
diff changeset
   202
            for i in range(1, len(newsols)):
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   203
                if vtype != newsols[i][vname]:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   204
                    unstable.add(vname)
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   205
    # remove unstable variables from exists solutions: the possible types of these variables are
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   206
    # not properly represented in exists solutions, so we have to remove and reinject them later
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   207
    # according to the outer solution (see `iter_exists_sols`)
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   208
    for sols, _ in existssols.values():
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   209
        for vname in unstable:
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   210
            for sol in sols:
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   211
                sol.pop(vname, None)
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   212
    if invariants:
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   213
        # filter out duplicates
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   214
        newsols_ = []
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   215
        for sol in newsols:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   216
            if sol not in newsols_:
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   217
                newsols_.append(sol)
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   218
        newsols = newsols_
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   219
        # reinsert solutions for invariants
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   220
        for sol in newsols:
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10652
diff changeset
   221
            for invvar, vartype in invariants[id(sol)].items():
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   222
                sol[invvar] = vartype
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   223
        for sol in existssols:
3866
2783c166ad1a fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3852
diff changeset
   224
            try:
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10652
diff changeset
   225
                for invvar, vartype in invariants[id(sol)].items():
3866
2783c166ad1a fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3852
diff changeset
   226
                    sol[invvar] = vartype
2783c166ad1a fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3852
diff changeset
   227
            except KeyError:
2783c166ad1a fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3852
diff changeset
   228
                continue
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   229
    if len(newsols) > 1:
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   230
        if rewrite_unstable_outer_join(rqlst, newsols, unstable, schema):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   231
            # remove variables extracted to subqueries from solutions
3852
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   232
            newsols = _new_solutions(rqlst, newsols)
03121ca1f85e test and fix case where remove_unsused_solutions remove some solutions that should be kept
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3815
diff changeset
   233
    return newsols, existssols, unstable
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   234
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   235
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   236
def relation_info(relation):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   237
    lhs, rhs = relation.get_variable_parts()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   238
    try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   239
        lhs = lhs.variable
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   240
        lhsconst = lhs.stinfo['constnode']
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   241
    except AttributeError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   242
        lhsconst = lhs
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   243
        lhs = None
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   244
    except KeyError:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   245
        lhsconst = None  # ColumnAlias
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   246
    try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   247
        rhs = rhs.variable
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   248
        rhsconst = rhs.stinfo['constnode']
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   249
    except AttributeError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   250
        rhsconst = rhs
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   251
        rhs = None
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   252
    except KeyError:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   253
        rhsconst = None  # ColumnAlias
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   254
    return lhs, lhsconst, rhs, rhsconst
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   255
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   256
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   257
def sort_term_selection(sorts, rqlst, groups):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   258
    # XXX beurk
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   259
    if isinstance(rqlst, list):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   260
        def append(term):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   261
            rqlst.append(term)
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   262
        selectionidx = set(str(term) for term in rqlst)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   263
    else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   264
        def append(term):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   265
            rqlst.selection.append(term.copy(rqlst))
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   266
        selectionidx = set(str(term) for term in rqlst.selection)
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   267
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   268
    for sortterm in sorts:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   269
        term = sortterm.term
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   270
        if not isinstance(term, Constant) and not str(term) in selectionidx:
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   271
            selectionidx.add(str(term))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   272
            append(term)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   273
            if groups:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   274
                for vref in term.iget_nodes(VariableRef):
10652
e3e4a8c45695 [server/rql2sql] use VariableRef.is_equivalent explicitly instead of relying on __eq__
Julien Cristau <julien.cristau@logilab.fr>
parents: 10651
diff changeset
   275
                    if not any(vref.is_equivalent(g) for g in groups):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   276
                        groups.append(vref)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   277
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   278
12296
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   279
def is_in_aggregat(node):
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   280
    while node:
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   281
        node = node.parent
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   282
        if isinstance(node, Function) and node.descr().aggregat:
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   283
            return True
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   284
    return False
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   285
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   286
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   287
def fix_selection_and_group(rqlst, needwrap, selectsortterms,
3752
4c77a1653374 when a query is grouped, ensure sort terms are grouped as well
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3736
diff changeset
   288
                            sorts, groups, having):
4c77a1653374 when a query is grouped, ensure sort terms are grouped as well
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3736
diff changeset
   289
    if selectsortterms and sorts:
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   290
        sort_term_selection(sorts, rqlst, not needwrap and groups)
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   291
    groupvrefs = [vref for term in groups for vref in term.iget_nodes(VariableRef)]
3752
4c77a1653374 when a query is grouped, ensure sort terms are grouped as well
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3736
diff changeset
   292
    if sorts and groups:
3754
a9c641f6193b document
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3752
diff changeset
   293
        # when a query is grouped, ensure sort terms are grouped as well
3752
4c77a1653374 when a query is grouped, ensure sort terms are grouped as well
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3736
diff changeset
   294
        for sortterm in sorts:
4c77a1653374 when a query is grouped, ensure sort terms are grouped as well
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3736
diff changeset
   295
            term = sortterm.term
12296
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   296
            for vref in term.iget_nodes(VariableRef):
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   297
                if not (any(vref.is_equivalent(group) for group in groupvrefs)
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   298
                        or is_in_aggregat(vref)):
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   299
                    groups.append(vref)
23bc9f385645 [rql2sql] fix handling of the ORDERBY clause when the aggregation function is "embedded"
David Douard <david.douard@logilab.fr>
parents: 12233
diff changeset
   300
                    groupvrefs.append(vref)
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   301
    if needwrap and (groups or having):
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   302
        selectedidx = set(vref.name for term in rqlst.selection
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   303
                          for vref in term.get_nodes(VariableRef))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   304
        if groups:
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   305
            for vref in groupvrefs:
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   306
                if vref.name not in selectedidx:
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   307
                    selectedidx.add(vref.name)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   308
                    rqlst.selection.append(vref)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   309
        if having:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   310
            for term in having:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   311
                for vref in term.iget_nodes(VariableRef):
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   312
                    if vref.name not in selectedidx:
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   313
                        selectedidx.add(vref.name)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   314
                        rqlst.selection.append(vref)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   315
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   316
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   317
def iter_mapped_var_sels(stmt, variable):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   318
    # variable is a Variable or ColumnAlias node mapped to a source side
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   319
    # callback
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   320
    if not (len(variable.stinfo['rhsrelations']) <= 1 and  # < 1 on column alias
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   321
            variable.stinfo['selected']):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   322
        raise QueryError("can't use %s as a restriction variable"
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   323
                         % variable.name)
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   324
    for selectidx in variable.stinfo['selected']:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   325
        vrefs = stmt.selection[selectidx].get_nodes(VariableRef)
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   326
        if len(vrefs) != 1:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   327
            raise QueryError()
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   328
        yield selectidx, vrefs[0]
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   329
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   330
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   331
def update_source_cb_stack(state, stmt, node, stack):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   332
    while True:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   333
        node = node.parent
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   334
        if node is stmt:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   335
            break
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   336
        if not isinstance(node, Function):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   337
            raise QueryError()
7421
5115daeeb2ff [rql2sql] closes #1697862: ORDERBY SUM(C) cancel GROUPBY by wrongly adding C to grouped variables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7396
diff changeset
   338
        funcd = get_func_descr(node.name)
5115daeeb2ff [rql2sql] closes #1697862: ORDERBY SUM(C) cancel GROUPBY by wrongly adding C to grouped variables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7396
diff changeset
   339
        if funcd.source_execute is None:
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   340
            raise QueryError('%s can not be called on mapped attribute'
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   341
                             % node.name)
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   342
        state.source_cb_funcs.add(node)
7421
5115daeeb2ff [rql2sql] closes #1697862: ORDERBY SUM(C) cancel GROUPBY by wrongly adding C to grouped variables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7396
diff changeset
   343
        funcd.update_cb_stack(stack)
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   344
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   345
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   346
# IGenerator implementation for RQL->SQL #######################################
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   347
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   348
class StateInfo(object):
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   349
    """this class stores data accumulated during the RQL syntax tree visit
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   350
    for later SQL generation.
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   351
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   352
    Attributes related to OUTER JOIN handling
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   353
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   354
    * `outer_chains`, list of list of strings. Each list represent a tables
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   355
      that have to be outer joined together.
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   356
8238
087bb529035c [spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7902
diff changeset
   357
    * `outer_tables`, dictionary used as index of tables used in outer join ::
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   358
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   359
        'table alias': (outertype, [conditions], [chain])
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   360
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   361
      where:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   362
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   363
      * `outertype` is one of None, 'LEFT', 'RIGHT', 'FULL'
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   364
      * `conditions` is a list of join conditions (string)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   365
      * `chain` is a list of table alias (the *outer chain*) in which the key
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   366
        alias appears
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   367
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   368
    * `outer_pending` is a dictionary containing some conditions that will have
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   369
      to be added to the outer join when the table will be turned into an
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   370
      outerjoin ::
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   371
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   372
       'table alias': [conditions]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   373
    """
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   374
    def __init__(self, select, existssols, unstablevars):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   375
        self.existssols = existssols
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   376
        self.unstablevars = unstablevars
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   377
        self.subtables = {}
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   378
        self.needs_source_cb = None
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   379
        self.subquery_source_cb = None
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   380
        self.source_cb_funcs = set()
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   381
        self.scopes = {select: 0}
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   382
        self.scope_nodes = []
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   383
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   384
    def reset(self, solution):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   385
        """reset some visit variables"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   386
        self.solution = solution
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   387
        self.count = 0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   388
        self.done = set()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   389
        self.tables = self.subtables.copy()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   390
        self.actual_tables = [[]]
10663
54b8a1f249fb [py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
   391
        for _, tsql in self.tables.values():
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   392
            self.actual_tables[-1].append(tsql)
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   393
        self.outer_chains = []
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   394
        self.outer_tables = {}
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   395
        self.outer_pending = {}
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   396
        self.duplicate_switches = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   397
        self.aliases = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   398
        self.restrictions = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   399
        self._restr_stack = []
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   400
        self._needs_source_cb = {}
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   401
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   402
    def merge_source_cbs(self, needs_source_cb):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   403
        if self.needs_source_cb is None:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   404
            self.needs_source_cb = needs_source_cb
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   405
        elif needs_source_cb != self.needs_source_cb:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   406
            raise QueryError('query fetch some source mapped attribute, some not')
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   407
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   408
    def finalize_source_cbs(self):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   409
        if self.subquery_source_cb is not None:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   410
            self.needs_source_cb.update(self.subquery_source_cb)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   411
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   412
    def add_restriction(self, restr):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   413
        if restr:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   414
            self.restrictions.append(restr)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   415
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   416
    def iter_exists_sols(self, exists):
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   417
        if exists not in self.existssols:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   418
            yield 1
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   419
            return
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   420
        thisexistssols, thisexistsvars = self.existssols[exists]
10475
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   421
        notdone_outside_vars = set()
7042
8bcf33c493f8 [sql generation] fix exists table scope pb: when iterating other solutions inner to an EXISTS subquery, we should reset variables which have this exists node as scope
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6940
diff changeset
   422
        # when iterating other solutions inner to an EXISTS subquery, we should
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   423
        # reset variables which have this EXISTS node as scope at each iteration
10663
54b8a1f249fb [py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10662
diff changeset
   424
        for var in exists.stmt.defined_vars.values():
7042
8bcf33c493f8 [sql generation] fix exists table scope pb: when iterating other solutions inner to an EXISTS subquery, we should reset variables which have this exists node as scope
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6940
diff changeset
   425
            if var.scope is exists:
8bcf33c493f8 [sql generation] fix exists table scope pb: when iterating other solutions inner to an EXISTS subquery, we should reset variables which have this exists node as scope
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6940
diff changeset
   426
                thisexistsvars.add(var.name)
10475
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   427
            elif var.name not in self.done:
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   428
                notdone_outside_vars.add(var)
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   429
        # make a copy of the outer statement's solution for later restore
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   430
        origsol = self.solution.copy()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   431
        origtables = self.tables
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   432
        done = self.done
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   433
        for thisexistssol in thisexistssols:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   434
            for vname in self.unstablevars:
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   435
                # check first if variable belong to the EXISTS's scope, else it may be missing from
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   436
                # `thisexistssol`
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   437
                if vname in thisexistsvars and thisexistssol[vname] != origsol[vname]:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   438
                    break
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   439
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   440
                self.tables = origtables.copy()
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   441
                # overwrite current outer solution by EXISTS solution (the later will be missing
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   442
                # unstable outer variables)
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   443
                self.solution.update(thisexistssol)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   444
                yield 1
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   445
                # cleanup self.done from stuff specific to EXISTS, so they will be reconsidered in
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   446
                # the next round
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   447
                for var in thisexistsvars:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   448
                    if var in done:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   449
                        done.remove(var)
10475
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   450
                for var in list(notdone_outside_vars):
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   451
                    if var.name in done and var._q_sqltable in self.tables:
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   452
                        origtables[var._q_sqltable] = self.tables[var._q_sqltable]
a1e8dbb7215b [rql2sql] Fix iter_exists_sols() excessive cleaning of _state.tables
Christophe de Vienne <christophe@unlish.com>
parents: 9543
diff changeset
   453
                        notdone_outside_vars.remove(var)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   454
                for rel in exists.iget_nodes(Relation):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   455
                    if rel in done:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   456
                        done.remove(rel)
11293
63c589e6b076 [rql2sql] Test and fix some case of sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 10677
diff changeset
   457
        # restore original solution
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   458
        self.solution = origsol
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   459
        self.tables = origtables
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   460
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   461
    def push_scope(self, scope_node):
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   462
        self.scope_nodes.append(scope_node)
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   463
        self.scopes[scope_node] = len(self.actual_tables)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   464
        self.actual_tables.append([])
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   465
        self._restr_stack.append(self.restrictions)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   466
        self.restrictions = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   467
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   468
    def pop_scope(self):
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   469
        del self.scopes[self.scope_nodes[-1]]
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   470
        self.scope_nodes.pop()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   471
        restrictions = self.restrictions
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   472
        self.restrictions = self._restr_stack.pop()
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   473
        scope = len(self.actual_tables) - 1
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   474
        # check if we have some outer chain for this scope
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   475
        matching_chains = []
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   476
        for chain in self.outer_chains:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   477
            for tablealias in chain:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   478
                if self.tables[tablealias][0] < scope:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   479
                    # chain belongs to outer scope
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   480
                    break
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   481
            else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   482
                # chain match current scope
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   483
                matching_chains.append(chain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   484
        # call to `tables_sql` will pop actual_tables
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   485
        tables = self.tables_sql(matching_chains)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   486
        # cleanup outer join related structure for tables in matching chains
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   487
        for chain in matching_chains:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   488
            self.outer_chains.remove(chain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   489
            for alias in chain:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   490
                del self.outer_tables[alias]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   491
        return restrictions, tables
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   492
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   493
    # tables handling #########################################################
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   494
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   495
    def add_table(self, table, key=None, scope=-1):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   496
        if key is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   497
            key = table
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   498
        if key in self.tables:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   499
            return
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   500
        if scope < 0:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   501
            scope = len(self.actual_tables) + scope
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   502
        self.tables[key] = (scope, table)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   503
        self.actual_tables[scope].append(table)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   504
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   505
    def alias_and_add_table(self, tablename, scope=-1):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   506
        alias = '%s%s' % (tablename, self.count)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   507
        self.count += 1
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   508
        self.add_table('%s AS %s' % (tablename, alias), alias, scope)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   509
        return alias
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   510
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   511
    def relation_table(self, relation):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   512
        """return the table alias used by the given relation"""
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   513
        if relation in self.done:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   514
            return relation._q_sqltable
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   515
        rid = 'rel_%s%s' % (relation.r_type, self.count)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   516
        # relation's table is belonging to the root scope if it is the principal
9324
a5ce068143ad [rql2sql] fix relation table scope when some variable from subquery is used. Closes #3252270
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9230
diff changeset
   517
        # table of one of its variable and that variable belong's to parent
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   518
        # scope
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   519
        for varref in relation.iget_nodes(VariableRef):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   520
            var = varref.variable
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   521
            # XXX may have a principal without being invariant for this generation,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   522
            #     not sure this is a pb or not
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   523
            if var.stinfo.get('principal') is relation and var.scope is var.stmt:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   524
                scope = 0
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   525
                break
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   526
        else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   527
            scope = -1
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   528
        self.count += 1
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   529
        self.add_table('%s_relation AS %s' % (relation.r_type, rid), rid, scope=scope)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   530
        relation._q_sqltable = rid
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   531
        self.done.add(relation)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   532
        return rid
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   533
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   534
    def fti_table(self, relation, fti_table):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   535
        """return the table alias used by the given has_text relation,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   536
        `fti_table` being the table name for the plain text index
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   537
        """
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   538
        if relation in self.done:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   539
            try:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   540
                return relation._q_sqltable
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   541
            except AttributeError:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   542
                pass
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   543
        self.done.add(relation)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   544
        scope = self.scopes[relation.scope]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   545
        alias = self.alias_and_add_table(fti_table, scope=scope)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   546
        relation._q_sqltable = alias
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   547
        return alias
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   548
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   549
    # outer join handling ######################################################
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   550
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   551
    def mark_as_used_in_outer_join(self, tablealias, addpending=True):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   552
        """Mark table of given alias as used in outer join. This must be called
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   553
        after `outer_tables[tablealias]` has been initialized.
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   554
        """
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   555
        # remove a table from actual_table because it's used in an outer join
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   556
        # chain
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   557
        scope, tabledef = self.tables[tablealias]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   558
        self.actual_tables[scope].remove(tabledef)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   559
        # check if there are some pending outer join condition for this table
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   560
        if addpending:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   561
            try:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   562
                pending_conditions = self.outer_pending.pop(tablealias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   563
            except KeyError:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   564
                pass
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   565
            else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   566
                self.outer_tables[tablealias][1].extend(pending_conditions)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   567
        else:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   568
            assert tablealias not in self.outer_pending
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   569
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   570
    def add_outer_join_condition(self, tablealias, condition):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   571
        try:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   572
            outer, conditions, chain = self.outer_tables[tablealias]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   573
            conditions.append(condition)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   574
        except KeyError:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   575
            self.outer_pending.setdefault(tablealias, []).append(condition)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   576
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   577
    def replace_tables_by_outer_join(self, leftalias, rightalias,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   578
                                     outertype, condition):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   579
        """tell we need <leftalias> <outertype> JOIN <rightalias> ON <condition>
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   580
        """
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   581
        assert leftalias != rightalias, leftalias
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   582
        outer_tables = self.outer_tables
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   583
        louter, lconditions, lchain = outer_tables.get(leftalias,
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   584
                                                       (None, None, None))
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   585
        router, rconditions, rchain = outer_tables.get(rightalias,
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   586
                                                       (None, None, None))
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   587
        if lchain is None and rchain is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   588
            # create a new outer chaine
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   589
            chain = [leftalias, rightalias]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   590
            outer_tables[leftalias] = (None, [], chain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   591
            outer_tables[rightalias] = (outertype, [condition], chain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   592
            self.outer_chains.append(chain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   593
            self.mark_as_used_in_outer_join(leftalias, addpending=False)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   594
            self.mark_as_used_in_outer_join(rightalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   595
        elif lchain is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   596
            # [A > B > C] + [D > A] -> [D > A > B > C]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   597
            if rightalias == rchain[0]:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   598
                outer_tables[leftalias] = (None, [], rchain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   599
                conditions = outer_tables[rightalias][1] + [condition]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   600
                outer_tables[rightalias] = (outertype, conditions, rchain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   601
                rchain.insert(0, leftalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   602
            else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   603
                # [A > B > C] + [D > B] -> [A > B > C < D]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   604
                if outertype == 'LEFT':
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   605
                    outertype = 'RIGHT'
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   606
                outer_tables[leftalias] = (outertype, [condition], rchain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   607
                rchain.append(leftalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   608
            self.mark_as_used_in_outer_join(leftalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   609
        elif rchain is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   610
            # [A > B > C] + [B > D] -> [A > B > C > D]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   611
            outer_tables[rightalias] = (outertype, [condition], lchain)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   612
            lchain.append(rightalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   613
            self.mark_as_used_in_outer_join(rightalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   614
        elif lchain is rchain:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   615
            # already in the same chain, simply check compatibility and append
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   616
            # the condition if it's ok
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   617
            lidx = lchain.index(leftalias)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   618
            ridx = lchain.index(rightalias)
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   619
            if ((outertype == 'FULL' and router != 'FULL')
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   620
                    or (lidx < ridx and router != 'LEFT')
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   621
                    or (ridx < lidx and louter != 'RIGHT')):
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   622
                raise BadRQLQuery()
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   623
            # merge conditions
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   624
            if lidx < ridx:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   625
                rconditions.append(condition)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   626
            else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   627
                lconditions.append(condition)
7357
5ad3154a8810 [rql2sql] fix bug avoiding outer join relation to be used as a variable principal. Closes #1659395
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7252
diff changeset
   628
        elif louter is None:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   629
            # merge chains
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   630
            self.outer_chains.remove(lchain)
7357
5ad3154a8810 [rql2sql] fix bug avoiding outer join relation to be used as a variable principal. Closes #1659395
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7252
diff changeset
   631
            rchain += lchain
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   632
            self.mark_as_used_in_outer_join(leftalias)
10662
10942ed172de [py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10652
diff changeset
   633
            for alias, (aouter, aconditions, achain) in outer_tables.items():
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   634
                if achain is lchain:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   635
                    outer_tables[alias] = (aouter, aconditions, rchain)
7357
5ad3154a8810 [rql2sql] fix bug avoiding outer join relation to be used as a variable principal. Closes #1659395
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7252
diff changeset
   636
        else:
5ad3154a8810 [rql2sql] fix bug avoiding outer join relation to be used as a variable principal. Closes #1659395
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7252
diff changeset
   637
            raise BadRQLQuery()
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   638
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   639
    # sql generation helpers ###################################################
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   640
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   641
    def tables_sql(self, outer_chains=None):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   642
        """generate SQL for FROM clause"""
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   643
        # sort for test predictability
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   644
        tables = sorted(self.actual_tables.pop())
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   645
        # process outer joins
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   646
        if outer_chains is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   647
            assert not self.actual_tables, self.actual_tables
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   648
            assert not self.outer_pending
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   649
            outer_chains = self.outer_chains
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   650
        for chain in sorted(outer_chains):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   651
            tablealias = chain[0]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   652
            outertype, conditions, _ = self.outer_tables[tablealias]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   653
            assert _ is chain, (chain, _)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   654
            assert outertype is None, (chain, self.outer_chains)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   655
            assert not conditions, (chain, self.outer_chains)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   656
            assert len(chain) > 1
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   657
            tabledef = self.tables[tablealias][1]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   658
            outerjoin = [tabledef]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   659
            for tablealias in chain[1:]:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   660
                outertype, conditions, _ = self.outer_tables[tablealias]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   661
                assert _ is chain, (chain, self.outer_chains)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   662
                assert outertype in ('LEFT', 'RIGHT', 'FULL'), (
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   663
                    tablealias, outertype, conditions)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   664
                assert isinstance(conditions, (list)), (
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   665
                    tablealias, outertype, conditions)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   666
                tabledef = self.tables[tablealias][1]
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   667
                outerjoin.append('%s OUTER JOIN %s ON (%s)' % (
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   668
                    outertype, tabledef, ' AND '.join(conditions)))
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   669
            tables.append(' '.join(outerjoin))
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   670
        return ', '.join(tables)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   671
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   672
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   673
def extract_fake_having_terms(having):
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   674
    """RQL's HAVING may be used to contains stuff that should go in the WHERE
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   675
    clause of the SQL query, due to RQL grammar limitation. Split them...
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   676
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   677
    Return a list nodes that can be ANDed with query's WHERE clause. Having
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   678
    subtrees updated in place.
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   679
    """
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   680
    fakehaving = []
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   681
    for subtree in having:
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   682
        ors, tocheck = set(), []
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   683
        for compnode in subtree.get_nodes(Comparison):
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   684
            for fnode in compnode.get_nodes(Function):
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   685
                if fnode.descr().aggregat:
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   686
                    p = compnode.parent
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   687
                    oor = None
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   688
                    while not isinstance(p, Select):
6929
e9464d975908 [rql2sql] fix bug with NOT in "fake" having terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6493
diff changeset
   689
                        if isinstance(p, (Or, Not)):
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   690
                            oor = p
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   691
                        p = p.parent
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   692
                    if oor is not None:
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   693
                        ors.add(oor)
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   694
                    break
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   695
            else:
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   696
                tocheck.append(compnode)
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   697
        # tocheck hold a set of comparison not implying an aggregat function
7672
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   698
        # put them in fakehaving if they don't share an Or node as ancestor
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   699
        # with another comparison containing an aggregat function
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   700
        for compnode in tocheck:
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   701
            p = compnode.parent
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   702
            oor = None
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   703
            while not isinstance(p, Select):
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   704
                if p in ors or p is None:  # p is None for nodes already in fakehaving
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   705
                    break
6929
e9464d975908 [rql2sql] fix bug with NOT in "fake" having terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6493
diff changeset
   706
                if isinstance(p, (Or, Not)):
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   707
                    oor = p
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   708
                p = p.parent
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   709
            else:
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   710
                node = oor or compnode
5887
3f55f0f10a22 [rql2sql] test and fix crash when OR in HAVING where both expresion are 'fake' having terms (eg not using aggregat function)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5844
diff changeset
   711
                fakehaving.append(node)
3f55f0f10a22 [rql2sql] test and fix crash when OR in HAVING where both expresion are 'fake' having terms (eg not using aggregat function)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5844
diff changeset
   712
                node.parent.remove(node)
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   713
    return fakehaving
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   714
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   715
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   716
class SQLGenerator(object):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   717
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   718
    generation of SQL from the fully expanded RQL syntax tree
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   719
    SQL is designed to be used with a CubicWeb SQL schema
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   720
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   721
    Groups and sort are not handled here since they should not be handled at
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   722
    this level (see cubicweb.server.querier)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   723
9492
c7fc56eecd1a English typography
Dimitri Papadopoulos <dimitri.papadopoulos@cea.fr>
parents: 9361
diff changeset
   724
    we should not have errors here!
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   725
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   726
    WARNING: a CubicWebSQLGenerator instance is not thread safe, but generate is
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   727
    protected by a lock
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   728
    """
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   729
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   730
    def __init__(self, schema, dbhelper, attrmap=None):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   731
        self.schema = schema
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   732
        self.dbhelper = dbhelper
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   733
        self.dbencoding = dbhelper.dbencoding
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   734
        self.keyword_map = {
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   735
            'NOW': self.dbhelper.sql_current_timestamp,
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   736
            'TODAY': self.dbhelper.sql_current_date,
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   737
        }
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   738
        if not self.dbhelper.union_parentheses_support:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   739
            self.union_sql = self.noparen_union_sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   740
        self._lock = threading.Lock()
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
   741
        if attrmap is None:
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
   742
            attrmap = {}
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
   743
        self.attr_map = attrmap
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   744
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
   745
    def generate(self, union, args=None):
8238
087bb529035c [spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7902
diff changeset
   746
        """return SQL queries and a variable dictionary from a RQL syntax tree
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   747
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   748
        :partrqls: a list of couple (rqlst, solutions)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   749
        :args: optional dictionary with values of substitutions used in the query
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   750
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   751
        return an sql string and a dictionary with substitutions values
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   752
        """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   753
        if args is None:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   754
            args = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   755
        self._lock.acquire()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   756
        self._args = args
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   757
        self._query_attrs = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   758
        self._state = None
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   759
        # self._not_scope_offset = 0
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   760
        try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   761
            # union query for each rqlst / solution
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   762
            sql = self.union_sql(union)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   763
            # we are done
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   764
            return sql, self._query_attrs, self._state.needs_source_cb
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   765
        finally:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   766
            self._lock.release()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   767
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   768
    def union_sql(self, union, needalias=False):  # pylint: disable=E0202
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   769
        if len(union.children) == 1:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   770
            return self.select_sql(union.children[0], needalias)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   771
        sqls = ('(%s)' % self.select_sql(select, needalias)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   772
                for select in union.children)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   773
        return '\nUNION ALL\n'.join(sqls)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   774
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   775
    def noparen_union_sql(self, union, needalias=False):
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   776
        # needed for sqlite backend which doesn't like parentheses around union
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   777
        # query. This may cause bug in some condition (sort in one of the
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   778
        # subquery) but will work in most case
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   779
        #
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   780
        # see http://www.sqlite.org/cvstrac/tktview?tn=3074
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   781
        sqls = (self.select_sql(select, needalias)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   782
                for i, select in enumerate(union.children))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   783
        return '\nUNION ALL\n'.join(sqls)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   784
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   785
    def select_sql(self, select, needalias=False):
8238
087bb529035c [spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7902
diff changeset
   786
        """return SQL queries and a variable dictionary from a RQL syntax tree
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   787
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   788
        :select: a selection statement of the syntax tree (`rql.stmts.Select`)
8238
087bb529035c [spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7902
diff changeset
   789
        :solution: a dictionary containing variables binding.
087bb529035c [spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7902
diff changeset
   790
          A solution's dictionary has variable's names as key and variable's
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   791
          types as values
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   792
        :needwrap: boolean telling if the query will be wrapped in an outer
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   793
          query (to deal with aggregat and/or grouping)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   794
        """
9518
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   795
        if select.distinct:
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   796
            distinct = True
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   797
        elif self.dbhelper.fti_need_distinct:
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   798
            distinct = getattr(select.parent, 'has_text_query', False)
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   799
        else:
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   800
            distinct = False
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   801
        sorts = select.orderby
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   802
        groups = select.groupby
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   803
        having = select.having
7672
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   804
        for restr in extract_fake_having_terms(having):
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   805
            scope = None
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   806
            for vref in restr.get_nodes(VariableRef):
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   807
                vscope = vref.variable.scope
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   808
                if vscope is select:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   809
                    # ignore select scope, so restriction is added to the innermost possible scope
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   810
                    continue
7672
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   811
                if scope is None:
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   812
                    scope = vscope
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   813
                elif vscope is not scope:
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   814
                    scope = common_parent(scope, vscope).scope
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   815
            if scope is None:
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   816
                scope = select
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   817
            scope.add_restriction(restr)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   818
        # remember selection, it may be changed and have to be restored
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   819
        origselection = select.selection[:]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   820
        # check if the query will have union subquery, if it need sort term
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   821
        # selection (union or distinct query) and wrapping (union with groups)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   822
        needwrap = False
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   823
        sols = select.solutions
9518
54ead5f372bb [rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 9492
diff changeset
   824
        selectsortterms = distinct
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   825
        if len(sols) > 1:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   826
            # remove invariant from solutions
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   827
            sols, existssols, unstable = remove_unused_solutions(
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
   828
                select, sols, self.schema)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   829
            if len(sols) > 1:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   830
                # if there is still more than one solution, a UNION will be
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   831
                # generated and so sort terms have to be selected
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   832
                selectsortterms = True
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   833
                # and if select is using group by or aggregat, a wrapping
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   834
                # query will be necessary
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   835
                if groups or select.has_aggregat:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   836
                    select.select_only_variables()
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   837
                    needwrap = True
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   838
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   839
            existssols, unstable = {}, ()
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   840
        state = StateInfo(select, existssols, unstable)
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   841
        if self._state is not None:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   842
            # state from a previous unioned select
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   843
            state.merge_source_cbs(self._state.needs_source_cb)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   844
        # treat subqueries
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   845
        self._subqueries_sql(select, state)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   846
        # generate sql for this select node
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   847
        if needwrap:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   848
            outerselection = origselection[:]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   849
            if sorts and selectsortterms:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   850
                if distinct:
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   851
                    sort_term_selection(sorts, outerselection, groups)
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   852
        fix_selection_and_group(select, needwrap, selectsortterms,
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   853
                                sorts, groups, having)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   854
        if needwrap:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   855
            fneedwrap = len(outerselection) != len(origselection)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   856
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   857
            fneedwrap = len(select.selection) != len(origselection)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   858
        if fneedwrap:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   859
            needalias = True
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   860
        self._in_wrapping_query = False
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   861
        self._state = state
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   862
        try:
7672
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   863
            sql = self._solutions_sql(select, sols, distinct,
5782
8ff48d1a319f [rql2sql] when using HAVING to by-pass rql limitation (not to filter on result of an aggregat function), we should emit SQL that doesn't use HAVING to avoid potential backend error because variables are not grouped. Closes #1061603.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   864
                                      needalias or needwrap)
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   865
            # generate groups / having before wrapping query selection to get
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   866
            # correct column aliases
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   867
            self._in_wrapping_query = needwrap
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   868
            if groups:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   869
                # no constant should be inserted in GROUP BY else the backend
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   870
                # will interpret it as a positional index in the selection
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   871
                groups = ','.join(vref.accept(self) for vref in groups
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   872
                                  if not isinstance(vref, Constant))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   873
            if having:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   874
                # filter out constants as for GROUP BY
5662
785837baabba HAVING sql clause don't know about comma...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5635
diff changeset
   875
                having = ' AND '.join(term.accept(self) for term in having
785837baabba HAVING sql clause don't know about comma...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5635
diff changeset
   876
                                      if not isinstance(term, Constant))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   877
            if needwrap:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   878
                sql = '%s FROM (%s) AS T1' % (
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   879
                    self._selection_sql(outerselection, distinct, needalias),
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   880
                    sql)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   881
            if groups:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   882
                sql += '\nGROUP BY %s' % groups
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   883
            if having:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   884
                sql += '\nHAVING %s' % having
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   885
            # sort
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   886
            if sorts:
7108
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   887
                sqlsortterms = []
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   888
                if needwrap:
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   889
                    selectidx = [str(term) for term in outerselection]
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   890
                else:
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   891
                    selectidx = [str(term) for term in select.selection]
7108
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   892
                for sortterm in sorts:
7579
5a610b34d2d2 [rql2sql] more cases fixed where something is wrongly added to GROUPBY, causing unexpected results for the query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7472
diff changeset
   893
                    _term = self._sortterm_sql(sortterm, selectidx)
7108
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   894
                    if _term is not None:
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   895
                        sqlsortterms.append(_term)
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   896
                if sqlsortterms:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   897
                    sql = self.dbhelper.sql_add_order_by(
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   898
                        sql, sqlsortterms, origselection, fneedwrap,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   899
                        select.limit or select.offset)
7108
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   900
            else:
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   901
                sqlsortterms = None
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   902
            state.finalize_source_cbs()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   903
        finally:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   904
            select.selection = origselection
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   905
        # limit / offset
7108
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   906
        sql = self.dbhelper.sql_add_limit_offset(sql,
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   907
                                                 select.limit,
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   908
                                                 select.offset,
bcdf22734059 Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 7042
diff changeset
   909
                                                 sqlsortterms)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   910
        return sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   911
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   912
    def _subqueries_sql(self, select, state):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   913
        for i, subquery in enumerate(select.with_):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   914
            sql = self.union_sql(subquery.query, needalias=True)
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
   915
            tablealias = '_T%s' % i  # XXX nested subqueries
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   916
            sql = '(%s) AS %s' % (sql, tablealias)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   917
            state.subtables[tablealias] = (0, sql)
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   918
            latest_state = self._state
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   919
            for vref in subquery.aliases:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   920
                alias = vref.variable
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   921
                alias._q_sqltable = tablealias
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   922
                alias._q_sql = '%s.C%s' % (tablealias, alias.colnum)
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   923
                try:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   924
                    stack = latest_state.needs_source_cb[alias.colnum]
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   925
                    if state.subquery_source_cb is None:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   926
                        state.subquery_source_cb = {}
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   927
                    for selectidx, vref in iter_mapped_var_sels(select, alias):
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   928
                        stack = stack[:]
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   929
                        update_source_cb_stack(state, select, vref, stack)
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   930
                        state.subquery_source_cb[selectidx] = stack
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   931
                except KeyError:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   932
                    continue
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   933
7672
f31f9882c90f [rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7642
diff changeset
   934
    def _solutions_sql(self, select, solutions, distinct, needalias):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   935
        sqls = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   936
        for solution in solutions:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   937
            self._state.reset(solution)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   938
            # visit restriction subtree
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   939
            if select.where is not None:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   940
                self._state.add_restriction(select.where.accept(self))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   941
            sql = [self._selection_sql(select.selection, distinct, needalias)]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   942
            if self._state.restrictions:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   943
                sql.append('WHERE %s' % ' AND '.join(self._state.restrictions))
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
   944
            self._state.merge_source_cbs(self._state._needs_source_cb)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   945
            # add required tables
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   946
            assert len(self._state.actual_tables) == 1, self._state.actual_tables
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   947
            tables = self._state.tables_sql()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   948
            if tables:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
   949
                sql.insert(1, 'FROM %s' % tables)
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
   950
            elif self._state.restrictions and self.dbhelper.needs_from_clause:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   951
                sql.insert(1, 'FROM (SELECT 1) AS _T')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   952
            sqls.append('\n'.join(sql))
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
   953
        if distinct:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   954
            return '\nUNION\n'.join(sqls)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   955
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   956
            return '\nUNION ALL\n'.join(sqls)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
   957
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   958
    def _selection_sql(self, selected, distinct, needaliasing=False):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   959
        clause = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   960
        for term in selected:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   961
            sql = term.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   962
            if needaliasing:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   963
                colalias = 'C%s' % len(clause)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   964
                clause.append('%s AS %s' % (sql, colalias))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   965
                if isinstance(term, VariableRef):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   966
                    self._state.aliases[term.name] = colalias
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   967
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   968
                clause.append(sql)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   969
        if distinct:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   970
            return 'SELECT DISTINCT %s' % ', '.join(clause)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   971
        return 'SELECT %s' % ', '.join(clause)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   972
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   973
    def _sortterm_sql(self, sortterm, selectidx):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   974
        term = sortterm.term
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   975
        try:
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   976
            sqlterm = selectidx.index(str(term)) + 1
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   977
        except ValueError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   978
            # Constant node or non selected term
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   979
            sqlterm = term.accept(self)
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   980
            if sqlterm is None:
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   981
                return None
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   982
        if sortterm.asc:
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
   983
            return str(sqlterm)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   984
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   985
            return '%s DESC' % sqlterm
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   986
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   987
    def visit_and(self, et):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   988
        """generate SQL for a AND subtree"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   989
        res = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   990
        for c in et.children:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   991
            part = c.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   992
            if part:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   993
                res.append(part)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   994
        return ' AND '.join(res)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   995
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   996
    def visit_or(self, ou):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   997
        """generate SQL for a OR subtree"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   998
        res = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   999
        for c in ou.children:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1000
            part = c.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1001
            if part:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1002
                res.append('(%s)' % part)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1003
        if res:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1004
            if len(res) > 1:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1005
                return '(%s)' % ' OR '.join(res)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1006
            return res[0]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1007
        return ''
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1008
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1009
    def visit_not(self, node):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1010
        csql = node.children[0].accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1011
        if node in self._state.done or not csql:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1012
            # already processed or no sql generated by children
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1013
            return csql
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
  1014
        return 'NOT (%s)' % csql
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1015
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1016
    def visit_exists(self, exists):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1017
        """generate SQL name for a exists subquery"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1018
        sqls = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1019
        for dummy in self._state.iter_exists_sols(exists):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1020
            sql = self._visit_exists(exists)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1021
            if sql:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1022
                sqls.append(sql)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1023
        if not sqls:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1024
            return ''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1025
        return 'EXISTS(%s)' % ' UNION '.join(sqls)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1026
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1027
    def _visit_exists(self, exists):
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
  1028
        self._state.push_scope(exists)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1029
        restriction = exists.children[0].accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1030
        restrictions, tables = self._state.pop_scope()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1031
        if restriction:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1032
            restrictions.append(restriction)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1033
        restriction = ' AND '.join(restrictions)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1034
        if not restriction:
6297
23c1e50ff97b [rql] fix bug with query like 'Any 1 WHERE NOT X in_group G': tables should be kept in EXISTS() even when there are no restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6286
diff changeset
  1035
            if tables:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1036
                return 'SELECT 1 FROM %s' % tables
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1037
            return ''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1038
        if not tables:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1039
            # XXX could leave surrounding EXISTS() in this case no?
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1040
            sql = 'SELECT 1 WHERE %s' % restriction
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1041
        else:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1042
            sql = 'SELECT 1 FROM %s WHERE %s' % (tables, restriction)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1043
        return sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1044
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1045
    def visit_relation(self, relation):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1046
        """generate SQL for a relation"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1047
        rtype = relation.r_type
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1048
        # don't care of type constraint statement (i.e. relation_type = 'is')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1049
        if relation.is_types_restriction():
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1050
            return ''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1051
        lhs, rhs = relation.get_parts()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1052
        rschema = self.schema.rschema(rtype)
3689
deb13e88e037 follow yams 0.25 api changes to improve performance
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3245
diff changeset
  1053
        if rschema.final:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1054
            if (rtype == 'eid' and lhs.variable._q_invariant
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1055
                    and lhs.variable.stinfo['constnode']):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1056
                # special case where this restriction is already generated by
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1057
                # some other relation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1058
                return ''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1059
            # attribute relation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1060
            if rtype == 'has_text':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1061
                sql = self._visit_has_text_relation(relation)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1062
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1063
                rhs_vars = rhs.get_nodes(VariableRef)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1064
                if rhs_vars:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1065
                    # if variable(s) in the RHS
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1066
                    sql = self._visit_var_attr_relation(relation, rhs_vars)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1067
                else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1068
                    # no variables in the RHS
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1069
                    sql = self._visit_attribute_relation(relation)
5706
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1070
        elif (rtype == 'is' and isinstance(rhs.children[0], Constant)
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1071
              and rhs.children[0].eval(self._args) is None):
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1072
            lhssql = lhs.accept(self)
5706
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1073
            return '%s%s' % (lhssql, rhs.accept(self))
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1074
        elif relation.optional:
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1075
            # OPTIONAL relation, generate a left|right outer join
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1076
            if rtype == 'identity' or rschema.inlined:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1077
                sql = self._visit_outer_join_inlined_relation(relation, rschema)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1078
            else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1079
                sql = self._visit_outer_join_relation(relation, rschema)
5706
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1080
        elif rschema.inlined:
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1081
            sql = self._visit_inlined_relation(relation)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1082
        else:
5706
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1083
            # regular (non final) relation
c2e8290bc7b7 [rql2sql] fix special 'X relation NULL' case (used by security insertion), broken by recent removal of IS operator in RQL
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5702
diff changeset
  1084
            sql = self._visit_relation(relation, rschema)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1085
        return sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1086
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1087
    def _visit_inlined_relation(self, relation):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1088
        lhsvar, _, rhsvar, rhsconst = relation_info(relation)
6003
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1089
        # we are sure lhsvar is not None
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1090
        lhssql = self._inlined_var_sql(lhsvar, relation.r_type)
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1091
        if rhsvar is None:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1092
            moresql = None
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1093
        else:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1094
            moresql = self._extra_join_sql(relation, lhssql, rhsvar)
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1095
        if isinstance(relation.parent, Not):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1096
            self._state.done.add(relation.parent)
6003
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1097
            if rhsvar is not None and rhsvar._q_invariant:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1098
                sql = '%s IS NULL' % lhssql
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1099
            else:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1100
                # column != 1234 may not get back rows where column is NULL...
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1101
                sql = '(%s IS NULL OR %s!=%s)' % (
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1102
                    lhssql, lhssql, (rhsvar or rhsconst).accept(self))
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1103
        elif rhsconst is not None:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1104
            sql = '%s=%s' % (lhssql, rhsconst.accept(self))
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1105
        elif isinstance(rhsvar, Variable) and rhsvar._q_invariant:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1106
            # if the rhs variable is only linked to this relation, this mean we
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1107
            # only want the relation to exists, eg NOT NULL in case of inlined
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1108
            # relation
6003
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1109
            if moresql is not None:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1110
                return moresql
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1111
            return '%s IS NOT NULL' % lhssql
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1112
        else:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1113
            sql = '%s=%s' % (lhssql, rhsvar.accept(self))
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1114
        if moresql is None:
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1115
            return sql
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1116
        return '%s AND %s' % (sql, moresql)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1117
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1118
    def _process_relation_term(self, relation, rid, termvar, termconst, relfield):
4794
81075b09ebf1 [rql2sql] fix potential crash when testing _q_invariant on a ColumnAlias instead of a Variable by always considering _q_invariant to false for them
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4719
diff changeset
  1119
        if termconst or not termvar._q_invariant:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1120
            termsql = termconst and termconst.accept(self) or termvar.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1121
            yield '%s.%s=%s' % (rid, relfield, termsql)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1122
        elif termvar._q_invariant:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1123
            extrajoin = self._extra_join_sql(relation, '%s.%s' % (rid, relfield), termvar)
6003
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1124
            if extrajoin is not None:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1125
                yield extrajoin
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1126
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1127
    def _visit_relation(self, relation, rschema):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1128
        """generate SQL for a relation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1129
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1130
        implements optimization 1.
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1131
        """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1132
        if relation.r_type == 'identity':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1133
            # special case "X identity Y"
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1134
            lhs, rhs = relation.get_parts()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1135
            return '%s%s' % (lhs.accept(self), rhs.accept(self))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1136
        lhsvar, lhsconst, rhsvar, rhsconst = relation_info(relation)
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1137
        rid = self._state.relation_table(relation)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1138
        sqls = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1139
        sqls += self._process_relation_term(relation, rid, lhsvar, lhsconst, 'eid_from')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1140
        sqls += self._process_relation_term(relation, rid, rhsvar, rhsconst, 'eid_to')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1141
        sql = ' AND '.join(sqls)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1142
        return sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1143
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1144
    def _visit_outer_join_relation(self, relation, rschema):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1145
        """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1146
        left outer join syntax (optional=='right'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1147
          X relation Y?
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1148
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1149
        right outer join syntax (optional=='left'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1150
          X? relation Y
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1151
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1152
        full outer join syntaxes (optional=='both'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1153
          X? relation Y?
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1154
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1155
        if relation is inlined:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1156
           if it's a left outer join:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1157
           -> X LEFT OUTER JOIN Y ON (X.relation=Y.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1158
           elif it's a right outer join:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1159
           -> Y LEFT OUTER JOIN X ON (X.relation=Y.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1160
           elif it's a full outer join:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1161
           -> X FULL OUTER JOIN Y ON (X.relation=Y.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1162
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1163
           if it's a left outer join:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1164
           -> X LEFT OUTER JOIN relation ON (relation.eid_from=X.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1165
              LEFT OUTER JOIN Y ON (relation.eid_to=Y.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1166
           elif it's a right outer join:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1167
           -> Y LEFT OUTER JOIN relation ON (relation.eid_to=Y.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1168
              LEFT OUTER JOIN X ON (relation.eid_from=X.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1169
           elif it's a full outer join:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1170
           -> X FULL OUTER JOIN Y ON (X.relation=Y.eid)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1171
        """
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1172
        leftvar, leftconst, rightvar, rightconst = relation_info(relation)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1173
        assert not (leftconst and rightconst), "doesn't make sense"
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1174
        if relation.optional == 'left':
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1175
            leftvar, rightvar = rightvar, leftvar
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1176
            leftconst, rightconst = rightconst, leftconst
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1177
            joinattr, restrattr = 'eid_to', 'eid_from'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1178
        else:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1179
            joinattr, restrattr = 'eid_from', 'eid_to'
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1180
        # search table for this variable, to use as left table of the outer join
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1181
        leftalias = None
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1182
        if leftvar:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1183
            # take care, may return None for invariant variable
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1184
            leftalias = self._var_table(leftvar)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1185
        if leftalias is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1186
            if leftvar.stinfo['principal'] is not relation:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1187
                # use variable's principal relation
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1188
                leftalias = leftvar.stinfo['principal']._q_sqltable
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1189
            else:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1190
                # search for relation on which we should join
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1191
                rschema = self.schema.rschema
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1192
                for orelation in leftvar.stinfo['relations']:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1193
                    if orelation is not relation and not rschema(orelation.r_type).final:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1194
                        break
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1195
                else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1196
                    for orelation in rightvar.stinfo['relations']:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1197
                        if (orelation is not relation
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1198
                                and not rschema(orelation.r_type).final
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1199
                                and orelation.optional):
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1200
                            break
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1201
                    else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1202
                        # unexpected
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1203
                        assert False, leftvar
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1204
                leftalias = self._state.relation_table(orelation)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1205
        # right table of the outer join
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1206
        rightalias = self._state.relation_table(relation)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1207
        # compute join condition
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1208
        if not leftconst or (leftvar and not leftvar._q_invariant):
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1209
            leftsql = leftvar.accept(self)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1210
        else:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1211
            leftsql = leftconst.accept(self)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1212
        condition = '%s.%s=%s' % (rightalias, joinattr, leftsql)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1213
        if rightconst:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1214
            condition += ' AND %s.%s=%s' % (rightalias, restrattr, rightconst.accept(self))
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1215
        # record outer join
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1216
        outertype = 'FULL' if relation.optional == 'both' else 'LEFT'
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1217
        self._state.replace_tables_by_outer_join(leftalias, rightalias,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1218
                                                 outertype, condition)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1219
        # need another join?
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1220
        if rightconst is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1221
            # we need another outer join for the other side of the relation (e.g.
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1222
            # for "X relation Y?" in RQL, we treated earlier the (cw_X.eid /
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1223
            # relation.eid_from) join, now we've to do (relation.eid_to /
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1224
            # cw_Y.eid)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1225
            leftalias = rightalias
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1226
            rightvar.accept(self)  # accept before using var_table
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1227
            rightalias = self._var_table(rightvar)
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1228
            if rightalias is None:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1229
                if rightvar.stinfo['principal'] is not relation:
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1230
                    self._state.replace_tables_by_outer_join(
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1231
                        leftalias, rightvar.stinfo['principal']._q_sqltable,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1232
                        outertype, '%s.%s=%s' % (leftalias, restrattr, rightvar.accept(self)))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1233
            else:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1234
                self._state.replace_tables_by_outer_join(
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1235
                    leftalias, rightalias, outertype,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1236
                    '%s.%s=%s' % (leftalias, restrattr, rightvar.accept(self)))
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1237
        # this relation will hence be expressed in FROM clause, return nothing
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1238
        # here
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1239
        return ''
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1240
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1241
    def _visit_outer_join_inlined_relation(self, relation, rschema):
7734
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1242
        lhsvar, lhsconst, rhsvar, rhsconst = relation_info(relation)
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1243
        assert not (lhsconst and rhsconst), "doesn't make sense"
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1244
        attr = 'eid' if relation.r_type == 'identity' else relation.r_type
7734
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1245
        lhsalias = self._var_table(lhsvar)
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1246
        rhsalias = rhsvar and self._var_table(rhsvar)
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1247
        if lhsalias is None:
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1248
            lhssql = lhsconst.accept(self)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1249
        elif attr == 'eid':
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1250
            lhssql = lhsvar.accept(self)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1251
        else:
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1252
            lhssql = '%s.%s%s' % (lhsalias, SQL_PREFIX, attr)
7734
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1253
        condition = '%s=%s' % (lhssql, (rhsconst or rhsvar).accept(self))
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1254
        # this is not a typo, rhs optional variable means lhs outer join and vice-versa
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1255
        if relation.optional == 'left':
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1256
            lhsvar, rhsvar = rhsvar, lhsvar
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1257
            lhsconst, rhsconst = rhsconst, lhsconst
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1258
            lhsalias, rhsalias = rhsalias, lhsalias
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1259
            outertype = 'LEFT'
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1260
        elif relation.optional == 'both':
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1261
            outertype = 'FULL'
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1262
        else:
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1263
            outertype = 'LEFT'
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1264
        if rhsalias is None:
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1265
            if rhsconst is not None:
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1266
                # inlined relation with invariant as rhs
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1267
                if relation.r_type != 'identity':
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1268
                    condition = '(%s OR %s IS NULL)' % (condition, lhssql)
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1269
                if not lhsvar.stinfo.get('optrelations'):
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1270
                    return condition
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1271
                self._state.add_outer_join_condition(lhsalias, condition)
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1272
            return
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1273
        if lhsalias is None:
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1274
            if lhsconst is not None and not rhsvar.stinfo.get('optrelations'):
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1275
                return condition
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1276
            lhsalias = lhsvar._q_sql.split('.', 1)[0]
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1277
        if lhsalias == rhsalias:
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1278
            self._state.add_outer_join_condition(lhsalias, condition)
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1279
        else:
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1280
            self._state.replace_tables_by_outer_join(
59fea81647e5 [rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7729
diff changeset
  1281
                lhsalias, rhsalias, outertype, condition)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1282
        return ''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1283
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1284
    def _visit_var_attr_relation(self, relation, rhs_vars):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1285
        """visit an attribute relation with variable(s) in the RHS
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1286
8457
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1287
        attribute variables are used either in the selection or for unification
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1288
        (eg X attr1 A, Y attr2 A). In case of selection, nothing to do here.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1289
        """
8457
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1290
        ored = relation.ored()
7472
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1291
        for vref in rhs_vars:
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1292
            var = vref.variable
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1293
            if isinstance(var, ColumnAlias):
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1294
                # force sql generation whatever the computed principal
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1295
                principal = 1
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1296
            else:
9833c09460f1 [rql2sql] fix missing sql restriction w/ attribute restriction where value comes from a subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7421
diff changeset
  1297
                principal = var.stinfo.get('principal')
8457
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1298
            # we've to return some sql if:
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1299
            # 1. visited relation is ored
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1300
            # 2. variable's principal is not this relation and not 1.
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1301
            if ored or (principal is not None and principal is not relation
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1302
                        and not getattr(principal, 'ored', lambda: 0)()):
6940
1172c25655b7 [rql2sql] should not select a neged relation as principal + simplify code for sql generation for attribute relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6929
diff changeset
  1303
                # we have to generate unification expression
8457
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1304
                if principal is relation:
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1305
                    # take care if ored case and principal is the relation to
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1306
                    # use the right relation in the unification term
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1307
                    _rel = [rel for rel in var.stinfo['rhsrelations']
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1308
                            if rel is not principal][0]
8457
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1309
                else:
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1310
                    _rel = relation
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1311
                lhssql = self._inlined_var_sql(_rel.children[0].variable,
69ad9a509bc3 [rql2sql] fix generated SQL when an attribute relation with a variable is ored with another attribute relation. Closes #2410405
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8245
diff changeset
  1312
                                               _rel.r_type)
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1313
                sql = lhssql + relation.children[1].accept(self)
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1314
                if relation.optional == 'right':
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1315
                    leftalias = self._var_table(principal.children[0].variable)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1316
                    rightalias = self._var_table(relation.children[0].variable)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1317
                    self._state.replace_tables_by_outer_join(
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1318
                        leftalias, rightalias, 'LEFT', sql)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1319
                    return ''
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1320
                return sql
6940
1172c25655b7 [rql2sql] should not select a neged relation as principal + simplify code for sql generation for attribute relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6929
diff changeset
  1321
        return ''
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1322
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1323
    def _visit_attribute_relation(self, rel):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1324
        """generate SQL for an attribute relation"""
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1325
        lhs, rhs = rel.get_parts()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1326
        rhssql = rhs.accept(self)
11733
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1327
        if isinstance(lhs.variable, ColumnAlias):
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1328
            if rel.r_type != 'eid':
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1329
                raise BadRQLQuery('Attribute %s of %s must be selected from subqueries'
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1330
                                  % (rel.r_type, lhs.variable))
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1331
            # nb: case where subquery variable isn't an eid will raise a TypeResolverException, no
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1332
            # need for defense here
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1333
            lhssql = lhs.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1334
        else:
11733
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1335
            table = self._var_table(lhs.variable)
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1336
            if table is None:
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1337
                # table is None if variable has been annotated as invariant, hence we don't expect
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1338
                # accessing another attribute than eid
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1339
                assert rel.r_type == 'eid'
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1340
                lhssql = lhs.accept(self)
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1341
            else:
11733
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1342
                mapkey = '%s.%s' % (self._state.solution[lhs.name], rel.r_type)
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1343
                if mapkey in self.attr_map:
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1344
                    cb, sourcecb = self.attr_map[mapkey]
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1345
                    if sourcecb:
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1346
                        # callback is a source callback, we can't use this
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1347
                        # attribute in restriction
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1348
                        raise QueryError("can't use %s (%s) in restriction"
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1349
                                         % (mapkey, rel.as_string()))
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1350
                    lhssql = cb(self, lhs.variable, rel)
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1351
                elif rel.r_type == 'eid':
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1352
                    lhssql = lhs.variable._q_sql
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1353
                else:
1913a3e8816a [rql2sql] Handle comparison of eid on variables from an subquery
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11347
diff changeset
  1354
                    lhssql = '%s.%s%s' % (table, SQL_PREFIX, rel.r_type)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1355
        try:
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1356
            if rel._q_needcast == 'TODAY':
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1357
                sql = 'DATE(%s)%s' % (lhssql, rhssql)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1358
            # XXX which cast function should be used
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1359
            # elif rel._q_needcast == 'NOW':
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1360
            #    sql = 'TIMESTAMP(%s)%s' % (lhssql, rhssql)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1361
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1362
                sql = '%s%s' % (lhssql, rhssql)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1363
        except AttributeError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1364
            sql = '%s%s' % (lhssql, rhssql)
5004
4cc020ee70e2 le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
  1365
        if lhs.variable.stinfo.get('optrelations'):
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1366
            self._state.add_outer_join_condition(table, sql)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1367
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1368
            return sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1369
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1370
    def _visit_has_text_relation(self, rel):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1371
        """generate SQL for a has_text relation"""
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1372
        lhs, rhs = rel.get_parts()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1373
        const = rhs.children[0]
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1374
        alias = self._state.fti_table(rel, self.dbhelper.fti_table)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1375
        jointo = lhs.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1376
        restriction = ''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1377
        lhsvar = lhs.variable
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1378
        me_is_principal = lhsvar.stinfo.get('principal') is rel
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1379
        if me_is_principal:
11770
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1380
            jointo = None
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1381
            if lhsvar.stinfo['typerel'] is not None:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1382
                if not lhsvar._q_invariant or len(lhsvar.stinfo['possibletypes']) == 1:
11770
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1383
                    ealias = lhsvar._q_sqltable = '_' + lhsvar.name
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1384
                    jointo = lhsvar._q_sql = '%s.cw_eid' % ealias
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1385
                    self._state.add_table('cw_%s AS %s' % (self._state.solution[lhs.name], ealias),
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1386
                                          ealias)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1387
                else:
11770
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1388
                    subquery = ' UNION '.join('SELECT cw_eid FROM cw_%s' % etype
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1389
                                              for etype in sorted(lhsvar.stinfo['possibletypes']))
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1390
                    restriction = ' AND %s IN (%s)' % (lhsvar._q_sql, subquery)
2354
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1391
        if isinstance(rel.parent, Not):
9b4bac626977 ability to map attributes to something else than usual cw mapping on sql generation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2199
diff changeset
  1392
            self._state.done.add(rel.parent)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1393
            not_ = True
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1394
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1395
            not_ = False
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1396
        query = const.eval(self._args)
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1397
        return self.dbhelper.fti_restriction_sql(alias, query,
5582
3e133b29a1a4 [rql2sql] follow rql 0.26.1 changes: NOT nodes normalization, allowing simplification of sql generation, and fix #XXX
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
  1398
                                                 jointo, not_) + restriction
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1399
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1400
    def visit_comparison(self, cmp):
3787
82bb2c7f083b C - fix typo. make `lgp check` happy.
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3762
diff changeset
  1401
        """generate SQL for a comparison"""
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1402
        optional = cmp.optional
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1403
        if len(cmp.children) == 2:
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1404
            # simplified expression from HAVING clause
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1405
            lhs, rhs = cmp.children
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1406
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1407
            lhs = None
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1408
            rhs = cmp.children[0]
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1409
            assert not optional
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1410
        sql = None
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1411
        operator = cmp.operator
5702
9fb240cf0f61 [rql] more update to 0.26.2 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5662
diff changeset
  1412
        if operator in ('LIKE', 'ILIKE'):
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
  1413
            if operator == 'ILIKE' and not self.dbhelper.ilike_support:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1414
                operator = ' LIKE '
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1415
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1416
                operator = ' %s ' % operator
7257
beea955b45e2 [rql] basic support for regexp-based pattern matching
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 7256
diff changeset
  1417
        elif operator == 'REGEXP':
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1418
            sql = ' %s' % self.dbhelper.sql_regexp_match_expression(rhs.accept(self))
1862
94dc8ccd320b #343322: should generate IS NULL in sql w/ None values in substitution
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1802
diff changeset
  1419
        elif (operator == '=' and isinstance(rhs, Constant)
94dc8ccd320b #343322: should generate IS NULL in sql w/ None values in substitution
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1802
diff changeset
  1420
              and rhs.eval(self._args) is None):
94dc8ccd320b #343322: should generate IS NULL in sql w/ None values in substitution
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1802
diff changeset
  1421
            if lhs is None:
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1422
                sql = ' IS NULL'
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1423
            else:
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1424
                sql = '%s IS NULL' % lhs.accept(self)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1425
        elif isinstance(rhs, Function) and rhs.name == 'IN':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1426
            assert operator == '='
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1427
            operator = ' '
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1428
        if sql is None:
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1429
            if lhs is None:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1430
                sql = '%s%s' % (operator, rhs.accept(self))
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1431
            else:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1432
                sql = '%s%s%s' % (lhs.accept(self), operator, rhs.accept(self))
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1433
        if optional is None:
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1434
            return sql
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1435
        leftvars = cmp.children[0].get_nodes(VariableRef)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1436
        assert len(leftvars) == 1
7902
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1437
        if leftvars[0].variable.stinfo['attrvar'] is None:
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1438
            assert isinstance(leftvars[0].variable, ColumnAlias)
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1439
            leftalias = leftvars[0].variable._q_sqltable
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1440
        else:
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1441
            leftalias = self._var_table(leftvars[0].variable.stinfo['attrvar'])
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1442
        rightvars = cmp.children[1].get_nodes(VariableRef)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1443
        assert len(rightvars) == 1
7902
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1444
        if rightvars[0].variable.stinfo['attrvar'] is None:
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1445
            assert isinstance(rightvars[0].variable, ColumnAlias)
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1446
            rightalias = rightvars[0].variable._q_sqltable
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1447
        else:
2ada3052e626 [rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7734
diff changeset
  1448
            rightalias = self._var_table(rightvars[0].variable.stinfo['attrvar'])
7707
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1449
        if optional == 'right':
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1450
            self._state.replace_tables_by_outer_join(
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1451
                leftalias, rightalias, 'LEFT', sql)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1452
        elif optional == 'left':
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1453
            self._state.replace_tables_by_outer_join(
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1454
                rightalias, leftalias, 'LEFT', sql)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1455
        else:
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1456
            self._state.replace_tables_by_outer_join(
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1457
                leftalias, rightalias, 'FULL', sql)
936530f8d32c [sql gen] handle optional on comparison node (eg HAVING expression) and on rhs of final relation. Closes #1859609
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7704
diff changeset
  1458
        return ''
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1459
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1460
    def visit_mathexpression(self, mexpr):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1461
        """generate SQL for a mathematic expression"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1462
        lhs, rhs = mexpr.get_parts()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1463
        # check for string concatenation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1464
        operator = mexpr.operator
8245
d53762ae5961 [rql2sql] correctly handle modulo operator (closes #2192457)
Julien Cristau <julien.cristau@logilab.fr>
parents: 8238
diff changeset
  1465
        if operator == '%':
d53762ae5961 [rql2sql] correctly handle modulo operator (closes #2192457)
Julien Cristau <julien.cristau@logilab.fr>
parents: 8238
diff changeset
  1466
            operator = '%%'
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1467
        try:
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1468
            if (mexpr.operator == '+'
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1469
                    and mexpr.get_type(self._state.solution, self._args) == 'String'):
5793
1faff41593df [rql2sql] use new dbhelper.sql_concat_string function to deal with sql string concatenation. This together with lgdb 1.0.4 fixes #1055133: SQL Server support : string concatenation issue
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5782
diff changeset
  1470
                return '(%s)' % self.dbhelper.sql_concat_string(lhs.accept(self),
1faff41593df [rql2sql] use new dbhelper.sql_concat_string function to deal with sql string concatenation. This together with lgdb 1.0.4 fixes #1055133: SQL Server support : string concatenation issue
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5782
diff changeset
  1471
                                                                rhs.accept(self))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1472
        except CoercionError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1473
            pass
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1474
        return '(%s %s %s)' % (lhs.accept(self), operator, rhs.accept(self))
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1475
7729
5f89f11143bc [rql2sql] closes #1892471: support for unary expression introduced in rql 0.30
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7718
diff changeset
  1476
    def visit_unaryexpression(self, uexpr):
5f89f11143bc [rql2sql] closes #1892471: support for unary expression introduced in rql 0.30
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7718
diff changeset
  1477
        """generate SQL for a unary expression"""
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1478
        return '%s%s' % (uexpr.operator, uexpr.children[0].accept(self))
7729
5f89f11143bc [rql2sql] closes #1892471: support for unary expression introduced in rql 0.30
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7718
diff changeset
  1479
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1480
    def visit_function(self, func):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1481
        """generate SQL name for a function"""
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1482
        if func.name == 'FTIRANK':
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1483
            try:
10669
155c29e0ed1c [py3k] use next builtin instead of next method
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10663
diff changeset
  1484
                rel = next(iter(func.children[0].variable.stinfo['ftirels']))
5768
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1485
            except KeyError:
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1486
                raise BadRQLQuery("can't use FTIRANK on variable not used in an"
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1487
                                  " 'has_text' relation (eg full-text search)")
1e73a466aa69 [fti] support for fti ranking: has_text query results sorted by relevance, and provides a way to control weight per entity / entity's attribute
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5706
diff changeset
  1488
            const = rel.get_parts()[1].children[0]
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1489
            return self.dbhelper.fti_rank_order(
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1490
                self._state.fti_table(rel, self.dbhelper.fti_table),
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1491
                const.eval(self._args))
5013
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1492
        args = [c.accept(self) for c in func.children]
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1493
        if func in self._state.source_cb_funcs:
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1494
            # function executed as a callback on the source
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1495
            assert len(args) == 1
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1496
            return args[0]
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1497
        # func_as_sql will check function is supported by the backend
ad91f93bbb93 [source storage] refactor source sql generation and results handling to allow repository side callbacks
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5010
diff changeset
  1498
        return self.dbhelper.func_as_sql(func.name, args)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1499
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1500
    def visit_constant(self, constant):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1501
        """generate SQL name for a constant"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1502
        if constant.type is None:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1503
            return 'NULL'
6286
4d10e9895679 cleanup
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6131
diff changeset
  1504
        value = constant.value
7256
ccd44caeb936 [rql] support CAST() Function
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 7252
diff changeset
  1505
        if constant.type == 'etype':
ccd44caeb936 [rql] support CAST() Function
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 7252
diff changeset
  1506
            return value
8894
b03abd90a785 [rql2sql] Remove an XXX by explaining why Int non-substitution is desired
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8893
diff changeset
  1507
        # don't substitute int, causes pb when used as sorting column number
b03abd90a785 [rql2sql] Remove an XXX by explaining why Int non-substitution is desired
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8893
diff changeset
  1508
        if constant.type == 'Int':
7704
0f49dd8e76b5 [rql2sql] don't introduce substitution for Int and Boolean constants. This is needed for COUNT(DISTINCT) support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7672
diff changeset
  1509
            return str(value)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1510
        if constant.type in ('Date', 'Datetime'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1511
            rel = constant.relation()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1512
            if rel is not None:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1513
                rel._q_needcast = value
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1514
            return self.keyword_map[value]()
4124
8f2f5f0a89e7 fix backout
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4121
diff changeset
  1515
        if constant.type == 'Substitute':
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1516
            _id = value
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1517
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1518
            _id = str(id(constant)).replace('-', '', 1)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1519
            self._query_attrs[_id] = value
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1520
        return '%%(%s)s' % _id
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1521
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1522
    def visit_variableref(self, variableref):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1523
        """get the sql name for a variable reference"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1524
        # use accept, .variable may be a variable or a columnalias
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1525
        return variableref.variable.accept(self)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1526
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1527
    def visit_columnalias(self, colalias):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1528
        """get the sql name for a subquery column alias"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1529
        return colalias._q_sql
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1530
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1531
    def visit_variable(self, variable):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1532
        """get the table name and sql string for a variable"""
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1533
        if variable.name in self._state.done:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1534
            if self._in_wrapping_query:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1535
                return 'T1.%s' % self._state.aliases[variable.name]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1536
            return variable._q_sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1537
        self._state.done.add(variable.name)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1538
        vtablename = None
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1539
        if variable.stinfo['attrvar']:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1540
            # attribute variable (systematically used in rhs of final
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1541
            # relation(s)), get table name and sql from any rhs relation
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1542
            sql = self._linked_var_sql(variable)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1543
        elif variable._q_invariant:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1544
            # since variable is invariant, we know we won't found final relation
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1545
            principal = variable.stinfo['principal']
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1546
            if principal is None:
11770
22b854d3e8b2 [rql2sql] Stop generating SQL query from RQL using entities.type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11734
diff changeset
  1547
                assert variable.stinfo['typerel'] is None
3762
e416186fb91c prefix sql aliases for entity table by '_' to avoid pb with variable such as 'AS' (eg a keyword in SQL)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3754
diff changeset
  1548
                vtablename = '_' + variable.name
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1549
                self._state.add_table('entities AS %s' % vtablename, vtablename)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1550
                sql = '%s.eid' % vtablename
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1551
            elif principal.r_type == 'has_text':
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1552
                sql = '%s.%s' % (self._state.fti_table(principal,
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1553
                                                       self.dbhelper.fti_table),
5010
b2c5aee8ca3f [cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4845
diff changeset
  1554
                                 self.dbhelper.fti_uid_attr)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1555
            elif principal in variable.stinfo['rhsrelations']:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1556
                if self.schema.rschema(principal.r_type).inlined:
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1557
                    sql = self._linked_var_sql(variable)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1558
                else:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1559
                    sql = '%s.eid_to' % self._state.relation_table(principal)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1560
            else:
7193
7eaef037ea9d [sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7108
diff changeset
  1561
                sql = '%s.eid_from' % self._state.relation_table(principal)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1562
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1563
            # standard variable: get table name according to etype and use .eid
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1564
            # attribute
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1565
            sql, vtablename = self._var_info(variable)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1566
        variable._q_sqltable = vtablename
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1567
        variable._q_sql = sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1568
        return sql
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1569
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1570
    # various utilities #######################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1571
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1572
    def _extra_join_sql(self, relation, sql, var):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1573
        # if rhs var is invariant, and this relation is not its principal,
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1574
        # generate extra join
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1575
        try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1576
            if not var.stinfo['principal'] is relation:
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1577
                op = relation.operator()
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1578
                if op == '=':
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1579
                    # need a predicable result for tests
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1580
                    args = sorted((sql, var.accept(self)))
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1581
                    args.insert(1, op)
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1582
                else:
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1583
                    args = (sql, op, var.accept(self))
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1584
                return '%s%s%s' % tuple(args)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1585
        except KeyError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1586
            # no principal defined, relation is necessarily the principal and
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1587
            # so nothing to return here
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1588
            pass
6003
5fbc1c4c13ff [rql2sql] fix bug with NOT of inlined relation: NULL values are not properly handled and hence some rows won't be returned while the should
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5901
diff changeset
  1589
        return None
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1590
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1591
    def _var_info(self, var):
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1592
        scope = self._state.scopes[var.scope]
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1593
        etype = self._state.solution[var.name]
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1594
        # XXX this check should be moved in rql.stcheck
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1595
        if self.schema.eschema(etype).final:
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1596
            raise BadRQLQuery(var.stmt.root)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1597
        tablealias = '_' + var.name
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1598
        sql = '%s.%seid' % (tablealias, SQL_PREFIX)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1599
        self._state.add_table('%s%s AS %s' % (SQL_PREFIX, etype, tablealias),
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1600
                              tablealias, scope=scope)
3762
e416186fb91c prefix sql aliases for entity table by '_' to avoid pb with variable such as 'AS' (eg a keyword in SQL)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3754
diff changeset
  1601
        return sql, tablealias
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1602
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1603
    def _inlined_var_sql(self, var, rtype):
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1604
        # rtype may be an attribute relation when called from
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1605
        # _visit_var_attr_relation.  take care about 'eid' rtype, since in
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1606
        # some case we may use the `entities` table, so in that case we've
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1607
        # to properly use variable'sql
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1608
        if rtype == 'eid':
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1609
            sql = var.accept(self)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1610
        else:
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1611
            sql = '%s.%s%s' % (self._var_table(var), SQL_PREFIX, rtype)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1612
        return sql
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1522
diff changeset
  1613
3815
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1614
    def _linked_var_sql(self, variable):
50b87f759b5d test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3787
diff changeset
  1615
        rel = (variable.stinfo.get('principal') or
10669
155c29e0ed1c [py3k] use next builtin instead of next method
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10663
diff changeset
  1616
               next(iter(variable.stinfo['rhsrelations'])))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1617
        linkedvar = rel.children[0].variable
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1618
        if rel.r_type == 'eid':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1619
            return linkedvar.accept(self)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1620
        if isinstance(linkedvar, ColumnAlias):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1621
            raise BadRQLQuery('variable %s should be selected by the subquery'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1622
                              % variable.name)
11237
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1623
        mapkey = '%s.%s' % (self._state.solution[linkedvar.name], rel.r_type)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1624
        if mapkey in self.attr_map:
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1625
            cb, sourcecb = self.attr_map[mapkey]
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1626
            if not sourcecb:
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1627
                return cb(self, linkedvar, rel)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1628
            # attribute mapped at the source level (bfss for instance)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1629
            stmt = rel.stmt
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1630
            for selectidx, vref in iter_mapped_var_sels(stmt, variable):
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1631
                stack = [cb]
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1632
                update_source_cb_stack(self._state, stmt, vref, stack)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1633
                self._state._needs_source_cb[selectidx] = stack
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1634
        linkedvar.accept(self)
f32134dd0067 [repository] drop remanescence of old multi-sources code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11057
diff changeset
  1635
        return '%s.%s%s' % (linkedvar._q_sqltable, SQL_PREFIX, rel.r_type)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1636
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1637
    # tables handling #########################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1638
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1639
    def _var_table(self, var):
11347
b4dcfd734686 [server] some pep8 in rql2sql
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11301
diff changeset
  1640
        var.accept(self)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
  1641
        return var._q_sqltable