server/sources/rql2sql.py
changeset 5768 1e73a466aa69
parent 5706 c2e8290bc7b7
child 5811 e77cea9721e7
equal deleted inserted replaced
5766:c397819f2482 5768:1e73a466aa69
   566                 sql += '\nGROUP BY %s' % groups
   566                 sql += '\nGROUP BY %s' % groups
   567             if having:
   567             if having:
   568                 sql += '\nHAVING %s' % having
   568                 sql += '\nHAVING %s' % having
   569             # sort
   569             # sort
   570             if sorts:
   570             if sorts:
   571                 sql += '\nORDER BY %s' % ','.join(self._sortterm_sql(sortterm,
   571                 sqlsortterms = [self._sortterm_sql(sortterm, fselectidx)
   572                                                                      fselectidx)
   572                                 for sortterm in sorts]
   573                                                   for sortterm in sorts)
   573                 sqlsortterms = [x for x in sqlsortterms if x is not None]
   574                 if fneedwrap:
   574                 if sqlsortterms:
   575                     selection = ['T1.C%s' % i for i in xrange(len(origselection))]
   575                     sql += '\nORDER BY %s' % ','.join(sqlsortterms)
   576                     sql = 'SELECT %s FROM (%s) AS T1' % (','.join(selection), sql)
   576                     if sorts and fneedwrap:
       
   577                         selection = ['T1.C%s' % i for i in xrange(len(origselection))]
       
   578                         sql = 'SELECT %s FROM (%s) AS T1' % (','.join(selection), sql)
   577             state.finalize_source_cbs()
   579             state.finalize_source_cbs()
   578         finally:
   580         finally:
   579             select.selection = origselection
   581             select.selection = origselection
   580         # limit / offset
   582         # limit / offset
   581         limit = select.limit
   583         limit = select.limit
   649         return 'SELECT %s' % ', '.join(clause)
   651         return 'SELECT %s' % ', '.join(clause)
   650 
   652 
   651     def _sortterm_sql(self, sortterm, selectidx):
   653     def _sortterm_sql(self, sortterm, selectidx):
   652         term = sortterm.term
   654         term = sortterm.term
   653         try:
   655         try:
   654             sqlterm = str(selectidx.index(str(term)) + 1)
   656             sqlterm = selectidx.index(str(term)) + 1
   655         except ValueError:
   657         except ValueError:
   656             # Constant node or non selected term
   658             # Constant node or non selected term
   657             sqlterm = str(term.accept(self))
   659             sqlterm = term.accept(self)
       
   660             if sqlterm is None:
       
   661                 return None
   658         if sortterm.asc:
   662         if sortterm.asc:
   659             return sqlterm
   663             return str(sqlterm)
   660         else:
   664         else:
   661             return '%s DESC' % sqlterm
   665             return '%s DESC' % sqlterm
   662 
   666 
   663     def visit_and(self, et):
   667     def visit_and(self, et):
   664         """generate SQL for a AND subtree"""
   668         """generate SQL for a AND subtree"""
  1012         if isinstance(rel.parent, Not):
  1016         if isinstance(rel.parent, Not):
  1013             self._state.done.add(rel.parent)
  1017             self._state.done.add(rel.parent)
  1014             not_ = True
  1018             not_ = True
  1015         else:
  1019         else:
  1016             not_ = False
  1020             not_ = False
  1017         return self.dbhelper.fti_restriction_sql(alias, const.eval(self._args),
  1021         query = const.eval(self._args)
       
  1022         return self.dbhelper.fti_restriction_sql(alias, query,
  1018                                                  jointo, not_) + restriction
  1023                                                  jointo, not_) + restriction
  1019 
  1024 
  1020     def visit_comparison(self, cmp):
  1025     def visit_comparison(self, cmp):
  1021         """generate SQL for a comparison"""
  1026         """generate SQL for a comparison"""
  1022         if len(cmp.children) == 2:
  1027         if len(cmp.children) == 2:
  1055             pass
  1060             pass
  1056         return '(%s %s %s)'% (lhs.accept(self), operator, rhs.accept(self))
  1061         return '(%s %s %s)'% (lhs.accept(self), operator, rhs.accept(self))
  1057 
  1062 
  1058     def visit_function(self, func):
  1063     def visit_function(self, func):
  1059         """generate SQL name for a function"""
  1064         """generate SQL name for a function"""
       
  1065         if func.name == 'FTIRANK':
       
  1066             try:
       
  1067                 rel = iter(func.children[0].variable.stinfo['ftirels']).next()
       
  1068             except KeyError:
       
  1069                 raise BadRQLQuery("can't use FTIRANK on variable not used in an"
       
  1070                                   " 'has_text' relation (eg full-text search)")
       
  1071             const = rel.get_parts()[1].children[0]
       
  1072             return self.dbhelper.fti_rank_order(self._fti_table(rel),
       
  1073                                                 const.eval(self._args))
  1060         args = [c.accept(self) for c in func.children]
  1074         args = [c.accept(self) for c in func.children]
  1061         if func in self._state.source_cb_funcs:
  1075         if func in self._state.source_cb_funcs:
  1062             # function executed as a callback on the source
  1076             # function executed as a callback on the source
  1063             assert len(args) == 1
  1077             assert len(args) == 1
  1064             return args[0]
  1078             return args[0]