Пример #1
0
str
MDBgetStackFrameN(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
{
	int n;
	bat *ret = getArgReference_bat(s, p, 0);
	bat *ret2 = getArgReference_bat(s, p, 1);
	BAT *b = BATnew(TYPE_void, TYPE_str, 256, TRANSIENT);
	BAT *bn = BATnew(TYPE_void, TYPE_str, 256, TRANSIENT);
	
	if (b == 0 || bn == 0) {
		BBPreclaim(b);
		BBPreclaim(bn);
		throw(MAL, "mdb.getStackFrame", MAL_MALLOC_FAIL);
	}
	BATseqbase(b,0);
	BATseqbase(bn,0);

	n = *getArgReference_int(s, p, 2);
	if (n < 0 || n >= getStkDepth(s)){
		BBPunfix(b->batCacheid);
		throw(MAL, "mdb.getStackFrame", ILLEGAL_ARGUMENT " Illegal depth.");
	}
	pseudo(ret,b,"view","stk","frame");
	pseudo(ret2,bn,"view","stk","frameB");
	return MDBgetFrame(b, bn, cntxt, m, s, n);
}
Пример #2
0
str
CMDcalcavg(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	dbl avg;
	BUN vals;
	bat *bid;
	BAT *b, *s = NULL;
	gdk_return ret;

	(void) cntxt;
	(void) mb;

	bid = getArgReference_bat(stk, pci, pci->retc + 0);
	if ((b = BATdescriptor(*bid)) == NULL)
		throw(MAL, "aggr.avg", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	if (pci->retc == pci->retc + 2) {
		bat *sid = getArgReference_bat(stk, pci, pci->retc + 1);
		if (*sid && (s = BATdescriptor(*sid)) == NULL) {
			BBPunfix(b->batCacheid);
			throw(MAL, "aggr.avg", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
	}
	ret = BATcalcavg(b, s, &avg, &vals);
	BBPunfix(b->batCacheid);
	if (s)
		BBPunfix(s->batCacheid);
	if (ret != GDK_SUCCEED)
		return mythrow(MAL, "aggr.avg", OPERATION_FAILED);
	* getArgReference_dbl(stk, pci, 0) = avg;
	if (pci->retc == 2)
		* getArgReference_lng(stk, pci, 1) = vals;
	return MAL_SUCCEED;
}
Пример #3
0
static str
CMDconvertbat(MalStkPtr stk, InstrPtr pci, int tp, int abort_on_error)
{
	bat *bid;
	BAT *b, *bn, *s = NULL;

	bid = getArgReference_bat(stk, pci, 1);
	if ((b = BATdescriptor(*bid)) == NULL)
		throw(MAL, "batcalc.convert", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	if (pci->argc == 3) {
		bat *sid = getArgReference_bat(stk, pci, 2);
		if (*sid && (s = BATdescriptor(*sid)) == NULL) {
			BBPunfix(b->batCacheid);
			throw(MAL, "batcalc.convert", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
	}

	bn = BATconvert(b, s, tp, abort_on_error);
	BBPunfix(b->batCacheid);
	if (s)
		BBPunfix(s->batCacheid);
	if (bn == NULL) {
		char buf[20];
		snprintf(buf, sizeof(buf), "batcalc.%s", ATOMname(tp));
		return mythrow(MAL, buf, OPERATION_FAILED);
	}
	bid = getArgReference_bat(stk, pci, 0);
	BBPkeepref(*bid = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #4
0
static str
CMDbatUNARY1(MalStkPtr stk, InstrPtr pci, int abort_on_error,
			 BAT *(*batfunc)(BAT *, BAT *, int), const char *malfunc)
{
	bat *bid;
	BAT *bn, *b, *s = NULL;

	bid = getArgReference_bat(stk, pci, 1);
	if ((b = BATdescriptor(*bid)) == NULL)
		throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	if (pci->argc == 3) {
		bat *sid = getArgReference_bat(stk, pci, 2);
		if (*sid && (s = BATdescriptor(*sid)) == NULL) {
			BBPunfix(b->batCacheid);
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
	}

	bn = (*batfunc)(b, s, abort_on_error);
	BBPunfix(b->batCacheid);
	if (s)
		BBPunfix(s->batCacheid);
	if (bn == NULL) {
		return mythrow(MAL, malfunc, OPERATION_FAILED);
	}
	bid = getArgReference_bat(stk, pci, 0);
	BBPkeepref(*bid = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #5
0
str
GROUPmulticolumngroup(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	bat *grp = getArgReference_bat(stk, pci, 0);
	bat *ext = getArgReference_bat(stk, pci, 1);
	bat *hist = getArgReference_bat(stk, pci, 2);
	int i, j;
	bat oldgrp, oldext, oldhist;
	str msg = MAL_SUCCEED;
	BAT *b;
	BUN count = 0;
	AGGRtask *aggr;

	aggr = GROUPcollect(cntxt, mb, stk, pci);
	if( aggr == NULL)
		throw(MAL,"group.multicolumn", SQLSTATE(HY001) MAL_MALLOC_FAIL);
	GROUPcollectSort(aggr, 0, aggr->last);

	/* (grp,ext,hist) := group.group(..) */
	/* use the old pattern to perform the incremental grouping */
	*grp = 0;
	*ext = 0;
	*hist = 0;
	msg = GRPgroup1(grp, ext, hist, &aggr->bid[0]);
	i = 1;
	if (msg == MAL_SUCCEED && aggr->last > 1)
		do {
			/* early break when there are as many groups as entries */
			b = BATdescriptor(*hist);
			if (b) {
				j = BATcount(b) == count;
				BBPunfix(*hist);
				if (j)
					break;
			}

			/* (grp,ext,hist) := group.subgroup(arg,grp,ext,hist) */
			oldgrp = *grp;
			oldext = *ext;
			oldhist = *hist;
			*grp = 0;
			*ext = 0;
			*hist = 0;
			msg = GRPsubgroup5(grp, ext, hist, &aggr->bid[i], NULL, &oldgrp, &oldext, &oldhist);
			BBPrelease(oldgrp);
			BBPrelease(oldext);
			BBPrelease(oldhist);
		} while (msg == MAL_SUCCEED && ++i < aggr->last);
	GROUPdelete(aggr);
	return msg;
}
Пример #6
0
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 = 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);
	}

	*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;
}
Пример #7
0
str
db_password_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	(void) mb;

	if (stk->stk[pci->argv[0]].vtype == TYPE_bat) {
		BAT *b = BATdescriptor(*getArgReference_bat(stk, pci, 1));
		if (b == NULL)
			throw(SQL, "sql.password", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		BAT *bn = COLnew(b->hseqbase, TYPE_str, BATcount(b), TRANSIENT);
		if (bn == NULL) {
			BBPunfix(b->batCacheid);
			throw(SQL, "sql.password", SQLSTATE(HY001) MAL_MALLOC_FAIL);
		}
		BATiter bi = bat_iterator(b);
		BUN p, q;
		BATloop(b, p, q) {
			char *hash, *msg;
			msg = AUTHgetPasswordHash(&hash, cntxt, BUNtvar(bi, p));
			if (msg != MAL_SUCCEED) {
				BBPunfix(b->batCacheid);
				BBPreclaim(bn);
				return msg;
			}
			if (BUNappend(bn, hash, false) != GDK_SUCCEED) {
				BBPunfix(b->batCacheid);
				BBPreclaim(bn);
				throw(SQL, "sql.password", SQLSTATE(HY001) MAL_MALLOC_FAIL);
			}
			GDKfree(hash);
		}
Пример #8
0
str
MATpackValues(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
{
	int i, type, first = 1;
	bat *ret;
	BAT *bn;

	(void) cntxt;
	type = getArgType(mb,p,first);
	bn = BATnew(TYPE_void, type, p->argc, TRANSIENT);
	if( bn == NULL)
		throw(MAL, "mat.pack", MAL_MALLOC_FAIL);

	if (ATOMextern(type)) {
		for(i = first; i < p->argc; i++)
			BUNappend(bn, stk->stk[getArg(p,i)].val.pval, TRUE);
	} else {
		for(i = first; i < p->argc; i++)
			BUNappend(bn, getArgReference(stk, p, i), TRUE);
	}
	BATseqbase(bn, 0);
	ret= getArgReference_bat(stk,p,0);
	BBPkeepref(*ret = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #9
0
str
MDBgetStackFrame(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
{
	bat *ret = getArgReference_bat(s, p, 0);
	bat *ret2 = getArgReference_bat(s, p, 1);
	BAT *b = BATnew(TYPE_void, TYPE_str, 256, TRANSIENT);
	BAT *bn = BATnew(TYPE_void, TYPE_str, 256, TRANSIENT);

	if (b == 0 || bn == 0) {
		BBPreclaim(b);
		BBPreclaim(bn);
		throw(MAL, "mdb.getStackFrame", MAL_MALLOC_FAIL);
	}
	BATseqbase(b,0);
	BATseqbase(bn,0);
	pseudo(ret,b,"view","stk","frame");
	pseudo(ret2,bn,"view","stk","frame");
	return MDBgetFrame(b,bn, cntxt, m, s, 0);
}
Пример #10
0
/*
 * Enable incremental packing. The SQL front-end requires
 * fixed oid sequences.
 */
str
MATpackIncrement(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
{
	bat *ret = getArgReference_bat(stk,p,0);
	int	pieces;
	BAT *b, *bb, *bn;
	size_t newsize;

	(void) cntxt;
	b = BATdescriptor( stk->stk[getArg(p,1)].val.ival);
	if ( b == NULL)
		throw(MAL, "mat.pack", RUNTIME_OBJECT_MISSING);

	if ( getArgType(mb,p,2) == TYPE_int){
		/* first step, estimate with some slack */
		pieces = stk->stk[getArg(p,2)].val.ival;
		bn = BATnew(TYPE_void, b->ttype?b->ttype:TYPE_oid, (BUN)(1.2 * BATcount(b) * pieces), TRANSIENT);
		if (bn == NULL)
			throw(MAL, "mat.pack", MAL_MALLOC_FAIL);
		/* allocate enough space for the vheap, but not for strings,
		 * since BATappend does clever things for strings */
		if ( b->T->vheap && bn->T->vheap && ATOMstorage(b->ttype) != TYPE_str){
			newsize =  b->T->vheap->size * pieces;
			if (HEAPextend(bn->T->vheap, newsize, TRUE) != GDK_SUCCEED)
				throw(MAL, "mat.pack", MAL_MALLOC_FAIL);
		}
		BATseqbase(bn, b->H->seq);
		BATseqbase(BATmirror(bn), b->T->seq);
		BATappend(bn,b,FALSE);
		assert(!bn->H->nil || !bn->H->nonil);
		assert(!bn->T->nil || !bn->T->nonil);
		bn->H->align = (pieces-1);
		BBPkeepref(*ret = bn->batCacheid);
		BBPunfix(b->batCacheid);
	} else {
		/* remaining steps */
		bb = BATdescriptor(stk->stk[getArg(p,2)].val.ival);
		if ( bb ){
			if (BATcount(b) == 0)
				BATseqbase(b, bb->H->seq);
			if (BATcount(b) == 0)
				BATseqbase(BATmirror(b), bb->T->seq);
			BATappend(b,bb,FALSE);
		}
		b->H->align--;
		if(b->H->align == 0)
			BATsetaccess(b, BAT_READ);
		assert(!b->H->nil || !b->H->nonil);
		assert(!b->T->nil || !b->T->nonil);
		BBPkeepref(*ret = b->batCacheid);
		if( bb) 
			BBPunfix(bb->batCacheid);
	}
	return MAL_SUCCEED;
}
Пример #11
0
static AGGRtask*
GROUPcollect( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){
	AGGRtask *a;
	int i;
	BAT *b, *bs, *bh = NULL;
	BUN sample;

	(void) mb;
	(void) cntxt;
	a= (AGGRtask *) GDKzalloc(sizeof(*a));
	if ( a == NULL)
		return NULL;
	a->bid = (bat*) GDKzalloc(pci->argc * sizeof(bat));
	a->cols = (BAT**) GDKzalloc(pci->argc * sizeof(BAT*));
	a->unique = (BUN *) GDKzalloc(pci->argc * sizeof(BUN));
	if ( a->cols == NULL || a->bid == NULL || a->unique == NULL){
		if(a->cols) GDKfree(a->cols);
		if(a->bid) GDKfree(a->bid);
		if(a->unique) GDKfree(a->unique);
		GDKfree(a);
		return NULL;
	}
	for ( i= pci->retc; i< pci->argc; i++, a->last++) {
		a->bid[a->last] = *getArgReference_bat(stk,pci,i);
		b = a->cols[a->last]= BATdescriptor(a->bid[a->last]);
		if ( a->cols[a->last] == NULL){
			for(a->last--; a->last>=0; a->last--)
				BBPunfix(a->cols[a->last]->batCacheid);
			GDKfree(a->cols);
			GDKfree(a->bid);
			GDKfree(a->unique);
			GDKfree(a);
			return NULL;
		}
		sample = BATcount(b) < 1000 ? BATcount(b): 1000;
		bs = BATsample( b, sample);
		if (bs) {
			bh = BATunique(b, bs);
			if (bh) {
				a->unique[a->last] = BATcount(bh);
				BBPunfix(bh->batCacheid);
			}
			BBPunfix(bs->batCacheid);
		}
		if ( b->tsorted)
			a->unique[a->last] = 1000; /* sorting helps grouping */
		a->size = BATcount(b);
	}

#ifdef _DEBUG_GROUPBY_
	for(i=0; i<a->last; i++)
		fprintf(stderr,"#group %d unique "BUNFMT "\n", i, a->unique[i]);
#endif
	return a;
}
Пример #12
0
str
JSONfold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	bat *id = 0, *key = 0, *val = 0;
	str *ret;

	(void) cntxt;
	(void) mb;

	assert(pci->retc == 1);
	if (pci->argc - pci->retc == 1) {
		val = getArgReference_bat(stk, pci, 1);
	} else if (pci->argc - pci->retc == 2) {
		id = 0;
		key = getArgReference_bat(stk, pci, 1);
		val = getArgReference_bat(stk, pci, 2);
	} else {
		assert(pci->argc - pci->retc == 3);
		id = getArgReference_bat(stk, pci, 1);
		key = getArgReference_bat(stk, pci, 2);
		val = getArgReference_bat(stk, pci, 3);
	}
	ret = getArgReference_TYPE(stk, pci, 0, json);
	return JSONfoldKeyValue(ret, id, key, val);
}
Пример #13
0
str 
SQLdiff(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	(void)cntxt;
	if (isaBatType(getArgType(mb, pci, 1))) {
		bat *res = getArgReference_bat(stk, pci, 0);
		bat *bid = getArgReference_bat(stk, pci, 1);
		BAT *b = BATdescriptor(*bid), *c, *r;
		gdk_return gdk_code;

		if (!b)
			throw(SQL, "sql.diff", SQLSTATE(HY005) "Cannot access column descriptor");
		voidresultBAT(r, TYPE_bit, BATcount(b), b, "sql.diff");
		if (pci->argc > 2) {
			c = b;
			bid = getArgReference_bat(stk, pci, 2);
			b = BATdescriptor(*bid);
			if (!b) {
				BBPunfix(c->batCacheid);
				throw(SQL, "sql.diff", SQLSTATE(HY005) "Cannot access column descriptor");
			}
			gdk_code = GDKanalyticaldiff(r, b, c, b->ttype);
			BBPunfix(c->batCacheid);
		} else {
			gdk_code = GDKanalyticaldiff(r, b, NULL, b->ttype);
		}
		BBPunfix(b->batCacheid);
		if(gdk_code == GDK_SUCCEED)
			BBPkeepref(*res = r->batCacheid);
		else
			throw(SQL, "sql.diff", GDK_EXCEPTION);
	} else {
		bit *res = getArgReference_bit(stk, pci, 0);

		*res = FALSE;
	}
	return MAL_SUCCEED;
}
Пример #14
0
str
db_users_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	bat *r = getArgReference_bat(stk, pci, 0);
	BAT *uid, *nme;
	str err;

	(void) mb;
	if ((err = AUTHgetUsers(&uid, &nme, cntxt)) != MAL_SUCCEED)
		return err;
	BBPunfix(uid->batCacheid);
	*r = nme->batCacheid;
	BBPkeepref(*r);
	return MAL_SUCCEED;
}
Пример #15
0
/*
 * The pack is an ordinary multi BAT insert. Oid synchronistion
 * between pieces should be ensured by the code generators.
 * The pack operation could be quite expensive, because it
 * may create a really large BAT.
 * The slice over a mat helps to avoid constructing intermediates
 * that are subsequently reduced.
 * Contrary to most operations, NIL arguments are skipped and
 * do not produce RUNTIME_OBJECT_MISSING.
 */
static str
MATpackInternal(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
{
	int i;
	bat *ret = getArgReference_bat(stk,p,0);
	BAT *b, *bn;
	BUN cap = 0;
	int tt = TYPE_any;
	(void) cntxt;
	(void) mb;

	for (i = 1; i < p->argc; i++) {
		bat bid = stk->stk[getArg(p,i)].val.bval;
		b = BBPquickdesc(abs(bid),FALSE);
		if( b ){
			if (tt == TYPE_any)
				tt = b->ttype;
			if (tt != b->ttype)
				throw(MAL, "mat.pack", "incompatible arguments");
			cap += BATcount(b);
		}
	}
	if (tt == TYPE_any){
		*ret = bat_nil;
		return MAL_SUCCEED;
	}

	bn = BATnew(TYPE_void, tt, cap, TRANSIENT);
	if (bn == NULL)
		throw(MAL, "mat.pack", MAL_MALLOC_FAIL);

	for (i = 1; i < p->argc; i++) {
		b = BATdescriptor(stk->stk[getArg(p,i)].val.ival);
		if( b ){
			if (BATcount(bn) == 0)
				BATseqbase(bn, b->H->seq);
			if (BATcount(bn) == 0)
				BATseqbase(BATmirror(bn), b->T->seq);
			BATappend(bn,b,FALSE);
			BBPunfix(b->batCacheid);
		}
	}
	assert(!bn->T->nil || !bn->T->nonil);
	BATsettrivprop(bn);
	BATderiveProps(bn,FALSE);
	BBPkeepref(*ret = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #16
0
str
TRNtrans_abort(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
{
	int i;
	bat *bid;
	BAT *b;

	(void) cntxt;
	(void) mb;
	for (i = p->retc; i < p->argc; i++) {
		bid = getArgReference_bat(stk, p, i);
		if ((b = BATdescriptor(*bid)) == NULL) {
			throw(MAL, "transaction.abort",  RUNTIME_OBJECT_MISSING);
		}
		BATundo(b);
		BBPunfix(b->batCacheid);
	}
	return MAL_SUCCEED;
}
Пример #17
0
/*
 * It is illustrative to dump the code when you
 * have encountered an error.
 */
str
MDBgetDefinition(Client cntxt, MalBlkPtr m, MalStkPtr stk, InstrPtr p)
{
	int i;
	bat *ret = getArgReference_bat(stk, p, 0);
	str ps;
	BAT *b = BATnew(TYPE_void, TYPE_str, 256, TRANSIENT);

	(void) cntxt;
	if (b == 0)
		throw(MAL, "mdb.getDefinition",  MAL_MALLOC_FAIL);
	BATseqbase(b,0);

	for (i = 0; i < m->stop; i++) {
		ps = instruction2str(m,0, getInstrPtr(m, i), 1);
		BUNappend(b, ps, FALSE);
		GDKfree(ps);
	}
	if (!(b->batDirty&2)) BATsetaccess(b, BAT_READ);
	pseudo(ret,b,"view","fcn","stmt");

	return MAL_SUCCEED;
}
Пример #18
0
str
JSONunfold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	bat *id = 0, *key = 0, *val = 0;
	json *js;

	(void) cntxt;
	(void) mb;

	if (pci->retc == 1) {
		val = getArgReference_bat(stk, pci, 0);
	} else if (pci->retc == 2) {
		id = 0;
		key = getArgReference_bat(stk, pci, 0);
		val = getArgReference_bat(stk, pci, 1);
	} else if (pci->retc == 3) {
		id = getArgReference_bat(stk, pci, 0);
		key = getArgReference_bat(stk, pci, 1);
		val = getArgReference_bat(stk, pci, 2);
	}
	js = getArgReference_TYPE(stk, pci, pci->retc, json);
	return JSONunfoldInternal(id, key, val, js);
}
Пример #19
0
static str
CMDbatBINARY2(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
			  BAT *(*batfunc)(BAT *, BAT *, BAT *, int, int),
			  BAT *(batfunc1)(BAT *, const ValRecord *, BAT *, int, int),
			  BAT *(batfunc2)(const ValRecord *, BAT *, BAT *, int, int),
			  int (*typefunc)(int, int),
			  int abort_on_error, const char *malfunc)
{
	bat *bid;
	BAT *bn, *b, *s = NULL;
	int tp1, tp2, tp3;

	tp1 = stk->stk[getArg(pci, 1)].vtype;
	tp2 = stk->stk[getArg(pci, 2)].vtype;
	tp3 = getArgType(mb, pci, 0);
	assert(isaBatType(tp3));
	tp3 = getBatType(tp3);
	if (pci->argc == 4) {
		bat *sid = getArgReference_bat(stk, pci, 3);
		if (*sid && (s = BATdescriptor(*sid)) == NULL)
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	}

	if (tp1 == TYPE_bat || isaBatType(tp1)) {
		BAT *b2 = NULL;
		bid = getArgReference_bat(stk, pci, 1);
		b = BATdescriptor(*bid);
		if (b == NULL) {
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
		if (tp2 == TYPE_bat || isaBatType(tp2)) {
			bid = getArgReference_bat(stk, pci, 2);
			b2 = BATdescriptor(*bid);
			if (b2 == NULL) {
				BBPunfix(b->batCacheid);
				if (s)
					BBPunfix(s->batCacheid);
				throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
			}
		}
		if (b2) {
			if (tp3 == TYPE_any)
				tp3 = (*typefunc)(b->ttype, b2->ttype);
			bn = (*batfunc)(b, b2, s, tp3, abort_on_error);
			BBPunfix(b2->batCacheid);
		} else {
			if (tp3 == TYPE_any)
				tp3 = (*typefunc)(b->ttype, tp2);
			bn = (*batfunc1)(b, &stk->stk[getArg(pci, 2)], s,
							 tp3, abort_on_error);
		}
	} else {
		assert(tp1 != TYPE_bat && !isaBatType(tp1));
		assert(tp2 == TYPE_bat || isaBatType(tp2));
		bid = getArgReference_bat(stk, pci, 2);
		b = BATdescriptor(*bid);
		if (b == NULL) {
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
		if (tp3 == TYPE_any)
			tp3 = (*typefunc)(tp1, b->ttype);
		bn = (*batfunc2)(&stk->stk[getArg(pci, 1)], b, s, tp3, abort_on_error);
	}
	BBPunfix(b->batCacheid);
	if (bn == NULL) {
		return mythrow(MAL, malfunc, OPERATION_FAILED);
	}
	bid = getArgReference_bat(stk, pci, 0);
	BBPkeepref(*bid = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #20
0
str
MDBStkTrace(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
{
	BAT *b, *bn;
	str msg;
	char *buf;
	bat *ret = getArgReference_bat(s, p, 0);
	bat *ret2 = getArgReference_bat(s, p, 1);
	int k = 0;
	size_t len,l;

	b = BATnew(TYPE_void, TYPE_int, 256, TRANSIENT);
	if ( b== NULL)
		throw(MAL, "mdb.getStackTrace", MAL_MALLOC_FAIL);
	bn = BATnew(TYPE_void, TYPE_str, 256, TRANSIENT);
	if ( bn== NULL) {
		BBPreclaim(b);
		throw(MAL, "mdb.getStackTrace", MAL_MALLOC_FAIL);
	}
	BATseqbase(b,0);
	BATseqbase(bn,0);
	(void) cntxt;
	msg = instruction2str(s->blk, s, p, LIST_MAL_DEBUG);
	len = strlen(msg);
	buf = (char*) GDKmalloc(len +1024);
	if ( buf == NULL){
		GDKfree(msg);
		throw(MAL,"mdb.setTrace",MAL_MALLOC_FAIL);
	}
	snprintf(buf,len+1024,"%s at %s.%s[%d]", msg,
		getModuleId(getInstrPtr(m,0)),
		getFunctionId(getInstrPtr(m,0)), getPC(m, p));
	BUNappend(b, &k, FALSE);
	BUNappend(bn, buf, FALSE);
	GDKfree(msg);

	for (s = s->up, k++; s != NULL; s = s->up, k++) {
		msg = instruction2str(s->blk, s, getInstrPtr(s->blk,s->pcup),LIST_MAL_DEBUG);
		l = strlen(msg);
		if (l>len){
			GDKfree(buf);
			len=l;
			buf = (char*) GDKmalloc(len +1024);
			if ( buf == NULL){
				GDKfree(msg);
				BBPunfix(b->batCacheid);
				BBPunfix(bn->batCacheid);
				throw(MAL,"mdb.setTrace",MAL_MALLOC_FAIL);
			}
		}
		snprintf(buf,len+1024,"%s at %s.%s[%d]", msg,
			getModuleId(getInstrPtr(s->blk,0)),
			getFunctionId(getInstrPtr(s->blk,0)), s->pcup);
		BUNappend(b, &k, FALSE);
		BUNappend(bn, buf, FALSE);
		GDKfree(msg);
	}
	GDKfree(buf);
	if (!(b->batDirty&2)) BATsetaccess(b, BAT_READ);
	if (!(bn->batDirty&2)) BATsetaccess(bn, BAT_READ);
	pseudo(ret,b,"view","stk","trace");
	pseudo(ret2,bn,"view","stk","traceB");
	return MAL_SUCCEED;
}
Пример #21
0
str
SQLwindow_bound(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	str msg = MAL_SUCCEED;
	bool preceding;
	lng first_half;
	int unit, bound, excl, part_offset = (pci->argc > 6);

	if ((pci->argc != 6 && pci->argc != 7) || getArgType(mb, pci, part_offset + 2) != TYPE_int ||
		getArgType(mb, pci, part_offset + 3) != TYPE_int || getArgType(mb, pci, part_offset + 4) != TYPE_int) {
		throw(SQL, "sql.window_bound", SQLSTATE(42000) "Invalid arguments");
	}

	unit = *getArgReference_int(stk, pci, part_offset + 2);
	bound = *getArgReference_int(stk, pci, part_offset + 3);
	excl = *getArgReference_int(stk, pci, part_offset + 4);

	assert(unit >= 0 && unit <= 3);
	assert(bound >= 0 && bound <= 5);
	assert(excl >= 0 && excl <= 2);
	preceding = (bound % 2 == 0);
	first_half = (bound < 2 || bound == 4);

	(void)cntxt;
	if (isaBatType(getArgType(mb, pci, 1))) {
		bat *res = getArgReference_bat(stk, pci, 0);
		BAT *b = BATdescriptor(*getArgReference_bat(stk, pci, part_offset + 1)), *p = NULL, *r, *l = NULL;
		int tp1 = getBatType(getArgType(mb, pci, part_offset + 1)), tp2 = getArgType(mb, pci, part_offset + 5);
		void* limit = NULL;
		bool is_negative = false, is_null = false, is_a_bat;
		gdk_return gdk_code;

		if (!b)
			throw(SQL, "sql.window_bound", SQLSTATE(HY005) "Cannot access column descriptor");

		if (excl != 0) {
			BBPunfix(b->batCacheid);
			throw(SQL, "sql.window_bound", SQLSTATE(42000) "Only EXCLUDE NO OTHERS exclusion is currently implemented");
		}

		is_a_bat = isaBatType(tp2);
		if(is_a_bat)
			tp2 = getBatType(tp2);

		voidresultBAT(r, TYPE_lng, BATcount(b), b, "sql.window_bound");
		if(is_a_bat) { //SQL_CURRENT_ROW shall never fall in limit validation
			l = BATdescriptor(*getArgReference_bat(stk, pci, part_offset + 5));
			if (!l) {
				BBPunfix(b->batCacheid);
				throw(SQL, "sql.window_bound", SQLSTATE(HY005) "Cannot access column descriptor");
			}
			switch (tp2) {
				case TYPE_bte:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(bte)
					break;
				case TYPE_sht:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(sht)
					break;
				case TYPE_int:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(int)
					break;
				case TYPE_lng:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(lng)
					break;
				case TYPE_flt:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(flt)
					break;
				case TYPE_dbl:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(dbl)
					break;
#ifdef HAVE_HGE
				case TYPE_hge:
					CHECK_NULLS_AND_NEGATIVES_COLUMN(hge)
					break;
#endif
				default: {
					BBPunfix(b->batCacheid);
					BBPunfix(l->batCacheid);
					throw(SQL, "sql.window_bound", SQLSTATE(42000) "%s limit not available for %s", "sql.window_bound", ATOMname(tp2));
				}
			}
			if(is_null || is_negative) {
				BBPunfix(b->batCacheid);
				BBPunfix(l->batCacheid);
				if(is_null)
					throw(SQL, "sql.window_bound", SQLSTATE(HY005) "All values on %s boundary must be non-null", preceding ? "PRECEDING" : "FOLLOWING");
				throw(SQL, "sql.window_bound", SQLSTATE(HY005) "All values on %s boundary must be non-negative", preceding ? "PRECEDING" : "FOLLOWING");
			}
		} else {
Пример #22
0
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);
}
Пример #23
0
str
CMDifthen(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	BAT *b = NULL, *b1 = NULL, *b2 = NULL, *bn;
	int tp0, tp1, tp2;
	bat *ret;
	BUN cnt = BUN_NONE;

	(void) cntxt;
	(void) mb;

	if (pci->argc != 4)
		throw(MAL, "batcalc.ifthen", "Operation not supported.");

	ret = getArgReference_bat(stk, pci, 0);
	tp0 = stk->stk[getArg(pci, 1)].vtype;
	tp1 = stk->stk[getArg(pci, 2)].vtype;
	tp2 = stk->stk[getArg(pci, 3)].vtype;
	if (tp0 == TYPE_bat || isaBatType(tp0)) {
		b = BATdescriptor(* getArgReference_bat(stk, pci, 1));
		if (b == NULL)
			throw(MAL, "batcalc.ifthenelse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		cnt = BATcount(b);
	}
	if (tp1 == TYPE_bat || isaBatType(tp1)) {
		b1 = BATdescriptor(* getArgReference_bat(stk, pci, 2));
		if (b1 == NULL) {
			if (b)
				BBPunfix(b->batCacheid);
			throw(MAL, "batcalc.ifthenelse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
		if (cnt == BUN_NONE)
			cnt = BATcount(b1);
		else if (BATcount(b1) != cnt) {
			BBPunfix(b->batCacheid);
			throw(MAL, "batcalc.ifthenelse", ILLEGAL_ARGUMENT);
		}
	}
	if (tp2 == TYPE_bat || isaBatType(tp2)) {
		b2 = BATdescriptor(* getArgReference_bat(stk, pci, 3));
		if (b2 == NULL) {
			if (b)
				BBPunfix(b->batCacheid);
			if (b1)
				BBPunfix(b1->batCacheid);
			throw(MAL, "batcalc.ifthenelse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
		if (cnt == BUN_NONE)
			cnt = BATcount(b2);
		else if (BATcount(b2) != cnt) {
			if (b)
				BBPunfix(b->batCacheid);
			if (b1)
				BBPunfix(b1->batCacheid);
			throw(MAL, "batcalc.ifthenelse", ILLEGAL_ARGUMENT);
		}
	}
	if (b == NULL && b1 == NULL && b2 == NULL) {
		/* at least one BAT required */
		throw(MAL, "batcalc.ifthenelse", ILLEGAL_ARGUMENT);
	}
	if (b != NULL) {
		if (b1 != NULL) {
			if (b2 != NULL) {
				bn = BATcalcifthenelse(b, b1, b2);
			} else {
				bn = BATcalcifthenelsecst(b, b1, &stk->stk[getArg(pci, 3)]);
			}
		} else {
			if (b2 != NULL) {
				bn = BATcalcifthencstelse(b, &stk->stk[getArg(pci, 2)], b2);
			} else {
				bn = BATcalcifthencstelsecst(b, &stk->stk[getArg(pci, 2)], &stk->stk[getArg(pci, 3)]);
			}
		}
	} else {
		bit v = *getArgReference_bit(stk, pci, 1);
		if (is_bit_nil(v)) {
			if (b1 != NULL)
				bn = BATconstant(b1->hseqbase, b1->ttype, ATOMnilptr(b1->ttype), BATcount(b1), TRANSIENT);
			else
				bn = BATconstant(b2->hseqbase, b2->ttype, ATOMnilptr(b2->ttype), BATcount(b2), TRANSIENT);
		} else if (v) {
			if (b1 != NULL)
				bn = COLcopy(b1, b1->ttype, 0, TRANSIENT);
			else
				bn = BATconstant(b2->hseqbase, b2->ttype, VALptr(&stk->stk[getArg(pci, 2)]), BATcount(b2), TRANSIENT);
		} else {
			if (b2 != NULL)
				bn = COLcopy(b2, b2->ttype, 0, TRANSIENT);
			else
				bn = BATconstant(b1->hseqbase, b1->ttype, VALptr(&stk->stk[getArg(pci, 3)]), BATcount(b1), TRANSIENT);
		}
	}
	if (b)
		BBPunfix(b->batCacheid);
	if (b1)
		BBPunfix(b1->batCacheid);
	if (b2)
		BBPunfix(b2->batCacheid);
	if (bn == NULL) {
		return mythrow(MAL, "batcalc.ifthenelse", OPERATION_FAILED);
	}
	BBPkeepref(*ret = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #24
0
static str
callbatBETWEEN(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int sym)
{
	bat *bid;
	BAT *bn, *b, *lo = NULL, *hi = NULL, *s = NULL;
	int tp1, tp2, tp3;

	(void) cntxt;
	(void) mb;

	tp1 = stk->stk[getArg(pci, 1)].vtype;
	tp2 = stk->stk[getArg(pci, 2)].vtype;
	tp3 = stk->stk[getArg(pci, 3)].vtype;
	if (pci->argc == 5) {
		bat *sid = getArgReference_bat(stk, pci, 4);
		if (*sid && (s = BATdescriptor(*sid)) == NULL)
			throw(MAL, "batcalc.between", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	}

	if (tp1 != TYPE_bat && !isaBatType(tp1)) {
		if (s)
			BBPunfix(s->batCacheid);
		throw(MAL, "batcalc.between", ILLEGAL_ARGUMENT);
	}
	bid = getArgReference_bat(stk, pci, 1);
	b = BATdescriptor(*bid);
	if (b == NULL) {
		if (s)
			BBPunfix(s->batCacheid);
		throw(MAL, "batcalc.between", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	}

	if (tp2 == TYPE_bat || isaBatType(tp2)) {
		bid = getArgReference_bat(stk, pci, 2);
		lo = BATdescriptor(*bid);
		if (lo == NULL) {
			BBPunfix(b->batCacheid);
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, "batcalc.between", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
	}
	if (tp3 == TYPE_bat || isaBatType(tp3)) {
		bid = getArgReference_bat(stk, pci, 3);
		hi = BATdescriptor(*bid);
		if (hi == NULL) {
			BBPunfix(b->batCacheid);
			if (lo)
				BBPunfix(lo->batCacheid);
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, "batcalc.between", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
	}
	if (lo == NULL) {
		if (hi == NULL) {
			bn = BATcalcbetweencstcst(b, &stk->stk[getArg(pci, 2)],
									  &stk->stk[getArg(pci, 3)], s, sym);
		} else {
			bn = BATcalcbetweencstbat(b, &stk->stk[getArg(pci, 2)], hi, s, sym);
		}
	} else {
		if (hi == NULL) {
			bn = BATcalcbetweenbatcst(b, lo, &stk->stk[getArg(pci, 3)], s, sym);
		} else {
			bn = BATcalcbetween(b, lo, hi, s, sym);
		}
	}
	BBPunfix(b->batCacheid);
	if (lo)
		BBPunfix(lo->batCacheid);
	if (hi)
		BBPunfix(hi->batCacheid);
	if (s)
		BBPunfix(s->batCacheid);
	if (bn == NULL) {
		return mythrow(MAL, "batcalc.between", OPERATION_FAILED);
	}
	bid = getArgReference_bat(stk, pci, 0);
	BBPkeepref(*bid = bn->batCacheid);
	return MAL_SUCCEED;
}
Пример #25
0
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;
}
Пример #26
0
static str
CMDbatBINARY0(MalStkPtr stk, InstrPtr pci,
			  BAT *(*batfunc)(BAT *, BAT *, BAT *),
			  BAT *(*batfunc1)(BAT *, const ValRecord *, BAT *),
			  BAT *(*batfunc2)(const ValRecord *, BAT *, BAT *),
			  const char *malfunc)
{
	bat *bid;
	BAT *bn, *b, *s = NULL;
	int tp1, tp2;

	tp1 = stk->stk[getArg(pci, 1)].vtype;
	tp2 = stk->stk[getArg(pci, 2)].vtype;
	if (pci->argc == 4) {
		bat *sid = getArgReference_bat(stk, pci, 3);
		if (*sid && (s = BATdescriptor(*sid)) == NULL)
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
	}

	if (tp1 == TYPE_bat || isaBatType(tp1)) {
		BAT *b2 = NULL;
		bid = getArgReference_bat(stk, pci, 1);
		b = BATdescriptor(*bid);
		if (b == NULL) {
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
		if (tp2 == TYPE_bat || isaBatType(tp2)) {
			bid = getArgReference_bat(stk, pci, 2);
			b2 = BATdescriptor(*bid);
			if (b2 == NULL) {
				BBPunfix(b->batCacheid);
				if (s)
					BBPunfix(s->batCacheid);
				throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
			}
		}
		if (b2) {
			bn = (*batfunc)(b, b2, s);
			BBPunfix(b2->batCacheid);
		} else if (batfunc1 == NULL) {
			BBPunfix(b->batCacheid);
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, malfunc, PROGRAM_NYI);
		} else {
			bn = (*batfunc1)(b, &stk->stk[getArg(pci, 2)], s);
		}
	} else if (batfunc2 == NULL) {
		throw(MAL, malfunc, PROGRAM_NYI);
	} else {
		assert(tp1 != TYPE_bat && !isaBatType(tp1));
		assert(tp2 == TYPE_bat || isaBatType(tp2));
		bid = getArgReference_bat(stk, pci, 2);
		b = BATdescriptor(*bid);
		if (b == NULL) {
			if (s)
				BBPunfix(s->batCacheid);
			throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
		}
		bn = (*batfunc2)(&stk->stk[getArg(pci, 1)], b, s);
	}
	BBPunfix(b->batCacheid);
	if (s)
		BBPunfix(s->batCacheid);
	if (bn == NULL) {
		return mythrow(MAL, malfunc, OPERATION_FAILED);
	}
	bid = getArgReference_bat(stk, pci, 0);
	BBPkeepref(*bid = bn->batCacheid);
	return MAL_SUCCEED;
}