str MACROprocessor(Client cntxt, MalBlkPtr mb, Symbol t) { InstrPtr q; int i, cnt = 0, last = -1; str msg = MAL_SUCCEED; (void) cntxt; if (t == NULL) return msg; msg = MACROvalidate(t->def); if (msg) return msg; for (i = 0; i < mb->stop; i++) { q = getInstrPtr(mb, i); if (getFunctionId(q) && idcmp(getFunctionId(q), t->name) == 0 && getSignature(t)->token == FUNCTIONsymbol) { if (i == last) throw(MAL, "optimizer.MACROoptimizer", MACRO_DUPLICATE); last = i; i = inlineMALblock(mb, i, t->def); cnt++; if (cnt > MAXEXPANSION) throw(MAL, "optimizer.MACROoptimizer", MACRO_TOO_DEEP); } } return msg; }
/* * For clarity we show the last optimizer applied * also as the last of the list, although it is linked with mb. */ void showMalBlkHistory(stream *out, MalBlkPtr mb) { MalBlkPtr m=mb; InstrPtr p,sig; int j=0; str msg; sig = getInstrPtr(mb,0); m= m->history; while(m){ p= getInstrPtr(m,m->stop-1); if( p->token == REMsymbol){ msg= instruction2str(m, 0, p, FALSE); if (msg ) { mnstr_printf(out,"%s.%s[%2d] %s\n", getModuleId(sig), getFunctionId(sig),j++,msg+3); GDKfree(msg); } } m= m->history; } p=getInstrPtr(mb,mb->stop-1); if( p->token == REMsymbol){ msg= instruction2str(mb, 0, p, FALSE); if (msg) { mnstr_printf(out,"%s.%s[%2d] %s\n", getModuleId(sig), getFunctionId(sig),j++,msg+3); GDKfree(msg); } } }
static int malMatch(InstrPtr p1, InstrPtr p2) { int i, j; if (getFunctionId(p1) == 0 && getFunctionId(p2) != 0) return 0; if (getModuleId(p1) == 0 && getModuleId(p2) != 0) return 0; if (getModuleId(p1) != getModuleId(p2)) return 0; if (getFunctionId(p2) == 0) return 0; if (getFunctionId(p1) != getFunctionId(p2)) return 0; if (p1->retc != p2->retc) return 0; if (p1->argc != p2->argc) return 0; if (p1->barrier != p2->barrier) return 0; for (i = 0; i < p1->argc; i++) for (j = i + 1; j < p1->argc; j++) if ((getArg(p1, i) == getArg(p1, j)) != (getArg(p2, i) == getArg(p2, j))) return 0; return 1; }
void addOptimizers(Client c, MalBlkPtr mb, char *pipe) { int i; InstrPtr q; backend *be; str msg; be = (backend *) c->sqlcontext; assert(be && be->mvc); /* SQL clients should always have their state set */ msg = addOptimizerPipe(c, mb, pipe ? pipe : "default_pipe"); if (msg) GDKfree(msg); /* what to do with an error? */ /* point queries do not require mitosis and dataflow */ if (be->mvc->point_query) { for (i = mb->stop - 1; i > 0; i--) { q = getInstrPtr(mb, i); if (q->token == ENDsymbol) break; if (getFunctionId(q) == mitosisRef || getFunctionId(q) == dataflowRef) q->token = REMsymbol; /* they are ignored */ } } SQLgetStatistics(c, be->mvc, mb); if (be->mvc->emod & mod_debug) addtoMalBlkHistory(mb, "getStatistics"); }
/* * Removal of elements from the symbol table should be * done with care. For, it should be assured that * there are no references to the definition at the * moment of removal. This situation can not easily * checked at runtime, without tremendous overhead. */ void deleteSymbol(Module scope, Symbol prg){ InstrPtr sig; int t; sig = getSignature(prg); #ifdef _DEBUG_MODULE_ fprintf(stderr,"#delete symbol %s.%s from %s\n", getModuleId(sig), getFunctionId(sig), prg->name); #endif if (getModuleId(sig) && getModuleId(sig)!= scope->name ){ /* move the definition to the proper place */ /* default scope is the last resort */ Module c= findModule(scope, getModuleId(sig)); if(c ) scope = c; } t = getSymbolIndex(getFunctionId(sig)); if (scope->space[t] == prg) { scope->space[t] = scope->space[t]->peer; freeSymbol(prg); } else { Symbol nxt = scope->space[t]; while (nxt->peer != NULL) { if (nxt->peer == prg) { nxt->peer = prg->peer; nxt->skip = prg->peer; freeSymbol(prg); return; } nxt = nxt->peer; } } }
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; }
static int OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p) { int i; (void)cntxt; if ( !(p->token == ASSIGNsymbol || getModuleId(p) == calcRef || getModuleId(p) == strRef || getModuleId(p) == mtimeRef || getModuleId(p) == mmathRef)) return FALSE; if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0) return FALSE; for (i = p->retc; i < p->argc; i++) if (isVarConstant(mb, getArg(p, i)) == FALSE) return FALSE; for (i = 0; i < p->retc; i++) { if (isaBatType(getArgType(mb, p, i))) return FALSE; if ( mb->unsafeProp ) return FALSE; } return TRUE; }
str shutdownFactoryByName(Client cntxt, Module m, str nme){ Plant pl, plim; InstrPtr p; Symbol s; plim = plants + lastPlant; for (pl = plants; pl < plim; pl++) if (pl->factory ) { MalStkPtr stk; p= getInstrPtr(pl->factory,0); if( strcmp(nme, getFunctionId(p)) != 0) continue; s = findSymbolInModule(m, nme ); if (s == NULL){ throw(MAL, "factory.remove", OPERATION_FAILED " SQL entry '%s' not found", putName(nme)); } stk = pl->stk; MSresetVariables(cntxt, pl->factory, stk, 0); shutdownFactory(cntxt, pl->factory); freeStack(stk); deleteSymbol(m,s); return MAL_SUCCEED; } return MAL_SUCCEED; }
int OPTinlineImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { int i; InstrPtr q,sig; int actions = 0; (void) p; (void)stk; for (i = 1; i < mb->stop; i++) { q = getInstrPtr(mb, i); if( q->blk ) { sig = getInstrPtr(q->blk,0); /* * Time for inlining functions that are used in multiplex operations. * They are produced by SQL compiler. */ if( getFunctionId(q)== multiplexRef && getModuleId(q) == malRef && OPTinlineMultiplex(cntxt,mb,q)) { OPTDEBUGinline { mnstr_printf(cntxt->fdout,"#multiplex inline function\n"); printInstruction(cntxt->fdout,mb,0,q,LIST_MAL_ALL); } varSetProp(mb, getArg(q,0), inlineProp, op_eq, NULL); } else /* * Check if the function definition is tagged as being inlined. */ if (sig->token == FUNCTIONsymbol &&
/* * After filling in a structure it is added to the multi-level symbol * table. We keep a skip list of similarly named function symbols. * This speeds up searching provided the modules adhere to the * structure and group the functions as well. */ void insertSymbol(Module scope, Symbol prg){ InstrPtr sig; int t; Module c; assert(scope); sig = getSignature(prg); #ifdef _DEBUG_MODULE_ fprintf(stderr,"#insertSymbol: %s.%s in %s ", getModuleId(sig), getFunctionId(sig), scope->name); #endif if(getModuleId(sig) && getModuleId(sig)!= scope->name){ /* move the definition to the proper place */ /* default scope is the last resort */ c= findModule(scope,getModuleId(sig)); if ( c ) scope = c; #ifdef _DEBUG_MODULE_ fprintf(stderr," found alternative module %s ", scope->name); #endif } t = getSymbolIndex(getFunctionId(sig)); if( scope->space == NULL) { scope->space = (Symbol *) GDKzalloc(MAXSCOPE * sizeof(Symbol)); if (scope->space == NULL) return; } assert(scope->space); if (scope->space[t] == prg){ /* already known, last inserted */ #ifdef _DEBUG_MODULE_ fprintf(stderr," unexpected double insert "); #endif } else { prg->peer= scope->space[t]; scope->space[t] = prg; if( prg->peer && idcmp(prg->name,prg->peer->name) == 0) prg->skip = prg->peer->skip; else prg->skip = prg->peer; } assert(prg != prg->peer); #ifdef _DEBUG_MODULE_ fprintf(stderr,"\n"); #endif }
static str addOptimizers(Client c, MalBlkPtr mb, char *pipe, int prepare) { int i; InstrPtr q; backend *be; str msg= MAL_SUCCEED; be = (backend *) c->sqlcontext; assert(be && be->mvc); /* SQL clients should always have their state set */ (void) SQLgetSpace(be->mvc, mb, prepare); // detect empty bats. /* The volcano optimizer seems relevant for traditional HDD settings. * It produced about 8 % improvement onf TPCH SF 100 on a 16G machine. * In a SSD setting it was counter productive, leading to worse parallel behavior. * The automatic switch to volcano is now disabled assuming more use of SSD. * The volcano optimizer pipeline can be used instead if(space && (pipe == NULL || strcmp(pipe,"default_pipe")== 0)){ if( space > (lng)(0.8 * MT_npages() * MT_pagesize()) && GDKnr_threads > 1){ pipe = "volcano_pipe"; //mnstr_printf(GDKout, "#use volcano optimizer pipeline? %zu\n", space); }else pipe = "default_pipe"; } else */ pipe = pipe? pipe: "default_pipe"; msg = addOptimizerPipe(c, mb, pipe); if (msg){ return msg; } mb->keephistory |= be->mvc->emod & mod_debug; if (be->mvc->no_mitosis) { for (i = mb->stop - 1; i > 0; i--) { q = getInstrPtr(mb, i); if (q->token == ENDsymbol) break; if (getFunctionId(q) == mitosisRef || getFunctionId(q) == dataflowRef) q->token = REMsymbol; /* they are ignored */ } } addtoMalBlkHistory(mb); return msg; }
void addFunctionToContext( SyntaxContext* ctx, RCString* name, Function* function ) { int id = getFunctionId( ctx, name ); if( ctx->functions[ -id-1 ].type == typeUndefined ) { ctx->functions[ -id-1 ] = newValueFunction( function ); } else { throw( MultipleFunctionDefinitions, *name ); } }
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; }
static lng SQLgetSpace(mvc *m, MalBlkPtr mb) { sql_trans *tr = m->session->tr; lng space = 0, i; for (i = 0; i < mb->stop; i++) { InstrPtr p = mb->stmt[i]; char *f = getFunctionId(p); if (getModuleId(p) == sqlRef && (f == bindRef || f == bindidxRef)) { int upd = (p->argc == 7 || p->argc == 9), mode = 0; char *sname = getVarConstant(mb, getArg(p, 2 + upd)).val.sval; char *tname = getVarConstant(mb, getArg(p, 3 + upd)).val.sval; char *cname = NULL; sql_schema *s = mvc_bind_schema(m, sname); if (!s || strcmp(s->base.name, dt_schema) == 0) continue; cname = getVarConstant(mb, getArg(p, 4 + upd)).val.sval; mode = getVarConstant(mb, getArg(p, 5 + upd)).val.ival; if (mode != 0 || !cname || !s) continue; if (f == bindidxRef) { sql_idx *i = mvc_bind_idx(m, s, cname); if (i && (!isRemote(i->t) && !isMergeTable(i->t))) { BAT *b = store_funcs.bind_idx(tr, i, RDONLY); if (b) { space += getBatSpace(b); BBPunfix(b->batCacheid); } } } else if (f == bindRef) { sql_table *t = mvc_bind_table(m, s, tname); sql_column *c = mvc_bind_column(m, t, cname); if (c && (!isRemote(c->t) && !isMergeTable(c->t))) { BAT *b = store_funcs.bind_col(tr, c, RDONLY); if (b) { space += getBatSpace(b); BBPunfix(b->batCacheid); } } } } } return space; }
void addOptimizers(Client c, MalBlkPtr mb, char *pipe) { int i; InstrPtr q; backend *be; str msg; lng space; be = (backend *) c->sqlcontext; assert(be && be->mvc); /* SQL clients should always have their state set */ space = SQLgetSpace(be->mvc, mb); if(space && (pipe == NULL || strcmp(pipe,"default_pipe")== 0)){ if( space > (lng)(0.8 * MT_npages() * MT_pagesize()) && GDKnr_threads > 1){ pipe = "volcano_pipe"; //mnstr_printf(GDKout, "#use volcano optimizer pipeline? "SZFMT"\n", space); }else pipe = "default_pipe"; } else pipe = pipe? pipe: "default_pipe"; msg = addOptimizerPipe(c, mb, pipe); if (msg) GDKfree(msg); /* what to do with an error? */ if (be->mvc->no_mitosis) { for (i = mb->stop - 1; i > 0; i--) { q = getInstrPtr(mb, i); if (q->token == ENDsymbol) break; if (getFunctionId(q) == mitosisRef || getFunctionId(q) == dataflowRef) q->token = REMsymbol; /* they are ignored */ } } if (be->mvc->emod & mod_debug) addtoMalBlkHistory(mb, "getStatistics"); }
void OneSheeldClass::processFrame(){ byte functionId = getFunctionId(); //Check the function ID if(functionId == DISCONNECTION_CHECK_FUNCTION) { isOneSheeldConnected=false; } else if(functionId == CONNECTION_CHECK_FUNCTION) { isOneSheeldConnected=true; } else if(functionId == LIBRARY_VERSION_REQUEST) { sendPacket(ONESHEELD_ID,0,SEND_LIBRARY_VERSION,0); } }
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; }
void BytecodeTranslatorVisitor::visitCallNode(CallNode* node) { onVisitNode(node); AstFunction* f = scope()->lookupFunction(node->name()); if (!f) ERROR("Unknown function " + f->name()); checkSignature(node, f); for (uint16_t i = 0; i < node->parametersNumber(); i++) visitTyped(node->parameterAt(i), f->parameterType(i)); if (isNative(f)) EMIT(BC_CALLNATIVE); else EMIT(BC_CALL); EMIT_ID(getFunctionId(f)); pushType(f->returnType()); }
static int isNewSource(InstrPtr p) { str mp= getModuleId(p); if( mp == sqlRef && getFunctionId(p) == bindRef) return 1; if( mp == calcRef) return 1; if( mp == batcalcRef) return 1; if( mp == strRef) return 1; if( mp == batstrRef) return 1; if( mp == putName("array",5)) return 1; if( mp == putName("url",3)) return 1; if( mp == putName("daytime",7)) return 1; if( mp == putName("day",3)) return 1; if( mp == putName("date",4)) return 1; if( mp == putName("time",4)) return 1; if( mp == putName("tzone",5)) return 1; if( mp == putName("color",4)) return 1; if( mp == putName("batcolor",8)) return 1; if( mp == putName("blob",4)) return 1; return 0; }
/* * The multiplexSimple is called by the MAL scenario. It bypasses * the optimizer infrastructure, to avoid excessive space allocation * and interpretation overhead. */ str OPTmultiplexSimple(Client cntxt) { MalBlkPtr mb= cntxt->curprg->def; int i, doit=0; InstrPtr p; if(mb) for( i=0; i<mb->stop; i++){ p= getInstrPtr(mb,i); if(getModuleId(p) == malRef && getFunctionId(p) == multiplexRef) doit++; } if( doit) { OPTmultiplexImplementation(cntxt, mb, 0, 0); chkTypes(cntxt->fdout, cntxt->nspace, mb,TRUE); if ( mb->errors == 0) { chkFlow(cntxt->fdout, mb); chkDeclarations(cntxt->fdout,mb); } } return 0; }
void OneSheeldClass::processRemoteData() { byte functionId = getFunctionId(); if(functionId == READ_MESSAGE_FLOAT) { char remoteAddress[37]; memcpy(remoteAddress,getArgumentData(0),36); remoteAddress[36]='\0'; // processed the remote address int keyLength = getArgumentLength(1); char key[keyLength+1]; memcpy(key,getArgumentData(1),keyLength); key[keyLength]='\0'; float incomingValue = convertBytesToFloat(getArgumentData(2)); if(!isInACallback()) { if(isSetOnFloatMessageInvoked) { enteringACallback(); (*changeFloatCallBack)(remoteAddress,key,incomingValue); exitingACallback(); } if(usedSetOnFloatWithString) { String remoteAddressInString(remoteAddress); String keyInString(key); enteringACallback(); (*changeFloatCallBackWithString)(remoteAddressInString,keyInString,incomingValue); exitingACallback(); } } } else if(functionId == READ_MESSAGE_STRING) { char remoteAddress[37]; memcpy(remoteAddress,getArgumentData(0),36); remoteAddress[36]='\0'; // processed the remote address int keyLength = getArgumentLength(1); char key[keyLength+1]; memcpy(key,getArgumentData(1),keyLength); key[keyLength]='\0'; int stringDataLength = getArgumentLength(2); char stringData[stringDataLength+2]; memcpy(stringData,getArgumentData(2),stringDataLength); stringData[stringDataLength]='\0'; if(!isInACallback()) { if(isSetOnStringMessageInvoked) { enteringACallback(); (*changeStringCallBack)(remoteAddress,key,stringData); exitingACallback(); } if(usedSetOnStringWithString) { String remoteAddressInString(remoteAddress); String keyInString(key); String stringDataInString(stringData); enteringACallback(); (*changeStringCallBackWithString)(remoteAddressInString,keyInString,stringDataInString); exitingACallback(); } } } }
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 malAtomProperty(MalBlkPtr mb, InstrPtr pci) { str name; int tpe; (void)mb; /* fool compilers */ assert(pci != 0); name = getFunctionId(pci); tpe = getTypeIndex(getModuleId(pci), (int)strlen(getModuleId(pci)), TYPE_any); if (tpe < 0 || tpe >= GDKatomcnt || tpe >= MAXATOMS) return 0; assert(pci->fcn != NULL); switch (name[0]) { case 'd': if (idcmp("del", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomDel = (void (*)(Heap *, var_t *))pci->fcn; setAtomName(pci); return 1; } break; case 'c': if (idcmp("cmp", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomCmp = (int (*)(const void *, const void *))pci->fcn; BATatoms[tpe].linear = 1; setAtomName(pci); return 1; } break; case 'f': if (idcmp("fromstr", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomFromStr = (int (*)(const char *, int *, ptr *))pci->fcn; setAtomName(pci); return 1; } if (idcmp("fix", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomFix = (int (*)(const void *))pci->fcn; setAtomName(pci); return 1; } break; case 'h': if (idcmp("heap", name) == 0 && pci->argc == 1) { /* heap function makes an atom varsized */ BATatoms[tpe].size = sizeof(var_t); assert_shift_width(ATOMelmshift(ATOMsize(tpe)), ATOMsize(tpe)); BATatoms[tpe].align = sizeof(var_t); BATatoms[tpe].atomHeap = (void (*)(Heap *, size_t))pci->fcn; setAtomName(pci); return 1; } if (idcmp("hash", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomHash = (BUN (*)(const void *))pci->fcn; setAtomName(pci); return 1; } break; case 'l': if (idcmp("length", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomLen = (int (*)(const void *))pci->fcn; setAtomName(pci); return 1; } break; case 'n': if (idcmp("null", name) == 0 && pci->argc == 1) { ptr atmnull = ((ptr (*)(void))pci->fcn)(); BATatoms[tpe].atomNull = atmnull; setAtomName(pci); return 1; } if (idcmp("nequal", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomCmp = (int (*)(const void *, const void *))pci->fcn; setAtomName(pci); return 1; } break; case 'p': if (idcmp("put", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomPut = (var_t (*)(Heap *, var_t *, const void *))pci->fcn; setAtomName(pci); return 1; } break; case 's': if (idcmp("storage", name) == 0 && pci->argc == 1) { BATatoms[tpe].storage = (*(int (*)(void))pci->fcn)(); setAtomName(pci); return 1; } break; case 't': if (idcmp("tostr", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomToStr = (int (*)(str *, int *, const void *))pci->fcn; setAtomName(pci); return 1; } break; case 'u': if (idcmp("unfix", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomUnfix = (int (*)(const void *))pci->fcn; setAtomName(pci); return 1; } break; case 'r': if (idcmp("read", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomRead = (void *(*)(void *, stream *, size_t))pci->fcn; setAtomName(pci); return 1; } break; case 'w': if (idcmp("write", name) == 0 && pci->argc == 1) { BATatoms[tpe].atomWrite = (gdk_return (*)(const void *, stream *, size_t))pci->fcn; setAtomName(pci); return 1; } break; } return 0; }
static void setAtomName(InstrPtr pci) { char buf[PATHLENGTH]; snprintf(buf, PATHLENGTH, "#%s", getFunctionId(pci)); setFunctionId(pci, putName(buf)); }
str shortStmtRendering(MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { int i; str base, s, t, nme; size_t len= (mb->stop < 1000? 1000: mb->stop) * 128 /* max realistic line length estimate */; base = s = GDKmalloc(len); if ( s == NULL) return s; *s =0; t=s; if (p->token == REMsymbol && !( getModuleId(p) && strcmp(getModuleId(p),"querylog") == 0 && getFunctionId(p) && strcmp(getFunctionId(p),"define") == 0)) return base; if (p->barrier == LEAVEsymbol || p->barrier == REDOsymbol || p->barrier == RETURNsymbol || p->barrier == YIELDsymbol || p->barrier == EXITsymbol || p->barrier == RAISEsymbol) { snprintf(t,(len-(t-base)), "%s ", operatorName(p->barrier)); advance(t,base,len); } if( p->token == FUNCTIONsymbol) { snprintf(t,(len-(t-base)), "function %s.", getModuleId(p)); advance(t,base,len); } if (p->token == ENDsymbol ){ snprintf(t,(len-(t-base)), "end %s.%s", getModuleId(getInstrPtr(mb,0)), getFunctionId(getInstrPtr(mb,0))); return base; } // handle the result variables for (i = 0; i < p->retc; i++) if ( !isTmpVar(mb,getArg(p,i)) || isVarUsed(mb, getArg(p, i)) || isVarUDFtype(mb,getArg(p,i))) break; if (i == p->retc) // no result arguments goto short_end; /* display optional multi-assignment list */ if( getArgType(mb,p,0) != TYPE_void){ if (p->retc > 1 && t < base + len-1){ *t++ = '('; *t=0; } for (i = 0; i < p->retc; i++) { nme = shortRenderingTerm(mb, stk, p,i); snprintf(t,(len-(t-base)), "%s%s", (i?", ":""), nme); GDKfree(nme); advance(t,base,len); } if (p->retc > 1 && t< base+len) *t++ = ')'; if( t < base +len) *t++ = ':'; if( t < base +len) *t++ = '='; if( t < base +len) *t++ = ' '; } *t =0; short_end: advance(t,base,len); // handle the instruction mapping snprintf(t, (len-(t-base)),"%s", (getFunctionId(p)?getFunctionId(p):"")); advance(t,base,len); // handle the arguments, constants should be shown including their non-default type /* display optional multi-assignment list */ if( t< base + len) *t++ = '('; for (i = p->retc; i < p->argc; i++) { nme = shortRenderingTerm(mb, stk, p,i); snprintf(t,(len-(t-base)), "%s%s", (i!= p->retc? ", ":" "), nme); GDKfree(nme); advance(t,base,len); if (i < p->retc - 1 && t < base+len){ *t++ = ','; *t++ = ' '; } } if( t < base + len) *t++ = ' '; if( t < base + len) *t++ = ')'; *t=0; if (t >= s + len) throw(MAL,"instruction2str:","instruction too long"); return base; }
str instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg) { int i; str base, t; size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */ str arg; t = base = GDKmalloc(len); if ( base == NULL) return NULL; if (!flg) { *t++ = '#'; len--; if (p->typechk == TYPE_UNKNOWN) { *t++ = '!'; /* error */ len--; } } *t = 0; if (p->token == REMsymbol && !( getModuleId(p) && strcmp(getModuleId(p),"querylog") == 0 && getFunctionId(p) && strcmp(getFunctionId(p),"define") == 0)) { /* do nothing */ } else if (p->barrier) { if (p->barrier == LEAVEsymbol || p->barrier == REDOsymbol || p->barrier == RETURNsymbol || p->barrier == YIELDsymbol || p->barrier == RAISEsymbol) { if (!copystring(&t, " ", &len)) return base; } arg = operatorName(p->barrier); if (!copystring(&t, arg, &len) || !copystring(&t, " ", &len)) return base; } else if( functionStart(p) && flg != LIST_MAL_CALL ){ return fcnDefinition(mb, p, t, flg, base, len + (t - base)); } else if (!functionExit(p) && flg!=LIST_MAL_CALL) { // beautify with tabs if (!copystring(&t, " ", &len)) return base; } switch (p->token<0?-p->token:p->token) { case FCNcall: case FACcall: case PATcall: case CMDcall: case ASSIGNsymbol : // is any variable explicit or used for (i = 0; i < p->retc; i++) if ( !isTmpVar(mb,getArg(p,i)) || isVarUsed(mb, getArg(p, i)) || isVarUDFtype(mb,getArg(p,i))) break; if (i == p->retc) break; /* display multi-assignment list */ if (p->retc > 1 && !copystring(&t, "(", &len)) return base; for (i = 0; i < p->retc; i++) { arg= renderTerm(mb, stk, p, i, flg); if (arg) { if (!copystring(&t, arg, &len)) { GDKfree(arg); return base; } GDKfree(arg); } if (i < p->retc - 1 && !copystring(&t, ", ", &len)) return base; } if (p->retc > 1 && !copystring(&t, ")", &len)) return base; if (p->argc > p->retc || getFunctionId(p)) { if (!copystring(&t, " := ", &len)) return base; } break; case ENDsymbol: if (!copystring(&t, "end ", &len) || !copystring(&t, getModuleId(getInstrPtr(mb,0)), &len) || !copystring(&t, ".", &len) || !copystring(&t, getFunctionId(getInstrPtr(mb, 0)), &len)) return base; break; case COMMANDsymbol: case FUNCTIONsymbol: case FACTORYsymbol: case PATTERNsymbol: if (flg & LIST_MAL_VALUE) { if (!copystring(&t, operatorName(p->token), &len) || !copystring(&t, " ", &len)) return base; } return fcnDefinition(mb, p, t, flg, base, len + (t - base)); case REMsymbol: case NOOPsymbol: if (!copystring(&t, "#", &len)) return base; if (getVar(mb, getArg(p, 0))->value.val.sval && getVar(mb, getArg(p, 0))->value.len > 0 && !copystring(&t, getVar(mb, getArg(p, 0))->value.val.sval, &len)) return base; if (!copystring(&t, " ", &len)) return base; break; default: i = snprintf(t, len, " unknown symbol ?%d? ", p->token); if (i < 0 || (size_t) i >= len) return base; len -= (size_t) i; t += i; break; } if (getModuleId(p)) { if (!copystring(&t, getModuleId(p), &len) || !copystring(&t, ".", &len)) return base; } if (getFunctionId(p)) { if (!copystring(&t, getFunctionId(p), &len) || !copystring(&t, "(", &len)) return base; } else if (p->argc > p->retc + 1) { if (!copystring(&t, "(", &len)) return base; } for (i = p->retc; i < p->argc; i++) { arg= renderTerm(mb, stk, p, i, flg); if (arg) { if (!copystring(&t, arg, &len)) { GDKfree(arg); return base; } GDKfree(arg); } if (i < p->argc -1 && !copystring(&t, ", ", &len)) return base; } if (getFunctionId(p) || p->argc > p->retc + 1) { if (!copystring(&t, ")", &len)) return base; } if (p->token != REMsymbol){ if (!copystring(&t, ";", &len)) return base; } return base; }
str fcnDefinition(MalBlkPtr mb, InstrPtr p, str t, int flg, str base, size_t len) { int i; str arg, tpe; len -= t - base; if (!flg && !copystring(&t, "#", &len)) return base; if( mb->inlineProp && !copystring(&t, "inline ", &len)) return base; if( mb->unsafeProp && !copystring(&t, "unsafe ", &len)) return base; if( mb->sealedProp && !copystring(&t, "sealed ", &len)) return base; if (!copystring(&t, operatorName(p->token), &len) || !copystring(&t, " ", &len) || !copystring(&t, getModuleId(p) ? getModuleId(p) : "user", &len) || !copystring(&t, ".", &len) || !copystring(&t, getFunctionId(p), &len) || !copystring(&t, "(", &len)) return base; for (i = p->retc; i < p->argc; i++) { arg = renderTerm(mb, 0, p, i, (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS)); if (arg && !copystring(&t, arg, &len)) { GDKfree(arg); return base; } GDKfree(arg); if( i<p->argc-1 && !copystring(&t, ", ", &len)) return base; } advance(t,base,len); if (p->varargs & VARARGS && !copystring(&t, "...", &len)) return base; if (p->retc == 1) { if (!copystring(&t, "):", &len)) return base; tpe = getTypeName(getVarType(mb, getArg(p,0))); if (!copystring(&t, tpe, &len)) { GDKfree(tpe); return base; } GDKfree(tpe); if (p->varargs & VARRETS && !copystring(&t, "...", &len)) return base; } else { if (!copystring(&t, ") (", &len)) return base; for (i = 0; i < p->retc; i++) { arg = renderTerm(mb, 0, p, i, (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS)); if (arg && !copystring(&t, arg, &len)) { GDKfree(arg); return base; } GDKfree(arg); if( i<p->retc-1 && !copystring(&t, ", ", &len)) return base; } if (p->varargs & VARRETS && !copystring(&t, "...", &len)) return base; if (!copystring(&t, ")", &len)) return base; } if (mb->binding[0]) { if (!copystring(&t, " address ", &len) || !copystring(&t, mb->binding, &len)) return base; } (void) copystring(&t, ";", &len); return base; }
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; }