Changeset: e7e8b6c61a3b for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=e7e8b6c61a3b Modified Files: clients/Tests/MAL-signatures.stable.out clients/Tests/MAL-signatures.stable.out.int128 sql/backends/monet5/rel_bin.c sql/backends/monet5/sql.c sql/backends/monet5/sql.h sql/backends/monet5/sql.mal sql/backends/monet5/sql_statement.c sql/backends/monet5/sql_statement.h sql/server/rel_optimizer.c sql/server/rel_rel.c sql/server/rel_rel.h sql/server/rel_select.c sql/server/rel_unnest.c sql/test/subquery/Tests/subquery3.stable.err sql/test/subquery/Tests/subquery3.stable.out sql/test/subquery/Tests/subquery4.stable.err sql/test/subquery/Tests/subquery4.stable.out Branch: default Log Message:
handle unionfunctions more generaly now. Solves issues with correlated table returning functions fixed problem with returning single values from psm functions where monetdb uses bats too represent the single value. added more checks for zero or one results diffs (truncated from 751 to 300 lines): diff --git a/clients/Tests/MAL-signatures.stable.out b/clients/Tests/MAL-signatures.stable.out --- a/clients/Tests/MAL-signatures.stable.out +++ b/clients/Tests/MAL-signatures.stable.out @@ -18886,6 +18886,7 @@ stdout of test 'MAL-signatures` in direc [ "sql", "transaction_commit", "pattern sql.transaction_commit(chain:int, name:str):void ", "SQLtransaction_commit;", "A transaction statement (type can be commit,release,rollback or start)" ] [ "sql", "transaction_release", "pattern sql.transaction_release(chain:int, name:str):void ", "SQLtransaction_release;", "A transaction statement (type can be commit,release,rollback or start)" ] [ "sql", "transaction_rollback", "pattern sql.transaction_rollback(chain:int, name:str):void ", "SQLtransaction_rollback;", "A transaction statement (type can be commit,release,rollback or start)" ] +[ "sql", "unionfunc", "pattern sql.unionfunc(mod:str, fcn:str, X_0:any...):any... ", "SQLunionfunc;", "" ] [ "sql", "update", "pattern sql.update(mvc:int, sname:str, tname:str, cname:str, rids:any, upd:any):int ", "mvc_update_wrap;", "Update the values of the column tname.cname. Returns sequence number for order dependence)" ] [ "sql", "update_schemas", "pattern sql.update_schemas():void ", "SYSupdate_schemas;", "Procedure triggered on update of the sys.schemas table" ] [ "sql", "update_tables", "pattern sql.update_tables():void ", "SYSupdate_tables;", "Procedure triggered on update of the sys._tables table" ] diff --git a/clients/Tests/MAL-signatures.stable.out.int128 b/clients/Tests/MAL-signatures.stable.out.int128 --- a/clients/Tests/MAL-signatures.stable.out.int128 +++ b/clients/Tests/MAL-signatures.stable.out.int128 @@ -26900,6 +26900,7 @@ stdout of test 'MAL-signatures` in direc [ "sql", "transaction_commit", "pattern sql.transaction_commit(chain:int, name:str):void ", "SQLtransaction_commit;", "A transaction statement (type can be commit,release,rollback or start)" ] [ "sql", "transaction_release", "pattern sql.transaction_release(chain:int, name:str):void ", "SQLtransaction_release;", "A transaction statement (type can be commit,release,rollback or start)" ] [ "sql", "transaction_rollback", "pattern sql.transaction_rollback(chain:int, name:str):void ", "SQLtransaction_rollback;", "A transaction statement (type can be commit,release,rollback or start)" ] +[ "sql", "unionfunc", "pattern sql.unionfunc(mod:str, fcn:str, X_0:any...):any... ", "SQLunionfunc;", "" ] [ "sql", "update", "pattern sql.update(mvc:int, sname:str, tname:str, cname:str, rids:any, upd:any):int ", "mvc_update_wrap;", "Update the values of the column tname.cname. Returns sequence number for order dependence)" ] [ "sql", "update_schemas", "pattern sql.update_schemas():void ", "SYSupdate_schemas;", "Procedure triggered on update of the sys.schemas table" ] [ "sql", "update_tables", "pattern sql.update_tables():void ", "SYSupdate_tables;", "Procedure triggered on update of the sys._tables table" ] 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 @@ -19,6 +19,8 @@ #include "rel_optimizer.h" #include "sql_env.h" #include "sql_optimizer.h" +#include "sql_gencode.h" +#include "mal_builder.h" #define OUTER_ZERO 64 @@ -513,6 +515,10 @@ exp_bin(backend *be, sql_exp *e, stmt *l for(n=lst->op4.lval->h; n; n = n->next) list_append(l, const_column(be, (stmt*)n->data)); r = stmt_list(be, l); + } else if (r->type == st_table && e->card == CARD_ATOM) { /* fetch value */ + r = lst->op4.lval->h->data; + if (!r->aggr) + r = stmt_fetch(be, r); } if (r->type == st_list) r = stmt_table(be, r, 1); @@ -1665,6 +1671,8 @@ rel2bin_table(backend *be, sql_rel *rel, int i; sql_subfunc *f = op->f; stmt *psub = NULL; + list *ops = NULL; + stmt *ids = NULL; if (rel->l) { /* first construct the sub relation */ sql_rel *l = rel->l; @@ -1680,11 +1688,28 @@ rel2bin_table(backend *be, sql_rel *rel, return NULL; } - assert(f); - psub = exp_bin(be, op, sub, NULL, NULL, NULL, NULL, NULL); /* table function */ - if (!psub) { - assert(sql->session->status == -10); /* Stack overflow errors shouldn't terminate the server */ - return NULL; + if (f->func->res && list_length(f->func->res) + 1 == list_length(rel->exps) && !f->func->varres) { + /* add inputs in correct order ie loop through args of f and pass column */ + list *exps = op->l; + ops = sa_list(be->mvc->sa); + if (exps) { + for (node *en = exps->h; en; en = en->next) { + sql_exp *e = en->data; + + /* find column */ + stmt *s = exp_bin(be, e, sub, NULL, NULL, NULL, NULL, NULL); + if (en->next) + append(ops, s); + else /* last added exp is the ids (todo use name base lookup !!) */ + ids = s; + } + } + } else { + psub = exp_bin(be, op, sub, NULL, NULL, NULL, NULL, NULL); /* table function */ + if (!f || !psub) { + assert(sql->session->status == -10); /* Stack overflow errors shouldn't terminate the server */ + return NULL; + } } l = sa_list(sql->sa); if (f->func->res) { @@ -1699,9 +1724,58 @@ rel2bin_table(backend *be, sql_rel *rel, list_append(l, s); } } else { - assert(list_length(f->func->res) == list_length(rel->exps)); - node *m; - for(i = 0, n = f->func->res->h, m = rel->exps->h; n && m; n = n->next, m = m->next, i++ ) { + node *m = rel->exps->h; + int i = 0; + + /* correlated table returning function */ + if (list_length(f->func->res) + 1 == list_length(rel->exps)) { + /* use a simple nested loop solution for this case, ie + * output a table of (input) row-ids, the output of the table producing function + */ + InstrPtr q = newStmt(be->mb, "sql", "unionfunc"); + /* Generate output rowid column and output of function f */ + for(i=0; m; m = m->next, i++) { + sql_exp *e = m->data; + int type = exp_subtype(e)->type->localtype; + + type = newBatType(type); + if (i) + q = pushReturn(be->mb, q, newTmpVariable(be->mb, type)); + else + getArg(q, 0) = newTmpVariable(be->mb, type); + } + str mod = sql_func_mod(f->func); + str fcn = sql_func_imp(f->func); + q = pushStr(be->mb, q, mod); + q = pushStr(be->mb, q, fcn); + if (backend_create_func(be, f->func, NULL, ops) < 0) + return NULL; + psub = stmt_direct_func(be, q); + + if (ids) /* push input rowids column */ + q = pushArgument(be->mb, q, ids->nr); + + /* add inputs in correct order ie loop through args of f and pass column */ + if (ops) { + for (node *en = ops->h; en; en = en->next) { + stmt *op = en->data; + + q = pushArgument(be->mb, q, op->nr); + } + } + + /* name output of dependent columns, output of function is handled the same as without correlation */ + int len = list_length(rel->exps)-list_length(f->func->res); + assert(len== 1); + for(i=0, m=rel->exps->h; m && i<len; m = m->next, i++ ) { + sql_exp *exp = m->data; + stmt *s = stmt_rs_column(be, psub, i, exp_subtype(exp)); + + s = stmt_alias(be, s, exp->l, exp->r); + list_append(l, s); + } + } + for(n = f->func->res->h; n && m; n = n->next, m = m->next, i++ ) { sql_arg *a = n->data; sql_exp *exp = m->data; stmt *s = stmt_rs_column(be, psub, i, &a->type); @@ -1710,7 +1784,9 @@ rel2bin_table(backend *be, sql_rel *rel, s = stmt_alias(be, s, rnme, a->name); list_append(l, s); } +#if 0 if (list_length(f->res) == list_length(f->func->res) + 1) { + assert(0); /* add missing %TID% column */ sql_subtype *t = f->res->t->data; stmt *s = stmt_rs_column(be, psub, i, t); @@ -1719,6 +1795,7 @@ rel2bin_table(backend *be, sql_rel *rel, s = stmt_alias(be, s, rnme, TID); list_append(l, s); } +#endif } } assert(rel->flag != TABLE_PROD_FUNC || !sub || !(sub->nrcols)); diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c --- a/sql/backends/monet5/sql.c +++ b/sql/backends/monet5/sql.c @@ -5553,3 +5553,123 @@ bailout: } return msg; } + +/* input id,row-input-values + * for each id call function(with row-input-values) return table + * return for each id the table, ie id (*length of table) and table results + */ +str +SQLunionfunc(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) +{ + int arg = pci->retc; + str mod, fcn, ret = MAL_SUCCEED; + InstrPtr npci; + + mod = *getArgReference_str(stk, pci, arg++); + fcn = *getArgReference_str(stk, pci, arg++); + npci = newStmt(mb, mod, fcn); + + for (int i = 1; i < pci->retc; i++) { + int type = getArgType(mb, pci, i); + + if (i==1) + getArg(npci, 0) = newTmpVariable(mb, type); + else + npci = pushReturn(mb, npci, newTmpVariable(mb, type)); + } + for (int i = pci->retc+2+1; i < pci->argc; i++) { + int type = getBatType(getArgType(mb, pci, i)); + + npci = pushNil(mb, npci, type); + } + /* check program to get the proper malblk */ + if (chkInstruction(cntxt->usermodule, mb, npci)) + return "ERORROR"; + + if (npci) { + BAT **res; + BAT **input; + BATiter *bi; + BUN cnt = 0; + int nrinput = pci->argc - 2 - pci->retc; + + input = GDKmalloc(sizeof(BAT*) * nrinput); + bi = GDKmalloc(sizeof(BATiter) * nrinput); + assert(nrinput == pci->retc); + for (int i = 0, j = pci->retc+2; j < pci->argc; i++, j++) { + bat *b = getArgReference_bat(stk, pci, j); + input[i] = BATdescriptor(*b); + bi[i] = bat_iterator(input[i]); + cnt = BATcount(input[i]); + } + + /* create result bats */ + res = GDKmalloc(sizeof(BAT*) * pci->retc); + for (int i = 0; i<pci->retc; i++) { + int type = getArgType(mb, pci, i); + + res[i] = COLnew(0, getBatType(type), cnt, TRANSIENT); + } + + MalBlkPtr nmb = copyMalBlk(npci->blk); + MalStkPtr env = prepareMALstack(nmb, nmb->vsize); /* needed for result */ + + InstrPtr q = getInstrPtr(nmb, 0); + + for(BUN cur = 0; cur<cnt && !ret; cur++ ) { + MalStkPtr nstk = prepareMALstack(nmb, nmb->vsize); + int i,ii; + + /* copy (input) arguments onto destination stack, skipping rowid col */ + for (i = 1, ii = q->retc; ii < q->argc; ii++) { + ValPtr lhs = &nstk->stk[q->argv[ii]]; + ptr rhs = (ptr)BUNtail(bi[i], cur); + + assert(lhs->vtype != TYPE_bat); + if (VALset(lhs, input[i]->ttype, rhs) == NULL) { + ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL); + break; + } + } + if (ret == MAL_SUCCEED && ii == q->argc) { + BAT *fres = NULL; + BUN ccnt = 0; + ret = runMALsequence(cntxt, nmb, 1, nmb->stop, nstk, env /* copy result in nstk first instruction*/, q); + + /* insert into result */ + fres = BATdescriptor(env->stk[q->argv[0]].val.bval); + ccnt = BATcount(fres); + BAT *p = NULL; + + if (BATappend(res[0], p = BATconstant(fres->hseqbase, res[0]->ttype, (ptr)BUNtail(bi[0], cur), ccnt, 0), NULL, FALSE) != GDK_SUCCEED) + ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL); + BBPunfix(p->batCacheid); + BBPunfix(fres->batCacheid); + + i=1; + for (ii = 0; i < pci->retc && !ret; i++) { + BAT *b = BATdescriptor(env->stk[q->argv[ii]].val.bval); + if (BATappend(res[i], b, NULL, FALSE) != GDK_SUCCEED) + ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL); + BBPrelease(b->batCacheid); /* release ref from env stack */ + BBPunfix(b->batCacheid); /* free pointer */ + } + } + GDKfree(nstk); + } + GDKfree(env); + freeMalBlk(nmb); + for (int i = 0; i<pci->retc; i++) { + bat *b = getArgReference_bat(stk, pci, i); + *b = res[i]->batCacheid; + BBPkeepref(*b); + } + GDKfree(res); + for (int i = 0; i<nrinput; i++) + BBPunfix(input[i]->batCacheid); + GDKfree(input); + GDKfree(bi); + } + return ret; +} + diff --git a/sql/backends/monet5/sql.h b/sql/backends/monet5/sql.h --- a/sql/backends/monet5/sql.h +++ b/sql/backends/monet5/sql.h @@ -314,4 +314,6 @@ sql5_export str SQLhot_snapshot(void *re sql5_export str SQLsession_prepared_statements(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list