Changeset: 8d98909b851e for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=8d98909b851e
Added Files:
        sql/test/analytics/Tests/analytics11.sql
        sql/test/analytics/Tests/analytics11.stable.err
        sql/test/analytics/Tests/analytics11.stable.out
Modified Files:
        sql/server/rel_optimizer.c
        sql/server/rel_select.c
        sql/server/sql_parser.y
        sql/server/sql_semantic.c
        sql/server/sql_tokens.h
        sql/test/analytics/Tests/All
Branch: grouping-analytics
Log Message:

Adding GROUPING special function call. It requires a non conventional way of 
compiling compared to a function call or aggregate


diffs (truncated from 403 to 300 lines):

diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -6291,7 +6291,7 @@ exps_mark_used(sql_allocator *sa, sql_re
                        nr += e->used;
                }
 
-               if (!nr && is_project(rel->op)) /* project atleast one column */
+               if (!nr && is_project(rel->op) && len > 0) /* project at least 
one column if exists */
                        exps[0]->used = 1; 
 
                for (i = len-1; i >= 0; i--) {
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
@@ -3848,19 +3848,15 @@ rel_intermediates_add_exp(mvc *sql, sql_
        }
 }
 
-static sql_exp *
-_rel_aggr(sql_query *query, sql_rel **rel, int distinct, sql_schema *s, char 
*aname, dnode *args, int f)
+
+static sql_rel *
+rel_find_groupby(sql_query *query, sql_rel *groupby, sql_rel **og, sql_rel 
**sel, int *group, int f, char* aname)
 {
        mvc *sql = query->sql;
-       exp_kind ek = {type_value, card_column, FALSE};
-       sql_subaggr *a = NULL;
-       int no_nil = 0, group = 0, freevar = 1;
-       sql_rel *groupby = *rel, *sel = NULL, *gr, *og = NULL;
-       list *exps = NULL;
 
        /* find having select */
        if (groupby && !is_processed(groupby) && is_sql_having(f)) { 
-               og = groupby;
+               *og = groupby;
                while(!is_processed(groupby) && !is_base(groupby->op)) {
                        if (is_select(groupby->op) || !groupby->l)
                                break;
@@ -3868,20 +3864,20 @@ static sql_exp *
                                groupby = groupby->l;
                }
                if (groupby && is_select(groupby->op) && 
!is_processed(groupby)) {
-                       group = 1;
-                       sel = groupby;
+                       *group = 1;
+                       *sel = groupby;
                        /* At the end we switch back to the old projection 
relation og. 
                         * During the partitioning and ordering we add the 
expressions to the intermediate relations. */
                }
-               if (!sel)
-                       groupby = og;
-               if (sel && sel->l)
-                       groupby = sel->l;
+               if (!*sel)
+                       groupby = *og;
+               if (*sel && (*sel)->l)
+                       groupby = (*sel)->l;
        }
 
        /* find groupby */
        if (groupby && !is_processed(groupby) && !is_base(groupby->op)) { 
-               og = groupby;
+               *og = groupby;
                while(!is_processed(groupby) && !is_base(groupby->op)) {
                        if (groupby->op == op_groupby || !groupby->l)
                                break;
@@ -3889,32 +3885,82 @@ static sql_exp *
                                groupby = groupby->l;
                }
                if (groupby && groupby->op == op_groupby) {
-                       group = 1;
+                       *group = 1;
                        /* At the end we switch back to the old projection 
relation og. 
                         * During the partitioning and ordering we add the 
expressions to the intermediate relations. */
                }
-               if (!group)
-                       groupby = og;
+               if (!*group)
+                       groupby = *og;
        }
 
        if (!groupby) {
                char *uaname = GDKmalloc(strlen(aname) + 1);
-               sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) "%s: missing 
group by",
-                                      uaname ? toUpperCopy(uaname, aname) : 
aname);
+               (void) sql_error(sql, 02, SQLSTATE(42000) "%s: missing group 
by",
+                                                uaname ? toUpperCopy(uaname, 
aname) : aname);
                if (uaname)
                        GDKfree(uaname);
-               return e;
+               return NULL;
        } else if(is_sql_groupby(f) || (is_sql_partitionby(f) && groupby->op != 
op_groupby)) {
                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);
