str MRgetCloud(int *ret, str *mrcluster) { str msg; BAT *cloud; BUN p, q; BATiter bi; char nodes[BUFSIZ]; char *n = nodes; int mapcount = 0; snprintf(nodes, sizeof(nodes), "*/%s/node/*", *mrcluster); if ((msg = RMTresolve(ret, &n)) != MAL_SUCCEED) return msg; MT_lock_set(&mal_contextLock, "mapreduce"); cloud = BATdescriptor(*ret); /* should succeed */ mapnodes = (mapnode*)GDKzalloc(sizeof(mapnode) * (BATcount(cloud) + 1)); if (mapnodes == NULL) { BBPreleaseref(*ret); throw(MAL, "mapreduce.getCloud", MAL_MALLOC_FAIL); } bi = bat_iterator(cloud); BATloop(cloud, p, q) { str t = (str)BUNtail(bi, p); mapnodes[mapcount].uri = GDKstrdup(t); mapnodes[mapcount].user = GDKstrdup("monetdb"); mapnodes[mapcount].pass = GDKstrdup("monetdb"); mapcount++; }
str batstr_2time_timestamptz(bat *res, const bat *bid, const int *digits, int *tz) { BAT *b, *dst; BATiter bi; BUN p, q; char *msg = NULL; if ((b = BATdescriptor(*bid)) == NULL) { throw(SQL, "batcalc.str_2time_timestamp", "Cannot access descriptor"); } bi = bat_iterator(b); dst = BATnew(TYPE_void, TYPE_timestamp, BATcount(b), TRANSIENT); if (dst == NULL) { BBPunfix(b->batCacheid); throw(SQL, "sql.timestamp", MAL_MALLOC_FAIL); } BATseqbase(dst, b->hseqbase); BATloop(b, p, q) { char *v = (char *) BUNtail(bi, p); union { lng l; timestamp r; } u; msg = str_2time_timestamptz(&u.r, &v, digits, tz); if (msg) { BBPunfix(dst->batCacheid); BBPunfix(b->batCacheid); return msg; } BUNappend(dst, &u.r, FALSE); }
static str do_batstr_int(bat *ret, const bat *l, const char *name, str (*func)(int *, const str *)) { BATiter bi; BAT *bn, *b; BUN p, q; str x; int y; str msg = MAL_SUCCEED; prepareOperand(b, l, name); prepareResult(bn, b, TYPE_int, name); bi = bat_iterator(b); BATloop(b, p, q) { x = (str) BUNtail(bi, p); if (x == 0 || strcmp(x, str_nil) == 0) { y = int_nil; bn->tnonil = 0; bn->tnil = 1; } else if ((msg = (*func)(&y, &x)) != MAL_SUCCEED) { goto bunins_failed; } bunfastapp(bn, &y); }
static void * column_find_value(sql_trans *tr, sql_column *c, oid rid) { BUN q; BAT *b, *d = NULL; void *res = NULL; sql_dbat *bat = c->t->data; if (bat->dbid) d = store_funcs.bind_del(tr, c->t, RDONLY); b = full_column(c, d, NULL); if (d) bat_destroy(d); q = BUNfnd(b, (ptr) &rid); if (q != BUN_NONE) { BATiter bi = bat_iterator(b); void *r; int sz; res = BUNtail(bi, q); sz = ATOMlen(b->ttype, res); r = GDKzalloc(sz); memcpy(r,res,sz); res = r; } bat_destroy(b); return res; }
str BATXMLxml2str(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.str", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_str, "str", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); if (strNil(t)) { bunfastapp(bn, t); bn->T->nonil = 0; } else { assert(*t == 'A' || *t == 'C' || *t == 'D'); bunfastapp(bn, t + 1); } } finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.str", OPERATION_FAILED " during bulk coercion"); }
str ITRbunNext(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { BATiter bi; BAT *b; oid *head; bat *bid; ValPtr tail; (void) cntxt; (void) mb; head = (oid *) getArgReference(stk, pci, 0); tail = getArgReference(stk,pci,1); bid = (bat *) getArgReference(stk, pci, 2); if ((b = BATdescriptor(*bid)) == NULL) { throw(MAL, "iterator.nextChunk", INTERNAL_BAT_ACCESS); } *head = (BUN)*head + 1; if (*head >= BUNlast(b)) { *head = oid_nil; BBPunfix(b->batCacheid); return MAL_SUCCEED; } bi = bat_iterator(b); VALinit(tail, b->ttype, BUNtail(bi, *(BUN*) head)); BBPunfix(b->batCacheid); return MAL_SUCCEED; }
static BAT * MATproject_any( BAT *map, BAT **bats, int len ) { BAT *res; int i; BUN j, cnt = BATcount(map); BATiter *bats_i; BUN *batsT; bte *mapT; res = BATnew(TYPE_void, bats[0]->ttype, cnt, TRANSIENT); batsT = (BUN*)GDKmalloc(sizeof(BUN) * len); bats_i = (BATiter*)GDKmalloc(sizeof(BATiter) * len); if (res == NULL || batsT == NULL || bats_i == NULL) { if (res) BBPreclaim(res); if (batsT) GDKfree(batsT); if (bats_i) GDKfree(bats_i); return NULL; } BATseqbase(res, map->hseqbase); mapT = (bte*)Tloc(map, 0); for (i=0; i<len; i++) { batsT[i] = 0; bats_i[i] = bat_iterator(bats[i]); } for (j=0; j<cnt; j++) BUNappend(res, BUNtail(bats_i[mapT[j]], batsT[mapT[j]]++), FALSE); GDKfree(batsT); GDKfree(bats_i); return res; }
static str gsl_bat_chisqprob_cst(bat * retval, bat chi2, dbl datapoints) { BAT *b, *bn; BATiter bi; BUN p,q; dbl r; char *msg = NULL; if (datapoints == dbl_nil) { throw(MAL, "GSLbat_chisqprob_cst", "Parameter datapoints should not be nil"); } if (datapoints < 0) throw(MAL, "gsl.chi2prob", "Wrong value for datapoints"); if ((b = BATdescriptor(chi2)) == NULL) { throw(MAL, "chisqprob", "Cannot access descriptor"); } bi = bat_iterator(b); bn = BATnew(TYPE_void, TYPE_dbl, BATcount(b), TRANSIENT); if (bn == NULL){ BBPunfix(b->batCacheid); throw(MAL, "gsl.chisqprob", MAL_MALLOC_FAIL); } BATseqbase(bn, b->hseqbase); BATloop(b,p,q) { dbl d = *(dbl*)BUNtail(bi,p); if ((d == dbl_nil) || (d < 0)) throw(MAL, "gsl.chi2prob", "Wrong value for chi2"); r = gsl_cdf_chisq_Q(d, datapoints); BUNappend(bn, &r, FALSE); }
static void * column_find_value(sql_trans *tr, sql_column *c, oid rid) { BUN q = BUN_NONE; BAT *b; void *res = NULL; b = full_column(tr, c); if (b) { if (rid < b->hseqbase || rid >= b->hseqbase + BATcount(b)) q = BUN_NONE; else q = rid - b->hseqbase; } if (q != BUN_NONE) { BATiter bi = bat_iterator(b); const void *r; size_t sz; r = BUNtail(bi, q); sz = ATOMlen(b->ttype, r); res = GDKmalloc(sz); if (res) memcpy(res, r, sz); } full_destroy(c, b); return res; }
/* * @- * The BUN- and BAT-stream manipulate a long handle, i.e. * the destination variable. It assumes it has been set to * zero as part of runtime stack initialization. Subsequently, * it fetches a bun and returns the increment to the control * variable. If it returns zero the control variable has been reset * to zero and end of stream has been reached. */ str ITRbunIterator(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { BATiter bi; BAT *b; oid *head; bat *bid; ValPtr tail; (void) cntxt; (void) mb; head = getArgReference_oid(stk, pci, 0); tail = &stk->stk[pci->argv[1]]; bid = getArgReference_bat(stk, pci, 2); if ((b = BATdescriptor(*bid)) == NULL) { throw(MAL, "iterator.nextChunk", INTERNAL_BAT_ACCESS); } if (BATcount(b) == 0) { *head = oid_nil; BBPunfix(b->batCacheid); return MAL_SUCCEED; } *head = BUNfirst(b); bi = bat_iterator(b); VALinit(tail, b->ttype, BUNtail(bi, *(BUN*) head)); BBPunfix(b->batCacheid); return MAL_SUCCEED; }
/** * Function returns the highest file id that currently exists in the * bam.files table and stores this number + 1 in the next_file_id * variable. Function doesn't use a mutex to guarantee that the * returned value is up to date at return time. If this is required, * the calling function should activate a mutex. */ str next_file_id(mvc * m, sql_table * files, lng * next_file_id) { sql_column *c; BAT *b = NULL; BATiter li; BUN p = 0, q = 0; lng max_file_id = 0; sht i; assert(m != NULL); assert(files != NULL); /* Try to bind the file_id column of the bam.files table */ if ((c = mvc_bind_column(m, files, "file_id")) == NULL) { throw(MAL, "next_file_id", "Could not retrieve the next file id: Error binding file_id column of 'files' table"); } /* Loop through BATs for this column and find the maximum file_id */ for(i=0; i<3; ++i) { b = store_funcs.bind_col(m->session->tr, c, i); li = bat_iterator(b); BATloop(b, p, q) { lng t = *(lng *) BUNtail(li, p); max_file_id = MAX(max_file_id, t); } BBPunfix(b->batCacheid); }
str BATXMLdocument(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; size_t size = BUFSIZ; str buf = GDKmalloc(size); const char *err = OPERATION_FAILED; if (buf == NULL) throw(MAL,"xml.document",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.document", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "document", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); xmlDocPtr doc; int len; xmlChar *s; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = (int) strlen(t); doc = xmlParseMemory(t, len); if (doc == NULL) { err = OPERATION_FAILED XML_PARSE_ERROR; goto bunins_failed; } xmlDocDumpMemory(doc, &s, &len); xmlFreeDoc(doc); if ((size_t) len + 2 >= size) { GDKfree(buf); size = (size_t) len + 128; buf = GDKmalloc(size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'D'; strcpy(buf + 1, (char *) s); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: GDKfree(buf); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.document", "%s", err); }
str BATXMLcomment(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf = GDKmalloc(size); BATiter bi; const char *err= OPERATION_FAILED; if (buf == NULL) throw(MAL, "xml.comment", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.comment", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "comment", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } if (strstr(t, "--") != NULL) { err = XML_COMMENT_ERROR; goto bunins_failed; } len = strlen(t); if (len + 9 >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } snprintf(buf, size, "C<!--%s-->", t); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.comment", "%s", err); }
/* actual implementation */ static char * UDFBATreverse_(BAT **ret, BAT *src) { BATiter li; BAT *bn = NULL; BUN p = 0, q = 0; /* assert calling sanity */ assert(ret != NULL); /* handle NULL pointer */ if (src == NULL) throw(MAL, "batudf.reverse", RUNTIME_OBJECT_MISSING); /* check tail type */ if (src->ttype != TYPE_str) { throw(MAL, "batudf.reverse", "tail-type of input BAT must be TYPE_str"); } /* allocate result BAT */ bn = BATnew(src->htype, TYPE_str, BATcount(src)); if (bn == NULL) { throw(MAL, "batudf.reverse", MAL_MALLOC_FAIL); } BATseqbase(bn, src->hseqbase); /* create BAT iterator */ li = bat_iterator(src); /* the core of the algorithm, expensive due to malloc/frees */ BATloop(src, p, q) { char *tr = NULL, *err = NULL; /* get original head & tail value */ ptr h = BUNhead(li, p); const char *t = (const char *) BUNtail(li, p); /* revert tail value */ err = UDFreverse_(&tr, t); if (err != MAL_SUCCEED) { /* error -> bail out */ BBPreleaseref(bn->batCacheid); return err; } /* assert logical sanity */ assert(tr != NULL); /* insert original head and reversed tail in result BAT */ /* BUNins() takes care of all necessary administration */ BUNins(bn, h, tr, FALSE); /* free memory allocated in UDFreverse_() */ GDKfree(tr); }
char * GDKgetenv(const char *name) { BUN b = BUNfnd(BATmirror(GDKkey), (ptr) name); if (b != BUN_NONE) { BATiter GDKenvi = bat_iterator(GDKval); return BUNtail(GDKenvi, b); } return NULL; }
/* * The core of the activity is str2xml, where the actual strings * are constructed. * To avoid repetitive copying we make sure that the garbage * collector does not remove the xml intermediates. * This way, we know that as long as the xml-variables are not * reused, the complete structure of the xml document(s) are available. * We merely have to collect the pieces. * [FOR LATER, FIRST GO FOR THE EASY IMPLEMENTATION] * XML values are represented by strings already. */ str BATXMLstr2xml(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; const char *err= OPERATION_FAILED; BATiter bi; buf = GDKmalloc(size); if (buf == NULL) throw(MAL,"xml.str2xml",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.xml", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "xml", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = strlen(t) * 6 + 1; if (size < len) { size = len + 128; GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'C'; XMLquotestring(t, buf + 1, size - 1); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.xml", "%s", err); }
BUN append_inserted(BAT *b, BAT *i ) { BUN nr = 0, r; BATiter ii = bat_iterator(i); for (r = i->batInserted; r < BUNlast(i); r++) { BUNappend(b, BUNtail(ii,r), TRUE); nr++; } return nr; }
str BATXMLgroup(xml *ret, const bat *bid) { BAT *b; BUN p, q; const char *t; size_t len, size = BUFSIZ, offset; str buf = GDKmalloc(size); BATiter bi; const char *err = NULL; if (buf == NULL) throw(MAL, "xml.aggr",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.aggr", RUNTIME_OBJECT_MISSING); } strcpy(buf, str_nil); offset = 0; bi = bat_iterator(b); BATloop(b, p, q) { int n; t = (const char *) BUNtail(bi, p); if (strNil(t)) continue; len = strlen(t) + 1; if (len >= size - offset) { size += len + 128; buf = GDKrealloc(buf, size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto failed; } } if (offset == 0) n = snprintf(buf, size, "%s", t); else if (buf[0] != *t) { err = "incompatible values in group"; goto failed; } else if (buf[0] == 'A') n = snprintf(buf + offset, size - offset, " %s", t + 1); else if (buf[0] == 'C') n = snprintf(buf + offset, size - offset, "%s", t + 1); else { err = "can only group attributes and element content"; goto failed; } offset += n; }
BUN copy_inserted(BAT *b, BAT *i ) { BUN nr = 0; BUN r; BATiter ii = bat_iterator(i); for (r = i->batInserted; r < BUNlast(i); r++) { BUNins(b, BUNhead(ii,r), BUNtail(ii,r), TRUE); nr++; } return nr; }
static int bat_max_strlength(BAT *b) { BUN p, q; int l = 0; int max = 0; BATiter bi = bat_iterator(b); BATloop(b, p, q) { str v = (str) BUNtail(bi, p); strLength(&l, v); if (l == int_nil) l = 0; if (l > max) max = l; }
static oid column_find_row(sql_trans *tr, sql_column *c, void *value, ...) { va_list va; BUN q; BAT *b = NULL, *s = NULL, *r = NULL, *d = NULL; oid rid = oid_nil; sql_column *nc; void *nv; sql_dbat *bat = c->t->data; if (bat->dbid) d = store_funcs.bind_del(tr, c->t, RDONLY); va_start(va, value); while ((nc = va_arg(va, sql_column *)) != NULL) { nv = va_arg(va, void *); b = full_column(c, d, s); if (s) bat_destroy(s); s = BATselect(b, value, value); bat_destroy(b); c = nc; value = nv; } va_end(va); b = full_column(c, d, s); if (s) bat_destroy(s); if (d) bat_destroy(d); r = BATmirror(b); q = BUNfnd(r, value); if (q != BUN_NONE) { BATiter ri = bat_iterator(r); rid = *(oid *) BUNtail(ri, q); } bat_destroy(b); return rid; }
static str JSONrenderRowObject(BAT **bl, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, BUN idx) { int i, tpe; char *row, *name = 0, *val = 0; size_t len, lim, l; void *p; BATiter bi; row = (char *) GDKmalloc(lim = BUFSIZ); row[0] = '{'; row[1] = 0; len = 1; val = (char *) GDKmalloc(BUFSIZ); for (i = pci->retc; i < pci->argc; i += 2) { name = stk->stk[getArg(pci, i)].val.sval; bi = bat_iterator(bl[i + 1]); p = BUNtail(bi, BUNfirst(bl[i + 1]) + idx); tpe = getColumnType(getArgType(mb, pci, i + 1)); ATOMformat(tpe, p, &val); if (strncmp(val, "nil", 3) == 0) strcpy(val, "null"); l = strlen(name) + strlen(val); while (l > lim - len) row = (char *) GDKrealloc(row, lim += BUFSIZ); snprintf(row + len, lim - len, "\"%s\":%s,", name, val); len += l + 4; } if (row[1]) row[len - 1] = '}'; else { row[1] = '}'; row[2] = 0; } GDKfree(val); return row; }
str BATXMLisdocument(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.isdocument", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_bit, "isdocument", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); xmlDocPtr doc; bit val; if (strNil(t)) { val = bit_nil; bn->T->nonil = 0; } else { doc = xmlParseMemory(t, (int) strlen(t)); if (doc == NULL) { val = 0; } else { xmlFreeDoc(doc); val = 1; } } bunfastapp(bn, &val); } finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.isdocument", OPERATION_FAILED " During bulk processing"); }
gdk_return TMsubcommit(BAT *b) { int cnt = 1; gdk_return ret = GDK_FAIL; bat *subcommit; BUN p, q; BATiter bi = bat_iterator(b); subcommit = (bat *) GDKmalloc((BATcount(b) + 1) * sizeof(bat)); if (subcommit == NULL) return GDK_FAIL; subcommit[0] = 0; /* BBP artifact: slot 0 in the array will be ignored */ /* collect the list and save the new bats outside any * locking */ BATloop(b, p, q) { bat bid = BBPindex((str) BUNtail(bi, p)); if (bid < 0) bid = -bid; if (bid) subcommit[cnt++] = bid; }
static str JSONrenderRowArray(BAT **bl, MalBlkPtr mb, InstrPtr pci, BUN idx) { int i, tpe; char *row, *val = 0; size_t len, lim, l; void *p; BATiter bi; row = (char *) GDKmalloc(lim = BUFSIZ); row[0] = '['; row[1] = 0; len = 1; val = (char *) GDKmalloc(BUFSIZ); for (i = pci->retc; i < pci->argc; i++) { bi = bat_iterator(bl[i]); p = BUNtail(bi, BUNfirst(bl[i]) + idx); tpe = getColumnType(getArgType(mb, pci, i)); ATOMformat(tpe, p, &val); if (strncmp(val, "nil", 3) == 0) strcpy(val, "null"); l = strlen(val); while (l > lim - len) row = (char *) GDKrealloc(row, lim += BUFSIZ); snprintf(row + len, lim - len, "%s,", val); len += l + 1; } if (row[1]) row[len - 1] = ']'; else { row[1] = '}'; row[2] = 0; } GDKfree(val); return row; }
str RAPIeval(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, bit grouped) { sql_func * sqlfun = NULL; str exprStr = *getArgReference_str(stk, pci, pci->retc + 1); SEXP x, env, retval; SEXP varname = R_NilValue; SEXP varvalue = R_NilValue; ParseStatus status; int i = 0; char argbuf[64]; char *argnames = NULL; size_t argnameslen; size_t pos; char* rcall = NULL; size_t rcalllen; int ret_cols = 0; /* int because pci->retc is int, too*/ str *args; int evalErr; char *msg = MAL_SUCCEED; BAT *b; node * argnode; int seengrp = FALSE; rapiClient = cntxt; if (!RAPIEnabled()) { throw(MAL, "rapi.eval", "Embedded R has not been enabled. Start server with --set %s=true", rapi_enableflag); } if (!rapiInitialized) { throw(MAL, "rapi.eval", "Embedded R initialization has failed"); } if (!grouped) { sql_subfunc *sqlmorefun = (*(sql_subfunc**) getArgReference(stk, pci, pci->retc)); if (sqlmorefun) sqlfun = (*(sql_subfunc**) getArgReference(stk, pci, pci->retc))->func; } else { sqlfun = *(sql_func**) getArgReference(stk, pci, pci->retc); } args = (str*) GDKzalloc(sizeof(str) * pci->argc); if (args == NULL) { throw(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); } // get the lock even before initialization of the R interpreter, as this can take a second and must be done only once. MT_lock_set(&rapiLock); env = PROTECT(eval(lang1(install("new.env")), R_GlobalEnv)); assert(env != NULL); // first argument after the return contains the pointer to the sql_func structure // NEW macro temporarily renamed to MNEW to allow including sql_catalog.h if (sqlfun != NULL && sqlfun->ops->cnt > 0) { int carg = pci->retc + 2; argnode = sqlfun->ops->h; while (argnode) { char* argname = ((sql_arg*) argnode->data)->name; args[carg] = GDKstrdup(argname); carg++; argnode = argnode->next; } } // the first unknown argument is the group, we don't really care for the rest. argnameslen = 2; for (i = pci->retc + 2; i < pci->argc; i++) { if (args[i] == NULL) { if (!seengrp && grouped) { args[i] = GDKstrdup("aggr_group"); seengrp = TRUE; } else { snprintf(argbuf, sizeof(argbuf), "arg%i", i - pci->retc - 1); args[i] = GDKstrdup(argbuf); } } argnameslen += strlen(args[i]) + 2; /* extra for ", " */ } // install the MAL variables into the R environment // we can basically map values to int ("INTEGER") or double ("REAL") for (i = pci->retc + 2; i < pci->argc; i++) { int bat_type = getBatType(getArgType(mb,pci,i)); // check for BAT or scalar first, keep code left if (!isaBatType(getArgType(mb,pci,i))) { b = COLnew(0, getArgType(mb, pci, i), 0, TRANSIENT); if (b == NULL) { msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } if ( getArgType(mb,pci,i) == TYPE_str) { if (BUNappend(b, *getArgReference_str(stk, pci, i), false) != GDK_SUCCEED) { BBPreclaim(b); b = NULL; msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } } else { if (BUNappend(b, getArgReference(stk, pci, i), false) != GDK_SUCCEED) { BBPreclaim(b); b = NULL; msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } } } else { b = BATdescriptor(*getArgReference_bat(stk, pci, i)); if (b == NULL) { msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } } // check the BAT count, if it is bigger than RAPI_MAX_TUPLES, fail if (BATcount(b) > RAPI_MAX_TUPLES) { msg = createException(MAL, "rapi.eval", "Got "BUNFMT" rows, but can only handle "LLFMT". Sorry.", BATcount(b), (lng) RAPI_MAX_TUPLES); BBPunfix(b->batCacheid); goto wrapup; } varname = PROTECT(Rf_install(args[i])); varvalue = bat_to_sexp(b, bat_type); if (varvalue == NULL) { msg = createException(MAL, "rapi.eval", "unknown argument type "); goto wrapup; } BBPunfix(b->batCacheid); // install vector into R environment Rf_defineVar(varname, varvalue, env); UNPROTECT(2); } /* we are going to evaluate the user function within an anonymous function call: * ret <- (function(arg1){return(arg1*2)})(42) * the user code is put inside the {}, this keeps our environment clean (TM) and gives * a clear path for return values, namely using the builtin return() function * this is also compatible with PL/R */ pos = 0; argnames = malloc(argnameslen); if (argnames == NULL) { msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } argnames[0] = '\0'; for (i = pci->retc + 2; i < pci->argc; i++) { pos += snprintf(argnames + pos, argnameslen - pos, "%s%s", args[i], i < pci->argc - 1 ? ", " : ""); } rcalllen = 2 * pos + strlen(exprStr) + 100; rcall = malloc(rcalllen); if (rcall == NULL) { msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } snprintf(rcall, rcalllen, "ret <- as.data.frame((function(%s){%s})(%s), nm=NA, stringsAsFactors=F)\n", argnames, exprStr, argnames); free(argnames); argnames = NULL; #ifdef _RAPI_DEBUG_ printf("# R call %s\n",rcall); #endif x = R_ParseVector(mkString(rcall), 1, &status, R_NilValue); if (LENGTH(x) != 1 || status != PARSE_OK) { msg = createException(MAL, "rapi.eval", "Error parsing R expression '%s'. ", exprStr); goto wrapup; } retval = R_tryEval(VECTOR_ELT(x, 0), env, &evalErr); if (evalErr != FALSE) { char* errormsg = strdup(R_curErrorBuf()); size_t c; if (errormsg == NULL) { msg = createException(MAL, "rapi.eval", "Error running R expression."); goto wrapup; } // remove newlines from error message so it fits into a MAPI error (lol) for (c = 0; c < strlen(errormsg); c++) { if (errormsg[c] == '\r' || errormsg[c] == '\n') { errormsg[c] = ' '; } } msg = createException(MAL, "rapi.eval", "Error running R expression: %s", errormsg); free(errormsg); goto wrapup; } // ret should be a data frame with exactly as many columns as we need from retc ret_cols = LENGTH(retval); if (ret_cols != pci->retc) { msg = createException(MAL, "rapi.eval", "Expected result of %d columns, got %d", pci->retc, ret_cols); goto wrapup; } // collect the return values for (i = 0; i < pci->retc; i++) { SEXP ret_col = VECTOR_ELT(retval, i); int bat_type = getBatType(getArgType(mb,pci,i)); if (bat_type == TYPE_any || bat_type == TYPE_void) { getArgType(mb,pci,i) = bat_type; msg = createException(MAL, "rapi.eval", "Unknown return value, possibly projecting with no parameters."); goto wrapup; } // hand over the vector into a BAT b = sexp_to_bat(ret_col, bat_type); if (b == NULL) { msg = createException(MAL, "rapi.eval", "Failed to convert column %i", i); goto wrapup; } // bat return if (isaBatType(getArgType(mb,pci,i))) { *getArgReference_bat(stk, pci, i) = b->batCacheid; } else { // single value return, only for non-grouped aggregations BATiter li = bat_iterator(b); if (VALinit(&stk->stk[pci->argv[i]], bat_type, BUNtail(li, 0)) == NULL) { // TODO BUNtail here msg = createException(MAL, "rapi.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } } msg = MAL_SUCCEED; } /* unprotect environment, so it will be eaten by the GC. */ UNPROTECT(1); wrapup: MT_lock_unset(&rapiLock); if (argnames) free(argnames); if (rcall) free(rcall); for (i = 0; i < pci->argc; i++) GDKfree(args[i]); GDKfree(args); return msg; }
str MKEYbathash(bat *res, const bat *bid) { BAT *b, *dst; wrd *r; BUN n; if ((b = BATdescriptor(*bid)) == NULL) throw(SQL, "mkey.bathash", RUNTIME_OBJECT_MISSING); assert(BAThvoid(b) || BAThrestricted(b)); n = BATcount(b); dst = BATnew(TYPE_void, TYPE_wrd, n, TRANSIENT); if (dst == NULL) { BBPunfix(b->batCacheid); throw(SQL, "mkey.bathash", MAL_MALLOC_FAIL); } BATseqbase(dst, b->hseqbase); BATsetcount(dst, n); r = (wrd *) Tloc(dst, BUNfirst(dst)); switch (ATOMstorage(b->ttype)) { case TYPE_void: { oid o = b->tseqbase; if (o == oid_nil) while (n-- > 0) *r++ = wrd_nil; else while (n-- > 0) *r++ = (wrd) o++; break; } case TYPE_bte: { bte *v = (bte *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_bte(v); v++; } break; } case TYPE_sht: { sht *v = (sht *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_sht(v); v++; } break; } case TYPE_int: case TYPE_flt: { int *v = (int *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_int(v); v++; } break; } case TYPE_lng: case TYPE_dbl: { lng *v = (lng *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_lng(v); v++; } break; } #ifdef HAVE_HGE case TYPE_hge: { hge *v = (hge *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_hge(v); v++; } break; } #endif default: { BATiter bi = bat_iterator(b); BUN (*hash)(const void *) = BATatoms[b->ttype].atomHash; int (*cmp)(const void *, const void *) = ATOMcompare(b->ttype); void *nil = ATOMnilptr(b->ttype); BUN i; const void *v; BATloop(b, i, n) { v = BUNtail(bi, i); if ((*cmp)(v, nil) == 0) *r++ = wrd_nil; else *r++ = (wrd) (*hash)(v); } break; } }
static BAT* MATsortloop_( bte *map_res, BAT *i1, bte *map_i1, BUN cnt_i1, BAT *i2, bte map_i2, BUN cnt_i2) { int c; BUN val_i1 = BUNfirst(i1); BUN val_i2 = BUNfirst(i2); BUN end_i1 = val_i1 + cnt_i1; BUN end_i2 = val_i2 + cnt_i2; BATiter bi_i1 = bat_iterator(i1); BATiter bi_i2 = bat_iterator(i2); int (*cmp) (const void *, const void *) = BATatoms[i1->ttype].atomCmp; BAT *res = BATnew(TYPE_void, i1->ttype, cnt_i1 + cnt_i2, TRANSIENT); if (res == NULL) return NULL; BATseqbase(res, 0); if (map_i1 == NULL) { /* map_i1 = 0 */ while ( val_i1 < end_i1 && val_i2 < end_i2) { if ((c = cmp(BUNtail(bi_i1,val_i1),BUNtail(bi_i2,val_i2))) <= 0) { BUNappend(res, BUNtail(bi_i1,val_i1), FALSE); *map_res++ = 0; val_i1++; } else if (c > 0) { BUNappend(res, BUNtail(bi_i2,val_i2), FALSE); *map_res++ = map_i2; val_i2++; } } while ( val_i1 < end_i1 ) { BUNappend(res, BUNtail(bi_i1,val_i1), FALSE); *map_res++ = 0; val_i1++; } } else { while ( val_i1 < end_i1 && val_i2 < end_i2) { if ((c = cmp(BUNtail(bi_i1,val_i1),BUNtail(bi_i2,val_i2))) <= 0) { BUNappend(res, BUNtail(bi_i1,val_i1), FALSE); *map_res++ = *map_i1++; val_i1++; } else if (c > 0) { BUNappend(res, BUNtail(bi_i2,val_i2), FALSE); *map_res++ = map_i2; val_i2++; } } while ( val_i1 < end_i1 ) { BUNappend(res, BUNtail(bi_i1,val_i1), FALSE); *map_res++ = *map_i1++; val_i1++; } } while ( val_i2 < end_i2 ) { BUNappend(res, BUNtail(bi_i2,val_i2), FALSE); *map_res++ = map_i2; val_i2++; } return res; }
str BATXMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { bat *ret = getArgReference_bat(stk, pci, 0); BAT *bn; BATiter *bi; BUN *p, *q; str buf; int i; size_t offset, len, size = BUFSIZ; const char *err = OPERATION_FAILED; (void) mb; (void) cntxt; buf = GDKmalloc(size); bi = GDKmalloc(sizeof(BATiter) * pci->argc); p = GDKmalloc(sizeof(BUN) * pci->argc); q = GDKmalloc(sizeof(BUN) * pci->argc); if (buf == NULL || bi == NULL || p == NULL || q == NULL) { if (buf) GDKfree(buf); if (bi) GDKfree(bi); if (p) GDKfree(p); if (q) GDKfree(q); throw(MAL, "xml.forest", MAL_MALLOC_FAIL); } /* collect the admin for the xml elements */ for (i = pci->retc; i < pci->argc; i++) { if ((bi[i].b = BATdescriptor(*getArgReference_bat(stk, pci, i))) == NULL) break; p[i] = BUNfirst(bi[i].b); q[i] = BUNlast(bi[i].b); } /* check for errors */ if (i != pci->argc) { for (i--; i >= pci->retc; i--) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf); throw(MAL, "xml.forest", INTERNAL_BAT_ACCESS); } prepareResult(bn, bi[pci->retc].b, TYPE_xml, "forest", for (i = pci->retc; i < pci->argc; i++) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf)); while (p[pci->retc] < q[pci->retc]) { const char *t; /* fetch the elements */ offset = 0; strcpy(buf, str_nil); for (i = pci->retc; i < pci->argc; i++) { int n; t = (const char *) BUNtail(bi[i], p[i]); if (strNil(t)) continue; if ((len = strlen(t)) >= size - offset) { size += len + 128; buf = GDKrealloc(buf, size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (offset == 0) n = snprintf(buf, size, "%s", t); else if (buf[0] != *t) { err = "incompatible values in forest"; goto bunins_failed; } else if (buf[0] == 'A') n = snprintf(buf + offset, size - offset, " %s", t + 1); else if (buf[0] == 'C') n = snprintf(buf + offset, size - offset, "%s", t + 1); else { err = "can only combine attributes and element content"; goto bunins_failed; } offset += n; } bunfastapp(bn, buf); if (offset == 0) bn->T->nonil = 0; for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) p[i]++; } GDKfree(buf); finalizeResult(ret, bn, bi[pci->retc].b); GDKfree(bi); GDKfree(p); GDKfree(q); return MAL_SUCCEED; bunins_failed: for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); GDKfree(bi); GDKfree(p); GDKfree(q); throw(MAL, "xml.forest", "%s", err); }
str BATXMLelement(bat *ret, const char * const *name, xml *nspace, xml *attr, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t elemlen, namelen; const char *err = OPERATION_FAILED; if (strNil(*name)) throw(MAL, "xml.element", XML_NO_ELEMENT); if (xmlValidateName((xmlChar *) *name, 0) != 0) throw(MAL, "xml.element", XML_ATTRIBUTE_INVALID); if (nspace && !strNil(*nspace) && **nspace) throw(MAL, "xml.element", XML_NO_NAMESPACE); namelen = strlen(*name); elemlen = namelen + 5; if (nspace && !strNil(*nspace)) { if (**nspace != 'A') throw(MAL, "xml.element", XML_ILLEGAL_NAMESPACE); elemlen += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */ } if (attr && !strNil(*attr)) { if (**attr != 'A') throw(MAL, "xml.element", XML_ILLEGAL_ATTRIBUTE); elemlen += strlen(*attr); /* " " + attr (attr contains initial 'A' which is replaced by space) */ } buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.attribute", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.element", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "element", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = elemlen; if (!strNil(t)) { if (*t != 'C') { err = XML_ILLEGAL_CONTENT; goto bunins_failed; } len += strlen(t + 1) + namelen + 2; /* extra "<", ">", and name ("/" already counted) */ } if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t) && (!attr || strNil(*attr))) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { int i = snprintf(buf, size, "C<%s", *name); if (nspace && !strNil(*nspace)) i += snprintf(buf + i, size - i, " %s", *nspace + 1); if (attr && !strNil(*attr)) i += snprintf(buf + i, size - i, " %s", *attr + 1); if (!strNil(t)) i += snprintf(buf + i, size - i, ">%s</%s>", t + 1, *name); else i += snprintf(buf + i, size - i, "/>"); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.element", "%s", err); }