int OPTgroupsImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { int i, actions=0; InstrPtr q; InstrPtr *old, *ref; int limit,slimit; (void) cntxt; (void) stk; if (varGetProp(mb, getArg(mb->stmt[0], 0), inlineProp) != NULL) { return 0; } /* beware, new variables and instructions are introduced */ ref= (InstrPtr*) GDKzalloc(sizeof(InstrPtr) * mb->vtop); /* to find last assignment */ if ( ref == NULL) { return 0; } old= mb->stmt; limit= mb->stop; slimit= mb->ssize; if ( newMalBlkStmt(mb,mb->ssize) <0) { GDKfree(ref); return 0; } for (i = 0; i<limit; i++){ p= old[i]; if (getModuleId(p) == groupRef && p->argc == 4 && getFunctionId(p) == subgroupRef ){ setFunctionId(p, multicolumnsRef); ref[getArg(p,0)] = p; actions++; OPTDEBUGgroups { mnstr_printf(cntxt->fdout,"#new groups instruction\n"); printInstruction(cntxt->fdout,mb, 0, p, LIST_MAL_ALL); } } if (getModuleId(p) == groupRef && p->argc == 5 && getFunctionId(p) == subgroupdoneRef && ref[getArg(p,4)] != NULL){ /* * Try to expand its argument list with what we have found so far. * This creates a series of derive paths, many of which will be removed during deadcode elimination. */ q= copyInstruction(ref[getArg(p,4)]); q= pushArgument(mb, q, getArg(p,3)); getArg(q,0) = getArg(p,0); getArg(q,1) = getArg(p,1); getArg(q,2) = getArg(p,2); ref[getArg(q,0)] = q; freeInstruction(p); p= q; OPTDEBUGgroups{ mnstr_printf(cntxt->fdout,"#new groups instruction extension\n"); printInstruction(cntxt->fdout,mb, 0, p, LIST_MAL_ALL); } }
int OPTpushselectImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, limit, slimit, actions=0, *vars, push_down_delta = 0, nr_topn = 0, nr_likes = 0; InstrPtr p, *old; subselect_t subselects; memset(&subselects, 0, sizeof(subselects)); if( mb->errors) return 0; OPTDEBUGpushselect mnstr_printf(cntxt->fdout,"#Push select optimizer started\n"); (void) stk; (void) pci; vars= (int*) GDKzalloc(sizeof(int)* mb->vtop); if( vars == NULL) return 0; limit = mb->stop; slimit= mb->ssize; old = mb->stmt; /* check for bailout conditions */ for (i = 1; i < limit; i++) { int lastbat; p = old[i]; for (j = 0; j<p->retc; j++) { int res = getArg(p, j); vars[res] = i; } if (getModuleId(p) == algebraRef && (getFunctionId(p) == tintersectRef || getFunctionId(p) == tinterRef || getFunctionId(p) == tdifferenceRef || getFunctionId(p) == tdiffRef)) { GDKfree(vars); return 0; } if (getModuleId(p) == algebraRef && getFunctionId(p) == sliceRef) nr_topn++; if (isLikeOp(p)) nr_likes++; if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef) push_down_delta++; if (getModuleId(p) == sqlRef && getFunctionId(p) == tidRef) { /* rewrite equal table ids */ int sname = getArg(p, 2), tname = getArg(p, 3), s; for (s = 0; s < subselects.nr; s++) { InstrPtr q = old[vars[subselects.tid[s]]]; int Qsname = getArg(q, 2), Qtname = getArg(q, 3); if (no_updates(old, vars, getArg(q,1), getArg(p,1)) && ((sname == Qsname && tname == Qtname) || (0 && strcmp(getVarConstant(mb, sname).val.sval, getVarConstant(mb, Qsname).val.sval) == 0 && strcmp(getVarConstant(mb, tname).val.sval, getVarConstant(mb, Qtname).val.sval) == 0))) { clrFunction(p); p->retc = 1; p->argc = 2; getArg(p, 1) = getArg(q, 0); break; } } } lastbat = lastbat_arg(mb, p); if (isSubSelect(p) && p->retc == 1 && /* no cand list */ getArgType(mb, p, lastbat) != newBatType(TYPE_oid, TYPE_oid)) { int i1 = getArg(p, 1), tid = 0; InstrPtr q = old[vars[i1]]; /* find the table ids */ while(!tid) { if (getModuleId(q) == algebraRef && getFunctionId(q) == leftfetchjoinRef) { int i1 = getArg(q, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); if (s->argc == 2 && s->retc == 1) { int i1 = getArg(s, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); } break; } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { int i1 = getArg(q, 1); q = old[vars[i1]]; } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { int i2 = getArg(q, 2); q = old[vars[i2]]; } else { break; } } if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { GDKfree(vars); return 0; } } /* left hand side */ if ( (GDKdebug & (1<<15)) && isMatJoinOp(p) && p->retc == 2) { int i1 = getArg(p, 2), tid = 0; InstrPtr q = old[vars[i1]]; /* find the table ids */ while(!tid) { if (getModuleId(q) == algebraRef && getFunctionId(q) == leftfetchjoinRef) { int i1 = getArg(q, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); break; } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { int i1 = getArg(q, 1); q = old[vars[i1]]; } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { int i2 = getArg(q, 2); q = old[vars[i2]]; } else { break; } } if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { GDKfree(vars); return 0; } } /* right hand side */ if ( (GDKdebug & (1<<15)) && isMatJoinOp(p) && p->retc == 2) { int i1 = getArg(p, 3), tid = 0; InstrPtr q = old[vars[i1]]; /* find the table ids */ while(!tid) { if (getModuleId(q) == algebraRef && getFunctionId(q) == leftfetchjoinRef) { int i1 = getArg(q, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); break; } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { int i1 = getArg(q, 1); q = old[vars[i1]]; } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { int i2 = getArg(q, 2); q = old[vars[i2]]; } else { break; } } if (tid && subselect_add(&subselects, tid, getArg(p, 1)) < 0) { GDKfree(vars); return 0; } } } if ((!subselects.nr && !nr_topn && !nr_likes) || newMalBlkStmt(mb, mb->ssize) <0 ) { GDKfree(vars); return 0; } pushInstruction(mb,old[0]); for (i = 1; i < limit; i++) { p = old[i]; /* rewrite batalgebra.like + subselect -> likesubselect */ if (getModuleId(p) == algebraRef && p->retc == 1 && getFunctionId(p) == subselectRef) { int var = getArg(p, 1); InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ if (isLikeOp(q)) { /* TODO check if getArg(p, 3) value == TRUE */ InstrPtr r = newInstruction(mb, ASSIGNsymbol); int has_cand = (getArgType(mb, p, 2) == newBatType(TYPE_oid, TYPE_oid)); int a, anti = (getFunctionId(q)[0] == 'n'), ignore_case = (getFunctionId(q)[anti?4:0] == 'i'); setModuleId(r, algebraRef); setFunctionId(r, likesubselectRef); getArg(r,0) = getArg(p,0); r = pushArgument(mb, r, getArg(q, 1)); if (has_cand) r = pushArgument(mb, r, getArg(p, 2)); for(a = 2; a<q->argc; a++) r = pushArgument(mb, r, getArg(q, a)); if (r->argc < (4+has_cand)) r = pushStr(mb, r, ""); /* default esc */ if (r->argc < (5+has_cand)) r = pushBit(mb, r, ignore_case); if (r->argc < (6+has_cand)) r = pushBit(mb, r, anti); freeInstruction(p); p = r; actions++; } } /* inject table ids into subselect * s = subselect(c, C1..) => subselect(c, t, C1..) */ if (isSubSelect(p) && p->retc == 1) { int tid = 0; if ((tid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { int lastbat = lastbat_arg(mb, p); if (getArgType(mb, p, lastbat) == TYPE_bat) /* empty candidate list bat_nil */ getArg(p, lastbat) = tid; else p = PushArgument(mb, p, tid, lastbat+1); /* make sure to resolve again */ p->token = ASSIGNsymbol; p->typechk = TYPE_UNKNOWN; p->fcn = NULL; p->blk = NULL; actions++; } } else if ( (GDKdebug & (1<<15)) && isMatJoinOp(p) && p->retc == 2 && !(getFunctionId(p) == joinRef && p->argc > 4) ) { int ltid = 0, rtid = 0, done = 0; int range = 0; if(getFunctionId(p) == joinRef) range = (p->argc >= 4); if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0 && (rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { p = PushArgument(mb, p, ltid, 4+range); p = PushArgument(mb, p, rtid, 5+range); done = 1; } else if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { p = PushArgument(mb, p, ltid, 4+range); p = PushNil(mb, p, 5+range, TYPE_bat); done = 1; } else if ((rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { p = PushNil(mb, p, 4+range, TYPE_bat); p = PushArgument(mb, p, rtid, 5+range); done = 1; } if (done) { if(getFunctionId(p) == antijoinRef) p = pushInt(mb, p, JOIN_NE); p = pushBit(mb, p, FALSE); /* do not match nils */ p = pushNil(mb, p, TYPE_lng); /* no estimate */ /* TODO join* -> subjoin* */ if(getFunctionId(p) == joinRef) getFunctionId(p) = subjoinRef; else if(getFunctionId(p) == antijoinRef) getFunctionId(p) = subthetajoinRef; else if(getFunctionId(p) == thetajoinRef) getFunctionId(p) = subthetajoinRef; else if(getFunctionId(p) == bandjoinRef) getFunctionId(p) = subbandjoinRef; /* make sure to resolve again */ p->token = ASSIGNsymbol; p->typechk = TYPE_UNKNOWN; p->fcn = NULL; p->blk = NULL; actions++; } } /* Leftfetchjoins involving rewriten table ids need to be flattend * l = leftfetchjoin(t, c); => l = c; * and * l = leftfetchjoin(s, ntids); => l = s; */ else if (getModuleId(p) == algebraRef && getFunctionId(p) == leftfetchjoinRef) { int var = getArg(p, 1); if (subselect_find_subselect(&subselects, var) > 0) { InstrPtr q = newAssignment(mb); getArg(q, 0) = getArg(p, 0); (void) pushArgument(mb, q, getArg(p, 2)); actions++; freeInstruction(p); continue; } else { /* deletes/updates use table ids */ int var = getArg(p, 2); InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ if (q->token == ASSIGNsymbol) { var = getArg(q, 1); q = mb->stmt[vars[var]]; } if (subselect_find_subselect(&subselects, var) > 0) { InstrPtr qq = newAssignment(mb); /* TODO: check result */ getArg(qq, 0) = getArg(p, 0); (void) pushArgument(mb, qq, getArg(p, 1)); actions++; freeInstruction(p); continue; } /* c = sql.delta(b,uid,uval,ins); * l = leftfetchjoin(x, c); * into * l = sql.projectdelta(x,b,uid,uval,ins); */ else if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef && q->argc == 5) { q = copyInstruction(q); setFunctionId(q, projectdeltaRef); getArg(q, 0) = getArg(p, 0); q = PushArgument(mb, q, getArg(p, 1), 1); freeInstruction(p); p = q; actions++; } } } pushInstruction(mb,p); } for (; i<limit; i++) if (old[i]) pushInstruction(mb,old[i]); for (; i<slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); if (!push_down_delta) { GDKfree(vars); return actions; } /* now push selects through delta's */ limit = mb->stop; slimit= mb->ssize; old = mb->stmt; if (newMalBlkStmt(mb, mb->stop+(5*push_down_delta)) <0 ) { mb->stmt = old; GDKfree(vars); return actions; } pushInstruction(mb,old[0]); for (i = 1; i < limit; i++) { int lastbat; p = old[i]; for (j = 0; j<p->retc; j++) { int res = getArg(p, j); vars[res] = i; } /* push subslice under projectdelta */ if (isSlice(p) && p->retc == 1) { int var = getArg(p, 1); InstrPtr q = old[vars[var]]; if (getModuleId(q) == sqlRef && getFunctionId(q) == projectdeltaRef) { InstrPtr r = copyInstruction(p); InstrPtr s = copyInstruction(q); ValRecord cst; /* slice the candidates */ setFunctionId(r, sliceRef); getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(r, 1) = getArg(s, 1); cst.vtype = getArgType(mb, r, 2); cst.val.wval = 0; getArg(r, 2) = defConstant(mb, cst.vtype, &cst); /* start from zero */ pushInstruction(mb,r); /* dummy result for the old q, will be removed by deadcode optimizer */ getArg(q, 0) = newTmpVariable(mb, getArgType(mb, q, 0)); getArg(s, 1) = getArg(r, 0); /* use result of subslice */ pushInstruction(mb, s); } } /* c = delta(b, uid, uvl, ins) * s = subselect(c, C1..) * * nc = subselect(b, C1..) * ni = subselect(ins, C1..) * nu = subselect(uvl, C1..) * s = subdelta(nc, uid, nu, ni); * * doesn't handle Xsubselect(x, .. z, C1.. cases) ie multicolumn selects */ lastbat = lastbat_arg(mb, p); if (isSubSelect(p) && p->retc == 1 && lastbat == 2) { int var = getArg(p, 1); InstrPtr q = old[vars[var]]; if (q->token == ASSIGNsymbol) { var = getArg(q, 1); q = old[vars[var]]; } if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef) { InstrPtr r = copyInstruction(p); InstrPtr s = copyInstruction(p); InstrPtr t = copyInstruction(p); InstrPtr u = copyInstruction(q); getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(r, 1) = getArg(q, 1); /* column */ pushInstruction(mb,r); getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(s, 1) = getArg(q, 3); /* updates */ s = ReplaceWithNil(mb, s, 2, TYPE_bat); /* no candidate list */ setArgType(mb, s, 2, newBatType(TYPE_oid,TYPE_oid)); /* make sure to resolve again */ s->token = ASSIGNsymbol; s->typechk = TYPE_UNKNOWN; s->fcn = NULL; s->blk = NULL; pushInstruction(mb,s); getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(t, 1) = getArg(q, 4); /* inserts */ pushInstruction(mb,t); setFunctionId(u, subdeltaRef); getArg(u, 0) = getArg(p,0); getArg(u, 1) = getArg(r,0); getArg(u, 2) = getArg(p,2); /* pre-cands */ getArg(u, 3) = getArg(q,2); /* update ids */ getArg(u, 4) = getArg(s,0); u = pushArgument(mb, u, getArg(t,0)); pushInstruction(mb,u); freeInstruction(p); continue; } } pushInstruction(mb,p); } for (; i<limit; i++) if (old[i]) pushInstruction(mb,old[i]); GDKfree(vars); GDKfree(old); return actions; }
int OPTquerylogImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, limit, slimit; InstrPtr p = 0, *old= mb->stmt, q,r; int argc, io, user,nice,sys,idle,iowait,load, arg, start,finish, name; int xtime=0, rtime = 0, tuples=0; InstrPtr defineQuery = NULL; // query log needed? if ( !QLOGisset() ) return 0; (void) pci; (void) stk; /* to fool compilers */ (void) cntxt; /* gather information */ for (i = 1; i < mb->stop; i++) { p = getInstrPtr(mb,i); if ( getModuleId(p) && idcmp(getModuleId(p), "querylog") == 0 && idcmp(getFunctionId(p),"define")==0){ defineQuery= p; getVarConstant(mb,getArg(p,3)).val.lval = GDKusec()-getVarConstant(mb,getArg(p,3)).val.lval ; } } if ( defineQuery == NULL) /* nothing to do */ return 0; limit= mb->stop; slimit= mb->ssize; if ( newMalBlkStmt(mb, mb->ssize) < 0) return 0; pushInstruction(mb, old[0]); /* run the querylog.define operation */ defineQuery = copyInstruction(defineQuery); setFunctionId(defineQuery, insertRef); getArg(defineQuery,0) = newTmpVariable(mb,TYPE_any); defineQuery->token = ASSIGNsymbol; setModuleId(defineQuery,querylogRef); /* collect the initial statistics */ q = newStmt(mb, "clients", "getUsername"); name= getArg(q,0)= newVariable(mb,GDKstrdup("name"),TYPE_str); defineQuery = pushArgument(mb,defineQuery,name); q = newStmt(mb, "mtime", "current_timestamp"); start= getArg(q,0)= newVariable(mb,GDKstrdup("start"),TYPE_timestamp); defineQuery = pushArgument(mb,defineQuery,start); pushInstruction(mb, defineQuery); q = newStmt1(mb, sqlRef, "argRecord"); for ( argc=1; argc < old[0]->argc; argc++) q = pushArgument(mb, q, getArg(old[0],argc)); arg= getArg(q,0)= newVariable(mb,GDKstrdup("args"),TYPE_str); q = newStmt(mb, "alarm", "usec"); xtime = getArg(q,0)= newVariable(mb,GDKstrdup("xtime"),TYPE_lng); user = newVariable(mb,GDKstrdup("user"),TYPE_lng); nice = newVariable(mb,GDKstrdup("nice"),TYPE_lng); sys = newVariable(mb,GDKstrdup("sys"),TYPE_lng); idle = newVariable(mb,GDKstrdup("idle"),TYPE_lng); iowait = newVariable(mb,GDKstrdup("iowait"),TYPE_lng); q = newStmt(mb, "profiler", "cpustats"); q->retc= q->argc =0; q = pushReturn(mb,q,user); q = pushReturn(mb,q,nice); q = pushReturn(mb,q,sys); q = pushReturn(mb,q,idle); q = pushReturn(mb,q,iowait); q = newAssignment(mb); tuples= getArg(q,0) = newVariable(mb,GDKstrdup("tuples"),TYPE_wrd); (void) pushWrd(mb,q,1); for (i = 1; i < limit; i++) { p = old[i]; if (getModuleId(p)==sqlRef && (idcmp(getFunctionId(p),"exportValue")==0 || idcmp(getFunctionId(p),"exportResult")==0 ) ) { q = newStmt(mb, "alarm", "usec"); r = newStmt1(mb, calcRef, "-"); r = pushArgument(mb, r, getArg(q,0)); r = pushArgument(mb, r, xtime); getArg(r,0)=xtime; q = newStmt(mb, "alarm", "usec"); rtime= getArg(q,0)= newVariable(mb,GDKstrdup("rtime"),TYPE_lng); pushInstruction(mb,p); continue; } if ( getModuleId(p) == sqlRef && idcmp(getFunctionId(p),"resultSet")==0 && isaBatType(getVarType(mb,getArg(p,3)))){ q = newStmt(mb, "aggr", "count"); getArg(q,0) = tuples; (void) pushArgument(mb,q, getArg(p,3)); pushInstruction(mb,p); continue; } if ( p->token== ENDsymbol || p->barrier == RETURNsymbol || p->barrier == YIELDsymbol){ if ( rtime == 0){ q = newStmt(mb, "alarm", "usec"); r = newStmt1(mb, calcRef, "-"); r = pushArgument(mb, r, getArg(q,0)); r = pushArgument(mb, r, xtime); getArg(r,0)=xtime; q = newStmt(mb, "alarm", "usec"); rtime= getArg(q,0)= newVariable(mb,GDKstrdup("rtime"),TYPE_lng); } q = newStmt(mb, "alarm", "usec"); r = newStmt1(mb, calcRef, "-"); r = pushArgument(mb, r, getArg(q,0)); r = pushArgument(mb, r, rtime); getArg(r,0)=rtime; /* * Post execution statistics gathering */ q = newStmt(mb, "mtime", "current_timestamp"); finish= getArg(q,0)= newVariable(mb,GDKstrdup("finish"),TYPE_any); q = newStmt(mb, "profiler", "cpuload"); load = newVariable(mb,GDKstrdup("load"),TYPE_int); getArg(q,0)= load; io = newVariable(mb,GDKstrdup("io"),TYPE_int); q= pushReturn(mb,q,io); q = pushArgument(mb,q,user); q = pushArgument(mb,q,nice); q = pushArgument(mb,q,sys); q = pushArgument(mb,q,idle); q = pushArgument(mb,q,iowait); q = newStmt(mb, querylogRef, "call"); q = pushArgument(mb, q, start); q = pushArgument(mb, q, finish); q = pushArgument(mb, q, arg); q = pushArgument(mb, q, tuples); q = pushArgument(mb, q, xtime); q = pushArgument(mb, q, rtime); q = pushArgument(mb, q, load); q = pushArgument(mb, q, io); pushInstruction(mb,p); continue; } pushInstruction(mb,p); if (p->barrier == YIELDsymbol){ /* the factory yield may return */ q = newStmt(mb, "mtime", "current_timestamp"); start= getArg(q,0)= newVariable(mb,GDKstrdup("start"),TYPE_any); q = newStmt1(mb, sqlRef, "argRecord"); for ( argc=1; argc < old[0]->argc; argc++) q = pushArgument(mb, q, getArg(old[0],argc)); arg= getArg(q,0)= newVariable(mb,GDKstrdup("args"),TYPE_str); q = newAssignment(mb); q = pushLng(mb,q,0); q = newAssignment(mb); q = pushWrd(mb,q,0); tuples= getArg(q,0)= newVariable(mb,GDKstrdup("tuples"),TYPE_wrd); newFcnCall(mb,"profiler","setMemoryFlag"); q->argc--; pushWrd(mb,q,1); q = newStmt(mb, "alarm", "usec"); xtime = getArg(q,0)= newVariable(mb,GDKstrdup("xtime"),TYPE_lng); } } for( ; i<slimit; i++) if(old[i]) freeInstruction(old[i]); GDKfree(old); return 1; }
/* * Macro inversions map a consecutive sequences of MAL instructions * into a single call. Subsequent resolution will bind it with the proper * function. The pattern being replaced should be a self-standing * assignment. [could be improved] * * The function being replaced should assign the result to * the signature variables. Otherwise it will be difficult * to assess which result to retain. */ static int replaceMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc) { int i, j, k, lim; InstrPtr p, q, rq; int *cvar, *mvar; int ctop = 0, mtop = 0; /* collect variable map */ cvar = (int *) GDKmalloc(mc->vtop * mc->maxarg * sizeof(*cvar)); if (cvar == NULL) return -1; mvar = (int *) GDKmalloc(mb->vtop * mc->maxarg * sizeof(*mvar)); if (mvar == NULL){ GDKfree(cvar); return -1; } lim = pc + mc->stop - 3; k = 1; for (i = pc; i < lim; i++, k++) { p = getInstrPtr(mb, i); q = getInstrPtr(mc, k); for (j = 0; j < q->argc; j++) cvar[ctop++] = getArg(q, j); assert(ctop < mc->vtop *mc->maxarg); for (j = 0; j < p->argc; j++) mvar[mtop++] = getArg(p, j); } assert(mtop == ctop); /*shouldn't happen */ p = getInstrPtr(mb, pc); q = copyInstruction(getInstrPtr(mc, 0)); /* the signature */ q->token = ASSIGNsymbol; mb->stmt[pc] = q; for (i = q->retc; i < q->argc; i++) for (j = 0; j < ctop; j++) if (q->argv[i] == cvar[j]) { q->argv[i] = mvar[j]; break; } /* take the return expression and match the variables*/ rq = getInstrPtr(mc, mc->stop - 2); for (i = 0; i < rq->retc; i++) for (j = 0; j < ctop; j++) if (rq->argv[i+rq->retc] == cvar[j]) { q->argv[i] = mvar[j]; break; } freeInstruction(p); /* strip signature, return, and end statements */ k = mc->stop - 3; j = pc + k; for (i = pc + 1; i < pc + k; i++) freeInstruction(mb->stmt[i]); for (i = pc + 1; i < mb->stop - k; i++) mb->stmt[i] = mb->stmt[j++]; k = i; for (; i < mb->stop; i++) mb->stmt[i] = 0; mb->stop = k; GDKfree(cvar); GDKfree(mvar); return pc; }
int inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc) { int i, k, l, n; InstrPtr *ns, p,q; int *nv, *np = NULL; p = getInstrPtr(mb, pc); q = getInstrPtr(mc, 0); ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr)); if (ns == NULL) return -1; if ( mc->ptop > 0){ np = (int*) GDKmalloc(mc->ptop * sizeof(int)); if (np == 0){ GDKfree(ns); return -1; } } nv = (int*) GDKmalloc(mc->vtop * sizeof(int)); if (nv == 0){ GDKfree(ns); if( np) GDKfree(np); return -1; } /* add all properties of the new block to the target environment */ for (n = 0; n < mc->ptop; n++) { int propid = newProperty(mb); if (propid < 0) { assert(0); return -1; } np[n] = propid; mb->prps[propid].idx = mc->prps[n].idx; mb->prps[propid].op = mc->prps[n].op; mb->prps[propid].var = mc->prps[n].var; /* fixed later */ } /* add all variables of the new block to the target environment */ for (n = 0; n < mc->vtop; n++) { VarPtr ov, v; if (isExceptionVariable(mc->var[n]->name)) { nv[n] = newVariable(mb,GDKstrdup(mc->var[n]->name),TYPE_str); if (isVarUDFtype(mc,n)) setVarUDFtype(mb,nv[n]); if (isVarUsed(mc,n)) setVarUsed(mb,nv[n]); } else if (isVarTypedef(mc,n)) { nv[n] = newTypeVariable(mb,getVarType(mc,n)); } else if (isVarConstant(mc,n)) { nv[n] = cpyConstant(mb,getVar(mc,n)); } else { nv[n] = newTmpVariable(mb, getVarType(mc, n)); if (isVarUDFtype(mc,n)) setVarUDFtype(mb,nv[n]); if (isVarUsed(mc,n)) setVarUsed(mb,nv[n]); } /* remap the properties */ ov = getVar(mc, n); v = getVar(mb, nv[n]); if (ov->propc > v->maxprop) { int size = sizeof(VarRecord); VarPtr vnew = (VarPtr) GDKzalloc(size + ov->propc * sizeof(int)); memcpy((char*) vnew, (char*) v, size); vnew->maxprop = ov->propc; mb->var[nv[n]] = vnew; GDKfree(v); v = getVar(mb, nv[n]); } for (i = 0; i < ov->propc; i++) v->prps[i] = np[ov->prps[i]]; v->propc = ov->propc; } /* change the property variables to the new context */ for (n = 0; n < mc->ptop; n++) { if (mc->prps[n].var) mb->prps[np[n]].var = nv[mc->prps[n].var]; assert( mb->prps[np[n]].var >= 0); } /* use an alias mapping to keep track of the actual arguments */ for (n = p->retc; n < p->argc; n++) nv[getArg(q,n)] = getArg(p, n); k = 0; /* find the return statement of the inline function */ for (i = 1; i < mc->stop - 1; i++) { q = mc->stmt[i]; if( q->barrier== RETURNsymbol || q->barrier== YIELDsymbol){ /* add the mapping of the return variables */ for(n=0; n<p->retc; n++) nv[getArg(q,n)] = getArg(p,n); } } /* copy the stable part */ for (i = 0; i < pc; i++) ns[k++] = mb->stmt[i]; for (i = 1; i < mc->stop - 1; i++) { q = mc->stmt[i]; if( q->token == ENDsymbol) break; /* copy the instruction and fix variable references */ ns[k] = copyInstruction(q); for (n = 0; n < q->argc; n++) getArg(ns[k], n) = nv[getArg(q, n)]; if (q->barrier == RETURNsymbol || q->barrier == YIELDsymbol) { for(n=0; n<q->retc; n++) clrVarFixed(mb,getArg(ns[k],n)); /* for typing */ setModuleId(ns[k],getModuleId(q)); setFunctionId(ns[k],getFunctionId(q)); ns[k]->barrier = 0; ns[k]->token = ASSIGNsymbol; } k++; } /* copy the remainder of the stable part */ freeInstruction(p); for (i = pc + 1; i < mb->stop; i++){ ns[k++] = mb->stmt[i]; } /* remove any free instruction */ for(; i<mb->ssize; i++) if( mb->stmt[i]){ freeInstruction(mb->stmt[i]); mb->stmt[i]= 0; } GDKfree(mb->stmt); mb->stmt = ns; mb->ssize = l; mb->stop = k; GDKfree(np); GDKfree(nv); return pc; }
int OPTaccumulatorsImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, limit,slimit; InstrPtr p,q; Module scope = cntxt->nspace; int actions = 0; InstrPtr *old; Lifespan span; (void) pci; (void) stk; /* to fool compilers */ span = setLifespan(mb); if( span == NULL) return 0; old= mb->stmt; limit= mb->stop; slimit= mb->ssize; if ( newMalBlkStmt(mb,mb->stop) < 0){ GDKfree(span); return 0; } for (i = 0; i < limit; i++) { p = old[i]; if( getModuleId(p) != batcalcRef ) { pushInstruction(mb,p); continue; } OPTDEBUGaccumulators printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); if (p->retc==1 && p->argc == 2) { /* unary operation, avoid clash with binary */ pushInstruction(mb,p); continue; } if( getLastUpdate(span,getArg(p,0)) != i ) { /* only consider the last update to this variable */ pushInstruction(mb,p); continue; } if (p->retc==1 && p->argc == 3 && isaBatType(getArgType(mb,p,0))) { int b1 =getEndLifespan(span,getArg(p,1))<=i && getArgType(mb,p,1) == getArgType(mb,p,0); int b2 =getEndLifespan(span,getArg(p,2))<=i && getArgType(mb,p,2) == getArgType(mb,p,0) ; if ( b1 == 0 && b2 == 0){ pushInstruction(mb,p); continue; } /* binary/unary operation, check arguments for being candidates */ q= copyInstruction(p); p= pushBit(mb,p, b1); p= pushBit(mb,p, b2); typeChecker(cntxt->fdout, scope, mb, p, TRUE); if (mb->errors || p->typechk == TYPE_UNKNOWN) { OPTDEBUGaccumulators{ mnstr_printf(cntxt->fdout,"# Failed typecheck"); printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); } /* reset instruction error buffer */ cntxt->errbuf[0]=0; mb->errors = 0; freeInstruction(p); p=q; /* restore */ } else {
int OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { int i, j, cnt, tp, c, actions = 0, marks = 0, delta = 0; Lifespan span; InstrPtr *old, q; int limit, updstmt = 0; char *recycled; short app_sc = -1, in = 0; ValRecord cst; (void) cntxt; (void) stk; limit = mb->stop; old = mb->stmt; for (i = 1; i < limit; i++) { p = old[i]; if (getModuleId(p) == sqlRef && (getFunctionId(p) == affectedRowsRef || getFunctionId(p) == exportOperationRef || getFunctionId(p) == appendRef || getFunctionId(p) == updateRef || getFunctionId(p) == deleteRef)) updstmt = 1; } span = setLifespan(mb); if (span == NULL) return 0; /* watch out, newly created instructions may introduce new variables */ recycled = GDKzalloc(sizeof(char) * mb->vtop * 2); if (recycled == NULL) return 0; if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(recycled); return 0; } pushInstruction(mb, old[0]); mb->recid = recycleSeq++; /* create a handle for recycler */ (void) newFcnCall(mb, "recycle", "prelude"); in = 1; for (i = 1; i < limit; i++) { p = old[i]; if (hasSideEffects(p, TRUE) || isUpdateInstruction(p) || isUnsafeFunction(p)) { if (getModuleId(p) == recycleRef) { /*don't inline recycle instr. */ freeInstruction(p); continue; } pushInstruction(mb, p); /* update instructions are not recycled but monitored*/ if (isUpdateInstruction(p)) { if (getModuleId(p) == batRef && (getArgType(mb, p, 1) == TYPE_bat || isaBatType(getArgType(mb, p, 1)))) { recycled[getArg(p, 1)] = 0; q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, getArg(p, 1)); actions++; } if (getModuleId(p) == sqlRef) { if (getFunctionId(p) == appendRef) { if (app_sc >= 0) continue; else app_sc = getArg(p, 2); } VALset(&cst, TYPE_int, &delta); c = defConstant(mb, TYPE_int, &cst); q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, c); pushArgument(mb, q, getArg(p, 2)); pushArgument(mb, q, getArg(p, 3)); if (getFunctionId(p) == updateRef) pushArgument(mb, q, getArg(p, 4)); actions++; } } /* take care of SQL catalog update instructions */ if (getModuleId(p) == sqlRef && getFunctionId(p) == catalogRef) { tp = *(int *) getVarValue(mb, getArg(p, 1)); if (tp == 22 || tp == 25) { delta = 2; VALset(&cst, TYPE_int, &delta); c = defConstant(mb, TYPE_int, &cst); q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, c); pushArgument(mb, q, getArg(p, 2)); if (tp == 25) pushArgument(mb, q, getArg(p, 3)); actions++; } } continue; } if (p->token == ENDsymbol || p->barrier == RETURNsymbol) { if (in) { /* if (updstmt && app_sc >= 0) { q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, app_sc); pushArgument(mb, q, app_tbl); } */ (void) newFcnCall(mb, "recycle", "epilogue"); in = 0; } pushInstruction(mb, p); continue; } if (p->barrier && p->token != CMDcall) { /* never save a barrier unless it is a command and side-effect free */ pushInstruction(mb, p); continue; } /* don't change instructions in update statements */ if (updstmt) { pushInstruction(mb, p); continue; } /* skip simple assignments */ if (p->token == ASSIGNsymbol) { pushInstruction(mb, p); continue; } if (getModuleId(p) == octopusRef && (getFunctionId(p) == bindRef || getFunctionId(p) == bindidxRef)) { recycled[getArg(p, 0)] = 1; p->recycle = recycleMaxInterest; marks++; } /* During base table recycling skip marking instructions other than octopus.bind */ if (baseTableMode) { pushInstruction(mb, p); continue; } /* general rule: all arguments are constants or recycled, ignore C pointer arguments from mvc */ cnt = 0; for (j = p->retc; j < p->argc; j++) if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j)) || ignoreVar(mb, getArg(p, j))) cnt++; if (cnt == p->argc - p->retc) { OPTDEBUGrecycle { mnstr_printf(cntxt->fdout, "#recycle instruction\n"); printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); } marks++; p->recycle = recycleMaxInterest; /* this instruction is to be monitored */ for (j = 0; j < p->retc; j++) if (getLastUpdate(span, getArg(p, j)) == i) recycled[getArg(p, j)] = 1; } /* * The expected gain is largest if we can re-use selections * on the base tables in SQL. These, however, are marked as * uselect() calls, which only produce the oid head. * For cheap types we preselect using select() and re-map uselect() back * over this temporary. * For the time being for all possible selects encountered * are marked for re-use. */ /* take care of semantic driven recyling */ /* for selections check the bat argument only the range is often template parameter*/ if ((getFunctionId(p) == selectRef || getFunctionId(p) == antiuselectRef || getFunctionId(p) == likeselectRef || getFunctionId(p) == likeRef || getFunctionId(p) == thetaselectRef) && recycled[getArg(p, 1)]) { p->recycle = recycleMaxInterest; marks++; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } if ((getFunctionId(p) == uselectRef || getFunctionId(p) == thetauselectRef) && recycled[getArg(p, 1)]) { if (!ATOMvarsized(getGDKType(getArgType(mb, p, 2)))) { q = copyInstruction(p); getArg(q, 0) = newTmpVariable(mb, TYPE_any); if (getFunctionId(p) == uselectRef) setFunctionId(q, selectRef); else setFunctionId(q, thetaselectRef); q->recycle = recycleMaxInterest; marks++; recycled[getArg(q, 0)] = 1; pushInstruction(mb, q); getArg(p, 1) = getArg(q, 0); setFunctionId(p, projectRef); p->argc = 2; } p->recycle = recycleMaxInterest; marks++; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } if (getModuleId(p) == pcreRef) { if ((getFunctionId(p) == selectRef && recycled[getArg(p, 2)]) || (getFunctionId(p) == uselectRef && recycled[getArg(p, 2)])) { p->recycle = recycleMaxInterest; marks++; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } else if (getFunctionId(p) == likeuselectRef && recycled[getArg(p, 1)]) { q = copyInstruction(p); getArg(q, 0) = newTmpVariable(mb, TYPE_any); setFunctionId(q, likeselectRef); q->recycle = recycleMaxInterest; recycled[getArg(q, 0)] = 1; pushInstruction(mb, q); getArg(p, 1) = getArg(q, 0); setFunctionId(p, projectRef); setModuleId(p, algebraRef); p->argc = 2; p->recycle = recycleMaxInterest; marks += 2; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } } /* * The sql.bind instructions should be handled carefully * The delete and update BATs should not be recycled, * because they may lead to view dependencies that later interferes * with the transaction commits. */ /* enable recycling of delta-bats if (getModuleId(p) == sqlRef && (((getFunctionId(p) == bindRef || getFunctionId(p) == putName("bind_idxbat", 11)) && getVarConstant(mb, getArg(p, 5)).val.ival != 0) || getFunctionId(p) == binddbatRef)) { recycled[getArg(p, 0)] = 0; p->recycle = REC_NO_INTEREST; } */ /* * The sql.bind instructions should be handled carefully * The delete and update BATs should not be recycled, * because they may lead to view dependencies that later interferes * with the transaction commits. */ /* enable recycling of delta-bats if (getModuleId(p)== sqlRef && (((getFunctionId(p)==bindRef || getFunctionId(p) == putName("bind_idxbat",11)) && getVarConstant(mb, getArg(p,5)).val.ival != 0) || getFunctionId(p)== binddbatRef) ) { recycled[getArg(p,0)]=0; p->recycle = REC_NO_INTEREST; } */ pushInstruction(mb, p); }
int OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, cnt, cand, actions = 1, marks = 0; InstrPtr *old, q,p; int limit; char *recycled; (void) cntxt; (void) stk; (void) pci; limit = mb->stop; old = mb->stmt; /* watch out, newly created instructions may introduce new variables */ recycled = GDKzalloc(sizeof(char) * mb->vtop * 2); if (recycled == NULL) return 0; if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(recycled); return 0; } pushInstruction(mb, old[0]); for (i = 1; i < limit; i++) { p = old[i]; if (p->token == ENDsymbol ) break; /* the first non-dataflow barrier breaks the recycler code*/ if (blockStart(p) && !(getFunctionId(p) && getFunctionId(p) == dataflowRef) ) break; if ( isUpdateInstruction(p) || hasSideEffects(p,TRUE)){ /* update instructions are not recycled but monitored*/ pushInstruction(mb, p); if (isUpdateInstruction(p)) { if (getModuleId(p) == batRef && isaBatType(getArgType(mb, p, 1))) { q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, getArg(p, 1)); actions++; } if (getModuleId(p) == sqlRef) { q= copyInstruction(p); getModuleId(q) = recycleRef; actions++; } } continue; } // Not all instruction may be recycled. In particular, we should avoid // MAL function with implicit/recursive side effects. // This can not always be detected easily. Likewise, we ignore cheap operations // Therefore, we use a safe subset to start with if ( ! (getModuleId(p) == sqlRef || getModuleId(p)== batRef || getModuleId(p) == algebraRef || getModuleId(p)==batcalcRef || getModuleId(p)== aggrRef || getModuleId(p)== groupRef || getModuleId(p)== batstrRef || getModuleId(p)== batmmathRef || getModuleId(p)== arrayRef || getModuleId(p)== batmtimeRef || getModuleId(p)== batcalcRef || getModuleId(p)== pcreRef || getModuleId(p)== mtimeRef || getModuleId(p) == calcRef || getModuleId(p)== dateRef || getModuleId(p) == timestampRef || getModuleId(p)== matRef ) ){ pushInstruction(mb,p); continue; } /* general rule: all arguments should be constants or recycled*/ cnt = 0; for (j = p->retc; j < p->argc; j++) if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j)) || isFunctionArgument(mb,getArg(p,j)) ) cnt++; cand = 0; for (j =0; j< p->retc; j++) if (recycled[getArg(p, j)] ==0) cand++; if (cnt == p->argc - p->retc && cand == p->retc) { marks++; p->recycle = RECYCLING; /* this instruction is to be monitored */ for (j = 0; j < p->retc; j++) recycled[getArg(p, j)] = 1; } pushInstruction(mb, p); } for (; i < limit; i++) pushInstruction(mb, old[i]); GDKfree(old); GDKfree(recycled); mb->recycle = marks > 0; OPTDEBUGrecycle { mnstr_printf(cntxt->fdout, "#recycle optimizer: "); printFunction(cntxt->fdout,mb, 0, LIST_MAL_ALL); } return actions + marks; }
str OPTwrapper (Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){ str modnme = "(NONE)"; str fcnnme = 0; str msg= MAL_SUCCEED; Symbol s= NULL; lng t,clk= GDKusec(); int i, actions = 0; char optimizer[256]; InstrPtr q; if( p == NULL) throw(MAL, "opt_wrapper", "missing optimizer statement"); snprintf(optimizer,256,"%s", fcnnme = getFunctionId(p)); q= copyInstruction(p); OPTIMIZERDEBUG mnstr_printf(cntxt->fdout,"=APPLY OPTIMIZER %s\n",fcnnme); if( p && p->argc > 1 ){ if( getArgType(mb,p,1) != TYPE_str || getArgType(mb,p,2) != TYPE_str || !isVarConstant(mb,getArg(p,1)) || !isVarConstant(mb,getArg(p,2)) ) { freeInstruction(q); throw(MAL, optimizer, ILLARG_CONSTANTS); } if( stk != 0){ modnme= *getArgReference_str(stk,p,1); fcnnme= *getArgReference_str(stk,p,2); } else { modnme= getArgDefault(mb,p,1); fcnnme= getArgDefault(mb,p,2); } removeInstruction(mb, p); s= findSymbol(cntxt->nspace, putName(modnme,strlen(modnme)),putName(fcnnme,strlen(fcnnme))); if( s == NULL) { freeInstruction(q); throw(MAL, optimizer, RUNTIME_OBJECT_UNDEFINED ":%s.%s", modnme, fcnnme); } mb = s->def; stk= 0; } else if( p ) removeInstruction(mb, p); if( mb->errors ){ /* when we have errors, we still want to see them */ addtoMalBlkHistory(mb,getModuleId(q)); freeInstruction(q); return MAL_SUCCEED; } for ( i=0; codes[i].nme; i++) if ( strcmp(codes[i].nme, optimizer)== 0 ){ actions = (int)(*(codes[i].fcn))(cntxt, mb, stk,0); break; } if ( codes[i].nme == 0){ freeInstruction(q); throw(MAL, optimizer, RUNTIME_OBJECT_UNDEFINED ":%s.%s", modnme, fcnnme); } msg= optimizerCheck(cntxt, mb, optimizer, actions, t=(GDKusec() - clk)); OPTIMIZERDEBUG { mnstr_printf(cntxt->fdout,"=FINISHED %s %d\n",optimizer, actions); printFunction(cntxt->fdout,mb,0,LIST_MAL_DEBUG ); } DEBUGoptimizers mnstr_printf(cntxt->fdout,"#optimizer %-11s %3d actions %5d MAL instructions ("SZFMT" K) " LLFMT" usec\n", optimizer, actions, mb->stop, ((sizeof( MalBlkRecord) +mb->ssize * offsetof(InstrRecord, argv)+ mb->vtop * sizeof(int) /* argv estimate */ +mb->vtop* sizeof(VarRecord) + mb->vsize*sizeof(VarPtr)+1023)/1024), t); QOTupdateStatistics(getModuleId(q),actions,t); addtoMalBlkHistory(mb,getModuleId(q)); freeInstruction(q); return msg; }
str OPToltpImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, limit, slimit, updates=0; InstrPtr p, q, lcks; int actions = 0; InstrPtr *old; lng usec = GDKusec(); OLTPlocks wlocks, rlocks; char buf[256]; str msg = MAL_SUCCEED; (void) pci; (void) cntxt; (void) stk; /* to fool compilers */ old= mb->stmt; limit= mb->stop; slimit = mb->ssize; // We use a fake collection of objects to speed up the checking later. OLTPclear(wlocks); OLTPclear(rlocks); for (i = 0; i < limit; i++) { p = old[i]; if( getModuleId(p) == sqlRef && getFunctionId(p) == bindRef) addLock(cntxt,rlocks, mb, p, p->retc + 1, p->retc + 2); else if( getModuleId(p) == sqlRef && getFunctionId(p) == bindidxRef) addLock(cntxt,rlocks, mb, p, p->retc + 1, p->retc + 2); else if( getModuleId(p) == sqlRef && getFunctionId(p) == appendRef ){ addLock(cntxt,wlocks, mb, p, p->retc + 1, p->retc + 2); updates++; } else if( getModuleId(p) == sqlRef && getFunctionId(p) == updateRef ){ addLock(cntxt,wlocks, mb, p, p->retc + 1, p->retc + 2); updates++; } else if( getModuleId(p) == sqlRef && getFunctionId(p) == deleteRef ){ addLock(cntxt,wlocks, mb, p, p->retc + 1, p->retc + 2); updates++; } else if( getModuleId(p) == sqlcatalogRef ){ addLock(cntxt,wlocks, mb, p, 0,0); updates++; } } if( updates == 0) return 0; // Get a free instruction, don't get it from mb lcks= newInstruction(0, oltpRef,lockRef); getArg(lcks,0)= newTmpVariable(mb, TYPE_void); for( i = 0; i< MAXOLTPLOCKS; i++) if( wlocks[i]) lcks = pushInt(mb, lcks, i); else if( rlocks[i]) lcks = pushInt(mb, lcks, -i); if( lcks->argc == 1 ){ freeInstruction(lcks); return MAL_SUCCEED; } // Now optimize the code if ( newMalBlkStmt(mb,mb->ssize + 6) < 0) { freeInstruction(lcks); return 0; } pushInstruction(mb,old[0]); pushInstruction(mb,lcks); for (i = 1; i < limit; i++) { p = old[i]; if( p->token == ENDsymbol){ // unlock all if there is an error q= newCatchStmt(mb,"MALexception"); q= newExitStmt(mb,"MALexception"); q= newCatchStmt(mb,"SQLexception"); q= newExitStmt(mb,"SQLexception"); q= copyInstruction(lcks); if( q == NULL){ for(; i<slimit; i++) if( old[i]) freeInstruction(old[i]); GDKfree(old); throw(MAL,"optimizer.oltp", SQLSTATE(HY001) MAL_MALLOC_FAIL); } setFunctionId(q, releaseRef); pushInstruction(mb,q); } pushInstruction(mb,p); } for(; i<slimit; i++) if( old[i]) freeInstruction(old[i]); GDKfree(old); /* Defense line against incorrect plans */ 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","oltp",actions, usec); newComment(mb,buf); if( actions >= 0) addtoMalBlkHistory(mb); return msg; }