Changeset: c577d5c7a0c9 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/c577d5c7a0c9
Modified Files:
sql/backends/monet5/rel_bin.c
sql/backends/monet5/sql_cat.c
sql/common/sql_types.c
sql/include/sql_catalog.h
sql/rel.txt
sql/scripts/10_sys_schema_extension.sql
sql/server/rel_dump.c
sql/server/rel_optimize_others.c
sql/server/rel_psm.c
sql/server/rel_select.c
sql/server/sql_env.c
sql/server/sql_mvc.c
sql/server/sql_mvc.h
sql/server/sql_parser.y
sql/server/sql_scan.c
sql/storage/sql_storage.h
sql/storage/store.c
Branch: ordered-set-aggregates
Log Message:
initial work on ordered-set-aggregates
diffs (truncated from 681 to 300 lines):
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
@@ -1687,10 +1687,17 @@ exp_bin(backend *be, sql_exp *e, stmt *l
} break;
case e_aggr: {
list *attr = e->l;
+ list *r = e->r;
stmt *as = NULL;
sql_subfunc *a = e->f;
assert(sel == NULL);
+ /* cases
+ * 0) count(*)
+ * 1) general aggregation
+ * 2) aggregation with required order (quantile etc)
+ * 3) aggregation with optional order by, group_concat,
xml_agg
+ * */
if (attr && attr->h) {
node *en;
list *l = sa_list(sql->sa);
@@ -1743,6 +1750,37 @@ exp_bin(backend *be, sql_exp *e, stmt *l
return NULL;
append(l, stmt_project(be, u, a));
}
+ if (r) {
+ list *obe = r->h->data;
+ if (obe) {
+ stmt *orderby = NULL, *orderby_vals,
*orderby_ids, *orderby_grp;
+ /* order by */
+ if (grp) {
+ orderby = stmt_order(be, grp,
true, true);
+
+ orderby_vals = stmt_result(be,
orderby, 0);
+ orderby_ids = stmt_result(be,
orderby, 1);
+ orderby_grp = stmt_result(be,
orderby, 2);
+ }
+ for (node *n = obe->h; n; n = n->next) {
+ sql_exp *oe = n->data;
+ stmt *os = exp_bin(be, oe,
left, right, NULL, NULL, NULL, sel, depth+1, 0, push);
+ if (orderby)
+ orderby =
stmt_reorder(be, os, is_ascending(oe), nulls_last(oe), orderby_ids,
orderby_grp);
+ else
+ orderby =
stmt_order(be, os, is_ascending(oe), nulls_last(oe));
+ orderby_vals = stmt_result(be,
orderby, 0);
+ orderby_ids = stmt_result(be,
orderby, 1);
+ orderby_grp = stmt_result(be,
orderby, 2);
+ }
+ /* depending on type of aggr project
input or ordered column */
+ stmt *h = l->h->data;
+ l->h->data = h = stmt_project(be,
orderby_ids, h);
+ if (grp)
+ grp = stmt_project(be,
orderby_ids, grp);
+ (void)orderby_vals;
+ }
+ }
as = stmt_list(be, l);
} else {
/* count(*) may need the default group (relation) and
diff --git a/sql/backends/monet5/sql_cat.c b/sql/backends/monet5/sql_cat.c
--- a/sql/backends/monet5/sql_cat.c
+++ b/sql/backends/monet5/sql_cat.c
@@ -1065,7 +1065,7 @@ create_func(mvc *sql, char *sname, char
sql->errstr[0] = '\0';
}
}
- switch (mvc_create_func(&nf, sql, NULL, s, f->base.name, f->ops,
f->res, f->type, f->lang, f->mod, f->imp, f->query, f->varres, f->vararg,
f->system, f->side_effect)) {
+ switch (mvc_create_func(&nf, sql, NULL, s, f->base.name, f->ops,
f->res, f->type, f->lang, f->mod, f->imp, f->query, f->varres, f->vararg,
f->system, f->side_effect, f->order_required, f->opt_order)) {
case -1:
throw(SQL,"sql.create_func", SQLSTATE(HY013)
MAL_MALLOC_FAIL);
case -2:
diff --git a/sql/common/sql_types.c b/sql/common/sql_types.c
--- a/sql/common/sql_types.c
+++ b/sql/common/sql_types.c
@@ -873,6 +873,19 @@ sql_create_aggr(allocator *sa, const cha
}
static sql_func *
+sql_create_aggr_optorder(allocator *sa, const char *name, const char *mod,
const char *imp, bit semantics, bit private, sql_type *fres, int nargs, ...)
+{
+ sql_func *res;
+ va_list valist;
+
+ va_start(valist, nargs);
+ res = sql_create_func_(sa, name, mod, imp, F_AGGR, semantics, private,
SCALE_NONE, 0, fres, nargs, valist);
+ va_end(valist);
+ res->opt_order = true;
+ return res;
+}
+
+static sql_func *
sql_create_filter(allocator *sa, const char *name, const char *mod, const char
*imp, bit semantics, bit private, int fix_scale,
unsigned int res_scale, int nargs, ...)
{
@@ -1189,8 +1202,8 @@ sqltypeinit( allocator *sa)
sql_create_aggr(sa, "count", "aggr", "count", TRUE, FALSE, LNG, 1, ANY);
sql_create_func(sa, "cnt", "sql", "count", TRUE, TRUE, SCALE_FIX, 0,
LNG, 2, STR, STR);
- sql_create_aggr(sa, "listagg", "aggr", "str_group_concat", TRUE, FALSE,
STR, 1, STR);
- sql_create_aggr(sa, "listagg", "aggr", "str_group_concat", TRUE, FALSE,
STR, 2, STR, STR);
+ sql_create_aggr_optorder(sa, "listagg", "aggr", "str_group_concat",
TRUE, FALSE, STR, 1, STR);
+ sql_create_aggr_optorder(sa, "listagg", "aggr", "str_group_concat",
TRUE, FALSE, STR, 2, STR, STR);
/* order based operators */
sql_create_analytic(sa, "diff", "sql", "diff", TRUE, BIT, 1, ANY);
diff --git a/sql/include/sql_catalog.h b/sql/include/sql_catalog.h
--- a/sql/include/sql_catalog.h
+++ b/sql/include/sql_catalog.h
@@ -507,8 +507,11 @@ typedef struct sql_func {
vararg:1, /* variable input arguments */
system:1, /* system function */
instantiated:1, /* if the function is instantiated */
- private:1; /* certain functions cannot be bound from user queries
*/
- int fix_scale;
+ private:1, /* certain functions cannot be bound from user queries
*/
+ order_required:1, /* some aggregate functions require an order */
+ opt_order:1; /* some aggregate functions could have the inputs
sorted */
+
+ short fix_scale;
/*
SCALE_NONE => nothing
SCALE_FIX => input scale fixing,
diff --git a/sql/rel.txt b/sql/rel.txt
--- a/sql/rel.txt
+++ b/sql/rel.txt
@@ -163,6 +163,8 @@ for aggr
-> flag DISTINCT and NO_NIL could be set
for window functions
-> r contains a list with two values: the first is a list with the
partition by expressions, and the second a list with order by expressions
+for aggregate functions
+ -> r contains a list with two values: the first is a list with the
order by expressions, and the second is a list with filter expressions
e_column
-> rname alias for the relation (i.e., alias of ->l, used by higher
expressions)
diff --git a/sql/scripts/10_sys_schema_extension.sql
b/sql/scripts/10_sys_schema_extension.sql
--- a/sql/scripts/10_sys_schema_extension.sql
+++ b/sql/scripts/10_sys_schema_extension.sql
@@ -527,9 +527,9 @@ SELECT 'pi', pi() UNION ALL
SELECT 'rowcnt', rowcnt;
GRANT SELECT ON sys.var_values TO PUBLIC;
-CREATE AGGREGATE sys.group_concat(str string) RETURNS string EXTERNAL NAME
"aggr"."str_group_concat";
+CREATE AGGREGATE sys.group_concat(str string) RETURNS string WITH ORDER
EXTERNAL NAME "aggr"."str_group_concat";
GRANT EXECUTE ON AGGREGATE sys.group_concat(string) TO PUBLIC;
-CREATE AGGREGATE sys.group_concat(str string, sep string) RETURNS string
EXTERNAL NAME "aggr"."str_group_concat";
+CREATE AGGREGATE sys.group_concat(str string, sep string) RETURNS string WITH
ORDER EXTERNAL NAME "aggr"."str_group_concat";
GRANT EXECUTE ON AGGREGATE sys.group_concat(string, string) TO PUBLIC;
CREATE WINDOW sys.group_concat(str string) RETURNS string EXTERNAL NAME
"sql"."str_group_concat";
diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c
--- a/sql/server/rel_dump.c
+++ b/sql/server/rel_dump.c
@@ -244,6 +244,15 @@ exp_print(mvc *sql, stream *fout, sql_ex
exps_print(sql, fout, e->l, depth, refs, 0, 1,
decorate, 0);
else
mnstr_printf(fout, "()");
+ if (e->r) { /* order by exps */
+ list *r = e->r;
+ list *obes = r->h->data;
+ exps_print(sql, fout, obes, depth, refs, 0, 1,
decorate, 0);
+ if (r->h->next) {
+ list *exps = r->h->next->data;
+ exps_print(sql, fout, exps, depth, refs, 0, 1,
decorate, 0);
+ }
+ }
} break;
case e_column: {
if (is_freevar(e))
diff --git a/sql/server/rel_optimize_others.c b/sql/server/rel_optimize_others.c
--- a/sql/server/rel_optimize_others.c
+++ b/sql/server/rel_optimize_others.c
@@ -277,7 +277,15 @@ exp_mark_used(sql_rel *subrel, sql_exp *
case e_func: {
if (e->l)
nr += exps_mark_used(subrel, e->l, local_proj);
- assert(!e->r);
+ if (e->r) {
+ list *r = e->r;
+ list *obes = r->h->data;
+ nr += exps_mark_used(subrel, obes, local_proj);
+ if (r->h->next) {
+ list *exps = r->h->next->data;
+ nr += exps_mark_used(subrel, exps, local_proj);
+ }
+ }
break;
}
case e_cmp:
diff --git a/sql/server/rel_psm.c b/sql/server/rel_psm.c
--- a/sql/server/rel_psm.c
+++ b/sql/server/rel_psm.c
@@ -854,7 +854,7 @@ rel_create_function(allocator *sa, const
}
static sql_rel *
-rel_create_func(sql_query *query, dlist *qname, dlist *params, symbol *res,
dlist *ext_name, dlist *body, sql_ftype type, sql_flang lang, int replace)
+rel_create_func(sql_query *query, dlist *qname, dlist *params, symbol *res,
dlist *ext_name, dlist *body, sql_ftype type, sql_flang lang, int replace, int
order_spec)
{
mvc *sql = query->sql;
const char *fname = qname_schema_object(qname);
@@ -869,6 +869,8 @@ rel_create_func(sql_query *query, dlist
int create = (!instantiate && !deps);
bit vararg = FALSE, union_err = 0;
char *F = NULL, *fn = NULL, is_func, *q = QUERY(sql->scanner);
+ bit order_required = (order_spec == 2);
+ bit opt_order = (order_spec == 1);
if (res && res->token == SQL_TABLE) {
if (type == F_FUNC)
@@ -1020,7 +1022,7 @@ rel_create_func(sql_query *query, dlist
sql->params = NULL;
if (create) {
bit side_effect = (list_empty(restype) || (!vararg &&
list_empty(l))); /* TODO make this more precise? */
- switch (mvc_create_func(&f, sql, sql->sa, s, fname, l,
restype, type, lang, mod, imp, lang_body, (type == F_LOADER)?TRUE:FALSE,
vararg, FALSE, side_effect)) {
+ switch (mvc_create_func(&f, sql, sql->sa, s, fname, l,
restype, type, lang, mod, imp, lang_body, (type == F_LOADER)?TRUE:FALSE,
vararg, FALSE, side_effect, order_required, opt_order)) {
case -1:
return sql_error(sql, 01,
SQLSTATE(HY013) MAL_MALLOC_FAIL);
case -2:
@@ -1040,7 +1042,7 @@ rel_create_func(sql_query *query, dlist
if (create) { /* needed for recursive functions */
bit side_effect = list_empty(restype) == 1; /* TODO
make this more precise? */
q = query_cleaned(sql->ta, q);
- switch (mvc_create_func(&f, sql, sql->sa, s, fname, l,
restype, type, lang, sql_shared_module_name, NULL, q, FALSE, vararg, FALSE,
side_effect)) {
+ switch (mvc_create_func(&f, sql, sql->sa, s, fname, l,
restype, type, lang, sql_shared_module_name, NULL, q, FALSE, vararg, FALSE,
side_effect, order_required, opt_order)) {
case -1:
return sql_error(sql, 01,
SQLSTATE(HY013) MAL_MALLOC_FAIL);
case -2:
@@ -1083,7 +1085,7 @@ rel_create_func(sql_query *query, dlist
sql->params = NULL;
if (create) {
q = query_cleaned(sql->ta, q);
- switch (mvc_create_func(&f, sql, sql->sa, s, fname, l,
restype, type, lang, fmod, fnme, q, FALSE, vararg, FALSE, FALSE)) {
+ switch (mvc_create_func(&f, sql, sql->sa, s, fname, l,
restype, type, lang, fmod, fnme, q, FALSE, vararg, FALSE, FALSE,
order_required, opt_order)) {
case -1:
return sql_error(sql, 01,
SQLSTATE(HY013) MAL_MALLOC_FAIL);
case -2:
@@ -1092,6 +1094,7 @@ rel_create_func(sql_query *query, dlist
default:
break;
}
+
/* instantiate MAL functions while being created. This
also sets the side-effects flag */
bool se = f->side_effect;
if (!backend_resolve_function(&clientid, f, fnme, &se))
@@ -1557,8 +1560,9 @@ rel_psm(sql_query *query, symbol *s)
sql_ftype type = (sql_ftype)
l->h->next->next->next->next->next->data.i_val;
sql_flang lang = (sql_flang)
l->h->next->next->next->next->next->next->data.i_val;
int repl =
l->h->next->next->next->next->next->next->next->data.i_val;
+ int order_spec =
l->h->next->next->next->next->next->next->next->next->data.i_val;
- ret = rel_create_func(query, l->h->data.lval,
l->h->next->data.lval, l->h->next->next->data.sym,
l->h->next->next->next->data.lval, l->h->next->next->next->next->data.lval,
type, lang, repl);
+ ret = rel_create_func(query, l->h->data.lval,
l->h->next->data.lval, l->h->next->next->data.sym,
l->h->next->next->next->data.lval, l->h->next->next->next->next->data.lval,
type, lang, repl, order_spec);
sql->type = Q_SCHEMA;
} break;
case SQL_DROP_FUNC:
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
@@ -3442,6 +3442,8 @@ exps_valid(sql_query *query, list *exps,
return NULL;
}
+static list * rel_order_by(sql_query *query, sql_rel **R, symbol *orderby, int
needs_distinct, int f);
+
static sql_exp *
_rel_aggr(sql_query *query, sql_rel **rel, int distinct, char *sname, char
*aname, dnode *args, int f)
{
@@ -3491,7 +3493,7 @@ static sql_exp *
bool arguments_correlated = true, all_const = true;
all_freevar = all_aggr?1:0;
- for (i = 0; args && args->data.sym; args = args->next, i++) {
+ for (i = 0; args && args->data.sym && args->data.sym->token !=
SQL_ORDERBY; args = args->next, i++) {
int base = (!groupby || !is_project(groupby->op) ||
is_base(groupby->op) || is_processed(groupby));
sql_rel *gl = base?groupby:groupby->l, *ogl = gl; /*
handle case of subqueries without correlation */
sql_exp *e = rel_value_exp(query, &gl, args->data.sym,
(f | sql_aggr)& ~sql_farg, ek);
@@ -3714,6 +3716,17 @@ static sql_exp *
if ((!exps || exps_card(exps) > CARD_ATOM) && (!res || !groupby))
return NULL;
+ list *obe = NULL;
+ if (args && args->data.sym && args->data.sym->token != SQL_ORDERBY)
+ return NULL;
+ if (args && args->data.sym) { /* handle order by */
+ int base = (!groupby || !is_project(groupby->op) ||
is_base(groupby->op) || is_processed(groupby));
+ sql_rel *gl = base?groupby:groupby->l;//, *ogl = gl; /* handle
case of subqueries without correlation */
+ obe = rel_order_by(query, &gl, args->data.sym, 0, f);
+ if (!obe)
+ return NULL;
+ }
+
if (all_freevar) {
query_update_outer(query, res, all_freevar-1);
} else if (rel) {
@@ -3725,6 +3738,7 @@ static sql_exp *
}
if (!has_args) { /* count(*) case */
+ obe = NULL; /* no errors, although the order by is useless */
sql_exp *e;
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]