Changeset: c21397c0acde for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/c21397c0acde Modified Files: sql/backends/monet5/rel_bin.c sql/common/sql_types.c sql/server/CMakeLists.txt sql/server/rel_select.c sql/server/rel_unnest.c sql/server/rel_updates.c sql/server/sql_parser.y sql/storage/bat/bat_storage.c sql/storage/store.c Branch: nested Log Message:
some initial array/setof unnest handling diffs (truncated from 406 to 300 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 @@ -695,6 +695,8 @@ tuple_create_result(backend *be, sql_exp (void)sql_error(be->mvc, 02, SQLSTATE(42000) "Cannot handle empty composite type"); return -1; } + if (multiset) /* rowid */ + append(cols, sa_list(be->mvc->sa)); for(node *n = attr->h; n; n = n->next) { sql_exp *e = n->data; @@ -705,9 +707,9 @@ tuple_create_result(backend *be, sql_exp } append(cols, sa_list(be->mvc->sa)); } - if (multiset) + if (multiset) /* multisetid */ append(cols, sa_list(be->mvc->sa)); - if (multiset == MS_ARRAY) + if (multiset == MS_ARRAY) /* multisetnr */ append(cols, sa_list(be->mvc->sa)); return 0; } @@ -726,8 +728,15 @@ append_tuple(backend *be, sql_exp *tuple } assert(tuple->row); list *attr = exp_get_values(tuple); - node *n, *m; - for(n = attr->h, m = cols->h; n; n = n->next, m = m->next) { + node *n, *m = cols->h; + if (multiset) { + if (lcnt == 1) { + list *vals = m->data; + append(vals, stmt_atom_int(be, rowcnt)); + } + m = m->next; + } + for(n = attr->h; n; n = n->next, m = m->next) { sql_exp *e = n->data; list *vals = m->data; @@ -781,9 +790,9 @@ value_list(backend *be, sql_exp *vals_ex list *attr = sa_list(be->mvc->sa); if (tuple_create_result(be, vals->h->data, attr, multiset) < 0) return NULL; - int rowcnt = 1; - for (node *n = vals->h; n; n = n->next, rowcnt++) { - if (append_tuple(be, n->data, left, sel, attr, rowcnt, 1, multiset) < 0) + int rowcnt = 1, lcnt = 1; + for (node *n = vals->h; n; n = n->next, lcnt++) { + if (append_tuple(be, n->data, left, sel, attr, rowcnt, lcnt++, multiset) < 0) return NULL; } return tuple_result(be, attr); @@ -1584,6 +1593,20 @@ is_const_func(sql_subfunc *f, list *attr } static stmt* +exp2bin_multiset(backend *be, sql_exp *fe, stmt *left, stmt *right, stmt *sel) +{ + (void)be; + (void)fe; + (void)right; + (void)sel; + assert(list_length(left->op4.lval) == 1); + stmt *s = left->op4.lval->h->data; + while(s->type == st_alias) + s = s->op1; + return s; +} + +static stmt* exp2bin_file_loader(backend *be, sql_exp *fe, stmt *left, stmt *right, stmt *sel) { assert(left == NULL); (void)left; @@ -1812,6 +1835,8 @@ exp_bin(backend *be, sql_exp *e, stmt *l return exp2bin_copyfrombinary(be, e, left, right, sel); if (strcmp(fname, "file_loader") == 0) return exp2bin_file_loader(be, e, left, right, sel); + if (strcmp(fname, "multiset") == 0) + return exp2bin_multiset(be, e, left, right, sel); if (strcmp(fname, "-1") == 0) /* map arguments to A0 .. An */ return exp2bin_named_placeholders(be, e); } @@ -2804,7 +2829,7 @@ rel2bin_table(backend *be, sql_rel *rel, } } } - assert(rel->flag != TABLE_PROD_FUNC || !sub || !(sub->nrcols)); + //assert(rel->flag != TABLE_PROD_FUNC || !sub || !(sub->nrcols)); sub = stmt_list(be, l); return sub; } else if (rel->l) { /* handle sub query via function */ @@ -5784,7 +5809,7 @@ rel2bin_insert(backend *be, sql_rel *rel for (n = ol_first_node(t->columns), m = inserts->op4.lval->h; n && m; m = m->next) { sql_column *c = n->data; - if (c->type.type->composite) { + if (c->type.type->composite && !c->type.multiset) { n = insert_composite(updates, c, n, m->data); } else { updates[c->colnr] = m->data; diff --git a/sql/common/sql_types.c b/sql/common/sql_types.c --- a/sql/common/sql_types.c +++ b/sql/common/sql_types.c @@ -1738,6 +1738,18 @@ sqltypeinit( allocator *sa) /* sys_update_schemas, sys_update_tables */ sql_create_procedure(sa, "sys_update_schemas", "sql", "update_schemas", FALSE, 0); sql_create_procedure(sa, "sys_update_tables", "sql", "update_tables", FALSE, 0); + + /* virtual multiset mapping functions */ + sql_create_func(sa, "rowid", "", "", TRUE, TRUE, SCALE_NONE, 0, OID, 0); + sql_create_func(sa, "multisetid", "", "", TRUE, TRUE, SCALE_NONE, 0, OID, 1, ANY); + sql_create_func(sa, "multisetnr", "", "", TRUE, TRUE, SCALE_NONE, 0, INT, 1, ANY); + sql_create_func(sa, "multisetfield", "", "", TRUE, TRUE, SCALE_NONE, 0, ANY, 1, ANY); + f = sql_create_union(sa, "multiset", "", "", TRUE, SCALE_NONE, 0, TABLE, 1, ANY); + f->vararg = 1; + f->varres = 1; + f = sql_create_union(sa, "unnest", "", "", TRUE, SCALE_NONE, 0, TABLE, 1, ANY); /* unnest multiset */ + f->vararg = 1; + f->varres = 1; } void diff --git a/sql/server/CMakeLists.txt b/sql/server/CMakeLists.txt --- a/sql/server/CMakeLists.txt +++ b/sql/server/CMakeLists.txt @@ -65,6 +65,7 @@ target_sources(sqlserver rel_xml.c rel_dump.c rel_file_loader.c + rel_multiset.c rel_dump.h rel_exp.h rel_rel.h rel_basetable.h rel_rewriter.h @@ -95,6 +96,7 @@ target_sources(sqlserver sql_tokens.h sql_partition.h rel_file_loader.h + rel_multiset.h ${BISON_sqlparser_OUTPUT_HEADER} ${BISON_sqlparser_OUTPUT_SOURCE} PUBLIC 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 @@ -716,6 +716,30 @@ file_loader_add_table_column_types(mvc * } static sql_rel * +rel_unnest_func(sql_query *query, list *exps, char *tname) +{ + if (list_empty(exps)) + return sql_error(query->sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: unnest multiset missing"); + for( node *n = exps->h; n; n = n->next) { + sql_exp *e = n->data; + if (!e->freevar || e->type != e_column) + return sql_error(query->sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: unnest multiset not found"); + sql_rel *r = query_fetch_outer(query, e->freevar-1); + if (!r || !is_basetable(r->op)) + return sql_error(query->sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: unnest multiset table missing"); + sql_table *t = r->l; + sql_column *c = t?mvc_bind_column(query->sql, t, exp_name(e)):NULL; + if (!c) + return sql_error(query->sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: unnest multiset column '%s' missing", exp_name(e)); + sql_table *st = mvc_bind_table(query->sql, t->s, c->storage_type); + if (!st) + return sql_error(query->sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: unnest multiset table '%s' missing", c->storage_type); + return rel_basetable(query->sql, st, a_create(query->sql->sa, tname?st->base.name:tname)); + } + return NULL; +} + +static sql_rel * rel_file_loader(mvc *sql, list *exps, list *tl, char *tname) { sql_subfunc *f = NULL; @@ -773,7 +797,10 @@ rel_named_table_function(sql_query *quer dnode *l = sym->data.lval->h, *n; char *fname = qname_schema_object(l->data.lval); char *sname = qname_schema(l->data.lval); - + bool unnest = (!sname && strcmp(fname, "unnest") == 0); + + if (unnest) + lateral = 1; tl = sa_list(sql->sa); exps = sa_list(sql->sa); if (l->next) @@ -811,12 +838,16 @@ rel_named_table_function(sql_query *quer append(exps, e); is_value &= exp_is_atom(e); } - if (!is_value || (lateral && outer)) - sq = rel_project(sql->sa, NULL, exps); - if (lateral && outer) { - sq = rel_crossproduct(sql->sa, sq, outer, op_join); - set_dependent(sq); - set_processed(sq); + if (unnest) { + is_value = 1; + } else { + if (!is_value || (lateral && outer)) + sq = rel_project(sql->sa, NULL, exps); + if (lateral && outer) { + sq = rel_crossproduct(sql->sa, sq, outer, op_join); + set_dependent(sq); + set_processed(sq); + } } } } @@ -838,8 +869,7 @@ rel_named_table_function(sql_query *quer append(tl, exp_subtype(e)); } } else { - for (node *en = exps->h; en; en = en->next) - append(tl, exp_subtype(en->data)); + tl = exp_types(sql->sa, exps); } } @@ -855,6 +885,10 @@ rel_named_table_function(sql_query *quer rel = rel_file_loader(sql, exps, tl, tname); if (!rel) return NULL; + } else if (!sname && strcmp(fname, "unnest") == 0) { + rel = rel_unnest_func(query, exps, tname); + if (!rel) + return NULL; } else if (!(e = find_table_function(sql, sname, fname, list_empty(exps) ? NULL : exps, tl, F_UNION))) return NULL; @@ -1221,8 +1255,17 @@ check_is_lateral(symbol *tableref) { if (tableref->token == SQL_NAME || tableref->token == SQL_TABLE || tableref->token == SQL_VALUES) { - if (dlist_length(tableref->data.lval) == 3) - return tableref->data.lval->h->next->data.i_val; + if (dlist_length(tableref->data.lval) == 3) { + if (tableref->data.lval->h->next->data.i_val) + return 1; + } + if (tableref->data.lval->h->type == type_symbol && tableref->data.lval->h->data.sym->token == SQL_NOP) { + symbol *sym = tableref->data.lval->h->data.sym; + dlist *qname = sym->data.lval->h->data.lval; + /* first is the qname */ + if (dlist_length(qname) == 1 && strcmp(qname->h->data.sval, "unnest")==0) + return 1; + } return 0; } else if (tableref->token == SQL_WITH) { if (dlist_length(tableref->data.lval) == 5) diff --git a/sql/server/rel_unnest.c b/sql/server/rel_unnest.c --- a/sql/server/rel_unnest.c +++ b/sql/server/rel_unnest.c @@ -18,6 +18,7 @@ #include "rel_exp.h" #include "rel_select.h" #include "rel_rewriter.h" +#include "rel_multiset.h" static void exp_set_freevar(mvc *sql, sql_exp *e, sql_rel *r) @@ -4594,6 +4595,7 @@ rel_unnest(mvc *sql, sql_rel *rel) { visitor v = { .sql = sql }; + rel = rel_multiset(sql, rel); rel = run_exp_rewriter(&v, rel, &rel_simplify_exp_and_rank, false, "simplify_exp_and_rank"); rel = run_rel_rewriter(&v, rel, &rel_unnest_simplify, "unnest_simplify"); rel = run_exp_rewriter(&v, rel, &rewrite_complex, true, "rewrite_complex"); diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c --- a/sql/server/rel_updates.c +++ b/sql/server/rel_updates.c @@ -307,6 +307,8 @@ rel_insert_table(sql_query *query, sql_t static node * skip_nested_columns(mvc *sql, sql_column *ct, node *n) { + if (ct->type.multiset) + return n; if (ct->type.multiset) { /* skip id and optional number columns */ n = n->next; if (ct->type.multiset == MS_ARRAY) diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y --- a/sql/server/sql_parser.y +++ b/sql/server/sql_parser.y @@ -3952,13 +3952,6 @@ table_ref: append_symbol($$->data.lval, $3); } } -/* - | select_with_parens - { $$ = NULL; - yyerror(m, "subquery table reference needs alias, use AS xxx"); - YYABORT; - } -*/ | joined_table { $$ = $1; _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org