54 |
54 |
55 from logilab.common.date import utcdatetime, utctime |
55 from logilab.common.date import utcdatetime, utctime |
56 from logilab.database import FunctionDescr, SQL_FUNCTIONS_REGISTRY |
56 from logilab.database import FunctionDescr, SQL_FUNCTIONS_REGISTRY |
57 |
57 |
58 from rql import BadRQLQuery, CoercionError |
58 from rql import BadRQLQuery, CoercionError |
|
59 from rql.utils import common_parent |
59 from rql.stmts import Union, Select |
60 from rql.stmts import Union, Select |
60 from rql.nodes import (SortTerm, VariableRef, Constant, Function, Variable, Or, |
61 from rql.nodes import (SortTerm, VariableRef, Constant, Function, Variable, Or, |
61 Not, Comparison, ColumnAlias, Relation, SubQuery, Exists) |
62 Not, Comparison, ColumnAlias, Relation, SubQuery, Exists) |
62 |
63 |
63 from cubicweb import QueryError |
64 from cubicweb import QueryError |
667 ors.add(oor) |
668 ors.add(oor) |
668 break |
669 break |
669 else: |
670 else: |
670 tocheck.append(compnode) |
671 tocheck.append(compnode) |
671 # tocheck hold a set of comparison not implying an aggregat function |
672 # tocheck hold a set of comparison not implying an aggregat function |
672 # put them in fakehaving if the don't share an Or node as ancestor |
673 # put them in fakehaving if they don't share an Or node as ancestor |
673 # with another comparison containing an aggregat function |
674 # with another comparison containing an aggregat function |
674 for compnode in tocheck: |
675 for compnode in tocheck: |
675 parents = set() |
676 parents = set() |
676 p = compnode.parent |
677 p = compnode.parent |
677 oor = None |
678 oor = None |
782 """ |
783 """ |
783 distinct = selectsortterms = select.need_distinct |
784 distinct = selectsortterms = select.need_distinct |
784 sorts = select.orderby |
785 sorts = select.orderby |
785 groups = select.groupby |
786 groups = select.groupby |
786 having = select.having |
787 having = select.having |
787 morerestr = extract_fake_having_terms(having) |
788 for restr in extract_fake_having_terms(having): |
|
789 scope = None |
|
790 for vref in restr.get_nodes(VariableRef): |
|
791 vscope = vref.variable.scope |
|
792 if vscope is select: |
|
793 continue # ignore select scope, so restriction is added to |
|
794 # the inner most scope possible |
|
795 if scope is None: |
|
796 scope = vscope |
|
797 elif vscope is not scope: |
|
798 scope = common_parent(scope, vscope).scope |
|
799 if scope is None: |
|
800 scope = select |
|
801 scope.add_restriction(restr) |
788 # remember selection, it may be changed and have to be restored |
802 # remember selection, it may be changed and have to be restored |
789 origselection = select.selection[:] |
803 origselection = select.selection[:] |
790 # check if the query will have union subquery, if it need sort term |
804 # check if the query will have union subquery, if it need sort term |
791 # selection (union or distinct query) and wrapping (union with groups) |
805 # selection (union or distinct query) and wrapping (union with groups) |
792 needwrap = False |
806 needwrap = False |
827 if fneedwrap: |
841 if fneedwrap: |
828 needalias = True |
842 needalias = True |
829 self._in_wrapping_query = False |
843 self._in_wrapping_query = False |
830 self._state = state |
844 self._state = state |
831 try: |
845 try: |
832 sql = self._solutions_sql(select, morerestr, sols, distinct, |
846 sql = self._solutions_sql(select, sols, distinct, |
833 needalias or needwrap) |
847 needalias or needwrap) |
834 # generate groups / having before wrapping query selection to get |
848 # generate groups / having before wrapping query selection to get |
835 # correct column aliases |
849 # correct column aliases |
836 self._in_wrapping_query = needwrap |
850 self._in_wrapping_query = needwrap |
837 if groups: |
851 if groups: |
898 update_source_cb_stack(state, select, vref, stack) |
912 update_source_cb_stack(state, select, vref, stack) |
899 state.subquery_source_cb[selectidx] = stack |
913 state.subquery_source_cb[selectidx] = stack |
900 except KeyError: |
914 except KeyError: |
901 continue |
915 continue |
902 |
916 |
903 def _solutions_sql(self, select, morerestr, solutions, distinct, needalias): |
917 def _solutions_sql(self, select, solutions, distinct, needalias): |
904 sqls = [] |
918 sqls = [] |
905 for solution in solutions: |
919 for solution in solutions: |
906 self._state.reset(solution) |
920 self._state.reset(solution) |
907 # visit restriction subtree |
921 # visit restriction subtree |
908 if select.where is not None: |
922 if select.where is not None: |
909 self._state.add_restriction(select.where.accept(self)) |
923 self._state.add_restriction(select.where.accept(self)) |
910 for restriction in morerestr: |
|
911 self._state.add_restriction(restriction.accept(self)) |
|
912 sql = [self._selection_sql(select.selection, distinct, needalias)] |
924 sql = [self._selection_sql(select.selection, distinct, needalias)] |
913 if self._state.restrictions: |
925 if self._state.restrictions: |
914 sql.append('WHERE %s' % ' AND '.join(self._state.restrictions)) |
926 sql.append('WHERE %s' % ' AND '.join(self._state.restrictions)) |
915 self._state.merge_source_cbs(self._state._needs_source_cb) |
927 self._state.merge_source_cbs(self._state._needs_source_cb) |
916 # add required tables |
928 # add required tables |