Changeset: 485edfce2d41 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=485edfce2d41
Modified Files:
        sql/backends/monet5/Tests/pyapi05.stable.out
        sql/server/rel_select.c
Branch: default
Log Message:

added support for multiple window functions with group by/aggregates


diffs (truncated from 349 to 300 lines):

diff --git a/sql/backends/monet5/Tests/pyapi05.stable.out 
b/sql/backends/monet5/Tests/pyapi05.stable.out
--- a/sql/backends/monet5/Tests/pyapi05.stable.out
+++ b/sql/backends/monet5/Tests/pyapi05.stable.out
@@ -49,7 +49,7 @@ Ready.
 #};
 #SELECT cluster FROM (SELECT MIN(x) AS minx, MAX(x) AS maxx, kmeans(x,5) AS 
cluster FROM xdata 
 #      GROUP BY cluster) as cdata ORDER BY cluster;
-% sys.cdata # table_name
+% sys.L12 # table_name
 % cluster # name
 % int # type
 % 1 # length
diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c
--- a/sql/server/rel_select.c
+++ b/sql/server/rel_select.c
@@ -183,17 +183,13 @@ rel_project2groupby(mvc *sql, sql_rel *g
 {
        if (g->op == op_project) {
                node *en;
-
-               g->card = CARD_ATOM; /* no groupby expressions */
-               g->op = op_groupby;
-               g->r = new_exp_list(sql->sa); /* add empty groupby column list 
*/
                
                if (!g->exps)
                        g->exps = new_exp_list(sql->sa);
                for (en = g->exps->h; en; en = en->next) {
                        sql_exp *e = en->data;
 
-                       if (e->card > g->card) {
+                       if (e->card > CARD_ATOM) {
                                if (e->type == e_column && e->r) {
                                        return sql_error(sql, 02, 
SQLSTATE(42000) "Cannot use non GROUP BY column '%s' in query results without 
an aggregate function", (char *) e->r);
                                } else {
@@ -201,6 +197,9 @@ rel_project2groupby(mvc *sql, sql_rel *g
                                }
                        }
                }
+               g->card = CARD_ATOM; /* no groupby expressions */
+               g->op = op_groupby;
+               g->r = new_exp_list(sql->sa); /* add empty groupby column list 
*/
                g = rel_project(sql->sa, g, rel_projections(sql, g, NULL, 1, 
1));
                reset_processed(g);
                return g;
@@ -3587,7 +3586,7 @@ static sql_exp *
                        r = r->l;
                }
 
-               if (is_sql_having(f) || is_sql_partitionby(f))
+               if (is_sql_having(f) || (r->op == op_groupby && 
is_sql_partitionby(f)))
                        project = groupby;
                if (is_sql_having(f) && r->op == op_select && r->l)
                        r = r->l;
@@ -4337,11 +4336,13 @@ rel_order_by_column_exp(mvc *sql, sql_re
        }
 
        if (!e) {
-               sql_rel *or = r;
+               //sql_rel *or = r;
 
                e = rel_value_exp(sql, &r, column_r, sql_sel | sql_orderby, ek);
+               /*
                if (r && or != r)
                        (*R)->l = r;
+                       */
                /* add to internal project */
                if (e && is_processed(r)) {
                        e = rel_project_add_exp(sql, r, e);
@@ -4662,6 +4663,40 @@ get_window_clauses(mvc *sql, char* ident
        return window_specification; //return something to say there were no 
errors
 }
 
+static void
+rel_intermediates_add_exp(mvc *sql, sql_rel *p, sql_rel *op, sql_exp *in)
+{
+       while(p != op) {
+               sql_rel *pp = op;
+
+               while(pp->l && pp->l != p) 
+                       pp = pp->l;
+               if (pp && pp->l == p) {
+                       assert(pp->op == op_project);
+                       in = exp_column(sql->sa, exp_relname(in), exp_name(in), 
exp_subtype(in), exp_card(in), has_nil(in), is_intern(in));
+                       in = rel_project_add_exp(sql, pp, in);
+               }
+               p = pp;
+       }
+}
+
+static sql_exp*
+opt_groupby_add_exp(mvc *sql, sql_rel *p, sql_rel *pp, sql_exp *in)
+{
+       if (p->op == op_groupby) {
+               if (!exp_name(in))
+                       exp_label(sql->sa, in, ++sql->label);
+               append(p->exps, in);
+               in = exp_column(sql->sa, exp_relname(in), exp_name(in), 
exp_subtype(in), exp_card(in), has_nil(in), is_intern(in));
+       } else if (pp && pp->op == op_groupby) {
+               if (!exp_name(in))
+                       exp_label(sql->sa, in, ++sql->label);
+               append(p->exps, in);
+               in = exp_column(sql->sa, exp_relname(in), exp_name(in), 
exp_subtype(in), exp_card(in), has_nil(in), is_intern(in));
+       }
+       return in;
+}
+
 /*
  * select x, y, rank_op() over (partition by x order by y) as, ...
                 aggr_op(z) over (partition by y order by x) as, ...
@@ -4686,11 +4721,11 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
        char *aname = NULL, *sname = NULL, *window_ident = NULL;
        sql_subfunc *wf = NULL;
        sql_exp *in = NULL, *pe = NULL, *oe = NULL, *call = NULL, *start = 
NULL, *eend = NULL, *fstart = NULL, *fend = NULL;
-       sql_rel *r = *rel, *p, *pp;
+       sql_rel *r = *rel, *p, *pp, *op;
        list *gbe = NULL, *obe = NULL, *args = NULL, *types = NULL, *fargs = 
NULL;
        sql_schema *s = sql->session->schema;
        dnode *dn = window_function->data.lval->h;
-       int distinct = 0, project_added = 0, is_last, frame_type, pos;
+       int distinct = 0, project_added = 0, is_last, frame_type, pos, group = 
0;
        bool is_nth_value, supports_frames;
 
        stack_clear_frame_visited_flag(sql); //clear visited flags before 
iterating
@@ -4735,6 +4770,12 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                return NULL;
        }
 
+       /* 
+        * We need to keep track of the input relation, pp (projection)
+        * which may in the first step (which could be in the partitioning, 
ordering or window operator) change into a group by.
+        * then we project the partitioning/ordering + require result columns 
(p).
+        * followed by the projection with window operators. 
+        */
        /* window operations are only allowed in the projection */
        if (r && r->op != op_project) {
                *rel = r = rel_project(sql->sa, r, rel_projections(sql, r, 
NULL, 1, 1));
@@ -4757,7 +4798,85 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
 
        if (p && !is_project(p->op))
                p = rel_project(sql->sa, p, rel_projections(sql, p, NULL, 1, 
1));
-       p = rel_project(sql->sa, p, sa_list(sql->sa));
+       pp = p;
+
+       if (p->l && !is_processed(p)) { /* ADD check for processed ! */
+               sql_rel *pl = p->l;
+
+               op = p;
+               while(p->l && !is_processed(p)) {
+                       pl = p->l;
+                       if (pl->op == op_groupby)
+                               break;
+                       p = pl;
+               }
+               if (pl && pl->op == op_groupby) {
+                       group = 1;
+                       p = pl;
+                       /* At the end we switch back to the old projection 
relation op. 
+                        * During the partitioning and ordering we add the 
expressions to the intermediate relations. */
+               }
+               if (!group)
+                       p = op;
+       } 
+       if (!group && list_length(r->exps))
+               p = pp = rel_project(sql->sa, p, rel_projections(sql, p, NULL, 
1, 1));
+
+       /* Partition By */
+       if (partition_by_clause) {
+               gbe = rel_group_by(sql, &pp, partition_by_clause, NULL /* 
cannot use (selection) column references, as this result is a selection column 
*/, f);
+               if (!gbe)
+                       return NULL;
+
+               for(n = gbe->h ; n ; n = n->next) {
+                       sql_exp *en = n->data;
+
+                       n->data = en = opt_groupby_add_exp(sql, p, NULL, en);
+                       set_direction(en, 1);
+               }
+               if (p->op == op_groupby) {
+                       sql_rel *npp = pp;
+
+                       pp = p;
+                       p = rel_project(sql->sa, npp, rel_projections(sql, npp, 
NULL, 1, 0));
+               }
+               p->r = gbe;
+       }
+       /* Order By */
+       if (order_by_clause) {
+               obe = rel_order_by(sql, &pp, order_by_clause, f);
+               if (!obe)
+                       return NULL;
+               if (p->op == op_groupby) {
+                       sql_rel *npp = pp;
+
+                       pp = p;
+                       p = rel_project(sql->sa, npp, rel_projections(sql, npp, 
NULL, 1, 0));
+               }
+               if (p->r) {
+                       p->r = list_merge(sa_list(sql->sa), p->r, (fdup)NULL); 
/* make sure the p->r is a different list than the gbe list */
+                       for(n = obe->h ; n ; n = n->next) {
+                               sql_exp *e1 = n->data;
+                               bool found = false;
+
+                               for(node *nn = ((list*)p->r)->h ; nn && !found 
; nn = nn->next) {
+                                       sql_exp *e2 = nn->data;
+                                       //the partition expression order should 
be the same as the one in the order by clause (if it's in there as well)
+                                       if(!exp_equal(e1, e2)) {
+                                               if(is_ascending(e1))
+                                                       e2->flag |= ASCENDING;
+                                               else
+                                                       e2->flag &= ~ASCENDING;
+                                               found = true;
+                                       }
+                               }
+                               if(!found)
+                                       append(p->r, e1);
+                       }
+               } else {
+                       p->r = obe;
+               }
+       }
 
        fargs = sa_list(sql->sa);
        if (window_function->token == SQL_RANK) { //rank function call
@@ -4768,7 +4887,12 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                int nfargs = 0;
 
                if(!dnn || is_ntile) { //pass an input column for analytic 
functions that don't require it
-                       sql_rel *lr = p->l;
+                       sql_rel *lr = p;//->l;
+
+                       if (!lr || !is_project(lr->op)) {
+                               p = pp = rel_project(sql->sa, p, 
rel_projections(sql, p, NULL, 1, 0));
+                               lr = p->l;
+                       }
                        in = lr->exps->h->data;
                        in = exp_column(sql->sa, exp_relname(in), exp_name(in), 
exp_subtype(in), exp_card(in), has_nil(in), is_intern(in));
                        if(!in)
@@ -4801,6 +4925,7 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                                        if(!(in = rel_check_type(sql, 
&first->tpe, in, type_equal)))
                                                return NULL;
                                }
+                               in = opt_groupby_add_exp(sql, p, pp, in);
                                append(fargs, in);
                                nfargs++;
                        }
@@ -4811,13 +4936,17 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                if (n) {
                        if (!n->next->data.sym) { /* count(*) */
                                sql_rel *lr = p->l;
+
+                               if (!lr || !is_project(lr->op)) {
+                                       p = pp = rel_project(sql->sa, p, 
rel_projections(sql, p, NULL, 1, 0));
+                                       lr = p->l;
+                               }
                                in = lr->exps->h->data;
                                in = exp_column(sql->sa, exp_relname(in), 
exp_name(in), exp_subtype(in), exp_card(in), has_nil(in), is_intern(in));
-                               if(!in)
-                                       return NULL;
                                append(fargs, in);
                                append(fargs, exp_atom_bool(sql->sa, 0)); 
//don't ignore nills
                        } else {
+                               sql_rel *lop = p;
                                is_last = 0;
                                exp_kind ek = {type_value, card_column, FALSE};
 
@@ -4827,8 +4956,18 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                                 * symbol compilation is required
                                 */
                                in = rel_value_exp2(sql, &p, n->next->data.sym, 
f, ek, &is_last);
+                               if (!in && !group) { /* try with implicit 
groupby */
+                                       /* reset error */
+                                       sql->session->status = 0;
+                                       sql->errstr[0] = '\0';
+                                       p = rel_project(sql->sa, lop, 
sa_list(sql->sa));
+                                       in = rel_value_exp2(sql, &p, 
n->next->data.sym, f, ek, &is_last);
+                               }
                                if(!in)
                                        return NULL;
+                               in = opt_groupby_add_exp(sql, p, pp, in);
+                               if (group) 
+                                       rel_intermediates_add_exp(sql, p, op, 
in);
                                append(fargs, in);
                                if(strcmp(s->base.name, "sys") == 0 && 
strcmp(aname, "count") == 0) {
                                        sql_subtype *empty = 
sql_bind_localtype("void"), *bte = sql_bind_localtype("bte");
@@ -4842,59 +4981,14 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                }
        }
 
-       p->l = rel_project(sql->sa, p->l, rel_projections(sql, p->l, NULL, 1, 
1));
-       pp = p->l;
-
-       /* Partition By */
-       if (partition_by_clause) {
-               gbe = rel_group_by(sql, &pp, partition_by_clause, NULL /* 
cannot use (selection) column references, as this result is a selection column 
*/, f | sql_partitionby );
-               if (!gbe)
-                       return NULL;
-               for(n = gbe->h ; n ; n = n->next) {
-                       sql_exp *en = n->data;
-                       set_direction(en, 1);
-               }
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to