Changeset: c1b8345795fe for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=c1b8345795fe Modified Files: sql/server/rel_select.c Branch: sciql Log Message:
we can now slice over arrays in the FROM clause. See sql/test/sciql/Tests/06_slice_01.sql for supported cases diffs (141 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 @@ -431,6 +431,97 @@ rel_copy( sql_allocator *sa, sql_rel *i return rel; } +static sql_rel * +rel_arrayslice(mvc *sql, sql_table *t, char *tname, symbol *dimref) +{ + node *cn = NULL; + dnode *idx_exp = NULL, *idx_term = NULL; + sql_rel *rel_tbl = rel_basetable(sql, t, tname), *rel = rel_basetable(sql, t, tname); + sql_exp *col_exp = NULL, *slc_val = NULL, *expin = NULL; + sql_column *col = NULL; + sql_subfunc *sf = NULL; + exp_kind ek = {type_value, card_value, FALSE}; + + assert(dimref->token == SQL_ARRAY_INDEX); + + if (t->ndims) + 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); + int skip = 1; + + 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; + + /* build the slc_val expression, which is going to compute a list of to be sliced dimensional values. */ + 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); + } else { + /* If the value of start/step/stop is omitted, we get its value from the dimension definition. + * TODO: deal with unbounded dimension */ + if (!col->dim->start || !col->dim->step || !col->dim->stop) + return sql_error(sql, 02, "slicing over unbounded dimension not supported"); + + /* the first <exp> is always the start */ + append(args, 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) : + exp_atom(sql->sa, atom_general(sql->sa, &col->type, col->dim->start))); + + + if(idx_exp->data.lval->cnt == 2) { + append(args, exp_atom(sql->sa, atom_general(sql->sa, &col->type, col->dim->step))); + } else { + idx_term = idx_term->next; + append(args, idx_term->data.sym ? + rel_check_type(sql, &col->type, rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) : + exp_atom(sql->sa, atom_general(sql->sa, &col->type, col->dim->step))); + } + + idx_term = idx_term->next; + append(args, idx_term->data.sym ? + rel_check_type(sql, &col->type, rel_value_exp(sql, &rel, idx_term->data.sym, sql_where, ek), type_cast) : + exp_atom(sql->sa, atom_general(sql->sa, &col->type, col->dim->stop))); + + /* Only create 1 group and repeat the numbers once */ + append(args, exp_atom_int(sql->sa, 1)); + append(args, exp_atom_int(sql->sa, 1)); + sf = sql_bind_func_(sql->sa, sql->session->schema, "array_series1", exps_subtype(args), F_FUNC); + if (!sf) + return sql_error(sql, 02, "failed to bind to the SQL function \"array_series\""); + slc_val = exp_op(sql->sa, args, sf); + } + + /* <col_exp> IN '(' <slc_val> ')' */ + col_exp = exp_column(sql->sa, t->base.name, col->base.name, &col->type, CARD_MULTI, 0, 0); + exp_label(sql->sa, slc_val, ++sql->label); + expin = exp_in(sql->sa, col_exp, append(new_exp_list(sql->sa), slc_val), cmp_in); + rel = rel_select(sql->sa, rel, expin); + } + + /* the number of sliced dimensions must be smaller than or equal to the number of dimensions */ + if (idx_exp) + return sql_error(sql, 02, "array slicing over too many columns"); + + rel->card = rel->card > exps_card(rel_tbl->exps) ? rel->card : exps_card(rel_tbl->exps); + return rel_project(sql->sa, rel, rel_tbl->exps); +} + sql_rel * _rel_basetable(sql_allocator *sa, sql_table *t, char *atname) { @@ -1538,11 +1629,11 @@ table_ref(mvc *sql, sql_rel *rel, symbol sql_table *t = NULL; (void)rel; - if (tableref->token == SQL_NAME) { + if (tableref->token == SQL_NAME || tableref->token == SQL_ARRAY) { sql_rel *temp_table = NULL; - char *sname = qname_schema(tableref->data.lval->h->data.lval); + char *sname = tableref->token == SQL_NAME ? qname_schema(tableref->data.lval->h->data.lval) : qname_schema(tableref->data.lval->h->data.sym->data.lval->h->data.lval); sql_schema *s = NULL; - tname = qname_table(tableref->data.lval->h->data.lval); + tname = tableref->token == SQL_NAME ? qname_table(tableref->data.lval->h->data.lval) : qname_table(tableref->data.lval->h->data.sym->data.lval->h->data.lval); if (sname && !(s=mvc_bind_schema(sql,sname))) return sql_error(sql, 02, "SELECT: no such schema '%s'", sname); @@ -1569,13 +1660,14 @@ table_ref(mvc *sql, sql_rel *rel, symbol } } if (!t && !temp_table) { - return sql_error(sql, 02, "SELECT: no such table '%s'", tname); + return sql_error(sql, 02, "SELECT: no such %s '%s'", tableref->token==SQL_ARRAY?"array":"table", tname); } else if (!temp_table && !table_privs(sql, t, PRIV_SELECT)) { return sql_error(sql, 02, "SELECT: access denied for %s to table '%s.%s'", stack_get_string(sql, "current_user"), s->base.name, tname); } if (tableref->data.lval->h->next->data.sym) { /* AS */ tname = tableref->data.lval->h->next->data.sym->data.lval->h->data.sval; } + if (temp_table && !t) { node *n; list *exps = rel_projections(sql, temp_table, NULL, 1, 1); @@ -1610,7 +1702,7 @@ table_ref(mvc *sql, sql_rel *rel, symbol } return rel; } - return rel_basetable(sql, t, tname); + return tableref->token == SQL_ARRAY ? rel_arrayslice(sql, t, tname, tableref->data.lval->h->data.sym) : rel_basetable(sql, t, tname); } else if (tableref->token == SQL_VALUES) { return rel_values(sql, tableref); } else if (tableref->token == SQL_TABLE) { _______________________________________________ Checkin-list mailing list Checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list