示例#1
0
str
OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	InstrPtr p;
	int i, k, limit, *alias = 0, barrier;
	MalStkPtr env = NULL;
	int profiler;
	int debugstate = cntxt->itrace, actions = 0, constantblock = 0;
	int *assigned = 0, use; 
	char buf[256];
	lng usec = GDKusec();
	str msg = MAL_SUCCEED;

	(void)stk;
	(void)pci;

	if ( mb->inlineProp )
		return MAL_SUCCEED;

	cntxt->itrace = 0;

#ifdef DEBUG_OPT_EVALUATE
	fprintf(stderr, "Constant expression optimizer started\n");
#endif

	assigned = (int*) GDKzalloc(sizeof(int) * mb->vtop);
	if (assigned == NULL)
		throw(MAL,"optimzier.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL);

	alias = (int*)GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */
	if (alias == NULL){
		GDKfree(assigned);
		throw(MAL,"optimzier.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL);
	}

	// arguments are implicitly assigned by context
	p = getInstrPtr(mb, 0);
	for ( k =p->retc;  k < p->argc; k++)
		assigned[getArg(p,k)]++;
	limit = mb->stop;
	for (i = 1; i < limit; i++) {
		p = getInstrPtr(mb, i);
		// The double count emerging from a barrier exit is ignored.
		if (! blockExit(p) || (blockExit(p) && p->retc != p->argc))
		for ( k =0;  k < p->retc; k++)
		if ( p->retc != p->argc || p->token != ASSIGNsymbol )
			assigned[getArg(p,k)]++;
	}

	for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
		p = getInstrPtr(mb, i);
		// to avoid management of duplicate assignments over multiple blocks
		// we limit ourselves to evaluation of the first assignment only.
		use = assigned[getArg(p,0)] == 1 && !(p->argc == p->retc && blockExit(p));
		for (k = p->retc; k < p->argc; k++)
			if (alias[getArg(p, k)])
				getArg(p, k) = alias[getArg(p, k)];
#ifdef DEBUG_OPT_EVALUATE
		fprintInstruction(stderr , mb, 0, p, LIST_MAL_ALL);
#endif
		/* be aware that you only assign once to a variable */
		if (use && p->retc == 1 && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
			barrier = p->barrier;
			p->barrier = 0;
			profiler = malProfileMode;	/* we don't trace it */
			malProfileMode = 0;
			if ( env == NULL) {
				env = prepareMALstack(mb,  2 * mb->vsize);
				if (!env) {
					msg = createException(MAL,"optimizer.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL);
					goto wrapup;
				}
				env->keepAlive = TRUE;
			}
			msg = reenterMAL(cntxt, mb, i, i + 1, env);
			malProfileMode= profiler;
			p->barrier = barrier;
#ifdef DEBUG_OPT_EVALUATE
			fprintf(stderr, "#retc var %s\n", getVarName(mb, getArg(p, 0)));
			fprintf(stderr, "#result:%s\n", msg == MAL_SUCCEED ? "ok" : msg);
#endif
			if (msg == MAL_SUCCEED) {
				int nvar;
				ValRecord cst;

				actions++;
				cst.vtype = 0;
				VALcopy(&cst, &env->stk[getArg(p, 0)]);
				/* You may not overwrite constants.  They may be used by
				 * other instructions */
				nvar = getArg(p, 1) = defConstant(mb, getArgType(mb, p, 0), &cst);
				if (nvar >= env->stktop) {
					VALcopy(&env->stk[getArg(p, 1)], &getVarConstant(mb, getArg(p, 1)));
					env->stktop = getArg(p, 1) + 1;
				}
				alias[getArg(p, 0)] = getArg(p, 1);
				p->argc = 2;
				p->token = ASSIGNsymbol;
				clrFunction(p);
				p->barrier = barrier;
				/* freeze the type */
				setVarFixed(mb,getArg(p,1));
				setVarUDFtype(mb,getArg(p,1));
#ifdef DEBUG_OPT_EVALUATE
				{str tpename;
				fprintf(stderr, "Evaluated new constant=%d -> %d:%s\n",
					getArg(p, 0), getArg(p, 1), tpename = getTypeName(getArgType(mb, p, 1)));
				GDKfree(tpename);
				}
#endif
			} else {
				/* if there is an error, we should postpone message handling,
					as the actual error (eg. division by zero ) may not happen) */
#ifdef DEBUG_OPT_EVALUATE
				fprintf(stderr, "Evaluated %s\n", msg);
#endif
				freeException(msg);
				msg= MAL_SUCCEED;
				mb->errors = 0;
			}
		}
		constantblock +=  blockStart(p) && OPTallConstant(cntxt, mb, p);	/* default */
	}
	// produces errors in SQL when enabled
	if ( constantblock)
		msg = OPTremoveUnusedBlocks(cntxt, mb);
	cntxt->itrace = debugstate;

    /* Defense line against incorrect plans */
	/* Plan is unaffected */
	chkTypes(cntxt->usermodule, mb, FALSE);
	chkFlow(mb);
	chkDeclarations(mb);
    
    /* keep all actions taken as a post block comment */
	usec = GDKusec()- usec;
    snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec","evaluate",actions,usec);
    newComment(mb,buf);
	if( actions >= 0)
		addtoMalBlkHistory(mb);

wrapup:
	if ( env) freeStack(env);
	if(assigned) GDKfree(assigned);
	if(alias)	GDKfree(alias);
	return msg;
}
示例#2
0
/*
 * The generic solution to the multiplex operators is to translate
 * them to a MAL loop.
 * The call optimizer.multiplex(MOD,FCN,A1,...An) introduces the following code
 * structure:
 *
 * 	resB:= bat.new(A1);
 * barrier (h,t1):= iterator.new(A1);
 * 	t2:= algebra.fetch(A2,h)
 * 	...
 * 	cr:= MOD.FCN(t1,...,tn);
 * 	bat.append(resB,cr);
 * 	redo (h,t):= iterator.next(A1);
 * end h;
 *
 * The algorithm consists of two phases: phase one deals with
 * collecting the relevant information, phase two is the actual
 * code construction.
 */
static str
OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
	int i = 2, iter = 0;
	int hvar, tvar;
	str mod, fcn;
	int *alias, *resB;
	InstrPtr q;
	int tt;
	int bat = (getModuleId(pci) == batmalRef) ;

	//if ( optimizerIsApplied(mb,"multiplex"))
		//return 0;
	(void) cntxt;
	(void) stk;
	for (i = 0; i < pci->retc; i++) {
		tt = getBatType(getArgType(mb, pci, i));
		if (tt== TYPE_any)
			throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Target tail type is missing");
		if (isAnyExpression(getArgType(mb, pci, i)))
			throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Target type is missing");
	}

	mod = VALget(&getVar(mb, getArg(pci, pci->retc))->value);
	mod = putName(mod);
	fcn = VALget(&getVar(mb, getArg(pci, pci->retc+1))->value);
	fcn = putName(fcn);
	if(mod == NULL || fcn == NULL)
		throw(MAL, "optimizer.multiplex", SQLSTATE(HY001) MAL_MALLOC_FAIL);
#ifndef NDEBUG
	fprintf(stderr,"#WARNING To speedup %s.%s a bulk operator implementation is needed\n#", mod,fcn);
	fprintInstruction(stderr, mb, stk, pci, LIST_MAL_DEBUG);
#endif

	/* search the iterator bat */
	for (i = pci->retc+2; i < pci->argc; i++)
		if (isaBatType(getArgType(mb, pci, i))) {
			iter = getArg(pci, i);
			break;
		}
	if( i == pci->argc)
		throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Iterator BAT type is missing");

#ifdef DEBUG_OPT_MULTIPLEX
	{	char *tpenme;
		fprintf(stderr,"#calling the optimize multiplex script routine\n");
		fprintFunction(stderr,mb, 0, LIST_MAL_ALL );
		tpenme = getTypeName(getVarType(mb,iter));
		fprintf(stderr,"#multiplex against operator %d %s\n",iter, tpenme);
		GDKfree(tpenme);
		fprintInstruction(stderr,mb, 0, pci,LIST_MAL_ALL);
	}
#endif
	/*
	 * Beware, the operator constant (arg=1) is passed along as well,
	 * because in the end we issue a recursive function call that should
	 * find the actual arguments at the proper place of the callee.
	 */

	alias= (int*) GDKmalloc(sizeof(int) * pci->maxarg);
	resB = (int*) GDKmalloc(sizeof(int) * pci->retc);
	if (alias == NULL || resB == NULL)  {
		GDKfree(alias);
		GDKfree(resB);
		return NULL;
	}

	/* resB := new(refBat) */
	for (i = 0; i < pci->retc; i++) {
		q = newFcnCall(mb, batRef, newRef);
		resB[i] = getArg(q, 0);

		tt = getBatType(getArgType(mb, pci, i));

		setVarType(mb, getArg(q, 0), newBatType(tt));
		q = pushType(mb, q, tt);
	}

	/* barrier (h,r) := iterator.new(refBat); */
	q = newFcnCall(mb, iteratorRef, newRef);
	q->barrier = BARRIERsymbol;
	hvar = newTmpVariable(mb, TYPE_any);
	getArg(q,0) = hvar;
	tvar = newTmpVariable(mb, TYPE_any);
	q= pushReturn(mb, q, tvar);
	(void) pushArgument(mb,q,iter);

	/* $1:= algebra.fetch(Ai,h) or constant */
	for (i = pci->retc+2; i < pci->argc; i++) {
		if (getArg(pci, i) != iter && isaBatType(getArgType(mb, pci, i))) {
			q = newFcnCall(mb, algebraRef, "fetch");
			alias[i] = newTmpVariable(mb, getBatType(getArgType(mb, pci, i)));
			getArg(q, 0) = alias[i];
			q= pushArgument(mb, q, getArg(pci, i));
			(void) pushArgument(mb, q, hvar);
		}
	}

	/* cr:= mod.CMD($1,...,$n); */
	q = newFcnCall(mb, mod, fcn);
	for (i = 0; i < pci->retc; i++) {
		int nvar = 0;
		if (bat) {
			tt = getBatType(getArgType(mb, pci, i));
			nvar = newTmpVariable(mb, newBatType(tt));
		} else {
			nvar = newTmpVariable(mb, TYPE_any);
		}
		if (i)
			q = pushReturn(mb, q, nvar);
		else
			getArg(q, 0) = nvar;
	}

	for (i = pci->retc+2; i < pci->argc; i++) {
		if (getArg(pci, i) == iter) {
			q = pushArgument(mb, q, tvar);
		} else if (isaBatType(getArgType(mb, pci, i))) {
			q = pushArgument(mb, q, alias[i]);
		} else {
			q = pushArgument(mb, q, getArg(pci, i));
		}
	}

	for (i = 0; i < pci->retc; i++) {
		InstrPtr a = newFcnCall(mb, batRef, appendRef);
		a = pushArgument(mb, a, resB[i]);
		(void) pushArgument(mb, a, getArg(q,i));
	}

/* redo (h,r):= iterator.next(refBat); */
	q = newFcnCall(mb, iteratorRef, nextRef);
	q->barrier = REDOsymbol;
	getArg(q,0) = hvar;
	q= pushReturn(mb, q, tvar);
	(void) pushArgument(mb,q,iter);

	q = newAssignment(mb);
	q->barrier = EXITsymbol;
	getArg(q,0) = hvar;
	(void) pushReturn(mb, q, tvar);

	for (i = 0; i < pci->retc; i++) {
		q = newAssignment(mb);
		getArg(q, 0) = getArg(pci, i);
		(void) pushArgument(mb, q, resB[i]);
	}
	GDKfree(alias);
	GDKfree(resB);
	return MAL_SUCCEED;
}