Changeset: e7d24060cb18 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=e7d24060cb18
Modified Files:
gdk/gdk_analytic.h
gdk/gdk_analytic_func.c
sql/backends/monet5/sql_rank.c
sql/backends/monet5/sql_rank.h
sql/backends/monet5/sql_rank.mal
sql/backends/monet5/sql_rank.mal.sh
sql/backends/monet5/sql_upgrades.c
sql/scripts/39_analytics.sql
sql/scripts/39_analytics_hge.sql
sql/test/analytics/Tests/analytics14.sql
sql/test/analytics/Tests/analytics14.stable.out
Branch: statistics-analytics
Log Message:
Implemented median as a window function
diffs (truncated from 494 to 300 lines):
diff --git a/gdk/gdk_analytic.h b/gdk/gdk_analytic.h
--- a/gdk/gdk_analytic.h
+++ b/gdk/gdk_analytic.h
@@ -42,5 +42,6 @@ gdk_export gdk_return GDKanalytical_stdd
gdk_export gdk_return GDKanalytical_stddev_pop(BAT *r, BAT *b, BAT *s, BAT *e,
int tpe);
gdk_export gdk_return GDKanalytical_variance_samp(BAT *r, BAT *b, BAT *s, BAT
*e, int tpe);
gdk_export gdk_return GDKanalytical_variance_pop(BAT *r, BAT *b, BAT *s, BAT
*e, int tpe);
+gdk_export gdk_return GDKanalytical_median(BAT *r, BAT *b, BAT *s, BAT *e, int
tpe);
#endif //_GDK_ANALYTIC_H_
diff --git a/gdk/gdk_analytic_func.c b/gdk/gdk_analytic_func.c
--- a/gdk/gdk_analytic_func.c
+++ b/gdk/gdk_analytic_func.c
@@ -1804,3 +1804,95 @@ GDK_ANALYTICAL_STDEV_VARIANCE(stddev_sam
GDK_ANALYTICAL_STDEV_VARIANCE(stddev_pop, 0, sqrt(m2 / (n - 0)))
GDK_ANALYTICAL_STDEV_VARIANCE(variance_samp, 1, m2 / (n - 1))
GDK_ANALYTICAL_STDEV_VARIANCE(variance_pop, 0, m2 / (n - 0))
+
+/* There will be always at least one value for the median, because we don't
implement the exclude clause yet */
+#define ANALYTICAL_MEDIAN(TPE) \
+ do { \
+ TPE *restrict bp = (TPE*) Tloc(b, 0), *restrict rb = (TPE*)
Tloc(r, 0), v; \
+ for (; i < cnt; i++, rb++) { \
+ ss = (BUN) start[i]; \
+ ee = (BUN) end[i]; \
+ f = (ee - ss - 1) * 0.5f; \
+ qindex = ss + ee - (BUN) (ee + 0.5f - f); \
+ assert(qindex >= ss && qindex < ee); \
+ v = bp[qindex]; \
+ *rb = v; \
+ has_nils |= (v == TPE##_nil); \
+ } \
+ } while (0)
+
+gdk_return
+GDKanalytical_median(BAT *r, BAT *b, BAT *s, BAT *e, int tpe)
+{
+ bool has_nils = false;
+ BUN i = 0, cnt = BATcount(b), qindex, ss, ee;
+ lng *restrict start, *restrict end;
+ dbl f;
+
+ assert(s && e);
+ start = (lng *) Tloc(s, 0);
+ end = (lng *) Tloc(e, 0);
+
+ if (!ATOMlinear(tpe)) {
+ GDKerror("GDKanalytical_median: cannot determine quantile on "
+ "non-linear type %s\n", ATOMname(tpe));
+ return GDK_FAIL;
+ }
+
+ switch (tpe) {
+ case TYPE_bit:
+ ANALYTICAL_MEDIAN(bit);
+ break;
+ case TYPE_bte:
+ ANALYTICAL_MEDIAN(bte);
+ break;
+ case TYPE_sht:
+ ANALYTICAL_MEDIAN(sht);
+ break;
+ case TYPE_int:
+ ANALYTICAL_MEDIAN(int);
+ break;
+ case TYPE_lng:
+ ANALYTICAL_MEDIAN(lng);
+ break;
+#ifdef HAVE_HGE
+ case TYPE_hge:
+ ANALYTICAL_MEDIAN(hge);
+ break;
+#endif
+ case TYPE_flt:
+ ANALYTICAL_MEDIAN(flt);
+ break;
+ case TYPE_dbl:
+ ANALYTICAL_MEDIAN(dbl);
+ break;
+ default: {
+ BATiter bpi = bat_iterator(b);
+ const void *nil = ATOMnilptr(tpe);
+ int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
+ void *curval;
+ for (; i < cnt; i++) {
+ ss = (BUN) start[i];
+ ee = (BUN) end[i];
+ f = (ee - ss - 1) * 0.5f;
+ qindex = ss + ee - (BUN) (ee + 0.5f - f);
+ assert(qindex >= ss && qindex < ee);
+ curval = BUNtail(bpi, qindex);
+ if (BUNappend(r, curval, false) != GDK_SUCCEED)
+ goto allocation_error;
+ if (atomcmp(curval, nil) == 0)
+ has_nils = true;
+ }
+ }
+ }
+ BATsetcount(r, cnt);
+ r->tkey = BATcount(r) <= 1;
+ r->tsorted = BATcount(r) <= 1;
+ r->trevsorted = BATcount(r) <= 1;
+ r->tnonil = !has_nils;
+ r->tnil = has_nils;
+ return GDK_SUCCEED;
+allocation_error:
+ GDKerror("GDKanalytical_median: malloc failure\n");
+ return GDK_FAIL;
+}
diff --git a/sql/backends/monet5/sql_rank.c b/sql/backends/monet5/sql_rank.c
--- a/sql/backends/monet5/sql_rank.c
+++ b/sql/backends/monet5/sql_rank.c
@@ -1611,3 +1611,9 @@ SQLvar_pop(Client cntxt, MalBlkPtr mb, M
return do_stddev_and_variance(cntxt, mb, stk, pci, "sql.variancep",
SQLSTATE(42000) "variancep(:any_1,:lng,:lng)",
GDKanalytical_variance_pop);
}
+
+str
+SQLmedian(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
+{
+ return SQLanalytical_func(cntxt, mb, stk, pci, "sql.median",
SQLSTATE(42000) "median(:any_1,:lng,:lng)", GDKanalytical_median);
+}
diff --git a/sql/backends/monet5/sql_rank.h b/sql/backends/monet5/sql_rank.h
--- a/sql/backends/monet5/sql_rank.h
+++ b/sql/backends/monet5/sql_rank.h
@@ -40,5 +40,6 @@ sql5_export str SQLstddev_samp(Client cn
sql5_export str SQLstddev_pop(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
InstrPtr pci);
sql5_export str SQLvar_samp(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
InstrPtr pci);
sql5_export str SQLvar_pop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr
pci);
+sql5_export str SQLmedian(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr
pci);
#endif /* _SQL_RANK_H */
diff --git a/sql/backends/monet5/sql_rank.mal b/sql/backends/monet5/sql_rank.mal
--- a/sql/backends/monet5/sql_rank.mal
+++ b/sql/backends/monet5/sql_rank.mal
@@ -785,6 +785,14 @@ pattern batsql.variancep(b:bat[:dbl], s:
address SQLvar_pop
comment "return the variance of groups";
+pattern sql.median(b:any_1, s:lng, e:lng) :any_1
+address SQLmedian
+comment "return the median value of groups";
+
+pattern batsql.median(b:bat[:any_1], s:bat[:lng], e:bat[:lng]) :bat[:any_1]
+address SQLmedian
+comment "return the median value of groups";
+
command aggr.exist(b:bat[:any_2], h:any_1):bit
address ALGexist;
diff --git a/sql/backends/monet5/sql_rank.mal.sh
b/sql/backends/monet5/sql_rank.mal.sh
--- a/sql/backends/monet5/sql_rank.mal.sh
+++ b/sql/backends/monet5/sql_rank.mal.sh
@@ -414,6 +414,17 @@ comment "return the variance of groups";
EOF
done
+ cat <<EOF
+pattern sql.median(b:any_1, s:lng, e:lng) :any_1
+address SQLmedian
+comment "return the median value of groups";
+
+pattern batsql.median(b:bat[:any_1], s:bat[:lng], e:bat[:lng]) :bat[:any_1]
+address SQLmedian
+comment "return the median value of groups";
+
+EOF
+
cat <<EOF
command aggr.exist(b:bat[:any_2], h:any_1):bit
address ALGexist;
diff --git a/sql/backends/monet5/sql_upgrades.c
b/sql/backends/monet5/sql_upgrades.c
--- a/sql/backends/monet5/sql_upgrades.c
+++ b/sql/backends/monet5/sql_upgrades.c
@@ -2578,7 +2578,7 @@ sql_update_default(Client c, mvc *sql, c
static str
sql_update_analytics(Client c, mvc *sql, const char *prev_schema, bool
*systabfixed)
{
- size_t bufsize = 8192, pos = 0;
+ size_t bufsize = 16384, pos = 0;
char *err = NULL, *buf = GDKmalloc(bufsize);
if (!*systabfixed &&
@@ -2686,7 +2686,43 @@ sql_update_analytics(Client c, mvc *sql,
"GRANT EXECUTE ON WINDOW var_pop(INTERVAL SECOND) TO
PUBLIC;\n"
"create window var_pop(val INTERVAL MONTH) returns
DOUBLE\n"
" external name \"sql\".\"variancep\";\n"
- "GRANT EXECUTE ON WINDOW var_pop(INTERVAL MONTH) TO
PUBLIC;\n");
+ "GRANT EXECUTE ON WINDOW var_pop(INTERVAL MONTH) TO
PUBLIC;\n"
+ "create window median(val TINYINT) returns TINYINT\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(TINYINT) TO PUBLIC;\n"
+ "create window median(val SMALLINT) returns SMALLINT\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(SMALLINT) TO PUBLIC;\n"
+ "create window median(val INTEGER) returns INTEGER\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(INTEGER) TO PUBLIC;\n"
+ "create window median(val BIGINT) returns BIGINT\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(BIGINT) TO PUBLIC;\n"
+ "create window median(val DECIMAL) returns DECIMAL\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(DECIMAL) TO PUBLIC;\n"
+ "create window median(val REAL) returns REAL\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(REAL) TO PUBLIC;\n"
+ "create window median(val DOUBLE) returns DOUBLE\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(DOUBLE) TO PUBLIC;\n"
+ "create window median(val DATE) returns DATE\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(DATE) TO PUBLIC;\n"
+ "create window median(val TIME) returns TIME\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(TIME) TO PUBLIC;\n"
+ "create window median(val TIMESTAMP) returns
TIMESTAMP\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(TIMESTAMP) TO PUBLIC;\n"
+ "create window median(val INTERVAL SECOND) returns
INTERVAL SECOND\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(INTERVAL SECOND) TO
PUBLIC;\n"
+ "create window median(val INTERVAL MONTH) returns
INTERVAL MONTH\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(INTERVAL MONTH) TO
PUBLIC;\n");
#ifdef HAVE_HGE
if (have_hge) {
@@ -2703,12 +2739,15 @@ sql_update_analytics(Client c, mvc *sql,
"GRANT EXECUTE ON WINDOW var_samp(HUGEINT) TO PUBLIC;\n"
"create window var_pop(val HUGEINT) returns DOUBLE\n"
" external name \"sql\".\"variancep\";\n"
- "GRANT EXECUTE ON WINDOW var_pop(HUGEINT) TO
PUBLIC;\n");
+ "GRANT EXECUTE ON WINDOW var_pop(HUGEINT) TO PUBLIC;\n"
+ "create window median(val HUGEINT) returns HUGEINT;\n"
+ " external name \"sql\".\"median\";\n"
+ "GRANT EXECUTE ON WINDOW median(HUGEINT) TO PUBLIC;\n");
}
#endif
pos += snprintf(buf + pos, bufsize - pos,
- "update sys.functions set system = true where name in
('stddev_samp', 'stddev_pop', 'var_samp', 'var_pop')"
+ "update sys.functions set system = true where name in
('stddev_samp', 'stddev_pop', 'var_samp', 'var_pop', 'median')"
" and schema_id = (select id from sys.schemas where
name = 'sys');\n");
pos += snprintf(buf + pos, bufsize - pos,
diff --git a/sql/scripts/39_analytics.sql b/sql/scripts/39_analytics.sql
--- a/sql/scripts/39_analytics.sql
+++ b/sql/scripts/39_analytics.sql
@@ -253,6 +253,44 @@ create aggregate median(val INTERVAL MON
external name "aggr"."median";
GRANT EXECUTE ON AGGREGATE median(INTERVAL MONTH) TO PUBLIC;
+create window median(val TINYINT) returns TINYINT
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(TINYINT) TO PUBLIC;
+create window median(val SMALLINT) returns SMALLINT
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(SMALLINT) TO PUBLIC;
+create window median(val INTEGER) returns INTEGER
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(INTEGER) TO PUBLIC;
+create window median(val BIGINT) returns BIGINT
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(BIGINT) TO PUBLIC;
+create window median(val DECIMAL) returns DECIMAL
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(DECIMAL) TO PUBLIC;
+create window median(val REAL) returns REAL
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(REAL) TO PUBLIC;
+create window median(val DOUBLE) returns DOUBLE
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(DOUBLE) TO PUBLIC;
+
+create window median(val DATE) returns DATE
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(DATE) TO PUBLIC;
+create window median(val TIME) returns TIME
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(TIME) TO PUBLIC;
+create window median(val TIMESTAMP) returns TIMESTAMP
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(TIMESTAMP) TO PUBLIC;
+create window median(val INTERVAL SECOND) returns INTERVAL SECOND
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(INTERVAL SECOND) TO PUBLIC;
+create window median(val INTERVAL MONTH) returns INTERVAL MONTH
+ external name "sql"."median";
+GRANT EXECUTE ON WINDOW median(INTERVAL MONTH) TO PUBLIC;
+
create aggregate quantile(val TINYINT, q DOUBLE) returns TINYINT
external name "aggr"."quantile";
GRANT EXECUTE ON AGGREGATE quantile(TINYINT, DOUBLE) TO PUBLIC;
diff --git a/sql/scripts/39_analytics_hge.sql b/sql/scripts/39_analytics_hge.sql
--- a/sql/scripts/39_analytics_hge.sql
+++ b/sql/scripts/39_analytics_hge.sql
@@ -35,6 +35,9 @@ GRANT EXECUTE ON WINDOW var_pop(HUGEINT)
create aggregate median(val HUGEINT) returns HUGEINT
external name "aggr"."median";
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list