1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
3 # |
3 # |
4 # This file is part of CubicWeb. |
4 # This file is part of CubicWeb. |
5 # |
5 # |
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
60 from rql.stmts import Union, Select |
60 from rql.stmts import Union, Select |
61 from rql.nodes import (SortTerm, VariableRef, Constant, Function, Variable, Or, |
61 from rql.nodes import (SortTerm, VariableRef, Constant, Function, Variable, Or, |
62 Not, Comparison, ColumnAlias, Relation, SubQuery, Exists) |
62 Not, Comparison, ColumnAlias, Relation, SubQuery, Exists) |
63 |
63 |
64 from cubicweb import QueryError |
64 from cubicweb import QueryError |
|
65 from cubicweb.rqlrewrite import cleanup_solutions |
65 from cubicweb.server.sqlutils import SQL_PREFIX |
66 from cubicweb.server.sqlutils import SQL_PREFIX |
66 from cubicweb.server.utils import cleanup_solutions |
|
67 |
67 |
68 ColumnAlias._q_invariant = False # avoid to check for ColumnAlias / Variable |
68 ColumnAlias._q_invariant = False # avoid to check for ColumnAlias / Variable |
69 |
69 |
70 FunctionDescr.source_execute = None |
70 FunctionDescr.source_execute = None |
71 |
71 |
240 rhs = None |
240 rhs = None |
241 except KeyError: |
241 except KeyError: |
242 rhsconst = None # ColumnAlias |
242 rhsconst = None # ColumnAlias |
243 return lhs, lhsconst, rhs, rhsconst |
243 return lhs, lhsconst, rhs, rhsconst |
244 |
244 |
245 def switch_relation_field(sql, table=''): |
|
246 switchedsql = sql.replace(table + '.eid_from', '__eid_from__') |
|
247 switchedsql = switchedsql.replace(table + '.eid_to', |
|
248 table + '.eid_from') |
|
249 return switchedsql.replace('__eid_from__', table + '.eid_to') |
|
250 |
|
251 def sort_term_selection(sorts, rqlst, groups): |
245 def sort_term_selection(sorts, rqlst, groups): |
252 # XXX beurk |
246 # XXX beurk |
253 if isinstance(rqlst, list): |
247 if isinstance(rqlst, list): |
254 def append(term): |
248 def append(term): |
255 rqlst.append(term) |
249 rqlst.append(term) |
484 """return the table alias used by the given relation""" |
478 """return the table alias used by the given relation""" |
485 if relation in self.done: |
479 if relation in self.done: |
486 return relation._q_sqltable |
480 return relation._q_sqltable |
487 rid = 'rel_%s%s' % (relation.r_type, self.count) |
481 rid = 'rel_%s%s' % (relation.r_type, self.count) |
488 # relation's table is belonging to the root scope if it is the principal |
482 # relation's table is belonging to the root scope if it is the principal |
489 # table of one of it's variable and if that variable belong's to parent |
483 # table of one of its variable and that variable belong's to parent |
490 # scope |
484 # scope |
491 for varref in relation.iget_nodes(VariableRef): |
485 for varref in relation.iget_nodes(VariableRef): |
492 var = varref.variable |
486 var = varref.variable |
493 if isinstance(var, ColumnAlias): |
|
494 scope = 0 |
|
495 break |
|
496 # XXX may have a principal without being invariant for this generation, |
487 # XXX may have a principal without being invariant for this generation, |
497 # not sure this is a pb or not |
488 # not sure this is a pb or not |
498 if var.stinfo.get('principal') is relation and var.scope is var.stmt: |
489 if var.stinfo.get('principal') is relation and var.scope is var.stmt: |
499 scope = 0 |
490 scope = 0 |
500 break |
491 break |
1133 rid = self._state.relation_table(relation) |
1124 rid = self._state.relation_table(relation) |
1134 sqls = [] |
1125 sqls = [] |
1135 sqls += self._process_relation_term(relation, rid, lhsvar, lhsconst, 'eid_from') |
1126 sqls += self._process_relation_term(relation, rid, lhsvar, lhsconst, 'eid_from') |
1136 sqls += self._process_relation_term(relation, rid, rhsvar, rhsconst, 'eid_to') |
1127 sqls += self._process_relation_term(relation, rid, rhsvar, rhsconst, 'eid_to') |
1137 sql = ' AND '.join(sqls) |
1128 sql = ' AND '.join(sqls) |
1138 if rschema.symmetric: |
|
1139 sql = '(%s OR %s)' % (sql, switch_relation_field(sql)) |
|
1140 return sql |
1129 return sql |
1141 |
1130 |
1142 def _visit_outer_join_relation(self, relation, rschema): |
1131 def _visit_outer_join_relation(self, relation, rschema): |
1143 """ |
1132 """ |
1144 left outer join syntax (optional=='right'): |
1133 left outer join syntax (optional=='right'): |
1246 try: |
1235 try: |
1247 lhssql = self._varmap['%s.%s' % (lhsvar.name, attr)] |
1236 lhssql = self._varmap['%s.%s' % (lhsvar.name, attr)] |
1248 except KeyError: |
1237 except KeyError: |
1249 if lhsalias is None: |
1238 if lhsalias is None: |
1250 lhssql = lhsconst.accept(self) |
1239 lhssql = lhsconst.accept(self) |
|
1240 elif attr == 'eid': |
|
1241 lhssql = lhsvar.accept(self) |
1251 else: |
1242 else: |
1252 lhssql = '%s.%s%s' % (lhsalias, SQL_PREFIX, attr) |
1243 lhssql = '%s.%s%s' % (lhsalias, SQL_PREFIX, attr) |
1253 condition = '%s=%s' % (lhssql, (rhsconst or rhsvar).accept(self)) |
1244 condition = '%s=%s' % (lhssql, (rhsconst or rhsvar).accept(self)) |
1254 # this is not a typo, rhs optional variable means lhs outer join and vice-versa |
1245 # this is not a typo, rhs optional variable means lhs outer join and vice-versa |
1255 if relation.optional == 'left': |
1246 if relation.optional == 'left': |