Changeset: ad9f722f533a for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=ad9f722f533a
Modified Files:
        sql/server/rel_select.c
Branch: sciql
Log Message:

improved relational plan generation for array slicing

instead of always generate a sliced candidate list using array.series, which is
then joined with the base column, we now translate slicing with [<range_term>]
into an equal selection, and slicing with [<range_term> : <range_term>] into a
range selection.


diffs (185 lines):

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
@@ -44,6 +44,9 @@
          list_length(((list*)((sql_exp*)(e))->f)->h->next->next->data) )
 
 
+static sql_rel *
+rel_compare_exp_(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp *rs, sql_exp 
*rs2, int type, int anti );
+
 sql_rel *
 rel_dup(sql_rel *r)
 {
@@ -613,7 +616,7 @@ rel_arrayslice(mvc *sql, sql_table *t, c
        dnode *idx_exp = NULL, *idx_term = NULL;
        /* initial a new rel_select with selection expressions to be added 
later*/
        sql_rel *rel = rel_select(sql->sa, rel_basetable(sql, t, tname), NULL);
-       sql_exp *slc_val = NULL, *exp = NULL, *ce = NULL;
+       sql_exp *ro = NULL, *ro2 = NULL, *slc_val = NULL, *exp = NULL, *ce = 
NULL;
        sql_column *col = NULL;
        sql_subfunc *sf = NULL;
        exp_kind ek = {type_value, card_value, FALSE};
@@ -631,11 +634,12 @@ rel_arrayslice(mvc *sql, sql_table *t, c
        for (cn = t->columns.set->h, idx_exp = 
dimref->data.lval->h->next->data.lval->h;
                        cn && idx_exp; cn = cn->next, idx_exp = idx_exp->next) {
                list *args = new_exp_list(sql->sa),
-                        *rng_exps = new_exp_list(sql->sa),
                         *srng_exps = new_exp_list(sql->sa);
+               sql_exp *col_strt = NULL, *col_step = NULL, *col_stop = NULL;
                int skip = 1;
 
-               assert(args != NULL && rng_exps != NULL && srng_exps != NULL);
+               if (args == NULL || srng_exps == NULL)
+                       return sql_error(sql, 02, "ARRAY SLICE: failed to 
allocate space");
 
                col = (sql_column *) cn->data;
                while(!col->dim) { /* skip the non-dimensional attributes in 
the table columns */
@@ -648,56 +652,92 @@ rel_arrayslice(mvc *sql, sql_table *t, c
                        if (idx_term->data.sym) skip = 0;
                if (skip) continue;
 
-               append(rng_exps, rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->strt), type_cast));
-               append(rng_exps, rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->step), type_cast));
-               append(rng_exps, rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->stop), type_cast));
-
-               /* build the slc_val expression, which is going to compute a 
list of to be sliced dimensional values. */
-               /* FIXME: some expressions of rng_exps and the slc_val are 
reused, because exp_column makes a complete copy of its input drngs? */
+               if (col->dim->strt == lng_nil || col->dim->step == lng_nil || 
col->dim->stop == lng_nil)
+                       return sql_error(sql, 02, "TODO: slicing over unbounded 
dimension");
+
+               col_strt = rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->strt), type_cast);
+               col_step = rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->step), type_cast);
+               col_stop = rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->stop), type_cast);
+
+               /* Translate a slice expression into:
+                *   a equal comparison, if the slicing expression is '[' 
range_term ']'; or
+                *   a range selection,  if the slicing expression is '[' 
range_term ':' range_term ']'; or
+                *   a join between the sliced column and the list of to be 
sliced dimensional values in slc_val,
+                *                       if the slicing expression is '[' 
range_term ':' range_term ':' range_term ']'.
+                */
+               /* If the value of start/step/stop is omitted, we get its value 
from the dimension definition. */
                idx_term = idx_exp->data.lval->h;
                if (idx_exp->data.lval->cnt == 1) {
-                       slc_val = rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast);
-                       append(srng_exps, slc_val); /* sliced start */
-                       append(srng_exps, rng_exps->h->next->data); /* sliced 
step == original step */
+                       ro = rel_check_type(sql, &col->type, rel_value_exp(sql, 
&rel, idx_term->data.sym, sql_where, ek), type_cast);
+                       append(srng_exps, ro); /* sliced start */
+                       append(srng_exps, col_step); /* sliced step == original 
step */
                        append(srng_exps, exp_binop( /* sliced stop = sliced 
start + original step */
-                                               sql->sa, exp_copy(sql->sa, 
slc_val), exp_copy(sql->sa, rng_exps->h->next->data),
+                                               sql->sa, exp_copy(sql->sa, ro), 
exp_copy(sql->sa, col_step),
                                                sql_bind_func(sql->sa, 
sql->session->schema, "sql_add", &col->type, &col->type, F_FUNC)));
+
                        if (!(ce = _slicing2basetable(sql, rel, tname, 
col->base.name, srng_exps)))
                                return NULL;
