server/sources/rql2sql.py
branchtls-sprint
changeset 1263 01152fffd593
parent 1134 f885df228fc0
parent 1251 af40e615dc89
child 1398 5fe84a5f7035
equal deleted inserted replaced
1246:76b3cd5d4f31 1263:01152fffd593
    23 Potential optimization information is collected by the querier, sql generation
    23 Potential optimization information is collected by the querier, sql generation
    24 is done according to this information
    24 is done according to this information
    25 
    25 
    26 
    26 
    27 :organization: Logilab
    27 :organization: Logilab
    28 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
    28 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
    29 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
    29 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
    30 """
    30 """
    31 __docformat__ = "restructuredtext en"
    31 __docformat__ = "restructuredtext en"
    32 
    32 
    33 import threading
    33 import threading
    36 from rql.stmts import Union, Select
    36 from rql.stmts import Union, Select
    37 from rql.nodes import (SortTerm, VariableRef, Constant, Function, Not,
    37 from rql.nodes import (SortTerm, VariableRef, Constant, Function, Not,
    38                        Variable, ColumnAlias, Relation, SubQuery, Exists)
    38                        Variable, ColumnAlias, Relation, SubQuery, Exists)
    39 
    39 
    40 from cubicweb import server
    40 from cubicweb import server
       
    41 from cubicweb.server.sqlutils import SQL_PREFIX
    41 from cubicweb.server.utils import cleanup_solutions
    42 from cubicweb.server.utils import cleanup_solutions
    42 
    43 
    43 def _new_var(select, varname): 
    44 def _new_var(select, varname): 
    44     newvar = select.get_variable(varname)
    45     newvar = select.get_variable(varname)
    45     if not 'relations' in newvar.stinfo:
    46     if not 'relations' in newvar.stinfo:
   762             # reset lhs/rhs, we need the initial order now
   763             # reset lhs/rhs, we need the initial order now
   763             lhs, rhs = relation.get_variable_parts()
   764             lhs, rhs = relation.get_variable_parts()
   764             if '%s.%s' % (lhs.name, attr) in self._varmap:
   765             if '%s.%s' % (lhs.name, attr) in self._varmap:
   765                 lhssql = self._varmap['%s.%s' % (lhs.name, attr)]
   766                 lhssql = self._varmap['%s.%s' % (lhs.name, attr)]
   766             else:
   767             else:
   767                 lhssql = '%s.%s' % (self._var_table(lhs.variable), attr)
   768                 lhssql = '%s.%s%s' % (self._var_table(lhs.variable), SQL_PREFIX, attr)
   768             if not rhsvar is None:
   769             if not rhsvar is None:
   769                 t2 = self._var_table(rhsvar)
   770                 t2 = self._var_table(rhsvar)
   770                 if t2 is None:
   771                 if t2 is None:
   771                     if rhsconst is not None:
   772                     if rhsconst is not None:
   772                         # inlined relation with invariant as rhs
   773                         # inlined relation with invariant as rhs
   799             if rhsconst:
   800             if rhsconst:
   800                 join += ' AND %s.%s=%s)' % (rid, restrattr, rhssql)
   801                 join += ' AND %s.%s=%s)' % (rid, restrattr, rhssql)
   801             else:
   802             else:
   802                 join += ')'
   803                 join += ')'
   803         if not rhsconst:
   804         if not rhsconst:
   804             rhstable = self._var_table(rhsvar)
   805             rhstable = rhsvar._q_sqltable
   805             if rhstable:
   806             if rhstable:
   806                 assert rhstable is not None, rhsvar
   807                 assert rhstable is not None, rhsvar
   807                 join += ' %s OUTER JOIN %s ON (%s.%s=%s)' % (
   808                 join += ' %s OUTER JOIN %s ON (%s.%s=%s)' % (
   808                     outertype, self._state.tables[rhstable][1], rid, restrattr, rhssql)
   809                     outertype, self._state.tables[rhstable][1], rid, restrattr,
       
   810                     rhssql)
   809                 toreplace.append(rhstable)
   811                 toreplace.append(rhstable)
   810         self.replace_tables_by_outer_join(join, maintable, *toreplace)
   812         self.replace_tables_by_outer_join(join, maintable, *toreplace)
   811         return ''
   813         return ''
   812 
   814 
   813     def _visit_var_attr_relation(self, relation, rhs_vars):
   815     def _visit_var_attr_relation(self, relation, rhs_vars):
   843             lhssql = lhs.accept(self)
   845             lhssql = lhs.accept(self)
   844         else:
   846         else:
   845             try:
   847             try:
   846                 lhssql = self._varmap['%s.%s' % (lhs.name, relation.r_type)]
   848                 lhssql = self._varmap['%s.%s' % (lhs.name, relation.r_type)]
   847             except KeyError:
   849             except KeyError:
   848                 lhssql = '%s.%s' % (table, relation.r_type)
   850                 if relation.r_type == 'eid':
       
   851                     lhssql = lhs.variable._q_sql
       
   852                 else:
       
   853                     lhssql = '%s.%s%s' % (table, SQL_PREFIX, relation.r_type)
   849         try:
   854         try:
   850             if relation._q_needcast == 'TODAY':
   855             if relation._q_needcast == 'TODAY':
   851                 sql = 'DATE(%s)%s' % (lhssql, rhssql)
   856                 sql = 'DATE(%s)%s' % (lhssql, rhssql)
   852             # XXX which cast function should be used
   857             # XXX which cast function should be used
   853             #elif relation._q_needcast == 'NOW':
   858             #elif relation._q_needcast == 'NOW':
   964 
   969 
   965     def visit_columnalias(self, colalias, contextrels=None):
   970     def visit_columnalias(self, colalias, contextrels=None):
   966         """get the sql name for a subquery column alias"""
   971         """get the sql name for a subquery column alias"""
   967         if colalias.name in self._varmap:
   972         if colalias.name in self._varmap:
   968             sql = self._varmap[colalias.name]
   973             sql = self._varmap[colalias.name]
   969             self.add_table(sql.split('.', 1)[0])
   974             table = sql.split('.', 1)[0]
       
   975             colalias._q_sqltable = table
       
   976             colalias._q_sql = sql
       
   977             self.add_table(table)
   970             return sql
   978             return sql
   971         return colalias._q_sql
   979         return colalias._q_sql
   972     
   980     
   973     def visit_variable(self, variable, contextrels=None):
   981     def visit_variable(self, variable, contextrels=None):
   974         """get the table name and sql string for a variable"""
   982         """get the table name and sql string for a variable"""
   987         elif variable._q_invariant:
   995         elif variable._q_invariant:
   988             # since variable is invariant, we know we won't found final relation
   996             # since variable is invariant, we know we won't found final relation
   989             principal = variable.stinfo['principal']
   997             principal = variable.stinfo['principal']
   990             if principal is None:
   998             if principal is None:
   991                 vtablename = variable.name
   999                 vtablename = variable.name
   992                 self.add_table('entities AS %s' % variable.name, vtablename)
  1000                 self.add_table('entities AS %s' % vtablename, vtablename)
   993                 sql = '%s.eid' % vtablename
  1001                 sql = '%s.eid' % vtablename
   994                 if variable.stinfo['typerels']:
  1002                 if variable.stinfo['typerels']:
   995                     # add additional restriction on entities.type column
  1003                     # add additional restriction on entities.type column
   996                     pts = variable.stinfo['possibletypes']
  1004                     pts = variable.stinfo['possibletypes']
   997                     if len(pts) == 1:
  1005                     if len(pts) == 1:
  1052             etype = self._state.solution[var.name]
  1060             etype = self._state.solution[var.name]
  1053             # XXX this check should be moved in rql.stcheck
  1061             # XXX this check should be moved in rql.stcheck
  1054             if self.schema.eschema(etype).is_final():
  1062             if self.schema.eschema(etype).is_final():
  1055                 raise BadRQLQuery(var.stmt.root)
  1063                 raise BadRQLQuery(var.stmt.root)
  1056             table = var.name
  1064             table = var.name
  1057             sql = '%s.eid' % table
  1065             sql = '%s.%seid' % (table, SQL_PREFIX)
  1058             self.add_table('%s AS %s' % (etype, table), table, scope=scope)
  1066             self.add_table('%s%s AS %s' % (SQL_PREFIX, etype, table), table, scope=scope)
  1059         return sql, table
  1067         return sql, table
  1060     
  1068     
  1061     def _inlined_var_sql(self, var, rtype):
  1069     def _inlined_var_sql(self, var, rtype):
  1062         try:
  1070         try:
  1063             sql = self._varmap['%s.%s' % (var.name, rtype)]
  1071             sql = self._varmap['%s.%s' % (var.name, rtype)]
  1064             scope = var.sqlscope is var.stmt and 0 or -1
  1072             scope = var.sqlscope is var.stmt and 0 or -1
  1065             self.add_table(sql.split('.', 1)[0], scope=scope)
  1073             self.add_table(sql.split('.', 1)[0], scope=scope)
  1066         except KeyError:
  1074         except KeyError:
  1067             sql = '%s.%s' % (self._var_table(var), rtype)
  1075             sql = '%s.%s%s' % (self._var_table(var), SQL_PREFIX, rtype)
  1068             #self._state.done.add(var.name)
  1076             #self._state.done.add(var.name)
  1069         return sql
  1077         return sql
  1070         
  1078         
  1071     def _linked_var_sql(self, variable, contextrels=None):
  1079     def _linked_var_sql(self, variable, contextrels=None):
  1072         if contextrels is None:
  1080         if contextrels is None:
  1085                               % variable.name)
  1093                               % variable.name)
  1086         try:
  1094         try:
  1087             sql = self._varmap['%s.%s' % (linkedvar.name, rel.r_type)]
  1095             sql = self._varmap['%s.%s' % (linkedvar.name, rel.r_type)]
  1088         except KeyError:
  1096         except KeyError:
  1089             linkedvar.accept(self)            
  1097             linkedvar.accept(self)            
  1090             sql = '%s.%s' % (linkedvar._q_sqltable, rel.r_type)
  1098             sql = '%s.%s%s' % (linkedvar._q_sqltable, SQL_PREFIX, rel.r_type)
  1091         return sql
  1099         return sql
  1092 
  1100 
  1093     # tables handling #########################################################
  1101     # tables handling #########################################################
  1094 
  1102 
  1095     def alias_and_add_table(self, tablename):
  1103     def alias_and_add_table(self, tablename):