server/sources/rql2sql.py
changeset 9402 2c48c091b6a2
parent 9361 0542a85fe667
child 9468 39b7a91a3f4c
child 9492 c7fc56eecd1a
equal deleted inserted replaced
9127:aff75b69db92 9402:2c48c091b6a2
     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':