Changeset: 3fd382ea80f4 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3fd382ea80f4
Modified Files:
        monetdb5/modules/mal/array.mx
        sql/scripts/29_array.sql
        sql/server/rel_select.c
Branch: sciql
Log Message:

Step 1/2 of fixing array slicing (with explicit step size)

Translate such array slicing into the new relation plan:

rel_project(
        rel_select(rel, array_slice()),
        dim1[, dim2, dim3])


diffs (truncated from 400 to 300 lines):

diff --git a/monetdb5/modules/mal/array.mx b/monetdb5/modules/mal/array.mx
--- a/monetdb5/modules/mal/array.mx
+++ b/monetdb5/modules/mal/array.mx
@@ -74,6 +74,10 @@ function filler_(cnt:lng, v:any_1)(id:ba
        return (b4,b2);
 end filler_;
 
+pattern slice(dim_strt:lng, dim_step:lng, dim_stop:lng, slc_strt:lng, 
slc_step:lng, slc_stop:lng...):bat[:oid,:oid]
+address ARRAYslice
+comment "Compute the OIDs of all cells selected by an array slicing"
+
 @= tilesAggrDecl
 module array;
 
@@ -162,6 +166,8 @@ comment "Construct the count over all ti
 array_export str ARRAYfiller_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr p);
 array_export str ARRAYfiller(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr p);
 