-               } else {
-                       /* If the value of start/step/stop is omitted, we get 
its value from the dimension definition.
-                        */
-                       if (col->dim->strt == lng_nil || col->dim->step == 
lng_nil || col->dim->stop == lng_nil)
-                               return sql_error(sql, 02, "TODO: slicing over 
unbounded dimension");
-
-                       /* the first <exp> is always the start */
+                       exp = exp_column(sql->sa, tname, col->base.name, 
&col->type, CARD_MULTI, 0, 0, ce->f);
+
+                       /* [<ro>]: <(column) exp> '=' <ro> */
+                       rel = rel_compare_exp_(sql, rel, exp, ro, NULL, 
cmp_equal, 0);
+                       if (rel == NULL)
+                               return NULL;
+               } else if (idx_exp->data.lval->cnt == 2) {
+                       /* sliced start */
+                       ro = idx_term->data.sym ? /* check for '*' */
+                                       rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
+                                       col_strt;
+                       append(srng_exps, ro);
+
+                       /* sliced step == original step */
+                       append(srng_exps, col_step);
+
+                       /* sliced stop */
+                       idx_term = idx_term->next;
+                       ro2 = idx_term->data.sym ?
+                                       rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
+                                       col_stop;
+                       append(srng_exps, ro2);
+
+                       if (!(ce = _slicing2basetable(sql, rel, tname, 
col->base.name, srng_exps)))
+                               return NULL;
+                       exp = exp_column(sql->sa, tname, col->base.name, 
&col->type, CARD_MULTI, 0, 0, ce->f);
+
+                       /* [<ro>:<ro2>]: <ro> '<=' <(column) exp> '<' <ro2> */
+                       rel = rel_compare_exp_(sql, rel, exp, ro,  NULL, 
cmp_gte, 0);
+                       if (rel == NULL)
+                               return NULL;
+                       rel = rel_compare_exp_(sql, rel, exp, ro2, NULL, 
cmp_lt,  0);
+                       if (rel == NULL)
+                               return NULL;
+               } else { /* idx_exp->data.lval->cnt == 3 */
+                       /* sliced start */
                        slc_val = idx_term->data.sym ? /* check for '*' */
-                                       rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
-                                       rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->strt), type_cast);
+                               rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
+                               col_strt;
                        append(args, slc_val);
                        append(srng_exps, slc_val);
 
-                       if (idx_exp->data.lval->cnt == 2) {
-                               slc_val = rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->step), type_cast);
-                               append(args, slc_val);
-                               append(srng_exps, slc_val);
-                       } else {
-                               idx_term = idx_term->next;
-                               slc_val = idx_term->data.sym ?
-                                       rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
-                                       rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->step), type_cast);
-                               append(args, slc_val);
-                               append(srng_exps, slc_val);
-                       }
-
+                       /* sliced step */
                        idx_term = idx_term->next;
                        slc_val = idx_term->data.sym ?
-                                       rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
-                                       rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->stop), type_cast);
+                               rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
+                               col_step;
                        append(args, slc_val);
                        append(srng_exps, slc_val);
+
+                       /* sliced stop */
+                       idx_term = idx_term->next;
+                       slc_val = idx_term->data.sym ?
+                               rel_check_type(sql, &col->type, 
rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) :
+                               col_stop;
+                       append(args, slc_val);
+                       append(srng_exps, slc_val);
+
                        if (!(ce = _slicing2basetable(sql, rel, tname, 
col->base.name, srng_exps)))
                                return NULL;
+                       exp = exp_column(sql->sa, tname, col->base.name, 
&col->type, CARD_MULTI, 0, 0, ce->f);
 
                        /* Only create 1 group and repeat the numbers once */
                        append(args, exp_atom_int(sql->sa, 1));
@@ -706,13 +746,14 @@ rel_arrayslice(mvc *sql, sql_table *t, c
                        if (!sf)
                                return sql_error(sql, 02, "failed to bind to 
the SQL function \"array_series1\"");
                        slc_val = exp_op(sql->sa, args, sf);
+                       /* <(column) exp> IN '(' <slc_val> ')' */
+                       exp_label(sql->sa, slc_val, ++sql->label);
+                       exp = exp_in(sql->sa, exp, 
append(new_exp_list(sql->sa), slc_val), cmp_in);
+                       rel_select_add_exp(rel, exp);
+                       /* TODO: if the sliced step can be detected to be the 
same as this
+                        *      column's step, translate this slice into a 
range selection instead
+                        */
                }
-
-               /* <(column) exp> IN '(' <slc_val> ')' */
-               exp = exp_column(sql->sa, tname, col->base.name, &col->type, 
CARD_MULTI, 0, 0, ce->f);
-               exp_label(sql->sa, slc_val, ++sql->label);
-               exp = exp_in(sql->sa, exp, append(new_exp_list(sql->sa), 
slc_val), cmp_in);
-               rel_select_add_exp(rel, exp);
        }
        
        /* the number of sliced dimensions must be smaller than or equal to the 
number of dimensions */
_______________________________________________
checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list

Reply via email to