Changeset: 4b068be98071 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=4b068be98071
Added Files:
        sql/test/analytics/Tests/analytics05.sql
        sql/test/analytics/Tests/analytics05.stable.err
        sql/test/analytics/Tests/analytics05.stable.out
Modified Files:
        clients/odbc/driver/SQLGetInfo.c
        sql/backends/monet5/rel_bin.c
        sql/scripts/51_sys_schema_extension.sql
        sql/server/rel_select.c
        sql/server/rel_updates.c
        sql/server/sql_mvc.c
        sql/server/sql_mvc.h
        sql/server/sql_parser.h
        sql/server/sql_parser.y
        sql/server/sql_scan.c
        sql/server/sql_symbol.c
        sql/server/sql_symbol.h
        sql/test/analytics/Tests/All
Branch: analytics
Log Message:

Introducing window aliases. After the from clause an optional WINDOW clause 
specifies the specification of the windows to be used in the projection clause 
(syntax sugar).

For every select command in a single statement, a new stack frame is pushed to 
store possible to be used window aliases in the select command.


diffs (truncated from 713 to 300 lines):

diff --git a/clients/odbc/driver/SQLGetInfo.c b/clients/odbc/driver/SQLGetInfo.c
--- a/clients/odbc/driver/SQLGetInfo.c
+++ b/clients/odbc/driver/SQLGetInfo.c
@@ -682,7 +682,7 @@ MNDBGetInfo(ODBCDbc *dbc,
                        "ROW_NUMBER,SAMPLE,SAVEPOINT,SEQUENCE,SERIAL,"
                        "SERIALIZABLE,SIMPLE,SPLIT_PART,STDIN,STDOUT,STREAM,"
                        "STRING,SYMMETRIC,TIES,TINYINT,TRIGGER,TRUNCATE,"
-                       "UNBOUNDED,UNCOMMITTED,UNENCRYPTED,WHILE,XMLAGG,"
+                       "UNBOUNDED,UNCOMMITTED,UNENCRYPTED,WHILE,WINDOW,XMLAGG,"
                        "XMLATTRIBUTES,XMLCOMMENT,XMLCONCAT,XMLDOCUMENT,"
                        "XMLELEMENT,XMLFOREST,XMLNAMESPACES,XMLPARSE,XMLPI,"
                        "XMLQUERY,XMLSCHEMA,XMLTEXT,XMLVALIDATE";
diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c
--- a/sql/backends/monet5/rel_bin.c
+++ b/sql/backends/monet5/rel_bin.c
@@ -504,8 +504,8 @@ exp_bin(backend *be, sql_exp *e, stmt *l
                                                es = stmt_const(be, 
bin_first_column(be, left), es);
                                }
                                /* last argument is condition, change into 
candidate list */
-                               if (!en->next && !f->func->varres && 
!f->func->vararg && list_length(exps) > list_length(f->func->ops)) {
-                                       if (!strcmp(f->func->base.name, 
"window_following_bound") && es->nrcols) {
+                               if (f->func->type != F_ANALYTIC && !en->next && 
!f->func->varres && !f->func->vararg && list_length(exps) > 
list_length(f->func->ops)) {
+                                       if (es->nrcols) {
                                                if (!nrcols) {
                                                        node *n;
                                                        list *nl = 
sa_list(sql->sa);
@@ -518,7 +518,7 @@ exp_bin(backend *be, sql_exp *e, stmt *l
 
                                                }
                                                es = stmt_uselect(be, es, 
stmt_bool(be,1), cmp_equal, NULL, 0);
-                                       } else if (f->func->type != 
F_ANALYTIC)/* need a condition */
+                                       } else /* need a condition */
                                                cond_execution = es;
                                }
                                if (es->nrcols > nrcols)
diff --git a/sql/scripts/51_sys_schema_extension.sql 
b/sql/scripts/51_sys_schema_extension.sql
--- a/sql/scripts/51_sys_schema_extension.sql
+++ b/sql/scripts/51_sys_schema_extension.sql
@@ -215,6 +215,7 @@ INSERT INTO sys.keywords (keyword) VALUE
   ('WHEN'),
   ('WHERE'),
   ('WHILE'),
+  ('WINDOW'),
   ('WITH'),
   ('WORK'),
   ('WRITE'),
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
@@ -4504,17 +4504,28 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
        node *n;
        dlist *l = se->data.lval;
        symbol *window_function = l->h->data.sym;
-       dlist *window_specification = l->h->next->data.lval;
        char *aname = NULL, *sname = 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;
        list *gbe = NULL, *obe = NULL, *args = NULL, *types = NULL, *fargs = 
NULL;
        sql_schema *s = sql->session->schema;
-       int distinct = 0, project_added = 0, aggr = (window_function->token != 
SQL_RANK), is_last,
-               has_order_by = (window_specification->h->next->data.sym != 
NULL),
-               frame_type = has_order_by ? FRAME_RANGE : FRAME_ROWS;
        dnode *dn = window_function->data.lval->h;
+       int distinct = 0, project_added = 0, aggr = (window_function->token != 
SQL_RANK), is_last, has_order_by, frame_type;
+       dlist *window_specification = NULL;
+
+       if(l->h->next->type == type_list) {
+               window_specification = l->h->next->data.lval;
+       } else if (l->h->next->type == type_string) {
+               const char* window_alias = l->h->next->data.sval;
+               if((window_specification = stack_get_window_def(sql, 
window_alias)) == NULL)
+                       return sql_error(sql, 02, SQLSTATE(42000) "SELECT: 
window '%s' not found on WINDOW specification list", window_alias);
+       } else {
+               assert(0);
+       }
+
+       has_order_by = (window_specification->h->next->data.sym != NULL),
+       frame_type = has_order_by ? FRAME_RANGE : FRAME_ROWS;
 
        aname = qname_fname(dn->data.lval);
        sname = qname_schema(dn->data.lval);
@@ -4655,7 +4666,8 @@ rel_rankop(mvc *sql, sql_rel **rel, symb
                        }
                }
        }
-       (void)distinct;
+       if(distinct)
+               return sql_error(sql, 02, SQLSTATE(42000) "SELECT: DISTINCT 
clause is not implemented for window functions");
 
        /* diff for partitions */
        if (gbe) {
@@ -5456,6 +5468,20 @@ rel_query(mvc *sql, sql_rel *rel, symbol
        if (ek.card != card_relation && sn->orderby)
                return sql_error(sql, 01, SQLSTATE(42000) "SELECT: ORDER BY 
only allowed on outermost SELECT");
 
+       if (sn->window) {
+               dlist *wl = sn->window->data.lval;
+               for (dnode *n = wl->h; n ; n = n->next) {
+                       dlist *wd = n->data.sym->data.lval;
+                       const char *name = wd->h->data.sval;
+                       dlist *wdef = wd->h->next->data.lval;
+                       if(stack_get_window_def(sql, name)) {
+                               return sql_error(sql, 01, SQLSTATE(42000) 
"SELECT: Duplicated definition of window '%s'", name);
+                       } else if(!stack_push_window_def(sql, name, wdef)) {
+                               return sql_error(sql, 02, SQLSTATE(HY001) 
MAL_MALLOC_FAIL);
+                       }
+               }
+       }
+
        sql->use_views = 1;
        if (sn->from) {         /* keep variable list with tables and names */
                dlist *fl = sn->from->data.lval;
@@ -5929,14 +5955,19 @@ rel_selects(mvc *sql, symbol *s)
                break;
        case SQL_SELECT: {
                exp_kind ek = {type_value, card_relation, TRUE};
-               SelectNode *sn = (SelectNode *) s;
+               SelectNode *sn = (SelectNode *) s;
+
+               if(!stack_push_frame(sql, "SELECT"))
+                       return sql_error(sql, 02, SQLSTATE(HY001) 
MAL_MALLOC_FAIL);
 
                if (sn->into) {
                        sql->type = Q_SCHEMA;
-                       return rel_select_with_into(sql, s);
+                       ret = rel_select_with_into(sql, s);
+               } else {
+                       ret = rel_subquery(sql, NULL, s, ek, APPLY_JOIN);
+                       sql->type = Q_TABLE;
                }
-               ret = rel_subquery(sql, NULL, s, ek, APPLY_JOIN);
-               sql->type = Q_TABLE;
+               stack_pop_frame(sql);
        }       break;
        case SQL_JOIN:
                ret = rel_joinquery(sql, NULL, s);
diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c
--- a/sql/server/rel_updates.c
+++ b/sql/server/rel_updates.c
@@ -967,7 +967,7 @@ update_table(mvc *sql, dlist *qname, dli
                                dlist_append_symbol(sql->sa, selection, a);
                        }
                       
-                       sym = newSelectNode(sql->sa, 0, selection, NULL, 
symbol_create_list(sql->sa, SQL_FROM, from_list), opt_where, NULL, NULL, NULL, 
NULL, NULL, NULL, NULL);
+                       sym = newSelectNode(sql->sa, 0, selection, NULL, 
symbol_create_list(sql->sa, SQL_FROM, from_list), opt_where, NULL, NULL, NULL, 
NULL, NULL, NULL, NULL, NULL);
                        sq = rel_selects(sql, sym);
                        if (sq)
                                sq = rel_optimizer(sql, sq, 0);
diff --git a/sql/server/sql_mvc.c b/sql/server/sql_mvc.c
--- a/sql/server/sql_mvc.c
+++ b/sql/server/sql_mvc.c
@@ -1549,7 +1549,7 @@ mvc_is_sorted(mvc *m, sql_column *col)
 
 /* variable management */
 static sql_var*
-stack_set(mvc *sql, int var, const char *name, sql_subtype *type, sql_rel 
*rel, sql_table *t, int view, int frame)
+stack_set(mvc *sql, int var, const char *name, sql_subtype *type, sql_rel 
*rel, sql_table *t, dlist *wdef, int view, int frame)
 {
        sql_var *v, *nvars;
        int nextsize = sql->sizevars;
@@ -1571,6 +1571,7 @@ stack_set(mvc *sql, int var, const char 
        v->t = t;
        v->view = view;
        v->frame = frame;
+       v->wdef = wdef;
        if (type) {
                int tpe = type->type->localtype;
                VALset(&sql->vars[var].a.data, tpe, (ptr) ATOMnilptr(tpe));
@@ -1587,7 +1588,7 @@ stack_set(mvc *sql, int var, const char 
 sql_var*
 stack_push_var(mvc *sql, const char *name, sql_subtype *type)
 {
-       sql_var* res = stack_set(sql, sql->topvars, name, type, NULL, NULL, 0, 
0);
+       sql_var* res = stack_set(sql, sql->topvars, name, type, NULL, NULL, 
NULL, 0, 0);
        if(res)
                sql->topvars++;
        return res;
@@ -1596,7 +1597,7 @@ stack_push_var(mvc *sql, const char *nam
 sql_var*
 stack_push_rel_var(mvc *sql, const char *name, sql_rel *var, sql_subtype *type)
 {
-       sql_var* res = stack_set(sql, sql->topvars, name, type, var, NULL, 0, 
0);
+       sql_var* res = stack_set(sql, sql->topvars, name, type, var, NULL, 
NULL, 0, 0);
        if(res)
                sql->topvars++;
        return res;
@@ -1605,7 +1606,7 @@ stack_push_rel_var(mvc *sql, const char 
 sql_var*
 stack_push_table(mvc *sql, const char *name, sql_rel *var, sql_table *t)
 {
-       sql_var* res = stack_set(sql, sql->topvars, name, NULL, var, t, 0, 0);
+       sql_var* res = stack_set(sql, sql->topvars, name, NULL, var, t, NULL, 
0, 0);
        if(res)
                sql->topvars++;
        return res;
@@ -1614,12 +1615,32 @@ stack_push_table(mvc *sql, const char *n
 sql_var*
 stack_push_rel_view(mvc *sql, const char *name, sql_rel *var)
 {
-       sql_var* res = stack_set(sql, sql->topvars, name, NULL, var, NULL, 1, 
0);
+       sql_var* res = stack_set(sql, sql->topvars, name, NULL, var, NULL, 
NULL, 1, 0);
        if(res)
                sql->topvars++;
        return res;
 }
 
+sql_var*
+stack_push_window_def(mvc *sql, const char *name, dlist *wdef)
+{
+       sql_var* res = stack_set(sql, sql->topvars, name, NULL, NULL, NULL, 
wdef, 0, 0);
+       if(res)
+               sql->topvars++;
+       return res;
+}
+
+dlist *
+stack_get_window_def(mvc *sql, const char *name)
+{
+       for (int i = sql->topvars-1; i >= 0; i--) {
+               if (!sql->vars[i].frame && sql->vars[i].wdef && 
strcmp(sql->vars[i].name, name)==0) {
+                       return sql->vars[i].wdef;
+               }
+       }
+       return NULL;
+}
+
 atom *
 stack_set_var(mvc *sql, const char *name, ValRecord *v)
 {
@@ -1658,7 +1679,7 @@ stack_get_var(mvc *sql, const char *name
 sql_var*
 stack_push_frame(mvc *sql, const char *name)
 {
-       sql_var* res = stack_set(sql, sql->topvars, name, NULL, NULL, NULL, 0, 
1);
+       sql_var* res = stack_set(sql, sql->topvars, name, NULL, NULL, NULL, 
NULL, 0, 1);
        if(res) {
                sql->topvars++;
                sql->frame++;
@@ -1675,6 +1696,7 @@ stack_pop_until(mvc *sql, int top)
                c_delete(v->name);
                VALclear(&v->a.data);
                v->a.data.vtype = 0;
+               v->wdef = NULL;
        }
 }
 
@@ -1687,10 +1709,11 @@ stack_pop_frame(mvc *sql)
                c_delete(v->name);
                VALclear(&v->a.data);
                v->a.data.vtype = 0;
-               if (v->t && v->view) 
+               if (v->t && v->view)
                        table_destroy(v->t);
                else if (v->rel)
                        rel_destroy(v->rel);
+               v->wdef = NULL;
        }
        if (sql->topvars && sql->vars[sql->topvars].name)  
                c_delete(sql->vars[sql->topvars].name);
@@ -1823,7 +1846,7 @@ stack_nr_of_declared_tables(mvc *sql)
        for (i = sql->topvars-1; i >= 0; i--) {
                if (sql->vars[i].rel && !sql->vars[i].view) {
                        sql_var *v = &sql->vars[i];
-                       if (v->t) 
+                       if (v->t)
                                dt++;
                }
        }
diff --git a/sql/server/sql_mvc.h b/sql/server/sql_mvc.h
--- a/sql/server/sql_mvc.h
+++ b/sql/server/sql_mvc.h
@@ -22,6 +22,7 @@
 #include "sql_keyword.h"
 #include "sql_atom.h"
 #include "sql_query.h"
+#include "sql_symbol.h"
 
 #define ERRSIZE 8192
 
@@ -69,7 +70,8 @@ typedef struct sql_var {
        const char *name;
        atom a;
        sql_table *t;
-       sql_rel *rel;   
+       sql_rel *rel;
+       dlist *wdef;
        char view;
        char frame;
 } sql_var;
@@ -230,6 +232,8 @@ extern sql_var* stack_push_var(mvc *sql,
 extern sql_var* stack_push_rel_var(mvc *sql, const char *name, sql_rel *var, 
sql_subtype *type);
 extern sql_var* stack_push_table(mvc *sql, const char *name, sql_rel *var, 
sql_table *t);
 extern sql_var* stack_push_rel_view(mvc *sql, const char *name, sql_rel *view);
+extern sql_var* stack_push_window_def(mvc *sql, const char *name, dlist *sym);
+extern dlist* stack_get_window_def(mvc *sql, const char *name);
 extern void stack_update_rel_view(mvc *sql, const char *name, sql_rel *view);
 
 extern sql_var* stack_push_frame(mvc *sql, const char *name);
diff --git a/sql/server/sql_parser.h b/sql/server/sql_parser.h
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to