Changeset: 22f1a37ba08a for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=22f1a37ba08a
Added Files:
        sql/test/miscellaneous/Tests/groupby_expressions.sql
        sql/test/miscellaneous/Tests/groupby_expressions.stable.err
        sql/test/miscellaneous/Tests/groupby_expressions.stable.out
Modified Files:
        clients/mapiclient/mhelp.c
        sql/backends/monet5/Tests/rapi05.stable.out
        sql/backends/monet5/rel_bin.c
        sql/backends/monet5/sql_scenario.c
        sql/server/rel_rel.c
        sql/server/rel_rel.h
        sql/server/rel_schema.c
        sql/server/rel_select.c
        sql/server/rel_updates.c
        sql/server/sql_mvc.c
        sql/server/sql_mvc.h
        sql/server/sql_parser.y
        sql/server/sql_qc.c
        sql/server/sql_qc.h
        sql/server/sql_semantic.c
        sql/server/sql_symbol.c
        sql/server/sql_symbol.h
        sql/server/sql_tokens.h
        
sql/test/BugTracker-2016/Tests/groupby_on_column_expression.Bug-3832.stable.err
        
sql/test/BugTracker-2016/Tests/groupby_on_column_expression.Bug-3832.stable.out
        
sql/test/BugTracker-2017/Tests/sqlitelogictest-aggregation-distinct-coalesce.Bug-6431.stable.err
        sql/test/analytics/Tests/analytics09.sql
        sql/test/analytics/Tests/analytics09.stable.err
        sql/test/analytics/Tests/analytics09.stable.out
        sql/test/miscellaneous/Tests/All
Branch: default
Log Message:

Merged groupby-expressions branch into default.


diffs (truncated from 2067 to 300 lines):

diff --git a/clients/mapiclient/mhelp.c b/clients/mapiclient/mhelp.c
--- a/clients/mapiclient/mhelp.c
+++ b/clients/mapiclient/mhelp.c
@@ -405,7 +405,7 @@ SQLhelp sqlhelp[] = {
         "[ FROM from_item [',' ...] ]\n"
         "[ WINDOW window_definition [',' ...] ]\n"
         "[ WHERE condition ]\n"
-        "[ GROUP BY grouping_element ',', ...] ]\n"
+        "[ GROUP BY expression ',', ...] ]\n"
         "[ HAVING condition [',' ...] ]\n"
         "[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] [ CORRESPONDING ] 
select ]\n"
         "[ ORDER BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [',' 
...] ]\n"
diff --git a/sql/backends/monet5/Tests/rapi05.stable.out 
b/sql/backends/monet5/Tests/rapi05.stable.out
--- a/sql/backends/monet5/Tests/rapi05.stable.out
+++ b/sql/backends/monet5/Tests/rapi05.stable.out
@@ -32,7 +32,7 @@ Ready.
 #language R {kmeans(arg1,arg2)$cluster};
 #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/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
