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