author | Rémi Cardona <remi.cardona@logilab.fr> |
Fri, 18 Sep 2015 11:58:29 +0200 | |
changeset 10707 | 3f4f190f8e35 |
parent 10677 | 59ec0aaae08b |
child 11293 | 63c589e6b076 |
permissions | -rw-r--r-- |
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
|
1 |
# copyright 2003-2013 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 | 18 |
"""RQL to SQL generator for native sources. |
19 |
||
20 |
||
21 |
SQL queries optimization |
|
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 | 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 | 26 |
which allow us to do :: |
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 | 31 |
|
32 |
||
33 |
2. Any X WHERE X nonfinal1 Y, Y nonfinal2 Z |
|
34 |
||
35 |
-> direct join between nonfinal1 and nonfinal2, whatever X,Y, Z (unless |
|
36 |
inlined...) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
37 |
|
0 | 38 |
NOT IMPLEMENTED (and quite hard to implement) |
39 |
||
40 |
Potential optimization information is collected by the querier, sql generation |
|
41 |
is done according to this information |
|
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 | 49 |
|
50 |
__docformat__ = "restructuredtext en" |
|
51 |
||
52 |
import threading |
|
53 |
||
10677 | 54 |
from six import PY2 |
10609
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10522
diff
changeset
|
55 |
from six.moves import range |
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10522
diff
changeset
|
56 |
|
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
|
57 |
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
|
58 |
|
0 | 59 |
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
|
60 |
from rql.utils import common_parent |
0 | 61 |
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
|
62 |
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
|
63 |
Not, Comparison, ColumnAlias, Relation, SubQuery) |
0 | 64 |
|
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
|
65 |
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
|
66 |
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
|
67 |
from cubicweb.server.sqlutils import SQL_PREFIX |
0 | 68 |
|
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
|
69 |
ColumnAlias._q_invariant = False # avoid to check for ColumnAlias / Variable |
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
|
70 |
|
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
|
71 |
FunctionDescr.source_execute = 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
|
72 |
|
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 |
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
|
74 |
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
|
75 |
FunctionDescr.update_cb_stack = default_update_cb_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
|
76 |
|
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 |
get_func_descr = SQL_FUNCTIONS_REGISTRY.get_function |
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 |
|
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
|
79 |
LENGTH = get_func_descr('LENGTH') |
5630
40d7c7e180f1
[storage] source's callback has a new prototype, update usage
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5593
diff
changeset
|
80 |
def length_source_execute(source, session, value): |
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
|
81 |
return len(value.getvalue()) |
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
|
82 |
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
|
83 |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
84 |
def _new_var(select, varname): |
0 | 85 |
newvar = select.get_variable(varname) |
86 |
if not 'relations' in newvar.stinfo: |
|
87 |
# not yet initialized |
|
88 |
newvar.prepare_annotation() |
|
89 |
newvar.stinfo['scope'] = select |
|
90 |
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
|
91 |
select.selection.append(VariableRef(newvar)) |
0 | 92 |
return newvar |
93 |
||
94 |
def _fill_to_wrap_rel(var, newselect, towrap, schema): |
|
95 |
for rel in var.stinfo['relations'] - var.stinfo['rhsrelations']: |
|
96 |
rschema = schema.rschema(rel.r_type) |
|
97 |
if rschema.inlined: |
|
98 |
towrap.add( (var, rel) ) |
|
99 |
for vref in rel.children[1].iget_nodes(VariableRef): |
|
100 |
newivar = _new_var(newselect, vref.name) |
|
101 |
_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
|
102 |
elif rschema.final: |
0 | 103 |
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
|
104 |
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
|
105 |
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
|
106 |
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
|
107 |
|
0 | 108 |
def rewrite_unstable_outer_join(select, solutions, unstable, schema): |
109 |
"""if some optional variables are unstable, they should be selected in a |
|
110 |
subquery. This function check this and rewrite the rql syntax tree if |
|
111 |
necessary (in place). Return a boolean telling if the tree has been modified |
|
112 |
""" |
|
113 |
modified = False |
|
114 |
for varname in tuple(unstable): |
|
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 | 117 |
continue |
118 |
unstable.remove(varname) |
|
119 |
newselect = Select() |
|
120 |
myunion = Union() |
|
121 |
myunion.append(newselect) |
|
122 |
# extract aliases / selection |
|
123 |
newvar = _new_var(newselect, var.name) |
|
124 |
newselect.selection = [VariableRef(newvar)] |
|
125 |
towrap_rels = set() |
|
126 |
_fill_to_wrap_rel(var, newselect, towrap_rels, schema) |
|
127 |
# extract relations |
|
128 |
for var, rel in towrap_rels: |
|
129 |
newrel = rel.copy(newselect) |
|
130 |
newselect.add_restriction(newrel) |
|
131 |
select.remove_node(rel) |
|
132 |
var.stinfo['relations'].remove(rel) |
|
133 |
newvar.stinfo['relations'].add(newrel) |
|
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 | 136 |
for vref in newrel.children[1].iget_nodes(VariableRef): |
137 |
var = vref.variable |
|
138 |
var.stinfo['relations'].add(newrel) |
|
139 |
var.stinfo['rhsrelations'].add(newrel) |
|
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 | 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 | 153 |
# full sub-query |
154 |
aliases = [VariableRef(select.get_variable(avar.name, i)) |
|
155 |
for i, avar in enumerate(newselect.selection)] |
|
156 |
select.add_subquery(SubQuery(aliases, myunion), check=False) |
|
157 |
return modified |
|
158 |
||
159 |
def _new_solutions(rqlst, solutions): |
|
160 |
"""first filter out subqueries variables from solutions""" |
|
161 |
newsolutions = [] |
|
162 |
for origsol in solutions: |
|
163 |
asol = {} |
|
164 |
for vname in rqlst.defined_vars: |
|
165 |
asol[vname] = origsol[vname] |
|
166 |
if not asol in newsolutions: |
|
167 |
newsolutions.append(asol) |
|
168 |
return newsolutions |
|
169 |
||
170 |
def remove_unused_solutions(rqlst, solutions, varmap, schema): |
|
171 |
"""cleanup solutions: remove solutions where invariant variables are taking |
|
172 |
different types |
|
173 |
""" |
|
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
|
174 |
newsols = _new_solutions(rqlst, solutions) |
0 | 175 |
existssols = {} |
176 |
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
|
177 |
invariants = {} |
10662
10942ed172de
[py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10652
diff
changeset
|
178 |
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
|
179 |
vtype = newsols[0][vname] |
0 | 180 |
if var._q_invariant or vname in varmap: |
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 |
# 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
|
182 |
# 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
|
183 |
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
|
184 |
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
|
185 |
elif var.scope is not rqlst: |
10450
c5c9e5b6fde0
[server/rql2sql] fix spelling in comment
Julien Cristau <julien.cristau@logilab.fr>
parents:
9543
diff
changeset
|
186 |
# move apart variables which are in a EXISTS scope and are variating |
0 | 187 |
try: |
188 |
thisexistssols, thisexistsvars = existssols[var.scope] |
|
189 |
except KeyError: |
|
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
|
190 |
thisexistssols = [newsols[0]] |
0 | 191 |
thisexistsvars = set() |
192 |
existssols[var.scope] = thisexistssols, thisexistsvars |
|
10609
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10522
diff
changeset
|
193 |
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
|
194 |
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
|
195 |
thisexistssols.append(newsols.pop(i)) |
0 | 196 |
thisexistsvars.add(vname) |
197 |
else: |
|
198 |
# remember unstable variables |
|
10609
e2d8e81bfe68
[py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10522
diff
changeset
|
199 |
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
|
200 |
if vtype != newsols[i][vname]: |
0 | 201 |
unstable.add(vname) |
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
|
202 |
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
|
203 |
# 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
|
204 |
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
|
205 |
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
|
206 |
if not 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
|
207 |
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
|
208 |
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
|
209 |
# 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
|
210 |
for sol in newsols: |
10662
10942ed172de
[py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10652
diff
changeset
|
211 |
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
|
212 |
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
|
213 |
for sol in existssols: |
3866
2783c166ad1a
fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3852
diff
changeset
|
214 |
try: |
10662
10942ed172de
[py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10652
diff
changeset
|
215 |
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
|
216 |
sol[invvar] = vartype |
2783c166ad1a
fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3852
diff
changeset
|
217 |
except KeyError: |
2783c166ad1a
fix potential key error
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3852
diff
changeset
|
218 |
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
|
219 |
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
|
220 |
if rewrite_unstable_outer_join(rqlst, newsols, unstable, schema): |
0 | 221 |
# 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
|
222 |
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
|
223 |
return newsols, existssols, unstable |
0 | 224 |
|
225 |
def relation_info(relation): |
|
226 |
lhs, rhs = relation.get_variable_parts() |
|
227 |
try: |
|
228 |
lhs = lhs.variable |
|
229 |
lhsconst = lhs.stinfo['constnode'] |
|
230 |
except AttributeError: |
|
231 |
lhsconst = lhs |
|
232 |
lhs = None |
|
233 |
except KeyError: |
|
234 |
lhsconst = None # ColumnAlias |
|
235 |
try: |
|
236 |
rhs = rhs.variable |
|
237 |
rhsconst = rhs.stinfo['constnode'] |
|
238 |
except AttributeError: |
|
239 |
rhsconst = rhs |
|
240 |
rhs = None |
|
241 |
except KeyError: |
|
242 |
rhsconst = None # ColumnAlias |
|
243 |
return lhs, lhsconst, rhs, rhsconst |
|
244 |
||
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
|
245 |
def sort_term_selection(sorts, rqlst, groups): |
0 | 246 |
# XXX beurk |
247 |
if isinstance(rqlst, list): |
|
248 |
def append(term): |
|
249 |
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
|
250 |
selectionidx = set(str(term) for term in rqlst) |
0 | 251 |
else: |
252 |
def append(term): |
|
253 |
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
|
254 |
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
|
255 |
|
0 | 256 |
for sortterm in sorts: |
257 |
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
|
258 |
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
|
259 |
selectionidx.add(str(term)) |
0 | 260 |
append(term) |
261 |
if groups: |
|
262 |
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
|
263 |
if not any(vref.is_equivalent(g) for g in groups): |
0 | 264 |
groups.append(vref) |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
265 |
|
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 |
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
|
267 |
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
|
268 |
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
|
269 |
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
|
270 |
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
|
271 |
if sorts and groups: |
3754 | 272 |
# 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
|
273 |
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
|
274 |
term = sortterm.term |
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
|
275 |
if not (isinstance(term, Constant) or \ |
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
|
276 |
(isinstance(term, Function) and |
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
|
277 |
get_func_descr(term.name).aggregat)): |
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
|
278 |
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
|
279 |
if not any(vref.is_equivalent(group) for group in groupvrefs): |
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
|
280 |
groups.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
|
281 |
groupvrefs.append(vref) |
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
|
282 |
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
|
283 |
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
|
284 |
for vref in term.get_nodes(VariableRef)) |
0 | 285 |
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
|
286 |
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
|
287 |
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
|
288 |
selectedidx.add(vref.name) |
0 | 289 |
rqlst.selection.append(vref) |
290 |
if having: |
|
291 |
for term in having: |
|
292 |
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
|
293 |
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
|
294 |
selectedidx.add(vref.name) |
0 | 295 |
rqlst.selection.append(vref) |
296 |
||
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
|
297 |
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
|
298 |
# 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
|
299 |
# callback |
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
|
300 |
if not (len(variable.stinfo['rhsrelations']) <= 1 and # < 1 on column 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
|
301 |
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
|
302 |
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
|
303 |
% 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
|
304 |
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
|
305 |
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
|
306 |
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
|
307 |
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
|
308 |
yield selectidx, vrefs[0] |
0 | 309 |
|
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
|
310 |
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
|
311 |
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
|
312 |
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
|
313 |
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
|
314 |
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
|
315 |
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
|
316 |
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
|
317 |
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
|
318 |
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
|
319 |
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
|
320 |
% 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
|
321 |
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
|
322 |
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
|
323 |
|
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 |
|
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 |
# IGenerator implementation for RQL->SQL ####################################### |
0 | 326 |
|
327 |
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
|
328 |
"""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
|
329 |
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
|
330 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
331 |
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
|
332 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
333 |
* `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
|
334 |
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
|
335 |
|
8238
087bb529035c
[spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7902
diff
changeset
|
336 |
* `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
|
337 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
338 |
'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
|
339 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
340 |
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
|
341 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
342 |
* `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
|
343 |
* `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
|
344 |
* `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
|
345 |
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
|
346 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
347 |
* `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
|
348 |
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
|
349 |
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
|
350 |
|
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 |
'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
|
352 |
""" |
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
|
353 |
def __init__(self, select, existssols, unstablevars): |
0 | 354 |
self.existssols = existssols |
355 |
self.unstablevars = unstablevars |
|
356 |
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
|
357 |
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
|
358 |
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
|
359 |
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
|
360 |
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
|
361 |
self.scope_nodes = [] |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
362 |
|
0 | 363 |
def reset(self, solution): |
364 |
"""reset some visit variables""" |
|
365 |
self.solution = solution |
|
366 |
self.count = 0 |
|
367 |
self.done = set() |
|
368 |
self.tables = self.subtables.copy() |
|
369 |
self.actual_tables = [[]] |
|
10663
54b8a1f249fb
[py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10662
diff
changeset
|
370 |
for _, tsql in self.tables.values(): |
0 | 371 |
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
|
372 |
self.outer_chains = [] |
0 | 373 |
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
|
374 |
self.outer_pending = {} |
0 | 375 |
self.duplicate_switches = [] |
376 |
self.aliases = {} |
|
377 |
self.restrictions = [] |
|
378 |
self._restr_stack = [] |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
379 |
self.ignore_varmap = False |
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
|
380 |
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
|
381 |
|
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
|
382 |
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
|
383 |
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
|
384 |
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
|
385 |
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
|
386 |
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
|
387 |
|
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
|
388 |
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
|
389 |
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
|
390 |
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
|
391 |
|
0 | 392 |
def add_restriction(self, restr): |
393 |
if restr: |
|
394 |
self.restrictions.append(restr) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
395 |
|
0 | 396 |
def iter_exists_sols(self, exists): |
397 |
if not exists in self.existssols: |
|
398 |
yield 1 |
|
399 |
return |
|
400 |
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
|
401 |
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
|
402 |
# when iterating other solutions inner to an EXISTS subquery, we should |
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
|
403 |
# 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
|
404 |
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
|
405 |
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
|
406 |
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
|
407 |
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
|
408 |
notdone_outside_vars.add(var) |
0 | 409 |
origsol = self.solution |
410 |
origtables = self.tables |
|
411 |
done = self.done |
|
412 |
for thisexistssol in thisexistssols: |
|
413 |
for vname in self.unstablevars: |
|
414 |
if thisexistssol[vname] != origsol[vname] and vname in thisexistsvars: |
|
415 |
break |
|
416 |
else: |
|
417 |
self.tables = origtables.copy() |
|
418 |
self.solution = thisexistssol |
|
419 |
yield 1 |
|
420 |
# cleanup self.done from stuff specific to exists |
|
421 |
for var in thisexistsvars: |
|
422 |
if var in done: |
|
423 |
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
|
424 |
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
|
425 |
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
|
426 |
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
|
427 |
notdone_outside_vars.remove(var) |
0 | 428 |
for rel in exists.iget_nodes(Relation): |
429 |
if rel in done: |
|
430 |
done.remove(rel) |
|
431 |
self.solution = origsol |
|
432 |
self.tables = origtables |
|
433 |
||
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
|
434 |
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
|
435 |
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
|
436 |
self.scopes[scope_node] = len(self.actual_tables) |
0 | 437 |
self.actual_tables.append([]) |
438 |
self._restr_stack.append(self.restrictions) |
|
439 |
self.restrictions = [] |
|
440 |
||
441 |
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
|
442 |
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
|
443 |
self.scope_nodes.pop() |
0 | 444 |
restrictions = self.restrictions |
445 |
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
|
446 |
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
|
447 |
# 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
|
448 |
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
|
449 |
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
|
450 |
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
|
451 |
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
|
452 |
# 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
|
453 |
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
|
454 |
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
|
455 |
# 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
|
456 |
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
|
457 |
# 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
|
458 |
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
|
459 |
# 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
|
460 |
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
|
461 |
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
|
462 |
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
|
463 |
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
|
464 |
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
|
465 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
466 |
# 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
|
467 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
468 |
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
|
469 |
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
|
470 |
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
|
471 |
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
|
472 |
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
|
473 |
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
|
474 |
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
|
475 |
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
|
476 |
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
|
477 |
|
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 |
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
|
479 |
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
|
480 |
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
|
481 |
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
|
482 |
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
|
483 |
|
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 |
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
|
485 |
"""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
|
486 |
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
|
487 |
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
|
488 |
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
|
489 |
# 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
|
490 |
# 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
|
491 |
# 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
|
492 |
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
|
493 |
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
|
494 |
# 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
|
495 |
# 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
|
496 |
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
|
497 |
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
|
498 |
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
|
499 |
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
|
500 |
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
|
501 |
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
|
502 |
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
|
503 |
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
|
504 |
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
|
505 |
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
|
506 |
|
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 |
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
|
508 |
"""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
|
509 |
`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
|
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 |
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
|
512 |
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
|
513 |
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
|
514 |
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
|
515 |
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
|
516 |
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
|
517 |
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
|
518 |
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
|
519 |
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
|
520 |
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
|
521 |
|
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 |
# 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
|
523 |
|
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 |
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
|
525 |
"""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
|
526 |
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
|
527 |
""" |
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 |
# 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
|
529 |
# 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
|
530 |
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
|
531 |
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
|
532 |
# 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
|
533 |
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
|
534 |
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
|
535 |
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
|
536 |
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
|
537 |
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
|
538 |
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
|
539 |
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
|
540 |
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
|
541 |
assert not tablealias in 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
|
542 |
|
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 |
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
|
544 |
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
|
545 |
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
|
546 |
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
|
547 |
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
|
548 |
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
|
549 |
|
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 |
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
|
551 |
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
|
552 |
"""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
|
553 |
""" |
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 |
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
|
555 |
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
|
556 |
louter, lconditions, lchain = outer_tables.get(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
|
557 |
(None, None, 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
|
558 |
router, rconditions, rchain = outer_tables.get(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
|
559 |
(None, None, 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
|
560 |
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
|
561 |
# 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
|
562 |
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
|
563 |
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
|
564 |
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
|
565 |
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
|
566 |
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
|
567 |
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
|
568 |
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
|
569 |
# [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
|
570 |
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
|
571 |
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
|
572 |
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
|
573 |
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
|
574 |
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
|
575 |
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
|
576 |
# [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
|
577 |
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
|
578 |
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
|
579 |
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
|
580 |
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
|
581 |
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
|
582 |
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
|
583 |
# [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
|
584 |
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
|
585 |
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
|
586 |
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
|
587 |
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
|
588 |
# 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
|
589 |
# 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
|
590 |
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
|
591 |
ridx = lchain.index(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
|
592 |
if (outertype == 'FULL' and router != '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
|
593 |
or (lidx < ridx and router != '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
|
594 |
or (ridx < lidx and louter != '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
|
595 |
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
|
596 |
# 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
|
597 |
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
|
598 |
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
|
599 |
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
|
600 |
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
|
601 |
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
|
602 |
# 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
|
603 |
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
|
604 |
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
|
605 |
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
|
606 |
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
|
607 |
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
|
608 |
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
|
609 |
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
|
610 |
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
|
611 |
|
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 |
# 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
|
613 |
|
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 |
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
|
615 |
"""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
|
616 |
# 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
|
617 |
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
|
618 |
# 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
|
619 |
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
|
620 |
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
|
621 |
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
|
622 |
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
|
623 |
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
|
624 |
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
|
625 |
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
|
626 |
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
|
627 |
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
|
628 |
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
|
629 |
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
|
630 |
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
|
631 |
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
|
632 |
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
|
633 |
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
|
634 |
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
|
635 |
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
|
636 |
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
|
637 |
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
|
638 |
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
|
639 |
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
|
640 |
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
|
641 |
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
|
642 |
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
|
643 |
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
|
644 |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
645 |
|
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
|
646 |
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
|
647 |
"""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
|
648 |
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
|
649 |
|
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
|
650 |
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
|
651 |
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
|
652 |
""" |
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
|
653 |
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
|
654 |
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
|
655 |
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
|
656 |
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
|
657 |
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
|
658 |
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
|
659 |
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
|
660 |
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
|
661 |
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
|
662 |
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
|
663 |
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
|
664 |
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
|
665 |
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
|
666 |
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
|
667 |
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
|
668 |
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
|
669 |
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
|
670 |
# 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
|
671 |
# 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
|
672 |
# 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
|
673 |
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
|
674 |
parents = 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
|
675 |
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
|
676 |
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
|
677 |
while not isinstance(p, Select): |
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
|
678 |
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
|
679 |
break |
6929
e9464d975908
[rql2sql] fix bug with NOT in "fake" having terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6493
diff
changeset
|
680 |
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
|
681 |
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
|
682 |
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
|
683 |
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
|
684 |
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
|
685 |
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
|
686 |
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
|
687 |
return fakehaving |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
688 |
|
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
|
689 |
|
0 | 690 |
class SQLGenerator(object): |
691 |
""" |
|
692 |
generation of SQL from the fully expanded RQL syntax tree |
|
693 |
SQL is designed to be used with a CubicWeb SQL schema |
|
694 |
||
695 |
Groups and sort are not handled here since they should not be handled at |
|
696 |
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
|
697 |
|
9492
c7fc56eecd1a
English typography
Dimitri Papadopoulos <dimitri.papadopoulos@cea.fr>
parents:
9361
diff
changeset
|
698 |
we should not have errors here! |
0 | 699 |
|
700 |
WARNING: a CubicWebSQLGenerator instance is not thread safe, but generate is |
|
701 |
protected by a lock |
|
702 |
""" |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
703 |
|
5010
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
704 |
def __init__(self, schema, dbhelper, attrmap=None): |
0 | 705 |
self.schema = schema |
5010
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
706 |
self.dbhelper = dbhelper |
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
707 |
self.dbencoding = dbhelper.dbencoding |
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
708 |
self.keyword_map = {'NOW' : self.dbhelper.sql_current_timestamp, |
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
709 |
'TODAY': self.dbhelper.sql_current_date, |
0 | 710 |
} |
5010
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
711 |
if not self.dbhelper.union_parentheses_support: |
0 | 712 |
self.union_sql = self.noparen_union_sql |
713 |
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
|
714 |
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
|
715 |
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
|
716 |
self.attr_map = attrmap |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
717 |
|
0 | 718 |
def generate(self, union, args=None, varmap=None): |
8238
087bb529035c
[spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7902
diff
changeset
|
719 |
"""return SQL queries and a variable dictionary from a RQL syntax tree |
0 | 720 |
|
721 |
:partrqls: a list of couple (rqlst, solutions) |
|
722 |
:args: optional dictionary with values of substitutions used in the query |
|
723 |
:varmap: optional dictionary mapping variable name to a special table |
|
724 |
name, in case the query as to fetch data from temporary tables |
|
725 |
||
726 |
return an sql string and a dictionary with substitutions values |
|
727 |
""" |
|
728 |
if args is None: |
|
729 |
args = {} |
|
730 |
if varmap is None: |
|
731 |
varmap = {} |
|
732 |
self._lock.acquire() |
|
733 |
self._args = args |
|
734 |
self._varmap = varmap |
|
735 |
self._query_attrs = {} |
|
736 |
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
|
737 |
# self._not_scope_offset = 0 |
0 | 738 |
try: |
739 |
# union query for each rqlst / solution |
|
740 |
sql = self.union_sql(union) |
|
741 |
# 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
|
742 |
return sql, self._query_attrs, self._state.needs_source_cb |
0 | 743 |
finally: |
744 |
self._lock.release() |
|
745 |
||
6491
ee9a10b6620e
pylint option update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6297
diff
changeset
|
746 |
def union_sql(self, union, needalias=False): # pylint: disable=E0202 |
0 | 747 |
if len(union.children) == 1: |
748 |
return self.select_sql(union.children[0], needalias) |
|
749 |
sqls = ('(%s)' % self.select_sql(select, needalias) |
|
750 |
for select in union.children) |
|
751 |
return '\nUNION ALL\n'.join(sqls) |
|
752 |
||
753 |
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
|
754 |
# 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
|
755 |
# 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
|
756 |
# 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
|
757 |
# |
0 | 758 |
# see http://www.sqlite.org/cvstrac/tktview?tn=3074 |
759 |
sqls = (self.select_sql(select, needalias) |
|
760 |
for i, select in enumerate(union.children)) |
|
761 |
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
|
762 |
|
0 | 763 |
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
|
764 |
"""return SQL queries and a variable dictionary from a RQL syntax tree |
0 | 765 |
|
766 |
: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
|
767 |
:solution: a dictionary containing variables binding. |
087bb529035c
[spelling] fix dictionnary -> dictionary typo
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7902
diff
changeset
|
768 |
A solution's dictionary has variable's names as key and variable's |
0 | 769 |
types as values |
770 |
:needwrap: boolean telling if the query will be wrapped in an outer |
|
771 |
query (to deal with aggregat and/or grouping) |
|
772 |
""" |
|
9518
54ead5f372bb
[rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9492
diff
changeset
|
773 |
if select.distinct: |
54ead5f372bb
[rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9492
diff
changeset
|
774 |
distinct = True |
54ead5f372bb
[rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9492
diff
changeset
|
775 |
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
|
776 |
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
|
777 |
else: |
54ead5f372bb
[rql2sql] remove special behaviour of symmetric relation vs DISTINCT
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9492
diff
changeset
|
778 |
distinct = False |
0 | 779 |
sorts = select.orderby |
780 |
groups = select.groupby |
|
781 |
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
|
782 |
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
|
783 |
scope = None |
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
784 |
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
|
785 |
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
|
786 |
if vscope is select: |
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
787 |
continue # ignore select scope, so restriction is added to |
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
788 |
# the inner most scope possible |
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
789 |
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
|
790 |
scope = vscope |
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
791 |
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
|
792 |
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
|
793 |
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
|
794 |
scope = select |
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
795 |
scope.add_restriction(restr) |
0 | 796 |
# remember selection, it may be changed and have to be restored |
797 |
origselection = select.selection[:] |
|
798 |
# check if the query will have union subquery, if it need sort term |
|
799 |
# selection (union or distinct query) and wrapping (union with groups) |
|
800 |
needwrap = False |
|
801 |
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
|
802 |
selectsortterms = distinct |
0 | 803 |
if len(sols) > 1: |
804 |
# remove invariant from solutions |
|
805 |
sols, existssols, unstable = remove_unused_solutions( |
|
806 |
select, sols, self._varmap, self.schema) |
|
807 |
if len(sols) > 1: |
|
808 |
# if there is still more than one solution, a UNION will be |
|
809 |
# generated and so sort terms have to be selected |
|
810 |
selectsortterms = True |
|
811 |
# and if select is using group by or aggregat, a wrapping |
|
812 |
# query will be necessary |
|
813 |
if groups or select.has_aggregat: |
|
814 |
select.select_only_variables() |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
815 |
needwrap = True |
0 | 816 |
else: |
817 |
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
|
818 |
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
|
819 |
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
|
820 |
# 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
|
821 |
state.merge_source_cbs(self._state.needs_source_cb) |
0 | 822 |
# treat subqueries |
823 |
self._subqueries_sql(select, state) |
|
824 |
# generate sql for this select node |
|
825 |
if needwrap: |
|
826 |
outerselection = origselection[:] |
|
827 |
if sorts and selectsortterms: |
|
828 |
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
|
829 |
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
|
830 |
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
|
831 |
sorts, groups, having) |
0 | 832 |
if needwrap: |
833 |
fneedwrap = len(outerselection) != len(origselection) |
|
834 |
else: |
|
835 |
fneedwrap = len(select.selection) != len(origselection) |
|
836 |
if fneedwrap: |
|
837 |
needalias = True |
|
838 |
self._in_wrapping_query = False |
|
839 |
self._state = state |
|
840 |
try: |
|
7672
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
841 |
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
|
842 |
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
|
843 |
# 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
|
844 |
# correct column aliases |
0 | 845 |
self._in_wrapping_query = needwrap |
846 |
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
|
847 |
# 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
|
848 |
# will interpret it as a positional index in the selection |
0 | 849 |
groups = ','.join(vref.accept(self) for vref in groups |
850 |
if not isinstance(vref, Constant)) |
|
851 |
if having: |
|
852 |
# 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
|
853 |
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
|
854 |
if not isinstance(term, Constant)) |
0 | 855 |
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
|
856 |
sql = '%s FROM (%s) AS T1' % ( |
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
857 |
self._selection_sql(outerselection, distinct,needalias), |
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
858 |
sql) |
0 | 859 |
if groups: |
860 |
sql += '\nGROUP BY %s' % groups |
|
861 |
if having: |
|
862 |
sql += '\nHAVING %s' % having |
|
863 |
# sort |
|
864 |
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
|
865 |
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
|
866 |
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
|
867 |
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
|
868 |
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
|
869 |
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
|
870 |
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
|
871 |
_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
|
872 |
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
|
873 |
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
|
874 |
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
|
875 |
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
|
876 |
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
|
877 |
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
|
878 |
else: |
bcdf22734059
Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents:
7042
diff
changeset
|
879 |
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
|
880 |
state.finalize_source_cbs() |
0 | 881 |
finally: |
882 |
select.selection = origselection |
|
883 |
# 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
|
884 |
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
|
885 |
select.limit, |
bcdf22734059
Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents:
7042
diff
changeset
|
886 |
select.offset, |
bcdf22734059
Abstract the support for ORDER BY and LIMIT/OFFSET SQL generation
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents:
7042
diff
changeset
|
887 |
sqlsortterms) |
0 | 888 |
return sql |
889 |
||
890 |
def _subqueries_sql(self, select, state): |
|
891 |
for i, subquery in enumerate(select.with_): |
|
892 |
sql = self.union_sql(subquery.query, needalias=True) |
|
5010
b2c5aee8ca3f
[cleanup] rename dbms_helper to dbhelper for consistency
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
893 |
tablealias = '_T%s' % i # XXX nested subqueries |
0 | 894 |
sql = '(%s) AS %s' % (sql, tablealias) |
895 |
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
|
896 |
latest_state = self._state |
0 | 897 |
for vref in subquery.aliases: |
898 |
alias = vref.variable |
|
899 |
alias._q_sqltable = tablealias |
|
900 |
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
|
901 |
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
|
902 |
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
|
903 |
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
|
904 |
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
|
905 |
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
|
906 |
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
|
907 |
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
|
908 |
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
|
909 |
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
|
910 |
continue |
0 | 911 |
|
7672
f31f9882c90f
[rql2sql] closes #1832859: fake HAVING terms w/ EXISTS terms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7642
diff
changeset
|
912 |
def _solutions_sql(self, select, solutions, distinct, needalias): |
0 | 913 |
sqls = [] |
914 |
for solution in solutions: |
|
915 |
self._state.reset(solution) |
|
916 |
# visit restriction subtree |
|
917 |
if select.where is not None: |
|
918 |
self._state.add_restriction(select.where.accept(self)) |
|
919 |
sql = [self._selection_sql(select.selection, distinct, needalias)] |
|
920 |
if self._state.restrictions: |
|
921 |
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
|
922 |
self._state.merge_source_cbs(self._state._needs_source_cb) |
0 | 923 |
# add required tables |
924 |
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
|
925 |
tables = self._state.tables_sql() |
0 | 926 |
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
|
927 |
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
|
928 |
elif self._state.restrictions and self.dbhelper.needs_from_clause: |
0 | 929 |
sql.insert(1, 'FROM (SELECT 1) AS _T') |
930 |
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
|
931 |
if distinct: |
0 | 932 |
return '\nUNION\n'.join(sqls) |
933 |
else: |
|
934 |
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
|
935 |
|
0 | 936 |
def _selection_sql(self, selected, distinct, needaliasing=False): |
937 |
clause = [] |
|
938 |
for term in selected: |
|
939 |
sql = term.accept(self) |
|
940 |
if needaliasing: |
|
941 |
colalias = 'C%s' % len(clause) |
|
942 |
clause.append('%s AS %s' % (sql, colalias)) |
|
943 |
if isinstance(term, VariableRef): |
|
944 |
self._state.aliases[term.name] = colalias |
|
945 |
else: |
|
946 |
clause.append(sql) |
|
947 |
if distinct: |
|
948 |
return 'SELECT DISTINCT %s' % ', '.join(clause) |
|
949 |
return 'SELECT %s' % ', '.join(clause) |
|
950 |
||
951 |
def _sortterm_sql(self, sortterm, selectidx): |
|
952 |
term = sortterm.term |
|
953 |
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
|
954 |
sqlterm = selectidx.index(str(term)) + 1 |
0 | 955 |
except ValueError: |
956 |
# 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
|
957 |
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
|
958 |
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
|
959 |
return None |
0 | 960 |
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
|
961 |
return str(sqlterm) |
0 | 962 |
else: |
963 |
return '%s DESC' % sqlterm |
|
964 |
||
965 |
def visit_and(self, et): |
|
966 |
"""generate SQL for a AND subtree""" |
|
967 |
res = [] |
|
968 |
for c in et.children: |
|
969 |
part = c.accept(self) |
|
970 |
if part: |
|
971 |
res.append(part) |
|
972 |
return ' AND '.join(res) |
|
973 |
||
974 |
def visit_or(self, ou): |
|
975 |
"""generate SQL for a OR subtree""" |
|
976 |
res = [] |
|
977 |
for c in ou.children: |
|
978 |
part = c.accept(self) |
|
979 |
if part: |
|
980 |
res.append('(%s)' % part) |
|
981 |
if res: |
|
982 |
if len(res) > 1: |
|
983 |
return '(%s)' % ' OR '.join(res) |
|
984 |
return res[0] |
|
985 |
return '' |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
986 |
|
0 | 987 |
def visit_not(self, node): |
988 |
csql = node.children[0].accept(self) |
|
989 |
if node in self._state.done or not csql: |
|
990 |
# already processed or no sql generated by children |
|
991 |
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
|
992 |
return 'NOT (%s)' % csql |
0 | 993 |
|
994 |
def visit_exists(self, exists): |
|
995 |
"""generate SQL name for a exists subquery""" |
|
996 |
sqls = [] |
|
997 |
for dummy in self._state.iter_exists_sols(exists): |
|
998 |
sql = self._visit_exists(exists) |
|
999 |
if sql: |
|
1000 |
sqls.append(sql) |
|
1001 |
if not sqls: |
|
1002 |
return '' |
|
1003 |
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
|
1004 |
|
0 | 1005 |
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
|
1006 |
self._state.push_scope(exists) |
0 | 1007 |
restriction = exists.children[0].accept(self) |
1008 |
restrictions, tables = self._state.pop_scope() |
|
1009 |
if restriction: |
|
1010 |
restrictions.append(restriction) |
|
1011 |
restriction = ' AND '.join(restrictions) |
|
1012 |
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
|
1013 |
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
|
1014 |
return 'SELECT 1 FROM %s' % tables |
0 | 1015 |
return '' |
1016 |
if not tables: |
|
1017 |
# 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
|
1018 |
sql = 'SELECT 1 WHERE %s' % restriction |
0 | 1019 |
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
|
1020 |
sql = 'SELECT 1 FROM %s WHERE %s' % (tables, restriction) |
0 | 1021 |
return sql |
1022 |
||
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1023 |
|
0 | 1024 |
def visit_relation(self, relation): |
1025 |
"""generate SQL for a relation""" |
|
1026 |
rtype = relation.r_type |
|
1027 |
# don't care of type constraint statement (i.e. relation_type = 'is') |
|
1028 |
if relation.is_types_restriction(): |
|
1029 |
return '' |
|
1030 |
lhs, rhs = relation.get_parts() |
|
1031 |
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
|
1032 |
if rschema.final: |
0 | 1033 |
if rtype == 'eid' and lhs.variable._q_invariant and \ |
1034 |
lhs.variable.stinfo['constnode']: |
|
1035 |
# special case where this restriction is already generated by |
|
1036 |
# some other relation |
|
1037 |
return '' |
|
1038 |
# attribute relation |
|
1039 |
if rtype == 'has_text': |
|
1040 |
sql = self._visit_has_text_relation(relation) |
|
1041 |
else: |
|
1042 |
rhs_vars = rhs.get_nodes(VariableRef) |
|
1043 |
if rhs_vars: |
|
1044 |
# if variable(s) in the RHS |
|
1045 |
sql = self._visit_var_attr_relation(relation, rhs_vars) |
|
1046 |
else: |
|
1047 |
# no variables in the RHS |
|
1048 |
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
|
1049 |
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
|
1050 |
and rhs.children[0].eval(self._args) is None): |
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
|
1051 |
# special case "C is NULL" |
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
|
1052 |
if lhs.name in self._varmap: |
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
|
1053 |
lhssql = self._varmap[lhs.name] |
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
|
1054 |
else: |
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
|
1055 |
lhssql = lhs.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
|
1056 |
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
|
1057 |
elif '%s.%s' % (lhs, relation.r_type) in self._varmap: |
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
|
1058 |
# relation has already been processed by a previous step |
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
|
1059 |
return '' |
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
|
1060 |
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
|
1061 |
# 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
|
1062 |
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
|
1063 |
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
|
1064 |
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
|
1065 |
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
|
1066 |
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
|
1067 |
sql = self._visit_inlined_relation(relation) |
0 | 1068 |
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
|
1069 |
# 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
|
1070 |
sql = self._visit_relation(relation, rschema) |
0 | 1071 |
return sql |
1072 |
||
1073 |
def _visit_inlined_relation(self, relation): |
|
1074 |
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
|
1075 |
# 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
|
1076 |
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
|
1077 |
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
|
1078 |
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
|
1079 |
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
|
1080 |
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
|
1081 |
if isinstance(relation.parent, Not): |
0 | 1082 |
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
|
1083 |
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
|
1084 |
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
|
1085 |
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
|
1086 |
# 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
|
1087 |
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
|
1088 |
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
|
1089 |
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
|
1090 |
sql = '%s=%s' % (lhssql, 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
|
1091 |
elif isinstance(rhsvar, Variable) and rhsvar._q_invariant and \ |
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 |
not rhsvar.name in self._varmap: |
0 | 1093 |
# if the rhs variable is only linked to this relation, this mean we |
1094 |
# only want the relation to exists, eg NOT NULL in case of inlined |
|
1095 |
# 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
|
1096 |
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
|
1097 |
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
|
1098 |
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
|
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 |
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
|
1101 |
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
|
1102 |
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
|
1103 |
return '%s AND %s' % (sql, moresql) |
0 | 1104 |
|
1105 |
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
|
1106 |
if termconst or not termvar._q_invariant: |
0 | 1107 |
termsql = termconst and termconst.accept(self) or termvar.accept(self) |
1108 |
yield '%s.%s=%s' % (rid, relfield, termsql) |
|
1109 |
elif termvar._q_invariant: |
|
1110 |
# if the variable is mapped, generate restriction anyway |
|
1111 |
if termvar.name in self._varmap: |
|
1112 |
termsql = termvar.accept(self) |
|
1113 |
yield '%s.%s=%s' % (rid, relfield, termsql) |
|
1114 |
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
|
1115 |
if extrajoin is not None: |
0 | 1116 |
yield extrajoin |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1117 |
|
0 | 1118 |
def _visit_relation(self, relation, rschema): |
1119 |
"""generate SQL for a relation |
|
1120 |
||
1121 |
implements optimization 1. |
|
1122 |
""" |
|
1123 |
if relation.r_type == 'identity': |
|
1124 |
# special case "X identity Y" |
|
1125 |
lhs, rhs = relation.get_parts() |
|
1126 |
return '%s%s' % (lhs.accept(self), rhs.accept(self)) |
|
1127 |
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
|
1128 |
rid = self._state.relation_table(relation) |
0 | 1129 |
sqls = [] |
1130 |
sqls += self._process_relation_term(relation, rid, lhsvar, lhsconst, 'eid_from') |
|
1131 |
sqls += self._process_relation_term(relation, rid, rhsvar, rhsconst, 'eid_to') |
|
1132 |
sql = ' AND '.join(sqls) |
|
1133 |
return sql |
|
1134 |
||
1135 |
def _visit_outer_join_relation(self, relation, rschema): |
|
1136 |
""" |
|
1137 |
left outer join syntax (optional=='right'): |
|
1138 |
X relation Y? |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1139 |
|
0 | 1140 |
right outer join syntax (optional=='left'): |
1141 |
X? relation Y |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1142 |
|
0 | 1143 |
full outer join syntaxes (optional=='both'): |
1144 |
X? relation Y? |
|
1145 |
||
1146 |
if relation is inlined: |
|
1147 |
if it's a left outer join: |
|
1148 |
-> X LEFT OUTER JOIN Y ON (X.relation=Y.eid) |
|
1149 |
elif it's a right outer join: |
|
1150 |
-> Y LEFT OUTER JOIN X ON (X.relation=Y.eid) |
|
1151 |
elif it's a full outer join: |
|
1152 |
-> X FULL OUTER JOIN Y ON (X.relation=Y.eid) |
|
1153 |
else: |
|
1154 |
if it's a left outer join: |
|
1155 |
-> X LEFT OUTER JOIN relation ON (relation.eid_from=X.eid) |
|
1156 |
LEFT OUTER JOIN Y ON (relation.eid_to=Y.eid) |
|
1157 |
elif it's a right outer join: |
|
1158 |
-> Y LEFT OUTER JOIN relation ON (relation.eid_to=Y.eid) |
|
1159 |
LEFT OUTER JOIN X ON (relation.eid_from=X.eid) |
|
1160 |
elif it's a full outer join: |
|
1161 |
-> X FULL OUTER JOIN Y ON (X.relation=Y.eid) |
|
1162 |
""" |
|
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
|
1163 |
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
|
1164 |
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
|
1165 |
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
|
1166 |
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
|
1167 |
leftconst, rightconst = rightconst, leftconst |
0 | 1168 |
joinattr, restrattr = 'eid_to', 'eid_from' |
1169 |
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
|
1170 |
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
|
1171 |
# 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
|
1172 |
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
|
1173 |
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
|
1174 |
# 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
|
1175 |
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
|
1176 |
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
|
1177 |
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
|
1178 |
# 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
|
1179 |
leftalias = leftvar.stinfo['principal']._q_sqltable |
0 | 1180 |
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
|
1181 |
# search for relation on which we should 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
|
1182 |
for orelation in leftvar.stinfo['relations']: |
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 |
if (orelation is not relation and |
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 |
not self.schema.rschema(orelation.r_type).final): |
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 |
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
|
1186 |
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
|
1187 |
for orelation in rightvar.stinfo['relations']: |
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 |
if (orelation is not relation and |
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
1189 |
not self.schema.rschema(orelation.r_type).final |
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 |
and orelation.optional): |
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
1191 |
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
|
1192 |
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
|
1193 |
# 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
|
1194 |
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
|
1195 |
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
|
1196 |
# 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
|
1197 |
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
|
1198 |
# 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
|
1199 |
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
|
1200 |
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
|
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 |
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
|
1203 |
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
|
1204 |
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
|
1205 |
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
|
1206 |
# 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
|
1207 |
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
|
1208 |
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
|
1209 |
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
|
1210 |
# 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
|
1211 |
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
|
1212 |
# 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
|
1213 |
# 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
|
1214 |
# 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
|
1215 |
# 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
|
1216 |
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
|
1217 |
rightsql = rightvar.accept(self) # accept before using var_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
|
1218 |
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
|
1219 |
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
|
1220 |
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
|
1221 |
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
|
1222 |
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
|
1223 |
outertype, '%s.%s=%s' % (leftalias, restrattr, rightvar.accept(self))) |
0 | 1224 |
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
|
1225 |
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
|
1226 |
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
|
1227 |
'%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
|
1228 |
# 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
|
1229 |
# 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
|
1230 |
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
|
1231 |
|
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 |
|
7eaef037ea9d
[sql generation] fix missing join with outer joins w/ rhs invariant variable...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7108
diff
changeset
|
1233 |
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
|
1234 |
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
|
1235 |
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
|
1236 |
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
|
1237 |
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
|
1238 |
rhsalias = rhsvar and self._var_table(rhsvar) |
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
|
1239 |
try: |
7734
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1240 |
lhssql = self._varmap['%s.%s' % (lhsvar.name, attr)] |
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
|
1241 |
except KeyError: |
7734
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1242 |
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
|
1243 |
lhssql = lhsconst.accept(self) |
9230
a68b2fe8a800
[rql2sql] fix bad sql generated when outer joining 'identity' relation and lhs var comes from a subquery. Closes #3099418
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9167
diff
changeset
|
1244 |
elif attr == 'eid': |
a68b2fe8a800
[rql2sql] fix bad sql generated when outer joining 'identity' relation and lhs var comes from a subquery. Closes #3099418
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9167
diff
changeset
|
1245 |
lhssql = lhsvar.accept(self) |
7734
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1246 |
else: |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1247 |
lhssql = '%s.%s%s' % (lhsalias, SQL_PREFIX, attr) |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1248 |
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
|
1249 |
# 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
|
1250 |
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
|
1251 |
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
|
1252 |
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
|
1253 |
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
|
1254 |
outertype = 'LEFT' |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1255 |
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
|
1256 |
outertype = 'FULL' |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1257 |
else: |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1258 |
outertype = 'LEFT' |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1259 |
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
|
1260 |
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
|
1261 |
# 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
|
1262 |
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
|
1263 |
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
|
1264 |
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
|
1265 |
return condition |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1266 |
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
|
1267 |
return |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1268 |
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
|
1269 |
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
|
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 |
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
|
1272 |
if lhsalias == rhsalias: |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1273 |
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
|
1274 |
else: |
59fea81647e5
[rql2sql] closes #1892473: enhance handling of optional inlined relation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7729
diff
changeset
|
1275 |
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
|
1276 |
lhsalias, rhsalias, outertype, condition) |
0 | 1277 |
return '' |
1278 |
||
1279 |
def _visit_var_attr_relation(self, relation, rhs_vars): |
|
1280 |
"""visit an attribute relation with variable(s) in the RHS |
|
1281 |
||
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
|
1282 |
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
|
1283 |
(eg X attr1 A, Y attr2 A). In case of selection, nothing to do here. |
0 | 1284 |
""" |
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
|
1285 |
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
|
1286 |
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
|
1287 |
var = vref.variable |
2073
173c646981a7
fix missing from close when using a var map
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
1288 |
if var.name in self._varmap: |
173c646981a7
fix missing from close when using a var map
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
1289 |
# ensure table is added |
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
|
1290 |
self._var_info(var) |
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 |
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
|
1292 |
# 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
|
1293 |
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
|
1294 |
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
|
1295 |
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
|
1296 |
# 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
|
1297 |
# 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
|
1298 |
# 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
|
1299 |
if ored or (principal is not None and principal is not relation |
8459
1931953226f2
[rql2sql] remove debug print and fix bug introduced in 8469:69ad9a509bc3
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
8457
diff
changeset
|
1300 |
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
|
1301 |
# 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
|
1302 |
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
|
1303 |
# 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
|
1304 |
# 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
|
1305 |
_rel = [rel for rel in var.stinfo['rhsrelations'] |
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 |
if not rel is principal][0] |
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 |
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
|
1308 |
_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
|
1309 |
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
|
1310 |
_rel.r_type) |
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
|
1311 |
try: |
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
|
1312 |
self._state.ignore_varmap = True |
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
|
1313 |
sql = lhssql + relation.children[1].accept(self) |
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
|
1314 |
finally: |
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
|
1315 |
self._state.ignore_varmap = False |
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
|
1316 |
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
|
1317 |
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
|
1318 |
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
|
1319 |
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
|
1320 |
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
|
1321 |
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
|
1322 |
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
|
1323 |
return '' |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1324 |
|
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 |
def _visit_attribute_relation(self, rel): |
0 | 1326 |
"""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
|
1327 |
lhs, rhs = rel.get_parts() |
0 | 1328 |
rhssql = rhs.accept(self) |
1329 |
table = self._var_table(lhs.variable) |
|
1330 |
if table is None: |
|
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
|
1331 |
assert rel.r_type == 'eid' |
0 | 1332 |
lhssql = lhs.accept(self) |
1333 |
else: |
|
1334 |
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
|
1335 |
lhssql = self._varmap['%s.%s' % (lhs.name, rel.r_type)] |
0 | 1336 |
except KeyError: |
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
|
1337 |
mapkey = '%s.%s' % (self._state.solution[lhs.name], rel.r_type) |
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
|
1338 |
if mapkey in self.attr_map: |
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
|
1339 |
cb, sourcecb = self.attr_map[mapkey] |
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
|
1340 |
if sourcecb: |
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
|
1341 |
# callback is a source callback, we can't use this |
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
|
1342 |
# attribute in restriction |
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
|
1343 |
raise QueryError("can't use %s (%s) in restriction" |
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
|
1344 |
% (mapkey, rel.as_string())) |
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
|
1345 |
lhssql = cb(self, lhs.variable, rel) |
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
|
1346 |
elif rel.r_type == 'eid': |
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
|
1347 |
lhssql = lhs.variable._q_sql |
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
|
1348 |
else: |
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
|
1349 |
lhssql = '%s.%s%s' % (table, SQL_PREFIX, rel.r_type) |
0 | 1350 |
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
|
1351 |
if rel._q_needcast == 'TODAY': |
0 | 1352 |
sql = 'DATE(%s)%s' % (lhssql, rhssql) |
1353 |
# XXX which cast function should be used |
|
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
|
1354 |
#elif rel._q_needcast == 'NOW': |
0 | 1355 |
# sql = 'TIMESTAMP(%s)%s' % (lhssql, rhssql) |
1356 |
else: |
|
1357 |
sql = '%s%s' % (lhssql, rhssql) |
|
1358 |
except AttributeError: |
|
1359 |
sql = '%s%s' % (lhssql, rhssql) |
|
5004
4cc020ee70e2
le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
1360 |
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
|
1361 |
self._state.add_outer_join_condition(table, sql) |
0 | 1362 |
else: |
1363 |
return sql |
|
1364 |
||
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
|
1365 |
def _visit_has_text_relation(self, rel): |
0 | 1366 |
"""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
|
1367 |
lhs, rhs = rel.get_parts() |
0 | 1368 |
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
|
1369 |
alias = self._state.fti_table(rel, self.dbhelper.fti_table) |
0 | 1370 |
jointo = lhs.accept(self) |
1371 |
restriction = '' |
|
1372 |
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
|
1373 |
me_is_principal = lhsvar.stinfo.get('principal') is rel |
0 | 1374 |
if me_is_principal: |
5004
4cc020ee70e2
le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
1375 |
if lhsvar.stinfo['typerel'] is None: |
0 | 1376 |
# the variable is using the fti table, no join needed |
1377 |
jointo = None |
|
1378 |
elif not lhsvar.name in self._varmap: |
|
1379 |
# join on entities instead of etype's table to get result for |
|
1380 |
# external entities on multisources configurations |
|
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
|
1381 |
ealias = lhsvar._q_sqltable = '_' + lhsvar.name |
0 | 1382 |
jointo = lhsvar._q_sql = '%s.eid' % ealias |
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
|
1383 |
self._state.add_table('entities AS %s' % ealias, ealias) |
0 | 1384 |
if not lhsvar._q_invariant or len(lhsvar.stinfo['possibletypes']) == 1: |
1385 |
restriction = " AND %s.type='%s'" % (ealias, self._state.solution[lhs.name]) |
|
1386 |
else: |
|
1387 |
etypes = ','.join("'%s'" % etype for etype in lhsvar.stinfo['possibletypes']) |
|
1388 |
restriction = " AND %s.type IN (%s)" % (ealias, etypes) |
|
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
|
1389 |
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
|
1390 |
self._state.done.add(rel.parent) |
0 | 1391 |
not_ = True |
1392 |
else: |
|
1393 |
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
|
1394 |
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
|
1395 |
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
|
1396 |
jointo, not_) + restriction |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1397 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1398 |
def visit_comparison(self, cmp): |
3787
82bb2c7f083b
C - fix typo. make `lgp check` happy.
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
3762
diff
changeset
|
1399 |
"""generate SQL for a comparison""" |
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
|
1400 |
optional = getattr(cmp, 'optional', None) # rql < 0.30 |
0 | 1401 |
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
|
1402 |
# simplified expression from HAVING clause |
0 | 1403 |
lhs, rhs = cmp.children |
1404 |
else: |
|
1405 |
lhs = None |
|
1406 |
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
|
1407 |
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
|
1408 |
sql = None |
0 | 1409 |
operator = cmp.operator |
5702
9fb240cf0f61
[rql] more update to 0.26.2 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5662
diff
changeset
|
1410 |
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
|
1411 |
if operator == 'ILIKE' and not self.dbhelper.ilike_support: |
0 | 1412 |
operator = ' LIKE ' |
1413 |
else: |
|
1414 |
operator = ' %s ' % operator |
|
7257
beea955b45e2
[rql] basic support for regexp-based pattern matching
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
7256
diff
changeset
|
1415 |
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
|
1416 |
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
|
1417 |
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
|
1418 |
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
|
1419 |
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
|
1420 |
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
|
1421 |
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
|
1422 |
sql = '%s IS NULL' % lhs.accept(self) |
0 | 1423 |
elif isinstance(rhs, Function) and rhs.name == 'IN': |
1424 |
assert operator == '=' |
|
1425 |
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
|
1426 |
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
|
1427 |
if lhs 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
|
1428 |
sql = '%s%s'% (operator, rhs.accept(self)) |
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 |
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
|
1430 |
sql = '%s%s%s'% (lhs.accept(self), operator, rhs.accept(self)) |
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 |
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
|
1432 |
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
|
1433 |
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
|
1434 |
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
|
1435 |
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
|
1436 |
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
|
1437 |
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
|
1438 |
else: |
2ada3052e626
[rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7734
diff
changeset
|
1439 |
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
|
1440 |
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
|
1441 |
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
|
1442 |
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
|
1443 |
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
|
1444 |
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
|
1445 |
else: |
2ada3052e626
[rql2sql] support for outer join on column alias (closes #1979645)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7734
diff
changeset
|
1446 |
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
|
1447 |
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
|
1448 |
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
|
1449 |
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
|
1450 |
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
|
1451 |
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
|
1452 |
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
|
1453 |
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
|
1454 |
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
|
1455 |
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
|
1456 |
return '' |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1457 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1458 |
def visit_mathexpression(self, mexpr): |
0 | 1459 |
"""generate SQL for a mathematic expression""" |
1460 |
lhs, rhs = mexpr.get_parts() |
|
1461 |
# check for string concatenation |
|
1462 |
operator = mexpr.operator |
|
8245
d53762ae5961
[rql2sql] correctly handle modulo operator (closes #2192457)
Julien Cristau <julien.cristau@logilab.fr>
parents:
8238
diff
changeset
|
1463 |
if operator == '%': |
d53762ae5961
[rql2sql] correctly handle modulo operator (closes #2192457)
Julien Cristau <julien.cristau@logilab.fr>
parents:
8238
diff
changeset
|
1464 |
operator = '%%' |
0 | 1465 |
try: |
1466 |
if mexpr.operator == '+' 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
|
1467 |
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
|
1468 |
rhs.accept(self)) |
0 | 1469 |
except CoercionError: |
1470 |
pass |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1471 |
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
|
1472 |
|
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
|
1473 |
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
|
1474 |
"""generate SQL for a unary expression""" |
5f89f11143bc
[rql2sql] closes #1892471: support for unary expression introduced in rql 0.30
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7718
diff
changeset
|
1475 |
return '%s%s'% (uexpr.operator, uexpr.children[0].accept(self)) |
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 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1477 |
def visit_function(self, func): |
0 | 1478 |
"""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
|
1479 |
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
|
1480 |
try: |
10669
155c29e0ed1c
[py3k] use next builtin instead of next method
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10663
diff
changeset
|
1481 |
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
|
1482 |
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
|
1483 |
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
|
1484 |
" '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
|
1485 |
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
|
1486 |
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
|
1487 |
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
|
1488 |
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
|
1489 |
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
|
1490 |
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
|
1491 |
# 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
|
1492 |
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
|
1493 |
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
|
1494 |
# 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
|
1495 |
return self.dbhelper.func_as_sql(func.name, args) |
0 | 1496 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1497 |
def visit_constant(self, constant): |
0 | 1498 |
"""generate SQL name for a constant""" |
1499 |
if constant.type is None: |
|
1500 |
return 'NULL' |
|
6286 | 1501 |
value = constant.value |
7256
ccd44caeb936
[rql] support CAST() Function
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
7252
diff
changeset
|
1502 |
if constant.type == 'etype': |
ccd44caeb936
[rql] support CAST() Function
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
7252
diff
changeset
|
1503 |
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
|
1504 |
# 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
|
1505 |
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
|
1506 |
return str(value) |
0 | 1507 |
if constant.type in ('Date', 'Datetime'): |
1508 |
rel = constant.relation() |
|
1509 |
if rel is not None: |
|
1510 |
rel._q_needcast = value |
|
1511 |
return self.keyword_map[value]() |
|
4124
8f2f5f0a89e7
fix backout
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4121
diff
changeset
|
1512 |
if constant.type == 'Substitute': |
6131
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1513 |
try: |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1514 |
# we may found constant from simplified var in varmap |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1515 |
return self._mapped_term(constant, '%%(%s)s' % value)[0] |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1516 |
except KeyError: |
6286 | 1517 |
_id = value |
10677 | 1518 |
if PY2 and isinstance(_id, unicode): |
6131
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1519 |
_id = _id.encode() |
0 | 1520 |
else: |
1521 |
_id = str(id(constant)).replace('-', '', 1) |
|
1522 |
self._query_attrs[_id] = value |
|
1523 |
return '%%(%s)s' % _id |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1524 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1525 |
def visit_variableref(self, variableref): |
0 | 1526 |
"""get the sql name for a variable reference""" |
1527 |
# 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
|
1528 |
return variableref.variable.accept(self) |
0 | 1529 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1530 |
def visit_columnalias(self, colalias): |
0 | 1531 |
"""get the sql name for a subquery column alias""" |
1532 |
if colalias.name in self._varmap: |
|
1533 |
sql = self._varmap[colalias.name] |
|
1122
9f37de24251f
fix rql2sq w/ outer join on subquery result
sylvain.thenault@logilab.fr
parents:
438
diff
changeset
|
1534 |
table = sql.split('.', 1)[0] |
9f37de24251f
fix rql2sq w/ outer join on subquery result
sylvain.thenault@logilab.fr
parents:
438
diff
changeset
|
1535 |
colalias._q_sqltable = table |
9f37de24251f
fix rql2sq w/ outer join on subquery result
sylvain.thenault@logilab.fr
parents:
438
diff
changeset
|
1536 |
colalias._q_sql = sql |
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
|
1537 |
self._state.add_table(table) |
0 | 1538 |
return sql |
1539 |
return colalias._q_sql |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1540 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1541 |
def visit_variable(self, variable): |
0 | 1542 |
"""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
|
1543 |
#if contextrels is None and variable.name in self._state.done: |
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1544 |
if variable.name in self._state.done: |
0 | 1545 |
if self._in_wrapping_query: |
1546 |
return 'T1.%s' % self._state.aliases[variable.name] |
|
1547 |
return variable._q_sql |
|
1548 |
self._state.done.add(variable.name) |
|
1549 |
vtablename = None |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1550 |
if not self._state.ignore_varmap and variable.name in self._varmap: |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1551 |
sql, vtablename = self._var_info(variable) |
0 | 1552 |
elif variable.stinfo['attrvar']: |
1553 |
# attribute variable (systematically used in rhs of final |
|
1554 |
# 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
|
1555 |
sql = self._linked_var_sql(variable) |
0 | 1556 |
elif variable._q_invariant: |
1557 |
# since variable is invariant, we know we won't found final relation |
|
1558 |
principal = variable.stinfo['principal'] |
|
1559 |
if principal 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
|
1560 |
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
|
1561 |
self._state.add_table('entities AS %s' % vtablename, vtablename) |
0 | 1562 |
sql = '%s.eid' % vtablename |
5004
4cc020ee70e2
le patch rql26 a été importé
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4845
diff
changeset
|
1563 |
if variable.stinfo['typerel'] is not None: |
0 | 1564 |
# add additional restriction on entities.type column |
1565 |
pts = variable.stinfo['possibletypes'] |
|
1566 |
if len(pts) == 1: |
|
10669
155c29e0ed1c
[py3k] use next builtin instead of next method
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10663
diff
changeset
|
1567 |
etype = next(iter(variable.stinfo['possibletypes'])) |
0 | 1568 |
restr = "%s.type='%s'" % (vtablename, etype) |
1569 |
else: |
|
1570 |
etypes = ','.join("'%s'" % et for et in pts) |
|
1571 |
restr = '%s.type IN (%s)' % (vtablename, etypes) |
|
1572 |
self._state.add_restriction(restr) |
|
1573 |
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
|
1574 |
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
|
1575 |
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
|
1576 |
self.dbhelper.fti_uid_attr) |
0 | 1577 |
elif principal in variable.stinfo['rhsrelations']: |
1578 |
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
|
1579 |
sql = self._linked_var_sql(variable) |
0 | 1580 |
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
|
1581 |
sql = '%s.eid_to' % self._state.relation_table(principal) |
0 | 1582 |
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
|
1583 |
sql = '%s.eid_from' % self._state.relation_table(principal) |
0 | 1584 |
else: |
1585 |
# standard variable: get table name according to etype and use .eid |
|
1586 |
# attribute |
|
1587 |
sql, vtablename = self._var_info(variable) |
|
1588 |
variable._q_sqltable = vtablename |
|
1589 |
variable._q_sql = sql |
|
1590 |
return sql |
|
1591 |
||
1592 |
# various utilities ####################################################### |
|
1593 |
||
1594 |
def _extra_join_sql(self, relation, sql, var): |
|
1595 |
# if rhs var is invariant, and this relation is not its principal, |
|
1596 |
# generate extra join |
|
1597 |
try: |
|
1598 |
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
|
1599 |
op = relation.operator() |
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1600 |
if op == '=': |
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1601 |
# need a predicable result for tests |
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1602 |
args = sorted( (sql, var.accept(self)) ) |
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1603 |
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
|
1604 |
else: |
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1605 |
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
|
1606 |
return '%s%s%s' % tuple(args) |
0 | 1607 |
except KeyError: |
1608 |
# no principal defined, relation is necessarily the principal and |
|
1609 |
# so nothing to return here |
|
1610 |
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
|
1611 |
return None |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1612 |
|
5593
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1613 |
def _temp_table_scope(self, select, table): |
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1614 |
scope = 9999 |
10662
10942ed172de
[py3k] dict.iteritems → dict.items
Rémi Cardona <remi.cardona@logilab.fr>
parents:
10652
diff
changeset
|
1615 |
for var, sql in self._varmap.items(): |
5635
56784e46509f
[rql2sql] fix scope computation of variable from temporary table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5630
diff
changeset
|
1616 |
# skip "attribute variable" in varmap (such 'T.login') |
56784e46509f
[rql2sql] fix scope computation of variable from temporary table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5630
diff
changeset
|
1617 |
if not '.' in var and table == sql.split('.', 1)[0]: |
5593
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1618 |
try: |
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1619 |
scope = min(scope, self._state.scopes[select.defined_vars[var].scope]) |
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1620 |
except KeyError: |
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1621 |
scope = 0 # XXX |
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1622 |
if scope == 0: |
5635
56784e46509f
[rql2sql] fix scope computation of variable from temporary table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5630
diff
changeset
|
1623 |
break |
56784e46509f
[rql2sql] fix scope computation of variable from temporary table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5630
diff
changeset
|
1624 |
return scope |
5593
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1625 |
|
6131
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1626 |
def _mapped_term(self, term, key): |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1627 |
"""return sql and table alias to the `term`, mapped as `key` or raise |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1628 |
KeyError when the key is not found in the varmap |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1629 |
""" |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1630 |
sql = self._varmap[key] |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1631 |
tablealias = sql.split('.', 1)[0] |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1632 |
scope = self._temp_table_scope(term.stmt, tablealias) |
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
|
1633 |
self._state.add_table(tablealias, scope=scope) |
6131
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1634 |
return sql, tablealias |
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1635 |
|
0 | 1636 |
def _var_info(self, var): |
1637 |
try: |
|
6131
087c5a168010
[ms] more planning bug fixes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6050
diff
changeset
|
1638 |
return self._mapped_term(var, var.name) |
0 | 1639 |
except KeyError: |
5593
f6c55bec9326
[rql2sql] properly compute scope for variable from temporary tables
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5582
diff
changeset
|
1640 |
scope = self._state.scopes[var.scope] |
0 | 1641 |
etype = self._state.solution[var.name] |
1642 |
# XXX this check should be moved in rql.stcheck |
|
3689
deb13e88e037
follow yams 0.25 api changes to improve performance
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3245
diff
changeset
|
1643 |
if self.schema.eschema(etype).final: |
0 | 1644 |
raise BadRQLQuery(var.stmt.root) |
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
|
1645 |
tablealias = '_' + var.name |
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
|
1646 |
sql = '%s.%seid' % (tablealias, SQL_PREFIX) |
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
|
1647 |
self._state.add_table('%s%s AS %s' % (SQL_PREFIX, etype, tablealias), |
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
|
1648 |
tablealias, scope=scope) |
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
|
1649 |
return sql, tablealias |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1650 |
|
0 | 1651 |
def _inlined_var_sql(self, var, rtype): |
1652 |
try: |
|
1653 |
sql = self._varmap['%s.%s' % (var.name, rtype)] |
|
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
|
1654 |
scope = self._state.scopes[var.scope] |
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
|
1655 |
self._state.add_table(sql.split('.', 1)[0], scope=scope) |
0 | 1656 |
except KeyError: |
7493
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1657 |
# rtype may be an attribute relation when called from |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1658 |
# _visit_var_attr_relation. take care about 'eid' rtype, since in |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1659 |
# some case we may use the `entities` table, so in that case we've |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1660 |
# to properly use variable'sql |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1661 |
if rtype == 'eid': |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1662 |
sql = var.accept(self) |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1663 |
else: |
3c46b9390871
[rql2sql] fix for some queries where eid variable used and entities picked as variable's table
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7473
diff
changeset
|
1664 |
sql = '%s.%s%s' % (self._var_table(var), SQL_PREFIX, rtype) |
0 | 1665 |
return sql |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1666 |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1667 |
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
|
1668 |
if not self._state.ignore_varmap: |
0 | 1669 |
try: |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1670 |
return self._varmap[variable.name] |
0 | 1671 |
except KeyError: |
1672 |
pass |
|
3815
50b87f759b5d
test and fix http://www.logilab.org/ticket/499838
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3787
diff
changeset
|
1673 |
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
|
1674 |
next(iter(variable.stinfo['rhsrelations']))) |
0 | 1675 |
linkedvar = rel.children[0].variable |
1676 |
if rel.r_type == 'eid': |
|
1677 |
return linkedvar.accept(self) |
|
1678 |
if isinstance(linkedvar, ColumnAlias): |
|
1679 |
raise BadRQLQuery('variable %s should be selected by the subquery' |
|
1680 |
% variable.name) |
|
1681 |
try: |
|
1682 |
sql = self._varmap['%s.%s' % (linkedvar.name, rel.r_type)] |
|
1683 |
except KeyError: |
|
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
|
1684 |
mapkey = '%s.%s' % (self._state.solution[linkedvar.name], rel.r_type) |
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
|
1685 |
if mapkey in self.attr_map: |
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
|
1686 |
cb, sourcecb = self.attr_map[mapkey] |
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
|
1687 |
if not sourcecb: |
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
|
1688 |
return cb(self, linkedvar, rel) |
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
|
1689 |
# attribute mapped at the source level (bfss for instance) |
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
|
1690 |
stmt = rel.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
|
1691 |
for selectidx, vref in 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
|
1692 |
stack = [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
|
1693 |
update_source_cb_stack(self._state, stmt, 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
|
1694 |
self._state._needs_source_cb[selectidx] = stack |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1522
diff
changeset
|
1695 |
linkedvar.accept(self) |
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
|
1696 |
sql = '%s.%s%s' % (linkedvar._q_sqltable, SQL_PREFIX, rel.r_type) |
0 | 1697 |
return sql |
1698 |
||
1699 |
# tables handling ######################################################### |
|
1700 |
||
1701 |
def _var_table(self, var): |
|
1702 |
var.accept(self)#.visit_variable(var) |
|
1703 |
return var._q_sqltable |