+               (void) 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 (groupby->op != op_groupby) {                /* implicit groupby */
+               return NULL;
+       }
+
+       return groupby;
+}
+
+static sql_exp *
+rel_grouping(sql_query *query, sql_rel **rel, symbol *se, int f)
+{
+       mvc *sql = query->sql;
+       sql_rel *groupby, *sel = NULL, *og = NULL;
+       int group = 0;
+       dlist *l = se->data.lval;
+       list *group_cols;
+
+       (void) group;
+       (void) sel;
+       (void) og;
+
+       if (is_sql_groupby(f) || is_sql_partitionby(f) || is_sql_where(f) || 
is_sql_from(f))
+               return sql_error(sql, 02, SQLSTATE(42000) "SELECT: GROUPING 
expression not allowed in %s clause", 
+                                                is_sql_groupby(f) ? "GROUP BY" 
: is_sql_partitionby(f) ? "PARTITION BY" : is_sql_where(f) ? "WHERE" : "FROM");
+       if (!(groupby = rel_find_groupby(query, *rel, &og, &sel, &group, f, 
"GROUPING")))
+               return NULL;
+       if (groupby->op != op_groupby)
+               return sql_error(sql, 02, SQLSTATE(42000) "SELECT: GROUPING 
requires a GROUP BY clause");
+
+       group_cols = (list*) groupby->r;
+
+       for (dnode *dn = l->h; dn; dn = dn->next) {
+               symbol *sym = dn->data.sym;
+               exp_kind ek = {type_value, card_column, FALSE};
+               sql_exp *col = rel_value_exp(query, rel, sym, f, ek);
+               if (!col)
+                       return NULL; /* GROUPING(x, ...) columns must be 
present in the GROUP BY clause */
+       }
+
+       return exp_atom(sql->sa, atom_int(sql->sa, sql_bind_localtype("int"), 
0));
+}
+
+static sql_exp *
+_rel_aggr(sql_query *query, sql_rel **rel, int distinct, sql_schema *s, char 
*aname, dnode *args, int f)
+{
+       mvc *sql = query->sql;
+       exp_kind ek = {type_value, card_column, FALSE};
+       sql_subaggr *a = NULL;
+       int no_nil = 0, group = 0, freevar = 1;
+       sql_rel *groupby, *sel = NULL, *gr, *og = NULL;
+       list *exps = NULL;
+
+       if (!(groupby = rel_find_groupby(query, *rel, &og, &sel, &group, f, 
aname)))
+               return NULL;
+
+       if (groupby->op != op_groupby) { /* implicit groupby */
                sql_rel *np = rel_project2groupby(sql, groupby);
 
                if (*rel == groupby) {
@@ -5990,6 +6036,8 @@ rel_value_exp2(sql_query *query, sql_rel
                        return exp_atom(sql->sa, atom_dup(sql->sa, an->a));
                }
        }
+       case SQL_GROUPING:
+               return rel_grouping(query, rel, se, f);
        case SQL_NEXT:
                return rel_next_value_for(sql, se);
        case SQL_CAST:
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -4253,27 +4253,26 @@ scalar_exp:
 
 value_exp:
     atom
- |  user               { $$ = _symbol_create_list( SQL_COLUMN, 
-                         append_string(L(), sa_strdup(SA, "current_user"))); }
- |  CURRENT_ROLE       { $$ = _symbol_create_list( SQL_COLUMN, 
-                         append_string(L(), sa_strdup(SA, "current_role"))); }
- |  window_function
- |  column_ref                 { $$ = _symbol_create_list( SQL_COLUMN, $1); }
- |  var_ref            
  |  aggr_ref
- |  func_ref
- |  NEXT VALUE FOR qname       { $$ = _symbol_create_list( SQL_NEXT, $4); }
- |  datetime_funcs
- |  string_funcs
  |  case_exp
  |  cast_exp
- |  XML_value_function
- |  param
+ |  column_ref                            { $$ = 
_symbol_create_list(SQL_COLUMN, $1); }
+ |  CURRENT_ROLE   { $$ = _symbol_create_list(SQL_COLUMN, append_string(L(), 
sa_strdup(SA, "current_role"))); }
+ |  datetime_funcs
+ |  func_ref
+ |  GROUPING '(' column_ref_commalist ')' { $$ = 
_symbol_create_list(SQL_GROUPING, $3); }
+ |  NEXT VALUE FOR qname                  { $$ = _symbol_create_list(SQL_NEXT, 
$4); }
  |  null
- ;
-
-param:  
-   '?'                 
+ |  param
+ |  string_funcs
+ |  user            { $$ = _symbol_create_list(SQL_COLUMN, append_string(L(), 
sa_strdup(SA, "current_user"))); }
+ |  var_ref
+ |  window_function
+ |  XML_value_function
+ ;
+
+param:
+   '?'
        { 
          int nr = (m->params)?list_length(m->params):0;
 
@@ -6657,6 +6656,7 @@ char *token2string(tokens token)
        SQL(GRANT);
        SQL(GRANT_ROLES);
        SQL(GROUPBY);
+       SQL(GROUPING);
        SQL(GROUPING_SETS);
        SQL(IDENT);
        SQL(IF);
diff --git a/sql/server/sql_semantic.c b/sql/server/sql_semantic.c
--- a/sql/server/sql_semantic.c
+++ b/sql/server/sql_semantic.c
@@ -329,6 +329,21 @@ char *symbol2string(mvc *sql, symbol *se
                }
                len = snprintf( buf+len, BUFSIZ-len, ")"); 
        } break;
+       case SQL_GROUPING: {
+               dnode *lst = se->data.lval->h;
+               dnode *ops = lst->data.lval->h;
+               len = snprintf( buf+len, BUFSIZ-len, "GROUPING("); 
+               for (; ops; ops = ops->next) {
+                       char *tmp = symbol2string(sql, ops->data.sym, 
expression, err);
+                       if (tmp == NULL)
+                               return NULL;
+                       len = snprintf( buf+len, BUFSIZ-len, "%s%s", 
+                               tmp, 
+                               (ops->next)?",":"");
+                       _DELETE(tmp);
+               }
+               len = snprintf( buf+len, BUFSIZ-len, ")"); 
+       } break;
        case SQL_BINOP: {
                dnode *lst = se->data.lval->h;
                char *op = qname_fname(lst->data.lval);
diff --git a/sql/server/sql_tokens.h b/sql/server/sql_tokens.h
--- a/sql/server/sql_tokens.h
+++ b/sql/server/sql_tokens.h
@@ -84,6 +84,7 @@ typedef enum tokens {
        SQL_GRANT,
        SQL_GRANT_ROLES,
        SQL_GROUPBY,
+       SQL_GROUPING,
        SQL_GROUPING_SETS,
        SQL_IDENT,
        SQL_IF,
diff --git a/sql/test/analytics/Tests/All b/sql/test/analytics/Tests/All
--- a/sql/test/analytics/Tests/All
+++ b/sql/test/analytics/Tests/All
@@ -12,3 +12,4 @@ analytics09
 
 # Rollup, Cube tests
 analytics10
+analytics11
diff --git a/sql/test/analytics/Tests/analytics11.sql 
b/sql/test/analytics/Tests/analytics11.sql
new file mode 100644
--- /dev/null
+++ b/sql/test/analytics/Tests/analytics11.sql
@@ -0,0 +1,21 @@
+CREATE TABLE tbl_ProductSales (ColID int, Product_Category  varchar(64), 
Product_Name  varchar(64), TotalSales int); 
+INSERT INTO tbl_ProductSales VALUES (1,'Game','Mobo Game',200),(2,'Game','PKO 
Game',400),(3,'Fashion','Shirt',500),(4,'Fashion','Shorts',100);
+
+SELECT 1
+FROM tbl_ProductSales
+GROUP BY Product_Category;
+
+SELECT 1
+FROM tbl_ProductSales
+GROUP BY ();
+
+SELECT
+    GROUPING()
+FROM tbl_ProductSales
+GROUP BY Product_Category; --error, "grouping" requires arguments
+
+SELECT
+    GROUPING(Product_Name)
+FROM tbl_ProductSales GROUP BY (); --error, Product_Name it's not a grouping 
column
+
+DROP TABLE tbl_ProductSales;
diff --git a/sql/test/analytics/Tests/analytics11.stable.err 
b/sql/test/analytics/Tests/analytics11.stable.err
new file mode 100644
--- /dev/null
+++ b/sql/test/analytics/Tests/analytics11.stable.err
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to