@@ -1190,7 +1190,7 @@ rel_parse_value(backend *be, char *query
        /* get out the single value as we don't want an enclosing projection! */
        if (m->sym->token == SQL_SELECT) {
                SelectNode *sn = (SelectNode *)m->sym;
-               if (sn->selection->h->data.sym->token == SQL_COLUMN) {
+               if (sn->selection->h->data.sym->token == SQL_COLUMN || 
sn->selection->h->data.sym->token == SQL_IDENT) {
                        int is_last = 0;
                        sql_rel *rel = NULL;
                        sql_exp *e = rel_value_exp2(m, &rel, 
sn->selection->h->data.sym->data.lval->h->data.sym, sql_sel, ek, &is_last);
diff --git a/sql/backends/monet5/sql_scenario.c 
b/sql/backends/monet5/sql_scenario.c
--- a/sql/backends/monet5/sql_scenario.c
+++ b/sql/backends/monet5/sql_scenario.c
@@ -1190,7 +1190,7 @@ SQLparser(Client c)
                        goto finalize;
                }
                scanner_query_processed(&(m->scanner));
-       } else if (caching(m) && cachable(m, NULL) && m->emode != m_prepare && 
(be->q = qc_match(m->qc, m->sym, m->args, m->argc, m->scanner.key ^ 
m->session->schema->base.id)) != NULL) {
+       } else if (caching(m) && cachable(m, NULL) && m->emode != m_prepare && 
(be->q = qc_match(m->qc, m, m->sym, m->args, m->argc, m->scanner.key ^ 
m->session->schema->base.id)) != NULL) {
                /* query template was found in the query cache */
                scanner_query_processed(&(m->scanner));
                m->no_mitosis = be->q->no_mitosis;
diff --git a/sql/server/rel_rel.c b/sql/server/rel_rel.c
--- a/sql/server/rel_rel.c
+++ b/sql/server/rel_rel.c
@@ -265,7 +265,7 @@ rel_bind_column( mvc *sql, sql_rel *rel,
 {
        sql_rel *p = NULL;
 
-       if (f == sql_sel && rel && is_project(rel->op) && !is_processed(rel))
+       if (is_sql_sel(f) && rel && is_project(rel->op) && !is_processed(rel))
                rel = rel->l;
 
        if (!rel || (rel = rel_bind_column_(sql, &p, rel, cname)) == NULL)
diff --git a/sql/server/rel_rel.h b/sql/server/rel_rel.h
--- a/sql/server/rel_rel.h
+++ b/sql/server/rel_rel.h
@@ -12,11 +12,21 @@
 #include "sql_relation.h"
 #include "sql_mvc.h"
 
-#define sql_from       0
-#define sql_where      1
-#define sql_sel        2       
-#define sql_having     3
-#define sql_orderby    4       
+#define sql_from     1
+#define sql_where    2
+#define sql_sel      4
+#define sql_having   8
+#define sql_orderby 16
+#define sql_groupby 32 //ORed
+#define sql_partitionby 64 //ORed
+
+#define is_sql_from(X)    ((X & sql_from) == sql_from)
+#define is_sql_where(X)   ((X & sql_where) == sql_where)
+#define is_sql_sel(X)     ((X & sql_sel) == sql_sel)
+#define is_sql_having(X)  ((X & sql_having) == sql_having)
+#define is_sql_orderby(X) ((X & sql_orderby) == sql_orderby)
+#define is_sql_groupby(X) ((X & sql_groupby) == sql_groupby)
+#define is_sql_partitionby(X) ((X & sql_partitionby) == sql_partitionby)
 
 #define ERR_AMBIGUOUS          050000
 
diff --git a/sql/server/rel_schema.c b/sql/server/rel_schema.c
--- a/sql/server/rel_schema.c
+++ b/sql/server/rel_schema.c
@@ -430,7 +430,7 @@ column_option(
                symbol *sym = s->data.sym;
                char *err = NULL, *r;
 
-               if (sym->token == SQL_COLUMN) {
+               if (sym->token == SQL_COLUMN || sym->token == SQL_IDENT) {
                        sql_exp *e = rel_logical_value_exp(sql, NULL, sym, 
sql_sel);
                        
                        if (e && is_atom(e->type)) {
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
@@ -1054,7 +1054,7 @@ rel_column_ref(mvc *sql, sql_rel **rel, 
        sql_exp *exp = NULL;
        dlist *l = NULL;
 
-       assert(column_r->token == SQL_COLUMN && column_r->type == type_list);
+       assert((column_r->token == SQL_COLUMN || column_r->token == SQL_IDENT) 
&& column_r->type == type_list);
        l = column_r->data.lval;
 
        if (dlist_length(l) == 1 && l->h->type == type_int) {
@@ -1102,7 +1102,7 @@ rel_column_ref(mvc *sql, sql_rel **rel, 
                        return rel_var_ref(sql, name, 0);
                }
                if (!exp && !var) {
-                       if (rel && *rel && (*rel)->card <= CARD_AGGR && f == 
sql_sel) {
+                       if (rel && *rel && (*rel)->card <= CARD_AGGR && 
is_sql_sel(f)) {
                                sql_rel *gb = *rel;
 
                                while(gb->l && !is_groupby(gb->op))
@@ -1110,7 +1110,7 @@ rel_column_ref(mvc *sql, sql_rel **rel, 
                                if (gb && gb->l && rel_bind_column(sql, gb->l, 
name, f)) 
                                        return sql_error(sql, 02, 
SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s' in query results 
without an aggregate function", name);
                        }
-                       if (f == sql_having)
+                       if (is_sql_having(f))
                                return sql_error(sql, 02, SQLSTATE(42000) 
"SELECT: cannot use non GROUP BY column '%s' in query results without an 
aggregate function", name);
                        return sql_error(sql, 02, SQLSTATE(42000) "SELECT: 
identifier '%s' unknown", name);
                }
@@ -1136,7 +1136,7 @@ rel_column_ref(mvc *sql, sql_rel **rel, 
                        }
                }
                if (!exp) {
-                       if (rel && *rel && (*rel)->card == CARD_AGGR && f == 
sql_sel) {
+                       if (rel && *rel && (*rel)->card == CARD_AGGR && 
is_sql_sel(f)) {
                                sql_rel *gb = *rel;
 
                                while(gb->l && !is_groupby(gb->op) && 
is_project(gb->op))
@@ -1144,7 +1144,7 @@ rel_column_ref(mvc *sql, sql_rel **rel, 
                                if (gb && is_groupby(gb->op) && gb->l && 
rel_bind_column2(sql, gb->l, tname, cname, f))
                                        return sql_error(sql, 02, 
SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s.%s' in query 
results without an aggregate function", tname, cname);
                        }
-                       if (f == sql_having)
+                       if (is_sql_having(f))
                                return sql_error(sql, 02, SQLSTATE(42S22) 
"SELECT: cannot use non GROUP BY column '%s.%s' in query results without an 
aggregate function", tname, cname);
                        return sql_error(sql, 02, SQLSTATE(42S22) "SELECT: no 
such column '%s.%s'", tname, cname);
                }
@@ -1783,14 +1783,14 @@ rel_compare(mvc *sql, sql_rel *rel, symb
                        /* reset error */
                        sql->session->status = 0;
                        sql->errstr[0] = 0;
-                       r = rel_subquery(sql, rel, ro, ek, f == 
sql_sel?APPLY_LOJ:APPLY_JOIN);
+                       r = rel_subquery(sql, rel, ro, ek, 
is_sql_sel(f)?APPLY_LOJ:APPLY_JOIN);
 
                        /* get inner queries result value, ie
                           get last expression of r */
                        if (r) {
                                rs = rel_lastexp(sql, r);
 
-                               if (f == sql_sel && r->card > CARD_ATOM && 
quantifier != 1) {
+                               if (is_sql_sel(f) && r->card > CARD_ATOM && 
quantifier != 1) {
                                        sql_subaggr *zero_or_one = 
sql_bind_aggr(sql->sa, sql->session->schema, compare_aggr_op(compare_op, 
quantifier), exp_subtype(rs));
                                        rs = exp_aggr1(sql->sa, rs, 
zero_or_one, 0, 0, CARD_ATOM, 0);
 
@@ -2017,7 +2017,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                                sql->session->status = 0;
                                sql->errstr[0] = 0;
                                if (!r)
-                                       r = rel_subquery(sql, *rel, ro, ek, f 
== sql_sel?APPLY_LOJ:APPLY_JOIN);
+                                       r = rel_subquery(sql, *rel, ro, ek, 
is_sql_sel(f)?APPLY_LOJ:APPLY_JOIN);
 
                                /* get inner queries result value, ie
                                   get last expression of r */
@@ -2025,7 +2025,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                                        rs = rel_lastexp(sql, r);
                                        *rel = r;
                                        e = exp_compare(sql->sa, ls, rs, 
compare_str2type(compare_op));
-                                       if (f != sql_sel)
+                                       if (!is_sql_sel(f))
                                                return e;
                        
                                        /* For selection we need to convert 
back into Boolean */
@@ -2040,7 +2040,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                                if (!l) {
                                        l = *rel = rel_project(sql->sa, NULL, 
new_exp_list(sql->sa));
                                        ls = rel_project_add_exp(sql, l, ls);
-                               } else if (f == sql_sel) { /* allways add left 
side in case of selections phase */
+                               } else if (is_sql_sel(f)) { /* allways add left 
side in case of selections phase */
                                        if (!l->processed) { /* add all 
expressions to the project */
                                                l->exps = list_merge(l->exps, 
rel_projections(sql, l->l, NULL, 1, 1), (fdup)NULL);
                                                l->exps = 
list_distinct(l->exps, (fcmp)exp_equal, (fdup)NULL);
@@ -2075,7 +2075,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                int needproj = 0, vals_only = 1, is_new = 0;
                list *vals = NULL, *pexps = NULL;
 
-               if (outer && f == sql_sel && is_project(outer->op) && 
!is_processed(outer) && !list_empty(outer->exps)) {
+               if (outer && is_sql_sel(f) && is_project(outer->op) && 
!is_processed(outer) && !list_empty(outer->exps)) {
                        needproj = 1;
                        pexps = outer->exps;
                        if (!outer->l) { /* list of constants */
@@ -2096,7 +2096,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                        }
                }
 
-               if (!left || (!left->l && f == sql_sel && 
list_empty(left->exps))) {
+               if (!left || (!left->l && is_sql_sel(f) && 
list_empty(left->exps))) {
                        needproj = (left != NULL);
                        left = rel_project_exp(sql->sa, l);
                        is_new = 1;
@@ -2144,7 +2144,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                                                                return NULL;
                                                }
                                        }
-                                       if (r && z && is_project(z->op) && z->l 
&& f == sql_sel) {
+                                       if (r && z && is_project(z->op) && z->l 
&& is_sql_sel(f)) {
                                                sql_rel *gp = z->l;
                                                r = rel_project_add_exp(sql, z, 
r);
                                                reset_processed(gp);
@@ -2224,7 +2224,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                                reset_processed(left);
                        } else
                                *rel = left;
-                       if (f == sql_sel) {
+                       if (is_sql_sel(f)) {
                                e = rel_unop_(sql, r, NULL, "isnull", 
card_value);
                                if (sc->token == SQL_IN)
                                        e = rel_unop_(sql, e, NULL, "not", 
card_value);
@@ -2378,6 +2378,7 @@ rel_logical_value_exp(mvc *sql, sql_rel 
                        return exp_atom(sql->sa, atom_dup(sql->sa, an->a));
                }
        }
+       case SQL_IDENT:
        case SQL_COLUMN:
                return rel_column_ref(sql, rel, sc, f);
        case SQL_UNION:
@@ -3013,6 +3014,7 @@ rel_logical_exp(mvc *sql, sql_rel *rel, 
                sql_exp *e = exp_atom(sql->sa, atom_dup(sql->sa, an->a));
                return rel_select(sql->sa, rel, e);
        }
+       case SQL_IDENT:
        case SQL_COLUMN: {
                sql_rel *or = rel;
                sql_exp *e = rel_column_ref(sql, &rel, sc, f);
@@ -3140,6 +3142,8 @@ rel_unop(mvc *sql, sql_rel **rel, symbol
                e = rel_value_exp(sql, rel, l->next->data.sym, fs, iek);
        if (!e) {
                if (!f && *rel && (*rel)->card == CARD_AGGR) {
+                       if (is_sql_having(fs) || is_sql_orderby(fs))
+                               return NULL;
                        /* reset error */
                        sql->session->status = 0;
                        sql->errstr[0] = '\0';
@@ -3433,6 +3437,8 @@ rel_binop(mvc *sql, sql_rel **rel, symbo
        if (!l || !r)
                sf = find_func(sql, s, fname, 2, F_AGGR, NULL);
        if (!sf && (!l || !r) && *rel && (*rel)->card == CARD_AGGR) {
+               if (is_sql_having(f) || is_sql_orderby(f))
+                       return NULL;
                /* reset error */
                sql->session->status = 0;
                sql->errstr[0] = '\0';
@@ -3523,6 +3529,8 @@ rel_nop(mvc *sql, sql_rel **rel, symbol 
        /* first try aggregate */
        f = find_func(sql, s, fname, nr_args, F_AGGR, NULL);
        if (!f && err && *rel && (*rel)->card == CARD_AGGR) {
+               if (is_sql_having(fs) || is_sql_orderby(fs))
+                       return NULL;
                /* reset error */
                sql->session->status = 0;
                sql->errstr[0] = '\0';
@@ -3558,24 +3566,32 @@ static sql_exp *
                if (uaname)
                        GDKfree(uaname);
                return e;
-       }
-
-       if (f == sql_having && is_select(groupby->op))
+       } else if(is_sql_groupby(f) || is_sql_partitionby(f)) {
+               const char *clause = is_sql_groupby(f) ? "GROUP BY":"PARTITION 
BY";
+               char *uaname = GDKmalloc(strlen(aname) + 1);
+               sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) "%s: aggregate 
function '%s' not allowed in %s clause",
+                                                          uaname ? 
toUpperCopy(uaname, aname) : aname, aname, clause);
+               if (uaname)
+                       GDKfree(uaname);
+               return e;
+       }
+
+       if (is_sql_having(f) && is_select(groupby->op))
                groupby = groupby->l;
 
        if (groupby->l && groupby->op == op_project) {
                sql_rel *r = groupby->l;        
 
-               if (!is_processed(r) && f == sql_sel && r->op == op_project) {
+               if (!is_processed(r) && is_sql_sel(f) && r->op == op_project) {
                        project = r;
                        r = r->l;
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to