Changeset: 39b18f5656dc for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=39b18f5656dc Modified Files: monetdb5/mal/mal_interpreter.c sql/backends/monet5/UDF/pyapi/pyloader.c sql/backends/monet5/rel_bin.c sql/backends/monet5/sql_statement.c sql/server/rel_psm.c sql/server/rel_select.c sql/server/rel_select.h sql/server/rel_updates.c Branch: default Log Message:
Make loader functions work with subqueries as input. diffs (truncated from 320 to 300 lines): diff --git a/monetdb5/mal/mal_interpreter.c b/monetdb5/mal/mal_interpreter.c --- a/monetdb5/mal/mal_interpreter.c +++ b/monetdb5/mal/mal_interpreter.c @@ -665,7 +665,7 @@ str runMALsequence(Client cntxt, MalBlkP } break; case CMDcall: - ret =malCommandCall(stk, pci); + ret = malCommandCall(stk, pci); #ifndef NDEBUG /* check that the types of actual results match * expected results */ diff --git a/sql/backends/monet5/UDF/pyapi/pyloader.c b/sql/backends/monet5/UDF/pyapi/pyloader.c --- a/sql/backends/monet5/UDF/pyapi/pyloader.c +++ b/sql/backends/monet5/UDF/pyapi/pyloader.c @@ -105,22 +105,39 @@ PYFUNCNAME(PyAPIevalLoader)(Client cntxt argnode = sqlfun && sqlfun->ops->cnt > 0 ? sqlfun->ops->h : NULL; for (i = pci->retc + 2; i < argcount; i++) { PyInput inp; + inp.bat = NULL; + inp.sql_subtype = NULL; PyObject *val = NULL; - if (isaBatType(getArgType(mb, pci, i))) { - msg = createException(MAL, "pyapi.eval_loader", - "Only scalar arguments are supported."); - goto wrapup; + if (!isaBatType(getArgType(mb, pci, i))) { + inp.scalar = true; + inp.bat_type = getArgType(mb, pci, i); + inp.count = 1; + if (inp.bat_type == TYPE_str) { + inp.dataptr = getArgReference_str(stk, pci, i); + } else { + inp.dataptr = getArgReference(stk, pci, i); + } + val = PyArrayObject_FromScalar(&inp, &msg); + } else { + BAT* b = BATdescriptor(*getArgReference_bat(stk, pci, i)); + if (b == NULL) { + msg = createException( + MAL, "pyapi.eval", + "The BAT passed to the function (argument #%d) is NULL.\n", + i - (pci->retc + 2) + 1); + goto wrapup; + } + inp.scalar = false; + inp.count = BATcount(b); + inp.bat_type = ATOMstorage(getBatType(getArgType(mb, pci, i))); + inp.bat = b; + + val = PyMaskedArray_FromBAT( + &inp, 0, inp.count, &msg, + false); + BBPunfix(inp.bat->batCacheid); } - inp.scalar = true; - inp.bat_type = getArgType(mb, pci, i); - inp.count = 1; - if (inp.bat_type == TYPE_str) { - inp.dataptr = getArgReference_str(stk, pci, i); - } else { - inp.dataptr = getArgReference(stk, pci, i); - } - val = PyArrayObject_FromScalar(&inp, &msg); if (msg != MAL_SUCCEED) { goto wrapup; } 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 @@ -436,7 +436,7 @@ exp_bin(backend *be, sql_exp *e, stmt *l if (!es) return NULL; - if (rows && en == exps->h) + if (rows && en == exps->h && f->func->type != F_LOADER) es = stmt_const(be, rows, es); if (es->nrcols > nrcols) nrcols = es->nrcols; @@ -1417,34 +1417,36 @@ rel2bin_table(backend *be, sql_rel *rel, return NULL; } l = sa_list(sql->sa); - if (f->func->varres) { - for(i=0, en = rel->exps->h, n = f->res->h; en; en = en->next, n = n->next, i++ ) { - sql_exp *exp = en->data; - sql_subtype *st = n->data; - const char *rnme = exp->rname?exp->rname:exp->l; - stmt *s = stmt_rs_column(be, psub, i, st); - - s = stmt_alias(be, s, rnme, exp->name); - list_append(l, s); - } - } else { - for(i = 0, n = f->func->res->h; n; n = n->next, i++ ) { - sql_arg *a = n->data; - stmt *s = stmt_rs_column(be, psub, i, &a->type); - const char *rnme = exp_find_rel_name(op); - - s = stmt_alias(be, s, rnme, a->name); - list_append(l, s); - } - if (list_length(f->res) == list_length(f->func->res) + 1) { - /* add missing %TID% column */ - sql_subtype *t = f->res->t->data; - stmt *s = stmt_rs_column(be, psub, i, t); - const char *rnme = exp_find_rel_name(op); - - s = stmt_alias(be, s, rnme, TID); - list_append(l, s); - } + if (f->func->res) { + if (f->func->varres) { + for(i=0, en = rel->exps->h, n = f->res->h; en; en = en->next, n = n->next, i++ ) { + sql_exp *exp = en->data; + sql_subtype *st = n->data; + const char *rnme = exp->rname?exp->rname:exp->l; + stmt *s = stmt_rs_column(be, psub, i, st); + + s = stmt_alias(be, s, rnme, exp->name); + list_append(l, s); + } + } else { + for(i = 0, n = f->func->res->h; n; n = n->next, i++ ) { + sql_arg *a = n->data; + stmt *s = stmt_rs_column(be, psub, i, &a->type); + const char *rnme = exp_find_rel_name(op); + + s = stmt_alias(be, s, rnme, a->name); + list_append(l, s); + } + if (list_length(f->res) == list_length(f->func->res) + 1) { + /* add missing %TID% column */ + sql_subtype *t = f->res->t->data; + stmt *s = stmt_rs_column(be, psub, i, t); + const char *rnme = exp_find_rel_name(op); + + s = stmt_alias(be, s, rnme, TID); + list_append(l, s); + } + } } if (!rel->flag && sub && sub->nrcols) { assert(0); diff --git a/sql/backends/monet5/sql_statement.c b/sql/backends/monet5/sql_statement.c --- a/sql/backends/monet5/sql_statement.c +++ b/sql/backends/monet5/sql_statement.c @@ -2591,7 +2591,7 @@ stmt_Nop(backend *be, stmt *ops, sql_sub return NULL; mod = sql_func_mod(f->func); fimp = sql_func_imp(f->func); - if (o && o->nrcols > 0) { + if (o && o->nrcols > 0 && f->func->type != F_LOADER) { sql_subtype *res = f->res->h->data; fimp = convertMultiplexFcn(fimp); q = NULL; diff --git a/sql/server/rel_psm.c b/sql/server/rel_psm.c --- a/sql/server/rel_psm.c +++ b/sql/server/rel_psm.c @@ -1339,14 +1339,12 @@ psm_analyze(mvc *sql, char *analyzeType, } static sql_rel* -create_table_from_loader(mvc *sql, dlist *qname, symbol *fcall) -{ +create_table_from_loader(mvc *sql, dlist *qname, symbol *fcall) { sql_schema *s = NULL; char *sname = qname_schema(qname); char *tname = qname_table(qname); - sql_exp *import = NULL; - exp_kind ek = {type_value, card_loader, FALSE}; - sql_rel *res = NULL; + sql_subfunc *loader = NULL; + sql_rel* rel = NULL; if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, "3F000!CREATE TABLE: no such schema '%s'", sname); @@ -1357,17 +1355,18 @@ create_table_from_loader(mvc *sql, dlist return sql_error(sql, 02, "42000!CREATE TABLE: insufficient privileges for user '%s' in schema '%s'", stack_get_string(sql, "current_user"), s->base.name); } - import = rel_value_exp(sql, &res, fcall, sql_sel, ek); - if (!import) { + rel = rel_loader_function(sql, fcall, &loader); + if (!rel || !loader) { return NULL; } - ((sql_subfunc*) import->f)->sname = sname ? sa_zalloc(sql->sa, strlen(sname) + 1) : NULL; - ((sql_subfunc*) import->f)->tname = tname ? sa_zalloc(sql->sa, strlen(tname) + 1) : NULL; + loader->sname = sname ? sa_zalloc(sql->sa, strlen(sname) + 1) : NULL; + loader->tname = tname ? sa_zalloc(sql->sa, strlen(tname) + 1) : NULL; - if (sname) strcpy(((sql_subfunc*) import->f)->sname, sname); - if (tname) strcpy(((sql_subfunc*) import->f)->tname, tname); + if (sname) strcpy(loader->sname, sname); + if (tname) strcpy(loader->tname, tname); - return rel_psm_stmt(sql->sa, import); + + return rel; } sql_rel * @@ -1423,8 +1422,8 @@ rel_psm(mvc *sql, symbol *s) dlist *qname = l->h->data.lval; symbol *sym = l->h->next->data.sym; - ret = create_table_from_loader(sql, qname, sym); - sql->type = Q_UPDATE; + ret = rel_psm_stmt(sql->sa, exp_rel(sql, create_table_from_loader(sql, qname, sym))); + sql->type = Q_SCHEMA; } break; case SQL_CREATE_TRIGGER: { 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 @@ -5415,3 +5415,70 @@ schema_selects(mvc *sql, sql_schema *sch return res; } +sql_rel * +rel_loader_function(mvc* sql, symbol* fcall, sql_subfunc **loader_function) { + list *exps = NULL, *tl; + exp_kind ek = { type_value, card_relation, TRUE }; + sql_rel *sq = NULL; + sql_exp *e = NULL; + symbol *sym = fcall; + dnode *l = sym->data.lval->h; + char *sname = qname_schema(l->data.lval); + char *fname = qname_fname(l->data.lval); + char *tname = NULL; + node *en; + sql_schema *s = sql->session->schema; + sql_subfunc* sf; + + tl = sa_list(sql->sa); + exps = new_exp_list(sql->sa); + if (l->next) { /* table call with subquery */ + if (l->next->type == type_symbol && l->next->data.sym->token == SQL_SELECT) { + if (l->next->next != NULL) + return sql_error(sql, 02, "SELECT: '%s' requires a single sub query", fname); + sq = rel_subquery(sql, NULL, l->next->data.sym, ek, 0 /*apply*/); + } else if (l->next->type == type_symbol || l->next->type == type_list) { + dnode *n; + exp_kind iek = {type_value, card_column, TRUE}; + list *exps = sa_list (sql->sa); + + if (l->next->type == type_symbol) + n = l->next; + else + n = l->next->data.lval->h; + for ( ; n; n = n->next) { + sql_exp *e = rel_value_exp(sql, NULL, n->data.sym, sql_sel, iek); + + if (!e) + return NULL; + append(exps, e); + } + sq = rel_project(sql->sa, NULL, exps); + } + + /* reset error */ + sql->session->status = 0; + sql->errstr[0] = '\0'; + if (!sq) + return sql_error(sql, 02, "SELECT: no such operator '%s'", fname); + for (en = sq->exps->h; en; en = en->next) { + sql_exp *e = en->data; + + append(exps, e=exp_alias_or_copy(sql, tname, exp_name(e), NULL, e)); + append(tl, exp_subtype(e)); + } + } + if (sname) + s = mvc_bind_schema(sql, sname); + sf = bind_func_(sql, s, fname, tl, F_LOADER); + if (!sf) + return sql_error(sql, 02, "SELECT: no such operator '%s'", fname); + e = exp_op(sql->sa, exps, sf); + + if (loader_function) { + *loader_function = sf; + } + + return rel_table_func(sql->sa, sq, e, new_exp_list(sql->sa), (sq != NULL)); +} + diff --git a/sql/server/rel_select.h b/sql/server/rel_select.h --- a/sql/server/rel_select.h +++ b/sql/server/rel_select.h @@ -31,4 +31,7 @@ extern sql_exp *rel_nop_(mvc *sql, sql_e extern sql_rel *rel_with_query(mvc *sql, symbol *q); extern sql_rel *table_ref(mvc *sql, sql_rel *rel, symbol *tableref, int lateral); + +extern sql_rel *rel_loader_function(mvc* sql, symbol* s, sql_subfunc **loader_function); + #endif /*_REL_SELECT_H_*/ _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list