+array_export str ARRAYslice(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr p);
+
 @= array_defs
 array_export str ARRAYseries_@1(int *ret, @1 *start, @1 *step, @1 *stop, int 
*grp, int *series);
 array_export str ARRAYtilesSum_@1(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
@@ -292,6 +298,17 @@ ARRAYfiller_bat(Client cntxt, MalBlkPtr 
 }
 
 str
+ARRAYslice(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
+{
+       (void) cntxt;
+       (void) mb;
+       (void) stk;
+       (void) pci;
+
+       return MAL_SUCCEED;
+}
+
+str
 ARRAYfiller(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
 {
        BAT *bn;
diff --git a/sql/scripts/29_array.sql b/sql/scripts/29_array.sql
--- a/sql/scripts/29_array.sql
+++ b/sql/scripts/29_array.sql
@@ -155,3 +155,7 @@ create function array_count(val bigint, 
 create function array_count(val real,     dim1 int, offsets1 int, size1 int, 
dim2 int, offsets2 int, size2 int, dim3 int, offsets3 int, size3 int) returns 
bigint external name "array".cnt;
 create function array_count(val double,   dim1 int, offsets1 int, size1 int, 
dim2 int, offsets2 int, size2 int, dim3 int, offsets3 int, size3 int) returns 
bigint external name "array".cnt;
 
+create function array_slice(dim1_strt bigint, dim1_step bigint, dim1_stop 
bigint, slice1_strt bigint, slice1_step bigint, slice1_stop bigint) returns oid 
external name "array".slice;
+create function array_slice(dim1_strt bigint, dim1_step bigint, dim1_stop 
bigint, slice1_strt bigint, slice1_step bigint, slice1_stop bigint, dim2_strt 
bigint, dim2_step bigint, dim2_stop bigint, slice2_strt bigint, slice2_step 
bigint, slice2_stop bigint) returns oid external name "array".slice;
+create function array_slice(dim1_strt bigint, dim1_step bigint, dim1_stop 
bigint, slice1_strt bigint, slice1_step bigint, slice1_stop bigint, dim2_strt 
bigint, dim2_step bigint, dim2_stop bigint, slice2_strt bigint, slice2_step 
bigint, slice2_stop bigint, dim3_strt bigint, dim3_step bigint, dim3_stop 
bigint, slice3_strt bigint, slice3_step bigint, slice3_stop bigint) returns oid 
external name "array".slice;
+
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
@@ -616,160 +616,202 @@ 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 *ro = NULL, *ro2 = NULL, *slc_val = NULL, *exp = NULL, *ce = 
NULL;
+       sql_exp *ce = NULL;
        sql_column *col = NULL;
        sql_subfunc *sf = NULL;
        exp_kind ek = {type_value, card_value, FALSE};
+       int realSlice = 0;
 
        assert(dimref->token == SQL_ARRAY_DIM_SLICE);
 
        if (!t->valence)
-               return sql_error(sql, 02, "array slicing over a table ('%s')not 
allowed", t->base.name);
-
-       /* Handling array slicing using normal SQL: WHERE <pred_exp> IN '(' 
<value_commalist> ')'.
-        * Loop over all table columns and sliced columns.  Translate each 
slicing
-        * <start>:<step>:<stop> into:
-        *     <column name> in '(' array_series(start, step, stop, 1, 1) ')'
-        */
-       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),
-                        *srng_exps = new_exp_list(sql->sa);
-               sql_exp *col_strt = NULL, *col_step = NULL, *col_stop = NULL;
-               int skip = 1;
-
-               if (args == NULL || srng_exps == NULL)
+               return sql_error(sql, 02, "array slicing over a table 
('%s.%s')not allowed", t->s->base.name, t->base.name);
+       if (dlist_length(dimref->data.lval->h->next->data.lval) > t->valence)
+               return sql_error(sql, 02, "array slicing over too many 
dimensions");
+
+       /* For comparing the performance of array.slice and range selection */
+       for (idx_exp = dimref->data.lval->h->next->data.lval->h; idx_exp; 
idx_exp = idx_exp->next) {
+               if (dlist_length(idx_exp->data.lval) == 3) 
+                       realSlice = 1;
+       }
+       if (realSlice && t->valence > 3)
+               return sql_error(sql, 02, "array slicing with step size over 
arrays with more than three dimensions not supported yet");
+
+       /* If none of the slicing ranges has a step size, translate the slicing 
into [range|point] selections */
+       if (!realSlice) {
+               sql_exp *ro = NULL, *ro2 = NULL, *exp = NULL;
+               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 *srng_exps = new_exp_list(sql->sa);
+                       sql_exp *dim_strt = NULL, *dim_step = NULL, *dim_stop = 
NULL;
+                       int skip = 1;
+
+                       if (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 */
+                               cn = cn->next;
+                               col = (sql_column*)cn->data;
+                       }
+
+                       /* In case of '[*]', '[*:*]' or '[*:*:*]', don't slice 
this column */
+                       for (idx_term = idx_exp->data.lval->h; idx_term; 
idx_term = idx_term->next)
+                               if (idx_term->data.sym) skip = 0;
+                       if (skip) continue;
+
+                       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");
+
+                       dim_strt = rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->strt), type_cast);
+                       dim_step = rel_check_type(sql, &col->type, 
exp_atom_lng(sql->sa, col->dim->step), type_cast);
+                       dim_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 (dlist_length(idx_exp->data.lval) == 1) {
+                               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, dim_step); /* sliced step == 
original step */
+                               append(srng_exps, exp_binop( /* sliced stop = 
sliced start + original step */
+                                                       sql->sa, 
exp_copy(sql->sa, ro), exp_copy(sql->sa, dim_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;
+                               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 { /* dlist_length(idx_exp->data.lval) == 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) :
+                                       dim_strt;
+                               append(srng_exps, ro);
+
+                               /* sliced step == original step */
+                               append(srng_exps, dim_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) :
+                                       dim_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);
+
+                               if (col->dim->step > 0) {
+                                       /* [<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 { /* col->dim->step < 0 */
+                                       /* [<ro>:<ro2>]: <ro> '>=' <(column) 
exp> '>' <ro2> */
+                                       rel = rel_compare_exp_(sql, rel, exp, 
ro,  NULL, cmp_lte, 0);
+                                       if (rel == NULL)
+                                               return NULL;
+                                       rel = rel_compare_exp_(sql, rel, exp, 
ro2, NULL, cmp_gt,  0);
+                                       if (rel == NULL)
+                                               return NULL;
+                               }
+                       }
+               }
+       } else {
+               list *slc_args = new_exp_list(sql->sa), *dims = 
new_exp_list(sql->sa);
+               sql_subtype *lng_tpe = sql_bind_localtype("lng");
+
+               if (slc_args == NULL || dims == 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 */
-                       cn = cn->next;
-                       col = (sql_column*)cn->data;
-               }
-
-               /* In case of '[*]', '[*:*]' or '[*:*:*]', don't slice this 
column */
-               for (idx_term = idx_exp->data.lval->h; idx_term; idx_term = 
idx_term->next)
-                       if (idx_term->data.sym) skip = 0;
-               if (skip) continue;
-
-               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) {
-                       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, ro), 
exp_copy(sql->sa, col_step),
-                                               sql_bind_func(sql->sa, 
sql->session->schema, "sql_add", &col->type, &col->type, F_FUNC)));
-
+               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 *srng_exps = new_exp_list(sql->sa);
+                       sql_exp *dim_strt = NULL, *dim_step = NULL, *dim_stop = 
NULL,
+                                       *slc_strt = NULL, *slc_step = NULL, 
*slc_stop = NULL;
+
+                       if (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 */
+                               cn = cn->next;
+                               col = (sql_column*)cn->data;
+                       }
+
+                       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");
+
+                       /* If the value of start/step/stop is omitted, we get 
its value from the dimension definition. */
+                       dim_strt = exp_atom_lng(sql->sa, col->dim->strt);
+                       dim_step = exp_atom_lng(sql->sa, col->dim->step);
+                       dim_stop = exp_atom_lng(sql->sa, col->dim->stop);
+
+                       /* The first idx_term is alreays the start */
+                       idx_term = idx_exp->data.lval->h;
+                       slc_strt = (idx_term->data.sym != NULL)?
+                               /* [<idx_term>], [<idx_term>:???], 
[<idx_term>:???:???] */
+                               rel_check_type(sql, lng_tpe, rel_value_exp(sql, 
&rel, idx_term->data.sym, sql_where, ek), type_cast):
+                               /* ['*'], ['*':???], ['*':???:???] */
+                               exp_copy(sql->sa, dim_strt); /* sliced start == 
original start */
+
+                       /* a slicing step is given explicitly, IFF there are 
three idx_terms and the second is not NULL */
+                       idx_term = idx_term->next;
+                       slc_step = (dlist_length(idx_exp->data.lval) == 3 && 
idx_term->data.sym != NULL)?
+                               /* [???:<idx_term>:???] */
+                               rel_check_type(sql, lng_tpe, rel_value_exp(sql, 
&rel, idx_term->data.sym, sql_where, ek), type_cast):
+                               /* [???], [???:???], [???:'*':???] */
+                               exp_copy(sql->sa, dim_step); /* sliced step == 
original step */
+
+                       /* the last idx_term, if exists, is always the slicing 
stop */
+                       idx_term = (dlist_length(idx_exp->data.lval) == 3)? 
idx_term->next : idx_term;
+                       slc_stop = (idx_term != NULL && idx_term->data.sym != 
NULL)?
+                               /* [???:<idx_term>],[???:???:<idx_term>] */
+                               rel_check_type(sql, lng_tpe, rel_value_exp(sql, 
&rel, idx_term->data.sym, sql_where, ek), type_cast):
+                               (idx_term == NULL && 
idx_exp->data.lval->h->data.sym != NULL)?
+                                       /* [<idx_term>] */
+                                       exp_binop( /* sliced stop = sliced 
start + original step */
+                                                       sql->sa, 
exp_copy(sql->sa, slc_strt), exp_copy(sql->sa, dim_step),
+                                                       sql_bind_func(sql->sa, 
sql->session->schema, "sql_add", lng_tpe, lng_tpe, F_FUNC)):
+                                       /* ['*'], [???:'*'], [???:???:'*'] */
+                                       exp_copy(sql->sa, dim_stop); /* sliced 
stop == original stop */
+
+                       append(slc_args, dim_strt);
+                       append(slc_args, dim_step);
+                       append(slc_args, dim_stop);
+                       append(slc_args, slc_strt);
+                       append(slc_args, slc_step);
+                       append(slc_args, slc_stop);
+                       append(srng_exps, exp_copy(sql->sa, slc_strt));
+                       append(srng_exps, exp_copy(sql->sa, slc_step));
+                       append(srng_exps, exp_copy(sql->sa, slc_stop));
                        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>]: <(column) exp> '=' <ro> */
-                       rel = rel_compare_exp_(sql, rel, exp, ro, NULL, 
cmp_equal, 0);
-                       if (rel == NULL)
-                               return NULL;
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
http://mail.monetdb.org/mailman/listinfo/checkin-list

Reply via email to