/* * Upon reaching the yield operator, the factory is * suspended until the next request arrives. * The information in the target list should be delivered * to the caller stack frame. */ int yieldResult(MalBlkPtr mb, InstrPtr p, int pc) { Plant pl, plim = plants + lastPlant; ValPtr lhs, rhs; int i; (void) p; (void) pc; for (pl = plants; pl < plim; pl++) if (pl->factory == mb ) { if( pl->env == NULL) return(int) (pl-plants); for (i = 0; i < p->retc; i++) { #ifdef DEBUG_MAL_FACTORY fprintf(stderr,"#lhs %d rhs %d\n", getArg(pl->pci, i), getArg(p, i)); #endif rhs = &pl->stk->stk[getArg(p, i)]; lhs = &pl->env->stk[getArg(pl->pci, i)]; if (VALcopy(lhs, rhs) == NULL) return -1; } return (int) (pl-plants); } return -1; }
void stack_set_var(mvc *sql, const char *name, ValRecord *v) { int i; for (i = sql->topvars-1; i >= 0; i--) { if (!sql->vars[i].frame && strcmp(sql->vars[i].name, name)==0) { VALclear(&sql->vars[i].value); VALcopy(&sql->vars[i].value, v); } } }
/* * At the end of the query plan we save the result in * a separate variable. */ str RUNpickResult(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { ValPtr lhs, rhs; int i; (void) cntxt; lhs = &stk->stk[getArg(p, 0)]; for (i = p->retc; i < p->argc; i++) if (!isVarDisabled(mb, getArg(p, i))) { rhs = &stk->stk[getArg(p, i)]; if ((rhs)->vtype < TYPE_str) *lhs = *rhs; else VALcopy(lhs, rhs); if (lhs->vtype == TYPE_bat) BBPincref(lhs->val.bval, TRUE); return MAL_SUCCEED; } throw(MAL, "scheduler.pick", OPERATION_FAILED "No result available"); }
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 {
str OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr p; int i, k, limit, *alias = 0, barrier; MalStkPtr env = NULL; int profiler; int debugstate = cntxt->itrace, actions = 0, constantblock = 0; int *assigned = 0, use; char buf[256]; lng usec = GDKusec(); str msg = MAL_SUCCEED; (void)stk; (void)pci; if ( mb->inlineProp ) return MAL_SUCCEED; cntxt->itrace = 0; #ifdef DEBUG_OPT_EVALUATE fprintf(stderr, "Constant expression optimizer started\n"); #endif assigned = (int*) GDKzalloc(sizeof(int) * mb->vtop); if (assigned == NULL) throw(MAL,"optimzier.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL); alias = (int*)GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */ if (alias == NULL){ GDKfree(assigned); throw(MAL,"optimzier.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL); } // arguments are implicitly assigned by context p = getInstrPtr(mb, 0); for ( k =p->retc; k < p->argc; k++) assigned[getArg(p,k)]++; limit = mb->stop; for (i = 1; i < limit; i++) { p = getInstrPtr(mb, i); // The double count emerging from a barrier exit is ignored. if (! blockExit(p) || (blockExit(p) && p->retc != p->argc)) for ( k =0; k < p->retc; k++) if ( p->retc != p->argc || p->token != ASSIGNsymbol ) assigned[getArg(p,k)]++; } for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) { p = getInstrPtr(mb, i); // to avoid management of duplicate assignments over multiple blocks // we limit ourselves to evaluation of the first assignment only. use = assigned[getArg(p,0)] == 1 && !(p->argc == p->retc && blockExit(p)); for (k = p->retc; k < p->argc; k++) if (alias[getArg(p, k)]) getArg(p, k) = alias[getArg(p, k)]; #ifdef DEBUG_OPT_EVALUATE fprintInstruction(stderr , mb, 0, p, LIST_MAL_ALL); #endif /* be aware that you only assign once to a variable */ if (use && p->retc == 1 && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) { barrier = p->barrier; p->barrier = 0; profiler = malProfileMode; /* we don't trace it */ malProfileMode = 0; if ( env == NULL) { env = prepareMALstack(mb, 2 * mb->vsize); if (!env) { msg = createException(MAL,"optimizer.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } env->keepAlive = TRUE; } msg = reenterMAL(cntxt, mb, i, i + 1, env); malProfileMode= profiler; p->barrier = barrier; #ifdef DEBUG_OPT_EVALUATE fprintf(stderr, "#retc var %s\n", getVarName(mb, getArg(p, 0))); fprintf(stderr, "#result:%s\n", msg == MAL_SUCCEED ? "ok" : msg); #endif if (msg == MAL_SUCCEED) { int nvar; ValRecord cst; actions++; cst.vtype = 0; VALcopy(&cst, &env->stk[getArg(p, 0)]); /* You may not overwrite constants. They may be used by * other instructions */ nvar = getArg(p, 1) = defConstant(mb, getArgType(mb, p, 0), &cst); if (nvar >= env->stktop) { VALcopy(&env->stk[getArg(p, 1)], &getVarConstant(mb, getArg(p, 1))); env->stktop = getArg(p, 1) + 1; } alias[getArg(p, 0)] = getArg(p, 1); p->argc = 2; p->token = ASSIGNsymbol; clrFunction(p); p->barrier = barrier; /* freeze the type */ setVarFixed(mb,getArg(p,1)); setVarUDFtype(mb,getArg(p,1)); #ifdef DEBUG_OPT_EVALUATE {str tpename; fprintf(stderr, "Evaluated new constant=%d -> %d:%s\n", getArg(p, 0), getArg(p, 1), tpename = getTypeName(getArgType(mb, p, 1))); GDKfree(tpename); } #endif } else { /* if there is an error, we should postpone message handling, as the actual error (eg. division by zero ) may not happen) */ #ifdef DEBUG_OPT_EVALUATE fprintf(stderr, "Evaluated %s\n", msg); #endif freeException(msg); msg= MAL_SUCCEED; mb->errors = 0; } } constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */ } // produces errors in SQL when enabled if ( constantblock) msg = OPTremoveUnusedBlocks(cntxt, mb); cntxt->itrace = debugstate; /* Defense line against incorrect plans */ /* Plan is unaffected */ chkTypes(cntxt->usermodule, mb, FALSE); chkFlow(mb); chkDeclarations(mb); /* keep all actions taken as a post block comment */ usec = GDKusec()- usec; snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec","evaluate",actions,usec); newComment(mb,buf); if( actions >= 0) addtoMalBlkHistory(mb); wrapup: if ( env) freeStack(env); if(assigned) GDKfree(assigned); if(alias) GDKfree(alias); return msg; }
str runFactory(Client cntxt, MalBlkPtr mb, MalBlkPtr mbcaller, MalStkPtr stk, InstrPtr pci) { Plant pl=0; int firstcall= TRUE, i, k; InstrPtr psig = getInstrPtr(mb, 0); ValPtr lhs, rhs; char cmd; str msg; #ifdef DEBUG_MAL_FACTORY fprintf(stderr, "#factoryMgr called\n"); #endif /* the lookup can be largely avoided by handing out the index upon factory definition. todo Alternative is to move them to the front */ for(i=0; i< lastPlant; i++) if( plants[i].factory == mb){ if(i > 0 && i< lastPlant ){ PlantRecord prec= plants[i-1]; plants[i-1] = plants[i]; plants[i]= prec; i--; } pl= plants+i; firstcall= FALSE; break; } if (pl == 0) { /* compress the plant table*/ for(k=i=0;i<=lastPlant; i++) if( plants[i].inuse) plants[k++]= plants[i]; lastPlant = k; /* initialize a new plant using the owner policy */ pl = newPlant(mb); if (pl == NULL) throw(MAL, "factory.new", SQLSTATE(HY001) MAL_MALLOC_FAIL); } /* * We have found a factory to process the request. * Let's call it as a synchronous action, without concern on parallelism. */ /* remember context */ pl->client = cntxt; pl->caller = mbcaller; pl->env = stk; pl->pci = pci; pl->inuse = 1; /* inherit debugging */ cmd = stk->cmd; if ( pl->stk == NULL) throw(MAL, "factory.new", "internal error, stack frame missing"); /* copy the calling arguments onto the stack of the factory */ i = psig->retc; for (k = pci->retc; i < pci->argc; i++, k++) { lhs = &pl->stk->stk[psig->argv[k]]; /* variable arguments ? */ if (k == psig->argc - 1) k--; rhs = &pl->env->stk[getArg(pci, i)]; if (VALcopy(lhs, rhs) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); if( lhs->vtype == TYPE_bat ) BBPretain(lhs->val.bval); } if (mb->errors) throw(MAL, "factory.call", PROGRAM_GENERAL); if (firstcall ){ /* initialize the stack */ for(i= psig->argc; i< mb->vtop; i++) { lhs = &pl->stk->stk[i]; if( isVarConstant(mb,i) > 0 ){ if( !isVarDisabled(mb,i)){ rhs = &getVarConstant(mb,i); if (VALcopy(lhs,rhs) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); } } else{ lhs->vtype = getVarGDKType(mb,i); lhs->val.pval = 0; lhs->len = 0; } } pl->stk->stkbot= mb->vtop; /* stack already initialized */ msg = runMAL(cntxt, mb, 0, pl->stk); } else { msg = reenterMAL(cntxt, mb, pl->pc, -1, pl->stk); } /* propagate change in debugging status */ if (cmd && pl->stk && pl->stk->cmd != cmd && cmd != 'x') for (; stk; stk = stk->up) stk->cmd = pl->stk->cmd; return msg; }
/* * The shortcut operator for factory calls assumes that the user is * not interested in the results produced. */ str callFactory(Client cntxt, MalBlkPtr mb, ValPtr argv[], char flag){ Plant pl; InstrPtr psig = getInstrPtr(mb, 0); int i; ValPtr lhs,rhs; MalStkPtr stk; str ret; i= findPlant(mb); if( i< 0) { /* first call? prepare the factory */ pl = newPlant(mb); if (pl == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); /* remember context, which does not exist. */ pl->client = cntxt; pl->caller = 0; pl->env = 0; pl->pci = 0; pl->inuse = 1; stk = pl->stk; /* initialize the stack */ stk->stktop= mb->vtop; stk->stksize= mb->vsize; stk->blk= mb; stk->up = 0; stk->cmd= flag; /* initialize the stack */ for(i= psig->argc; i< mb->vtop; i++) if( isVarConstant(mb,i) > 0 ){ lhs = &stk->stk[i]; rhs = &getVarConstant(mb,i); if (VALcopy(lhs,rhs) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); } else { lhs = &stk->stk[i]; lhs->vtype = getVarGDKType(mb,i); } pl->stk= stk; } else { pl= plants+i; /* * When you re-enter the factory the old arguments should be * released to make room for the new ones. */ for (i = psig->retc; i < psig->argc; i++) { lhs = &pl->stk->stk[psig->argv[i]]; if( lhs->vtype == TYPE_bat ) BBPrelease(lhs->val.bval); } } /* copy the calling arguments onto the stack of the factory */ i = psig->retc; for (i = psig->retc; i < psig->argc; i++) { lhs = &pl->stk->stk[psig->argv[i]]; if (VALcopy(lhs, argv[i]) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); if( lhs->vtype == TYPE_bat ) BBPretain(lhs->val.bval); } ret= reenterMAL(cntxt, mb, pl->pc, -1, pl->stk); /* garbage collect the string arguments, these positions will simply be overwritten the next time. for (i = psig->retc; i < psig->argc; i++) garbageElement(lhs = &pl->stk->stk[psig->argv[i]]); */ return ret; }