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 OPTjsonImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, limit, slimit; int bu = 0, br = 0, bj = 0; str nme; InstrPtr p,q; int actions = 0; InstrPtr *old; (void) pci; (void) cntxt; (void) stk; /* to fool compilers */ old= mb->stmt; limit= mb->stop; slimit = mb->ssize; if ( newMalBlkStmt(mb,mb->stop) < 0) return 0; for (i = 0; i < limit; i++) { p = old[i]; if( getModuleId(p) == sqlRef && getFunctionId(p) == affectedRowsRef) { q = newStmt(mb, jsonRef, resultSetRef); q = pushArgument(mb, q, bu); q = pushArgument(mb, q, br); q = pushArgument(mb, q, bj); j = getArg(q,0); p= getInstrPtr(mb,0); setVarType(mb,getArg(p,0),TYPE_str); q = newReturnStmt(mb); getArg(q,0)= getArg(p,0); pushArgument(mb,q,j); continue; } if( getModuleId(p) == sqlRef && getFunctionId(p) == rsColumnRef) { nme = getVarConstant(mb,getArg(p,4)).val.sval; if (strcmp(nme,"uuid")==0) bu = getArg(p,7); if (strcmp(nme,"lng")==0) br = getArg(p,7); if (strcmp(nme,"json")==0) bj = getArg(p,7); freeInstruction(p); continue; } pushInstruction(mb,p); } for(; i<slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); return actions; }
int OPTmultiplexImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr *old, p; int i, limit, slimit, actions= 0; str msg= MAL_SUCCEED; (void) stk; (void) pci; old = mb->stmt; limit = mb->stop; slimit = mb->ssize; if ( newMalBlkStmt(mb, mb->ssize) < 0 ) return 0; for (i = 0; i < limit; i++) { p = old[i]; if (msg == MAL_SUCCEED && getModuleId(p) == malRef && getFunctionId(p) == multiplexRef) { if ( MANIFOLDtypecheck(cntxt,mb,p) != NULL){ setFunctionId(p, manifoldRef); pushInstruction(mb, p); actions++; continue; } msg = OPTexpandMultiplex(cntxt, mb, stk, p); if( msg== MAL_SUCCEED){ freeInstruction(p); old[i]=0; actions++; continue; } pushInstruction(mb, p); actions++; } else if( old[i]) pushInstruction(mb, p); } for(;i<slimit; i++) if( old[i]) freeInstruction(old[i]); GDKfree(old); if (mb->errors){ /* rollback */ } GDKfree(msg); return mb->errors? 0: actions; }
int OPTmatpackImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int v, i, j, limit, slimit; InstrPtr p,q; int actions = 0; InstrPtr *old; char *packIncrementRef = putName("packIncrement", 13); (void) pci; (void) cntxt; (void) stk; /* to fool compilers */ old= mb->stmt; limit= mb->stop; slimit = mb->ssize; if ( newMalBlkStmt(mb,mb->stop) < 0) return 0; for (i = 0; i < limit; i++) { p = old[i]; if( getModuleId(p) == matRef && getFunctionId(p) == packRef && isaBatType(getArgType(mb,p,1))) { q = newStmt(mb, matRef, packIncrementRef); v = getArg(q,0); setVarType(mb,v,getArgType(mb,p,1)); q = pushArgument(mb, q, getArg(p,1)); q = pushInt(mb,q, p->argc - p->retc); for ( j = 2; j < p->argc; j++) { q = newStmt(mb,matRef, packIncrementRef); q = pushArgument(mb, q, v); q = pushArgument(mb, q, getArg(p,j)); setVarType(mb,getArg(q,0),getVarType(mb,v)); v = getArg(q,0); } getArg(q,0) = getArg(p,0); freeInstruction(p); continue; } pushInstruction(mb,p); } for(; i<slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); return actions; }
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; }
static int OPTsql_appendImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr *old = NULL; int i, limit, slimit, actions = 0; (void) pci; /* Tell compilers that we know that we do not */ (void) stk; /* use these function parameters, here. */ /* In general, a MAL optimizer transforms a given MAL program into a * modified one by sequentially walking through the given program * and concurrently creating a new one from scratch by * (1) copying statements as is, modified, or in a different order, * or (2) omitting statements or (3) introducing new statements. */ /* check for logical error: mb must never be NULL */ assert (mb != NULL); /* save the old stage of the MAL block */ old = mb->stmt; limit= mb->stop; slimit = mb->ssize; /* initialize the statement list. Notice, the symbol table remains intact */ if (newMalBlkStmt(mb, mb->ssize) < 0) return 0; /* the plan signature can be copied safely */ pushInstruction(mb, old[0]); /* iterate over the instructions of the input MAL program */ for (i = 1; i < limit; i++) { InstrPtr p = old[i]; /* check for * v3 := sql.append( ..., ..., ..., ..., v0 ); */ if (getModuleId(p) == sqlRef && getFunctionId(p) == appendRef && p->argc > 5 && p->retc == 1 && isaBatType(getArgType(mb, p, 5))) { /* found * v3 := sql.append( ..., ..., ..., ..., v0 ); */ int j = 0, k = 0; InstrPtr q1 = NULL, q2 = NULL; bit found = FALSE; /* check whether next is * v4 := aggr.count(v0); */ if (i+1 < limit) { InstrPtr q = old[i+1]; if (getModuleId(q) == aggrRef && getFunctionId(q) == countRef && q->argc == 2 && q->retc == 1 && getArg(q, 1) == getArg(p, 5)) { /* found * v3 := sql.append( ..., ..., ..., ..., v0 ); * v4 := aggr.count(v0); */ /* issue/execute * v4 := aggr.count(v0); * before * v3 := sql.append( ..., ..., ..., ..., v0 ); */ pushInstruction(mb, q); q1 = q; i++; actions++; /* to keep track if anything has been done */ } } /* look for * v5 := ... v0 ...; */ /* an expensive loop, better would be to remember that v0 * has a different role. A typical method is to keep a * map from variable -> instruction where it was * detected. Then you can check each assignment for use of * v0 */ for (j = i+1; !found && j < limit; j++) for (k = old[j]->retc; !found && k < old[j]->argc; k++) found = (getArg(old[j], k) == getArg(p, 5)); if (found) { /* replace * v3 := sql.append( ..., ..., ..., ..., v0 ); * with * v1 := aggr.count( v0 ); * v2 := algebra.slice( v0, 0, v1 ); * v3 := sql.append( ..., ..., ..., ..., v2 ); */ /* push new v1 := aggr.count( v0 ); unless already available */ if (q1 == NULL) { /* use mal_builder.h primitives * q1 = newStmt(mb, aggrRef,countRef); * setArgType(mb,q1,TYPE_wrd) */ /* it will be added to the block and even my * re-use MAL instructions */ q1 = newInstruction(mb,ASSIGNsymbol); getArg(q1,0) = newTmpVariable(mb, TYPE_wrd); setModuleId(q1, aggrRef); setFunctionId(q1, countRef); q1 = pushArgument(mb, q1, getArg(p, 5)); pushInstruction(mb, q1); } /* push new v2 := algebra.slice( v0, 0, v1 ); */ /* use mal_builder.h primitives * q1 = newStmt(mb, algebraRef,sliceRef); */ q2 = newInstruction(mb,ASSIGNsymbol); getArg(q2,0) = newTmpVariable(mb, TYPE_any); setModuleId(q2, algebraRef); setFunctionId(q2, sliceRef); q2 = pushArgument(mb, q2, getArg(p, 5)); q2 = pushWrd(mb, q2, 0); q2 = pushArgument(mb, q2, getArg(q1, 0)); pushInstruction(mb, q2); /* push modified v3 := sql.append( ..., ..., ..., ..., v2 ); */ getArg(p, 5) = getArg(q2, 0); pushInstruction(mb, p); actions++; continue; } } pushInstruction(mb, p); if (p->token == ENDsymbol) break; } /* We would like to retain everything from the ENDsymbol * up to the end of the plan, because after the ENDsymbol * the remaining optimizer steps are stored. */ for(i++; i<limit; i++) if (old[i]) pushInstruction(mb, old[i]); /* any remaining MAL instruction records are removed */ for(; i<slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); /* for statistics we return if/how many patches have been made */ DEBUGoptimizers mnstr_printf(cntxt->fdout,"#opt_sql_append: %d statements added\n", actions); 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; }
str OPTvolcanoImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, limit; int mvcvar = -1; int count=0; InstrPtr p,q, *old = mb->stmt; char buf[256]; lng usec = GDKusec(); str msg = MAL_SUCCEED; (void) pci; (void) cntxt; (void) stk; /* to fool compilers */ if ( mb->inlineProp ) return MAL_SUCCEED; limit= mb->stop; if ( newMalBlkStmt(mb, mb->ssize + 20) < 0) throw(MAL,"optimizer.volcano", SQLSTATE(HY001) MAL_MALLOC_FAIL); for (i = 0; i < limit; i++) { p = old[i]; pushInstruction(mb,p); if( getModuleId(p) == sqlRef && getFunctionId(p)== mvcRef ){ mvcvar = getArg(p,0); continue; } if( count < MAXdelays && getModuleId(p) == algebraRef ){ if( getFunctionId(p) == selectRef || getFunctionId(p) == thetaselectRef || getFunctionId(p) == likeselectRef || getFunctionId(p) == joinRef ){ q= newInstruction(0,languageRef,blockRef); setDestVar(q, newTmpVariable(mb,TYPE_any)); q = pushArgument(mb,q,mvcvar); q = pushArgument(mb,q,getArg(p,0)); mvcvar= getArg(q,0); pushInstruction(mb,q); count++; } continue; } if( count < MAXdelays && getModuleId(p) == groupRef ){ if( getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef ){ q= newInstruction(0,languageRef,blockRef); setDestVar(q, newTmpVariable(mb,TYPE_any)); q = pushArgument(mb,q,mvcvar); q = pushArgument(mb,q,getArg(p,0)); mvcvar= getArg(q,0); pushInstruction(mb,q); count++; } } if( getModuleId(p) == sqlRef){ if ( getFunctionId(p) == bindRef || getFunctionId(p) == bindidxRef || getFunctionId(p)== tidRef || getFunctionId(p)== appendRef || getFunctionId(p)== updateRef || getFunctionId(p)== deleteRef ){ setArg(p,p->retc,mvcvar); } } } GDKfree(old); /* Defense line against incorrect plans */ if( count){ 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","volcano",count,usec); newComment(mb,buf); if( count >= 0) addtoMalBlkHistory(mb); return msg; }
str OPTmultiplexImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr *old = 0, p; int i, limit, slimit, actions= 0; str msg= MAL_SUCCEED; char buf[256]; lng usec = GDKusec(); (void) stk; (void) pci; old = mb->stmt; limit = mb->stop; slimit = mb->ssize; if ( newMalBlkStmt(mb, mb->ssize) < 0 ) throw(MAL,"optimizer.mergetable", SQLSTATE(HY001) MAL_MALLOC_FAIL); for (i = 0; i < limit; i++) { p = old[i]; if (msg == MAL_SUCCEED && isMultiplex(p)) { if ( MANIFOLDtypecheck(cntxt,mb,p,0) != NULL){ setFunctionId(p, manifoldRef); p->typechk = TYPE_UNKNOWN; pushInstruction(mb, p); actions++; continue; } msg = OPTexpandMultiplex(cntxt, mb, stk, p); if( msg== MAL_SUCCEED){ freeInstruction(p); old[i]=0; actions++; continue; } pushInstruction(mb, p); actions++; } else if( old[i]) pushInstruction(mb, p); } for(;i<slimit; i++) if( old[i]) freeInstruction(old[i]); GDKfree(old); /* Defense line against incorrect plans */ if( msg == MAL_SUCCEED && actions > 0){ 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","multiplex",actions, usec); newComment(mb,buf); if( actions >= 0) addtoMalBlkHistory(mb); return msg; }
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); }
/* * Keeping variables around beyond their end-of-life-span * can be marked with the proper 'keep'. */ int OPTgarbageCollectorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, k, n = 0, limit, vlimit, depth=0, slimit; InstrPtr p, q, *old; int actions = 0; Lifespan span; (void) pci; (void) cntxt; (void) stk; if (varGetProp(mb, getArg(mb->stmt[0], 0), inlineProp) != NULL) return 0; span = setLifespan(mb); if ( span == NULL) return 0; old= mb->stmt; limit = mb->stop; slimit = mb->ssize; vlimit = mb->vtop; if ( newMalBlkStmt(mb,mb->ssize) < 0) { GDKfree(span); return 0; } p = NULL; for (i = 0; i < limit; i++) { p = old[i]; p->gc &= ~GARBAGECONTROL; if ( p->barrier == RETURNsymbol){ pushInstruction(mb, p); continue; } if (blockStart(p) ) depth++; if ( p->token == ENDsymbol) break; pushInstruction(mb, p); n = mb->stop-1; for (j = 0; j < p->argc; j++) { if (getEndLifespan(span,getArg(p,j)) == i && isaBatType(getArgType(mb, p, j)) ){ mb->var[getArg(p,j)]->eolife = n; p->gc |= GARBAGECONTROL; } } if (blockExit(p) ){ /* force garbage collection of all within upper block */ depth--; for (k = 0; k < vlimit; k++) { if (getBeginLifespan(span,k) > 0 && getEndLifespan(span,k) == i && isaBatType(getVarType(mb,k)) && varGetProp(mb, k, keepProp) == NULL){ q= newAssignment(mb); getArg(q,0) = k; setVarUDFtype(mb,k); setVarFixed(mb,k); q= pushNil(mb,q, getVarType(mb,k)); q->gc |= GARBAGECONTROL; mb->var[k]->eolife = mb->stop-1; actions++; } } } } assert(p); assert( p->token == ENDsymbol); pushInstruction(mb, p); for (i++; i < limit; i++) pushInstruction(mb, old[i]); for (; i < slimit; i++) if (old[i]) freeInstruction(old[i]); getInstrPtr(mb,0)->gc |= GARBAGECONTROL; GDKfree(old); OPTDEBUGgarbageCollector{ int k; mnstr_printf(cntxt->fdout, "#Garbage collected BAT variables \n"); for ( k =0; k < vlimit; k++) mnstr_printf(cntxt->fdout,"%10s eolife %3d begin %3d lastupd %3d end %3d\n", getVarName(mb,k), mb->var[k]->eolife, getBeginLifespan(span,k), getLastUpdate(span,k), getEndLifespan(span,k)); mnstr_printf(cntxt->fdout, "End of GCoptimizer\n"); } GDKfree(span); return actions+1; }
str OPTjsonImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, limit, slimit; int bu = 0, br = 0, bj = 0; str nme; InstrPtr p,q; int actions = 0; InstrPtr *old; char buf[256]; lng usec = GDKusec(); str msg = MAL_SUCCEED; (void) pci; (void) cntxt; (void) stk; /* to fool compilers */ old= mb->stmt; limit= mb->stop; slimit = mb->ssize; if ( newMalBlkStmt(mb,mb->stop) < 0) throw(MAL,"optimizer.json", SQLSTATE(HY001) MAL_MALLOC_FAIL); for (i = 0; i < limit; i++) { p = old[i]; if( getModuleId(p) == sqlRef && getFunctionId(p) == affectedRowsRef) { q = newInstruction(0, jsonRef, resultSetRef); q = pushArgument(mb, q, bu); q = pushArgument(mb, q, br); q = pushArgument(mb, q, bj); j = getArg(q,0); p= getInstrPtr(mb,0); setDestVar(q, newTmpVariable(mb, TYPE_str)); pushInstruction(mb,p); q = newInstruction(0, NULL, NULL); q->barrier = RETURNsymbol; getArg(q,0)= getArg(p,0); pushArgument(mb,q,j); pushInstruction(mb,q); actions++; continue; } if( getModuleId(p) == sqlRef && getFunctionId(p) == rsColumnRef) { nme = getVarConstant(mb,getArg(p,4)).val.sval; if (strcmp(nme,"uuid")==0) bu = getArg(p,7); if (strcmp(nme,"lng")==0) br = getArg(p,7); if (strcmp(nme,"json")==0) bj = getArg(p,7); freeInstruction(p); actions++; continue; } pushInstruction(mb,p); } for(; i<slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); /* Defense line against incorrect plans */ if( actions > 0){ 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","json",actions, usec); newComment(mb,buf); if( actions >= 0) addtoMalBlkHistory(mb); return msg; }
str OPTgeneratorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr p,q, *old, *series; int i, k, limit, slimit, actions=0; str m; str bteRef = getName("bte"); str shtRef = getName("sht"); str intRef = getName("int"); str lngRef = getName("lng"); str fltRef = getName("flt"); str dblRef = getName("dbl"); char buf[256]; lng usec= GDKusec(); (void) cntxt; (void) stk; (void) pci; series = (InstrPtr*) GDKzalloc(sizeof(InstrPtr) * mb->vtop); if(series == NULL) throw(MAL,"optimizer.generator", SQLSTATE(HY001) MAL_MALLOC_FAIL); old = mb->stmt; limit = mb->stop; slimit = mb->ssize; // check applicability first for( i=0; i < limit; i++){ p = old[i]; if ( getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef) break; } if (i == limit) { GDKfree(series); return 0; } if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(series); throw(MAL,"optimizer.generator", SQLSTATE(HY001) MAL_MALLOC_FAIL); } for( i=0; i < limit; i++){ p = old[i]; if (p->token == ENDsymbol){ pushInstruction(mb,p); break; } if ( getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef){ series[getArg(p,0)] = p; setModuleId(p, generatorRef); setFunctionId(p, parametersRef); typeChecker(cntxt->usermodule, mb, p, TRUE); pushInstruction(mb,p); } else if ( getModuleId(p) == algebraRef && getFunctionId(p) == selectRef && series[getArg(p,1)]){ errorCheck(p,algebraRef,getArg(p,1)); } else if ( getModuleId(p) == algebraRef && getFunctionId(p) == thetaselectRef && series[getArg(p,1)]){ errorCheck(p,algebraRef,getArg(p,1)); } else if ( getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef && series[getArg(p,2)]){ errorCheck(p,algebraRef,getArg(p,2)); } else if ( getModuleId(p) == sqlRef && getFunctionId(p) == putName("exportValue") && isaBatType(getArgType(mb,p,0)) ){ // interface expects scalar type only, not expressable in MAL signature mb->errors=createException(MAL, "generate_series", SQLSTATE(42000) "internal error, generate_series is a table producing function"); }else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == bteRef && series[getArg(p,1)] && p->argc == 2 ){ casting(bte); } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == shtRef && series[getArg(p,1)] && p->argc == 2 ){ casting(sht); } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == intRef && series[getArg(p,1)] && p->argc == 2 ){ casting(int); } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == lngRef && series[getArg(p,1)] && p->argc == 2 ){ casting(lng); } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == fltRef && series[getArg(p,1)] && p->argc == 2 ){ casting(flt); } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == dblRef && series[getArg(p,1)] && p->argc == 2 ){ casting(dbl); } else if ( getModuleId(p) == languageRef && getFunctionId(p) == passRef ) pushInstruction(mb,p); else { // check for use without conversion for(k = p->retc; k < p->argc; k++) if( series[getArg(p,k)]){ m = getModuleId(p); setModuleId(p, generatorRef); typeChecker(cntxt->usermodule, mb, p, TRUE); if(p->typechk == TYPE_UNKNOWN){ setModuleId(p,m); typeChecker(cntxt->usermodule, mb, p, TRUE); setModuleId(series[getArg(p,k)], generatorRef); setFunctionId(series[getArg(p,k)], seriesRef); typeChecker(cntxt->usermodule, mb, series[getArg(p,k)], TRUE); } } pushInstruction(mb,p); } } for (i++; i < limit; i++) pushInstruction(mb, old[i]); for (; i < slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); GDKfree(series); #ifdef VLT_DEBUG fprintFunction(stderr,mb,0,LIST_MAL_ALL); #endif /* Defense line against incorrect plans */ /* all new/modified statements are already checked */ //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","generator",actions, usec); newComment(mb,buf); if( actions >= 0) addtoMalBlkHistory(mb); return MAL_SUCCEED; }
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 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; }