Changeset: f2fcaac8069c for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=f2fcaac8069c
Modified Files:
sql/server/rel_statistics.c
Branch: properties
Log Message:
Propagating some min/max values, but still a lot to be done
diffs (truncated from 423 to 300 lines):
diff --git a/sql/server/rel_statistics.c b/sql/server/rel_statistics.c
--- a/sql/server/rel_statistics.c
+++ b/sql/server/rel_statistics.c
@@ -16,6 +16,228 @@
#include "rel_rewriter.h"
#include "sql_mvc.h"
+static bool
+exps_have_or(list *exps)
+{
+ for (node *n = exps->h ; n ; n = n->next) {
+ sql_exp *e = n->data;
+ assert(e->type == e_cmp);
+ if (e->flag == cmp_or)
+ return true;
+ }
+ return false;
+}
+
+static inline void
+set_max_of_values(mvc *sql, sql_exp *e, rel_prop kind, ValPtr lval, ValPtr
rval)
+{
+ prop *p;
+ ValRecord res;
+
+ VARcalcgt(&res, lval, rval);
+ p = e->p = prop_create(sql->sa, kind, e->p);
+ p->value = res.val.btval == 1 ? lval : rval;
+}
+
+static inline void
+set_min_of_values(mvc *sql, sql_exp *e, rel_prop kind, ValPtr lval, ValPtr
rval)
+{
+ prop *p;
+ ValRecord res;
+
+ VARcalcgt(&res, lval, rval);
+ p = e->p = prop_create(sql->sa, kind, e->p);
+ p->value = res.val.btval == 1 ? rval : lval;
+}
+
+static inline void
+copy_property(mvc *sql, sql_exp *e, rel_prop kind, ValPtr val)
+{
+ prop *p = e->p = prop_create(sql->sa, kind, e->p);
+ p->value = val;
+}
+
+static sql_exp *
+comparison_find_column(sql_exp *input, sql_exp *e)
+{
+ switch (input->type) {
+ case e_convert: /* if the conversion is for a different SQL
class, the min and max cannot be converted */
+ if (((sql_subtype*)exp_fromtype(input))->type->eclass
== ((sql_subtype*)exp_totype(input))->type->eclass)
+ return comparison_find_column(input->l, e);
+ return NULL;
+ case e_column:
+ return exp_match(e, input) ? input : NULL;
+ default:
+ return NULL;
+ }
+}
+
+static sql_exp *
+rel_propagate_column_ref_statistics(mvc *sql, sql_rel *rel, sql_exp *e)
+{
+ ValPtr lval, rval;
+ sql_exp *ne = NULL;
+
+ assert(e->type == e_column);
+ if (rel) {
+ switch(rel->op) {
+ case op_left:
+ case op_right:
+ case op_full:
+ case op_join:
+ case op_select:
+ /* case op_anti: later */
+ case op_semi: {
+ if (!list_empty(rel->exps) && !exps_have_or(rel->exps))
{ /* if there's an or, the MIN and MAX get difficult to propagate */
+ for (node *n = rel->exps->h ; n && !ne; n =
n->next) {
+ sql_exp *comp = n->data;
+
+ switch (comp->flag) {
+ case cmp_equal: {
+ sql_exp *le = comp->l, *re =
comp->r, *rne = NULL;
+
+ if ((ne =
comparison_find_column(le, e)) || (rne = comparison_find_column(re, e))) {
+ if
(is_outerjoin(rel->op)) {
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, lval);
+ } else {
+ if ((lval =
find_prop_and_get(le->p, PROP_MAX)) && (rval = find_prop_and_get(re->p,
PROP_MAX)))
+
set_min_of_values(sql, e, PROP_MAX, lval, rval); /* for equality reduce */
+ if ((lval =
find_prop_and_get(le->p, PROP_MIN)) && (rval = find_prop_and_get(re->p,
PROP_MIN)))
+
set_max_of_values(sql, e, PROP_MIN, lval, rval);
+ }
+ }
+ ne = ne ? ne : rne;
+ } break;
+ case cmp_notequal: {
+ sql_exp *le = comp->l, *re =
comp->r, *rne = NULL;
+
+ if ((ne =
comparison_find_column(le, e)) || (rne = comparison_find_column(re, e))) {
+ if
(is_outerjoin(rel->op)) {
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, lval);
+ } else {
+ if ((lval =
find_prop_and_get(le->p, PROP_MAX)) && (rval = find_prop_and_get(re->p,
PROP_MAX)))
+
set_max_of_values(sql, e, PROP_MAX, lval, rval); /* for inequality expand */
+ if ((lval =
find_prop_and_get(le->p, PROP_MIN)) && (rval = find_prop_and_get(re->p,
PROP_MIN)))
+
set_min_of_values(sql, e, PROP_MIN, lval, rval);
+ }
+ }
+ ne = ne ? ne : rne;
+ } break;
+ case cmp_gt:
+ case cmp_gte: {
+ sql_exp *le = comp->l, *re =
comp->r, *rne = NULL;
+
+ assert(!comp->f);
+ if ((ne =
comparison_find_column(le, e)) || (rne = comparison_find_column(re, e))) {
+ if
(is_outerjoin(rel->op)) {
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, lval);
+ } else if (ne) {
+ if ((lval =
find_prop_and_get(le->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((rval =
find_prop_and_get(re->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MIN, rval);
+ } else {
+ if ((lval =
find_prop_and_get(le->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((rval =
find_prop_and_get(re->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, rval);
+ }
+ }
+ ne = ne ? ne : rne;
+ } break;
+ case cmp_lt:
+ case cmp_lte: {
+ sql_exp *le = comp->l, *re =
comp->r, *fe = comp->f, *rne = NULL, *fne = NULL;
+
+ if ((ne =
comparison_find_column(le, e)) || (rne = comparison_find_column(re, e)) || (fe
&& (fne = comparison_find_column(fe, e)))) {
+ if
(is_outerjoin(rel->op)) {
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne ? rne->p : fne->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((lval =
find_prop_and_get(ne ? ne->p : rne ? rne->p : fne->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, lval);
+ } else if (ne) {
+ if (fe) { /*
range case */
+ if
((lval = find_prop_and_get(fe->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if
((rval = find_prop_and_get(re->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MIN, rval);
+ } else {
+ if
((lval = find_prop_and_get(re->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if
((rval = find_prop_and_get(le->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, rval);
+ }
+ } else if (rne) {
+ if (fe) { /*
range case */
+ if
((lval = find_prop_and_get(re->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if
((rval = find_prop_and_get(le->p, PROP_MIN)))
+
copy_property(sql, e, PROP_MIN, rval);
+ } else {
+ if
((lval = find_prop_and_get(re->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if
((rval = find_prop_and_get(le->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MIN, rval);
+ }
+ } else { /* range case
*/
+ if ((lval =
find_prop_and_get(fe->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MAX, lval);
+ if ((rval =
find_prop_and_get(le->p, PROP_MAX)))
+
copy_property(sql, e, PROP_MIN, rval);
+ }
+ }
+ ne = ne ? ne : rne ? rne : fne;
+ } break;
+ default: /* Maybe later I can do cmp_in
and cmp_notin */
+ break;
+ }
+ }
+ }
+ if (ne && !find_prop(e->p, PROP_MAX) &&
!find_prop(e->p, PROP_MIN)) /* ne was found, but the properties could not be
propagated */
+ ne = NULL;
+ if (!ne)
+ ne = rel_propagate_column_ref_statistics(sql,
rel->l, e);
+ if (!ne && is_join(rel->op))
+ ne = rel_propagate_column_ref_statistics(sql,
rel->r, e);
+ } break;
+ /* case op_table: later */
+ case op_basetable: {
+ if (e->l && (ne = exps_bind_column2(rel->exps, e->l,
e->r, NULL))) {
+ if ((lval = find_prop_and_get(ne->p, PROP_MAX)))
+ copy_property(sql, e, PROP_MAX, lval);
+ if ((lval = find_prop_and_get(ne->p, PROP_MIN)))
+ copy_property(sql, e, PROP_MIN, lval);
+ }
+ } break;
+ case op_union:
+ case op_except:
+ case op_inter:
+ case op_project:
+ case op_groupby: {
+ ne = e->l ? exps_bind_column2(rel->exps, e->l, e->r,
NULL) : exps_bind_column(rel->exps, e->r, NULL, NULL, 1);
+ if (ne) {
+ if ((lval = find_prop_and_get(ne->p, PROP_MAX)))
+ copy_property(sql, e, PROP_MAX, lval);
+ if ((lval = find_prop_and_get(ne->p, PROP_MIN)))
+ copy_property(sql, e, PROP_MIN, lval);
+ }
+ } break;
+ default: /* if there is a topN or sample relation in between,
then the MIN and MAX values are lost */
+ break;
+ }
+ }
+ return ne;
+}
+
static sql_exp *
rel_basetable_get_statistics(visitor *v, sql_rel *rel, sql_exp *e, int depth)
{
@@ -29,42 +251,174 @@ rel_basetable_get_statistics(visitor *v,
if (has_nil(e) && mvc_has_no_nil(sql, c))
set_has_no_nil(e);
+ if ((max = mvc_has_max_value(sql, c))) {
+ prop *p = e->p = prop_create(sql->sa, PROP_MAX, e->p);
+ p->value = max;
+ }
if ((min = mvc_has_min_value(sql, c))) {
prop *p = e->p = prop_create(sql->sa, PROP_MIN, e->p);
p->value = min;
}
- if ((max = mvc_has_max_value(sql, c))) {
- prop *p = e->p = prop_create(sql->sa, PROP_MAX, e->p);
- p->value = max;
+ }
+ return e;
+}
+
+static void
+rel_set_get_statistics(mvc *sql, sql_rel *rel, sql_exp *e, int i)
+{
+ sql_exp *le = list_fetch(((sql_rel*)(rel->l))->exps, i);
+ sql_exp *re = list_fetch(((sql_rel*)(rel->r))->exps, i);
+ ValPtr lval, rval;
+
+ assert(le && e);
+ if ((lval = find_prop_and_get(le->p, PROP_MAX)) && (rval =
find_prop_and_get(re->p, PROP_MAX))) {
+ if (rel->op == op_union)
+ set_max_of_values(sql, e, PROP_MAX, lval, rval); /* for
union the new max will be the max of the two */
+ else if (rel->op == op_inter)
+ set_min_of_values(sql, e, PROP_MAX, lval, rval); /* for
intersect the new max will be the min of the two */
+ else
+ copy_property(sql, e, PROP_MAX, lval);
+ }
+ if ((lval = find_prop_and_get(le->p, PROP_MIN)) && (rval =
find_prop_and_get(re->p, PROP_MIN))) {
+ if (rel->op == op_union)
+ set_min_of_values(sql, e, PROP_MIN, lval, rval); /* for
union the new min will be the min of the two */
+ else if (rel->op == op_inter)
+ set_max_of_values(sql, e, PROP_MIN, lval, rval); /* for
intersect the new min will be the max of the two */
+ else
+ copy_property(sql, e, PROP_MIN, lval);
+ }
+}
+
+static sql_exp *
+rel_propagate_statistics(visitor *v, sql_rel *rel, sql_exp *e, int depth)
+{
+ mvc *sql = v->sql;
+ ValPtr lval;
+
+ (void) depth;
+ switch(e->type) {
+ case e_column: {
+ switch (rel->op) {
+ case op_join:
+ case op_left:
+ case op_right:
+ case op_full: {
+ sql_exp *found =
rel_propagate_column_ref_statistics(sql, rel->l, e);
+ if (!found)
+ (void) rel_propagate_column_ref_statistics(sql,
rel->r, e);
+ } break;
+ case op_semi:
+ case op_select:
+ case op_project:
+ case op_groupby:
+ (void) rel_propagate_column_ref_statistics(sql, rel->l,
e);
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list