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

Reply via email to