Changeset: 05426c8cd12b for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=05426c8cd12b Modified Files: monetdb5/extras/jaql/Tests/transform00.stable.out monetdb5/extras/jaql/jaql.c monetdb5/extras/jaql/jaql.h monetdb5/extras/jaql/jaql.mal monetdb5/extras/jaql/jaqlfunc.mal monetdb5/extras/jaql/jaqlgencode.c monetdb5/extras/jaql/jaqltests/Tests/calculations.jaql monetdb5/extras/jaql/jaqltests/Tests/calculations.stable.out monetdb5/mal/mal_instruction.c Branch: default Log Message:
Merge with Oct2012 branch. diffs (truncated from 541 to 300 lines): diff --git a/monetdb5/extras/jaql/Tests/transform00.stable.out b/monetdb5/extras/jaql/Tests/transform00.stable.out --- a/monetdb5/extras/jaql/Tests/transform00.stable.out +++ b/monetdb5/extras/jaql/Tests/transform00.stable.out @@ -15,7 +15,6 @@ stdout of test 'transform00` in director # Listening for connection requests on mapi:monetdb://sofia.ins.cwi.nl:35341/ # MonetDB/GIS module loaded # MonetDB/SQL module loaded -# MonetDB/DataCell module not loaded: MALException:jaql.context:JAQL environment not found function user.main():void; jaql.x("[1,2,3] -> transform 2 * 2;"); jaql.x("[1,2,3] -> transform {\"value\":2 + 2};"); diff --git a/monetdb5/extras/jaql/jaql.c b/monetdb5/extras/jaql/jaql.c --- a/monetdb5/extras/jaql/jaql.c +++ b/monetdb5/extras/jaql/jaql.c @@ -1162,8 +1162,9 @@ make_op(enum comptype t) /* create an operation over two vars/literals, apply some simple rules * to reduce work lateron (e.g. static calculations) - * return is either a j_num, j_dbl or j_operation with tval1 being j_val - * or j_operation and tval2 being j_num, j_dbl, j_val or j_operation */ + * return is either a j_num, j_dbl, j_str or j_operation with tval1 + * being j_val or j_operation and tval2 being j_num, j_dbl, j_val or + * j_operation */ tree * make_operation(tree *var1, tree *op, tree *var2) { @@ -1173,13 +1174,13 @@ make_operation(tree *var1, tree *op, tre assert(op != NULL && op->type == j_op); assert(var2 != NULL); - if (var1->type == j_bool || var1->type == j_str || - var2->type == j_bool || var2->type == j_str) + if (var1->type == j_bool || var1->type == j_null || + var2->type == j_bool || var2->type == j_null) { /* we can't do arithmetic with these */ res->type = j_error; res->sval = GDKstrdup("transform: cannot perform arithmetic on " - "string or boolean values"); + "null or boolean values"); freetree(var1); freetree(op); freetree(var2); @@ -1197,7 +1198,32 @@ make_operation(tree *var1, tree *op, tre var2->dval = (double)var2->nval; switch (op->cval) { case j_plus: - if (var1->type == j_dbl || var2->type == j_dbl) { + if (var1->type == j_str || var2->type == j_str) { + size_t tsize; + + if (var1->type != var2->type) { + res->type = j_error; + res->sval = GDKstrdup("transform: can only concatenate " + "two strings"); + freetree(var1); + freetree(op); + freetree(var2); + return res; + } + + tsize = strlen(var1->sval) + strlen(var2->sval) + 1; + res->type = j_str; + if ((res->sval = GDKmalloc(tsize)) == NULL) { + res->type = j_error; + res->sval = GDKstrdup("transform: str concat: " + "out of memory"); + freetree(var1); + freetree(op); + freetree(var2); + return res; + } + snprintf(res->sval, tsize, "%s%s", var1->sval, var2->sval); + } else if (var1->type == j_dbl || var2->type == j_dbl) { res->type = j_dbl; res->dval = var1->dval + var2->dval; } else { @@ -1206,7 +1232,15 @@ make_operation(tree *var1, tree *op, tre } break; case j_min: - if (var1->type == j_dbl || var2->type == j_dbl) { + if (var1->type == j_str || var2->type == j_str) { + res->type = j_error; + res->sval = GDKstrdup("transform: cannot perform " + "minus on strings"); + freetree(var1); + freetree(op); + freetree(var2); + return res; + } else if (var1->type == j_dbl || var2->type == j_dbl) { res->type = j_dbl; res->dval = var1->dval - var2->dval; } else { @@ -1215,7 +1249,15 @@ make_operation(tree *var1, tree *op, tre } break; case j_multiply: - if (var1->type == j_dbl || var2->type == j_dbl) { + if (var1->type == j_str || var2->type == j_str) { + res->type = j_error; + res->sval = GDKstrdup("transform: cannot perform " + "multiplication on strings"); + freetree(var1); + freetree(op); + freetree(var2); + return res; + } else if (var1->type == j_dbl || var2->type == j_dbl) { res->type = j_dbl; res->dval = var1->dval * var2->dval; } else { @@ -1224,7 +1266,15 @@ make_operation(tree *var1, tree *op, tre } break; case j_divide: - if (var1->type == j_dbl || var2->type == j_dbl) { + if (var1->type == j_str || var2->type == j_str) { + res->type = j_error; + res->sval = GDKstrdup("transform: cannot perform " + "division on strings"); + freetree(var1); + freetree(op); + freetree(var2); + return res; + } else if (var1->type == j_dbl || var2->type == j_dbl) { res->type = j_dbl; res->dval = var1->dval / var2->dval; } else { @@ -2092,3 +2142,69 @@ JAQLcast(Client cntxt, MalBlkPtr mb, Mal *ret = *b; return MAL_SUCCEED; } + +/* BAT-wise string concat, currently missing in-core */ +str +JAQLbatconcat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) +{ + int *ret = (int *)getArgReference(stk, pci, 0); + int *l = (int *)getArgReference(stk, pci, 1); + int *r = (int *)getArgReference(stk, pci, 2); + BAT *left, *right, *b; + BATiter bil, bir; + BUN pl, ql, pr; + char *vall, *valr, *valc; + size_t valsize, valcsize = 1024; + + (void)mb; + (void)cntxt; + + left = BATdescriptor(ABS(*l)); + if (*l < 0) + left = BATmirror(left); + right = BATdescriptor(ABS(*r)); + if (*r < 0) + right = BATmirror(right); + + bil = bat_iterator(left); + bir = bat_iterator(right); + + if (BATcount(left) != BATcount(right)) + throw(MAL, "jaql.batconcat", "both input BATs must have same count"); + + if (left->ttype != TYPE_str || right->ttype != TYPE_str) + throw(MAL, "jaql.batconcat", "BAT tail types must be str"); + + b = BATnew(TYPE_oid, TYPE_str, BATcount(left)); + if (b == NULL) + throw(MAL, "jaql.batconcat", "failed to create return BAT"); + + valc = GDKmalloc(valcsize); + if (valc == NULL) + throw(MAL, "jaql.batconcat", "failed to allocate memory " + "for result string"); + + for (ql = BUNlast(left), pl = BUNfirst(left), pr = BUNfirst(right); pl < ql; pl++, pr++) { + vall = (char *)BUNtail(bil, pl); + valr = (char *)BUNtail(bir, pr); + valsize = strlen(vall) + strlen(valr); + + if (valsize >= valcsize) { + GDKfree(valc); + valcsize = valsize + 24; /* allocate some extra for the future */ + valc = GDKmalloc(valcsize); + if (valc == NULL) { + BBPunfix(b->batCacheid); + throw(MAL, "jaql.batconcat", "failed to allocate memory " + "for result string"); + } + } + snprintf(valc, valcsize, "%s%s", vall, valr); + BUNins(b, BUNhead(bil, pl), valc, FALSE); + } + GDKfree(valc); + + BBPkeepref(b->batCacheid); + *ret = b->batCacheid; + return MAL_SUCCEED; +} diff --git a/monetdb5/extras/jaql/jaql.h b/monetdb5/extras/jaql/jaql.h --- a/monetdb5/extras/jaql/jaql.h +++ b/monetdb5/extras/jaql/jaql.h @@ -42,6 +42,7 @@ jaql_export str JAQLexecute(Client cntxt jaql_export str JAQLgetVar(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); jaql_export str JAQLsetVar(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); jaql_export str JAQLcast(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); +jaql_export str JAQLbatconcat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); #endif diff --git a/monetdb5/extras/jaql/jaql.mal b/monetdb5/extras/jaql/jaql.mal --- a/monetdb5/extras/jaql/jaql.mal +++ b/monetdb5/extras/jaql/jaql.mal @@ -37,6 +37,10 @@ pattern cast(b:bat[:oid,:any], t:any_1): address JAQLcast comment "Return BAT b as BAT with tail type of t, if the BAT tail in reality is of that type"; +pattern batconcat(l:bat[:oid,:str], r:bat[:oid,:str]):bat[:oid,:str] +address JAQLbatconcat +comment "Return the string concatenation of the tails of both input BATs"; + # scenario functions and init call command prelude() address JAQLprelude; diff --git a/monetdb5/extras/jaql/jaqlfunc.mal b/monetdb5/extras/jaql/jaqlfunc.mal --- a/monetdb5/extras/jaql/jaqlfunc.mal +++ b/monetdb5/extras/jaql/jaqlfunc.mal @@ -305,6 +305,8 @@ function count(v:bat[:oid,:any]):bat[:oi return r; end count; +# generates a continuous array of numbers +# http://code.google.com/p/jaql/wiki/Builtin_functions#range() function range(start:bat[:oid,:lng], vend:bat[:oid,:lng], skip:bat[:oid,:lng]):bat[:oid,:lng]; ret := bat.new(:oid,:lng); barrier (h,t) := iterator.new(start); @@ -321,13 +323,11 @@ function range(start:bat[:oid,:lng], ven exit (h,t); return ret; end range; - function range(start:bat[:oid,:lng], vend:bat[:oid,:lng]):bat[:oid,:lng]; step := algebra.project(start, 1:lng); ret := jaqlfunc.range(start, vend, step); return ret; end range; - function range(size:bat[:oid,:lng]):bat[:oid,:lng]; start := algebra.project(size, 0:lng); vend := batcalc.-(size,1); diff --git a/monetdb5/extras/jaql/jaqlgencode.c b/monetdb5/extras/jaql/jaqlgencode.c --- a/monetdb5/extras/jaql/jaqlgencode.c +++ b/monetdb5/extras/jaql/jaqlgencode.c @@ -2877,7 +2877,7 @@ dumpvariabletransformation(jc *j, Client case j_operation: { int r, s; int u = -1, v; - int h, i, k = -1, l = -1, m; + int h, i, k = -1, l = -1, m, n = -1; InstrPtr p; b = c = -1; switch (t->tval1->type) { @@ -2885,6 +2885,7 @@ dumpvariabletransformation(jc *j, Client case j_operation: case j_num: case j_dbl: + case j_str: b = dumpvariabletransformation(j, cntxt, mb, t->tval1, elems); q = newInstruction(mb, ASSIGNsymbol); @@ -2912,6 +2913,7 @@ dumpvariabletransformation(jc *j, Client switch (t->tval3->type) { case j_var: case j_operation: + case j_str: c = dumpvariabletransformation(j, cntxt, mb, t->tval3, elems); q = newInstruction(mb, ASSIGNsymbol); @@ -3055,6 +3057,131 @@ dumpvariabletransformation(jc *j, Client v = f; } + if (t->tval2->cval == j_plus && c != -1) { + int s1, s2, s3, s4, s5; + /* special case for string concatenations, jaql performs + * implicit concat on str/str additions only */ + q = newInstruction(mb, ASSIGNsymbol); + setModuleId(q, algebraRef); + setFunctionId(q, semijoinRef); + q = pushReturn(mb, q, newTmpVariable(mb, TYPE_any)); + q = pushArgument(mb, q, j->j2); + q = pushArgument(mb, q, b); + s1 = getArg(q, 0); + pushInstruction(mb, q); + q = newInstruction(mb, ASSIGNsymbol); + setModuleId(q, algebraRef); + setFunctionId(q, semijoinRef); + q = pushReturn(mb, q, newTmpVariable(mb, TYPE_any)); + q = pushArgument(mb, q, j->j2); + q = pushArgument(mb, q, c); + s2 = getArg(q, 0); _______________________________________________ checkin-list mailing list checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list