Changeset: 2168721f39bf for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=2168721f39bf Modified Files: sql/backends/monet5/rel_bin.c sql/backends/monet5/sql_gencode.c sql/rel.txt sql/scripts/29_array.sql sql/server/rel_select.c Branch: sciql Log Message:
Changed the array_slice function into a (new type of) filter function. The array_slice function is a general implementation of array slicing, which is now used when one slicing range contains an explicit step size. The array_slice function is now implemented as a filter function, so that cheap leftfetchjoin can be used to filter out the selected cells, i.s.o. expensive joins in the old code. However, the implementation is a bit hacky, because the array_slice filter has different properties than the normal filters, namely, it doesn't have a single value at the left/right sides for the comparison, but takes a list of dimension/slicing ranges to compute the values that should be filtered out. The hacks are documented in the code. diffs (161 lines): diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c --- a/sql/backends/monet5/rel_bin.c +++ b/sql/backends/monet5/rel_bin.c @@ -640,8 +640,24 @@ exp_bin(mvc *sql, sql_exp *e, stmt *left return j; } ops = sa_list(sql->sa); - append(ops, r); - append(ops, r2); + if (list_length(e->r) > 2) { + /* NB: this is a HACK to make the array_slice filter work. + * Unlike the normal filters, the array_slice doesn't have + * right-side comparison value. + * Instead, it has a list of dimension and slicing ranges, + * contained in e->r, that need to be passed to the filter + * function. + * Here we create a stmt for each of them and add it to the ops + * list. + */ + node *n; + for (n = ((list*)e->r)->h; n; n = n->next) { + append(ops, exp_bin(sql, n->data, NULL, NULL, NULL, NULL, NULL, NULL)); + } + } else { /* the normal/original filter case */ + append(ops, r); + append(ops, r2); + } r = stmt_list(sql->sa, ops); s = stmt_genselect(sql->sa, l, r, e->f, sel); if (s && is_anti(e)) diff --git a/sql/backends/monet5/sql_gencode.c b/sql/backends/monet5/sql_gencode.c --- a/sql/backends/monet5/sql_gencode.c +++ b/sql/backends/monet5/sql_gencode.c @@ -1126,23 +1126,37 @@ _dumpstmt(backend *sql, MalBlkPtr mb, st if (get_cmp(s) == cmp_filter) { node *n; char *mod, *fimp; + int isArraySlice = 0; if (backend_create_func(sql, s->op4.funcval->func) < 0) return -1; mod = sql_func_mod(s->op4.funcval->func); fimp = sql_func_imp(s->op4.funcval->func); + isArraySlice = (strcmp(mod, "array") == 0 && strcmp(fimp, "slice") == 0); q = newStmt(mb, mod, convertOperator(fimp)); - q = pushArgument(mb, q, l); - if (sub > 0) - q = pushArgument(mb, q, sub); + /* NB: this is a HACK to make the array_slice filter work. + * The array_slice function computes the selected OIDs only + * based on its scalar parameters. + * It doens't need a left-side column 'l', nor does it + * use/reduce any previous results 'sub'. + */ + if (!isArraySlice) { + q = pushArgument(mb, q, l); + if (sub > 0) + q = pushArgument(mb, q, sub); + } for (n = s->op2->op4.lval->h; n; n = n->next) { stmt *op = n->data; q = pushArgument(mb, q, op->nr); } - q = pushBit(mb, q, anti); + /* We don't have any 'anti' comparison in array slicing + * (yet). */ + if (!isArraySlice) { + q = pushBit(mb, q, anti); + } s->nr = getDestVar(q); break; } diff --git a/sql/rel.txt b/sql/rel.txt --- a/sql/rel.txt +++ b/sql/rel.txt @@ -99,8 +99,11 @@ e_convert -> r list of from and to subtypes e_cmp - -> l left sub expression - -> r right sub expression (f second arg for range expressions) + -> l left sub expression, or + the to be filtered dimension in case of an array slcing + -> r right sub expression (f second arg for range expressions), or + the (>= 6) parameters to the array_slice filter function in case of an array slicing + -> f the compare/filter function -> flag compare type ( cmp_gt = 0, cmp_gte = 1, 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,7 +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; +create filter function array_slice(dim1_strt bigint, dim1_step bigint, dim1_stop bigint, slice1_strt bigint, slice1_step bigint, slice1_stop bigint) external name "array".slice; +create filter 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) external name "array".slice; +create filter 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) 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 @@ -732,10 +732,10 @@ rel_arrayslice(mvc *sql, sql_table *t, c } } } else { - list *slc_args = new_exp_list(sql->sa), *dims = new_exp_list(sql->sa); + list *slc_args = new_exp_list(sql->sa), *cols = new_exp_list(sql->sa); sql_subtype *lng_tpe = sql_bind_localtype("lng"); - if (slc_args == NULL || dims == NULL) + if (slc_args == NULL || cols == NULL) return sql_error(sql, 02, "ARRAY SLICE: failed to allocate space"); for (cn = t->columns.set->h, idx_exp = dimref->data.lval->h->next->data.lval->h; @@ -749,6 +749,8 @@ rel_arrayslice(mvc *sql, sql_table *t, c col = (sql_column *) cn->data; while(!col->dim) { /* skip the non-dimensional attributes in the table columns */ + append(cols, exp_column(sql->sa, tname, col->base.name, &col->type, CARD_MULTI, 0, 0, NULL)); + cn = cn->next; col = (sql_column*)cn->data; } @@ -801,16 +803,21 @@ rel_arrayslice(mvc *sql, sql_table *t, c append(srng_exps, exp_copy(sql->sa, slc_stop)); if (!(ce = _slicing2basetable(sql, rel, tname, col->base.name, srng_exps))) return NULL; - append(dims, exp_column(sql->sa, tname, col->base.name, &col->type, CARD_MULTI, 0, 0, ce->f)); - } - - sf = sql_bind_func_(sql->sa, mvc_bind_schema(sql, "sys"), "array_slice", exps_subtype(slc_args), F_FUNC); + append(cols, exp_column(sql->sa, tname, col->base.name, &col->type, CARD_MULTI, 0, 0, ce->f)); + } + + sf = sql_bind_func_(sql->sa, mvc_bind_schema(sql, "sys"), "array_slice", exps_subtype(slc_args), F_FILT); if (!sf) return sql_error(sql, 02, "failed to bind to the SQL function \"array_slice\""); - /* add the array.slicing op to the rel_select to select the slicing candidates */ - rel_select_add_exp(rel, exp_op(sql->sa, slc_args, sf)); - /* then project the selection on all dimensions */ - rel = rel_project(sql->sa, rel, dims); + + /* apply our array_slice filter function on all columns of the sliced array */ + for (cn = cols->h; cn; cn = cn->next) { + /* give the to be sliced column cn->data as the left side exp of + * the filter exp, the function args slc_args as the right side exp + * of the filter exp */ + ce = exp_filter(sql->sa, cn->data, slc_args, sf, 0); + rel = rel_push_select(sql->sa, rel, cn->data, ce); + } } return rel; } _______________________________________________ checkin-list mailing list checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list