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 OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr p; int i, k, limit, *alias, barrier; MalStkPtr env = NULL; int profiler; str msg; int debugstate = cntxt->itrace, actions = 0, constantblock = 0; int *assigned, setonce; cntxt->itrace = 0; (void)stk; (void)pci; if (varGetProp(mb, getArg(mb->stmt[0], 0), inlineProp) != NULL) return 0; (void)cntxt; OPTDEBUGevaluate mnstr_printf(cntxt->fdout, "Constant expression optimizer started\n"); assigned = (int*) GDKzalloc(sizeof(int) * mb->vtop); if (assigned == NULL) return 0; alias = (int*)GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */ if (alias == NULL){ GDKfree(assigned); return 0; } // arguments are implicitly assigned by context p = getInstrPtr(mb, 0); for ( k =p->retc; k < p->argc; k++) assigned[getArg(p,k)]++; limit = mb->stop; for (i = 1; i < limit; i++) { p = getInstrPtr(mb, i); // The double count emerging from a barrier exit is ignored. if (! blockExit(p) || (blockExit(p) && p->retc != p->argc)) for ( k =0; k < p->retc; k++) assigned[getArg(p,k)]++; } for (i = 1; i < limit; i++) { p = getInstrPtr(mb, i); for (k = p->retc; k < p->argc; k++) if (alias[getArg(p, k)]) getArg(p, k) = alias[getArg(p, k)]; // to avoid management of duplicate assignments over multiple blocks // we limit ourselfs to evaluation of the first assignment only. setonce = assigned[getArg(p,0)] == 1; OPTDEBUGevaluate printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); constantblock += blockStart(p) && OPTallConstant(cntxt,mb,p); /* be aware that you only assign once to a variable */ if (setonce && p->retc == 1 && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) { barrier = p->barrier; p->barrier = 0; profiler = malProfileMode; /* we don't trace it */ malProfileMode = 0; if ( env == NULL) { env = prepareMALstack(mb, 2 * mb->vsize ); env->keepAlive = TRUE; } msg = reenterMAL(cntxt, mb, i, i + 1, env); malProfileMode= profiler; p->barrier = barrier; OPTDEBUGevaluate { mnstr_printf(cntxt->fdout, "#retc var %s\n", getVarName(mb, getArg(p, 0))); mnstr_printf(cntxt->fdout, "#result:%s\n", msg == MAL_SUCCEED ? "ok" : msg); } if (msg == MAL_SUCCEED) { int nvar; ValRecord cst; actions++; cst.vtype = 0; VALcopy(&cst, &env->stk[getArg(p, 0)]); /* You may not overwrite constants. They may be used by * other instructions */ nvar = getArg(p, 1) = defConstant(mb, getArgType(mb, p, 0), &cst); if (nvar >= env->stktop) { VALcopy(&env->stk[getArg(p, 1)], &getVarConstant(mb, getArg(p, 1))); env->stktop = getArg(p, 1) + 1; } alias[getArg(p, 0)] = getArg(p, 1); p->argc = 2; p->token = ASSIGNsymbol; clrFunction(p); p->barrier = barrier; /* freeze the type */ setVarFixed(mb,getArg(p,1)); setVarUDFtype(mb,getArg(p,1)); OPTDEBUGevaluate { mnstr_printf(cntxt->fdout, "Evaluated new constant=%d -> %d:%s\n", getArg(p, 0), getArg(p, 1), getTypeName(getArgType(mb, p, 1))); } } else {
/* * 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 SQLengineIntern(Client c, backend *be) { str msg = MAL_SUCCEED; MalStkPtr oldglb = c->glb; char oldlang = be->language; mvc *m = be->mvc; InstrPtr p; MalBlkPtr mb; if (oldlang == 'X') { /* return directly from X-commands */ sqlcleanup(be->mvc, 0); return MAL_SUCCEED; } if (m->emod & mod_explain) { if (be->q && be->q->code) printFunction(c->fdout, ((Symbol) (be->q->code))->def, 0, LIST_MAL_NAME | LIST_MAL_VALUE | LIST_MAL_MAPI); else if (be->q) msg = createException(PARSE, "SQLparser", "%s", (*m->errstr) ? m->errstr : "39000!program contains errors"); else if (c->curprg->def) printFunction(c->fdout, c->curprg->def, 0, LIST_MAL_NAME | LIST_MAL_VALUE | LIST_MAL_MAPI); goto cleanup_engine; } if (m->emod & mod_dot) { if (be->q && be->q->code) showFlowGraph(((Symbol) (be->q->code))->def, 0, "stdout-mapi"); else if (be->q) msg = createException(PARSE, "SQLparser", "%s", (*m->errstr) ? m->errstr : "39000!program contains errors"); else if (c->curprg->def) showFlowGraph(c->curprg->def, 0, "stdout-mapi"); goto cleanup_engine; } #ifdef SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#Ready to execute SQL statement\n"); #endif if (c->curprg->def->stop == 1) { sqlcleanup(be->mvc, 0); return MAL_SUCCEED; } if (m->emode == m_inplace) { msg = SQLexecutePrepared(c, be, be->q); goto cleanup_engine; } if (m->emode == m_prepare) goto cleanup_engine; assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = 0; be->language = 'D'; /* * The code below is copied from MALengine, which handles execution * in the context of a user global environment. We have a private * environment. */ if (MALcommentsOnly(c->curprg->def)) { msg = MAL_SUCCEED; } else { msg = (str) runMAL(c, c->curprg->def, 0, 0); } cleanup_engine: if (m->type == Q_SCHEMA) qc_clean(m->qc); if (msg) { enum malexception type = getExceptionType(msg); if (type == OPTIMIZER) { MSresetInstructions(c->curprg->def, 1); freeVariables(c, c->curprg->def, NULL, be->vtop); be->language = oldlang; assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; if ( msg) GDKfree(msg); return SQLrecompile(c, be); // retry compilation } else { /* don't print exception decoration, just the message */ char *n = NULL; char *o = msg; while ((n = strchr(o, '\n')) != NULL) { *n = '\0'; mnstr_printf(c->fdout, "!%s\n", getExceptionMessage(o)); *n++ = '\n'; o = n; } if (*o != 0) mnstr_printf(c->fdout, "!%s\n", getExceptionMessage(o)); } showErrors(c); m->session->status = -10; } mb = c->curprg->def; if (m->type != Q_SCHEMA && be->q && msg) { qc_delete(m->qc, be->q); } else if (m->type != Q_SCHEMA && be->q && mb && varGetProp(mb, getArg(p = getInstrPtr(mb, 0), 0), runonceProp)) { msg = SQLCacheRemove(c, getFunctionId(p)); qc_delete(be->mvc->qc, be->q); ///* this should invalidate any match */ //be->q->key= -1; //be->q->paramlen = -1; ///* qc_delete(be->q) */ } be->q = NULL; sqlcleanup(be->mvc, (!msg) ? 0 : -1); MSresetInstructions(c->curprg->def, 1); freeVariables(c, c->curprg->def, NULL, be->vtop); be->language = oldlang; /* * Any error encountered during execution should block further processing * unless auto_commit has been set. */ assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; return msg; }