void listModules(stream *out, Module s) { while(s){ mnstr_printf(out,"Unexpected module %s\n", s->name); s= s->link; } }
static void terminate(Actuator ac) { #ifdef _DEBUG_ACTUATOR_ mnstr_printf(ACout, "about to shutdown the actuator\n"); #endif shutdown(ac->newsockfd, SHUT_RDWR); exit(0); }
/* * The statistics are shown after a fixed number of tuples * have been received.Align this number with the batches * generated by the sensor and you get a good impression * of batch effect. */ static void showStatistics(void) { double elaps; int tuplesIntheBuffer = 2222; if (received == 0) return; mnstr_printf(ACout, "MYBUFSIZ :%d\n", MYBUFSIZ); mnstr_printf(ACout, "Tuples in the buffer :%d\n", tuplesIntheBuffer); mnstr_printf(ACout, "\nEvents %d\n", received); mnstr_printf(ACout, "Latency per tuple %6.2f microsec\n", (((double) totallatency) / received) / tuplesIntheBuffer); elaps = (double) ((receivedLast - sendFirst) * tuplesIntheBuffer / (received)); /*mnstr_printf(ACout, "receivedLast-sendFirst %d microsec\n", receivedLast-sendFirst);*/ mnstr_printf(ACout, "Elapsed per batch %5.2f microsec\n", elaps); mnstr_printf(ACout, "Throughput %8.2f tpl/sec\n", 1000000.0 / elaps * tuplesIntheBuffer); mnstr_printf(ACout, "Bandwidth " SZFMT " bytes\n", characters * sizeof(char)); /* send a short tuple to stderr for gnuplot datafile*/ fprintf(stderr, "events %d throughput %6.2f\n", received, 1000000.0 / elaps * tuplesIntheBuffer); received = 0; totallatency = 0; receivedFirst = receivedLast = 0; characters = 0; }
str optimizeQuery(Client c) { MalBlkPtr mb; backend *be; str msg = 0, pipe; be = (backend *) c->sqlcontext; assert(be && be->mvc); /* SQL clients should always have their state set */ pipe = getSQLoptimizer(be->mvc); trimMalBlk(c->curprg->def); c->blkmode = 0; mb = c->curprg->def; chkProgram(c->fdout, c->nspace, mb); #ifdef _SQL_OPTIMIZER_DEBUG mnstr_printf(GDKout, "Optimize query\n"); printFunction(GDKout, mb, 0, LIST_MAL_ALL); #endif /* * An error in the compilation should be reported to the user. * And if the debugging option is set, the debugger is called * to allow inspection. */ if (mb->errors) { showErrors(c); if (c->listing) printFunction(c->fdout, mb, 0, c->listing); return NULL; } addOptimizers(c, mb, pipe); msg = optimizeMALBlock(c, mb); if (msg) return msg; /* time to execute the optimizers */ if (c->debug) optimizerCheck(c, mb, "sql.baseline", -1, 0); #ifdef _SQL_OPTIMIZER_DEBUG mnstr_printf(GDKout, "End Optimize Query\n"); printFunction(GDKout, mb, 0, LIST_MAL_ALL); #endif return NULL; }
void printSignature(stream *fd, Symbol s, int flg) { InstrPtr p; str txt; if ( s->def == 0 ){ mnstr_printf(fd, "missing definition of %s\n", s->name); return; } txt = GDKzalloc(MAXLISTING); /* some slack for large blocks */ if( txt){ p = getSignature(s); (void) fcnDefinition(s->def, p, txt, flg, txt, MAXLISTING); mnstr_printf(fd, "%s\n", txt); GDKfree(txt); } else mnstr_printf(fd, "printSignature: " MAL_MALLOC_FAIL); }
/* * Access control enforcement. Except for the server owner * running a scenario should be explicitly permitted. */ static str runScenarioBody(Client c, int once) { str msg= MAL_SUCCEED; c->exception_buf_initialized = 1; if (setjmp( c->exception_buf) < 0) c->mode = FINISHCLIENT; while (c->mode > FINISHCLIENT && !GDKexiting()) { // be aware that a MAL call may initialize a different scenario if ( !c->state[0] && (msg = runPhase(c, MAL_SCENARIO_INITCLIENT)) ) goto wrapup; if ( c->mode <= FINISHCLIENT || (msg = runPhase(c, MAL_SCENARIO_READER)) ) goto wrapup; if ( c->mode <= FINISHCLIENT || (msg = runPhase(c, MAL_SCENARIO_PARSER)) || c->blkmode) goto wrapup; if ( c->mode <= FINISHCLIENT || (msg = runPhase(c, MAL_SCENARIO_OPTIMIZE)) ) goto wrapup; if ( c->mode <= FINISHCLIENT || (msg = runPhase(c, MAL_SCENARIO_SCHEDULER))) goto wrapup; if ( c->mode <= FINISHCLIENT || (msg = runPhase(c, MAL_SCENARIO_ENGINE))) goto wrapup; wrapup: if (msg != MAL_SUCCEED){ if(c->phase[MAL_SCENARIO_CALLBACK]) msg = (str) (*c->phase[MAL_SCENARIO_CALLBACK])(c, msg); if (msg) { mnstr_printf(c->fdout,"!%s%s", msg, (msg[strlen(msg)-1] == '\n'? "":"\n")); freeException(msg); msg = MAL_SUCCEED; } } if( GDKerrbuf && GDKerrbuf[0]) mnstr_printf(c->fdout,"!GDKerror: %s\n",GDKerrbuf); assert(c->curprg->def->errors == NULL); c->actions++; if( once) break; } c->exception_buf_initialized = 0; if (once == 0 && c->phase[MAL_SCENARIO_EXITCLIENT]) msg = (*c->phase[MAL_SCENARIO_EXITCLIENT]) (c); return msg; }
// perform sanity check on duplicate occurrences as well void dumpModules(stream *out) { int i; Module s,n; for( i = 0; i< MODULE_HASH_SIZE; i++){ s= moduleIndex[i]; while(s){ mnstr_printf(out,"[%d] module %s\n", i, s->name); n = s->link; while(n){ if( n == s) mnstr_printf(out,"ASSERTION error, double occurrence of symbol in symbol table\n"); n= n->link; } s= s->link; } } }
str SQLexit(Client c) { #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#SQLexit\n"); #endif (void) c; /* not used */ if (SQLinitialized == FALSE) throw(SQL, "SQLexit", "Catalogue not available"); return MAL_SUCCEED; }
str MDBstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { stk->cmd = 0; cntxt->itrace = 0; cntxt->debugOptimizer= FALSE; mnstr_printf(cntxt->fdout,"mdb>#EOD\n"); (void) mb; (void) p; return MAL_SUCCEED; }
static void monet5_freestack(int clientid, backend_stack stk) { MalStkPtr p = (ptr) stk; (void) clientid; if (p != NULL) freeStack(p); #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#monet5_freestack\n"); #endif }
str runScenario(Client c) { str msg = MAL_SUCCEED; if (c == 0 || c->phase[MAL_SCENARIO_READER] == 0) return msg; msg = runScenarioBody(c); if (msg != MAL_SUCCEED && strcmp(msg,"MALException:client.quit:Server stopped.")) mnstr_printf(c->fdout,"!%s\n",msg); return msg; }
static str SQLinit(void) { char *debug_str = GDKgetenv("sql_debug"), *msg = MAL_SUCCEED; int readonly = GDKgetenv_isyes("gdk_readonly"); int single_user = GDKgetenv_isyes("gdk_single_user"); const char *gmt = "GMT"; tzone tz; #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#SQLinit Monet 5\n"); #endif if (SQLinitialized) return MAL_SUCCEED; #ifdef NEED_MT_LOCK_INIT MT_lock_init(&sql_contextLock, "sql_contextLock"); #endif MT_lock_set(&sql_contextLock); memset((char *) &be_funcs, 0, sizeof(backend_functions)); be_funcs.fstack = &monet5_freestack; be_funcs.fcode = &monet5_freecode; be_funcs.fresolve_function = &monet5_resolve_function; monet5_user_init(&be_funcs); msg = MTIMEtimezone(&tz, &gmt); if (msg) return msg; (void) tz; if (debug_str) SQLdebug = strtol(debug_str, NULL, 10); if (single_user) SQLdebug |= 64; if (readonly) SQLdebug |= 32; if ((SQLnewcatalog = mvc_init(SQLdebug, store_bat, readonly, single_user, 0)) < 0) throw(SQL, "SQLinit", "Catalogue initialization failed"); SQLinitialized = TRUE; MT_lock_unset(&sql_contextLock); if (MT_create_thread(&sqllogthread, (void (*)(void *)) mvc_logmanager, NULL, MT_THR_DETACHED) != 0) { throw(SQL, "SQLinit", "Starting log manager failed"); } #if 0 if (MT_create_thread(&minmaxthread, (void (*)(void *)) mvc_minmaxmanager, NULL, MT_THR_DETACHED) != 0) { throw(SQL, "SQLinit", "Starting minmax manager failed"); } #endif return MAL_SUCCEED; }
static lng estimateOverhead(void) { int i; lng l; lng t0 = GDKusec(); for (i = 0; i < 10000; i++) l = GDKusec(); t0 = (GDKusec() - t0) / 10000; #ifdef SENSOR_DEBUG mnstr_printf(SEout, "#Timing overhead " LLFMT " GDKusec\n", t0); #endif return l; }
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); } else { mnstr_printf(out,"#failed instruction2str()\n"); } } m= m->history; } }
/* Remote execution of MAL calls for more type/property information to be exchanged */ str mal2str(MalBlkPtr mb, int first, int last) { str ps = NULL, *txt; int i, *len, totlen = 0; txt = GDKmalloc(sizeof(str) * mb->stop); len = GDKmalloc(sizeof(int) * mb->stop); if( txt == NULL || len == NULL){ GDKerror("mal2str: " MAL_MALLOC_FAIL); if( txt ) GDKfree(txt); if( len ) GDKfree(len); return NULL; } for (i = first; i < last; i++) { if( i == 0) txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i), LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS); else txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i), LIST_MAL_CALL | LIST_MAL_PROPS | LIST_MAL_REMOTE); #ifdef _DEBUG_LISTING_ mnstr_printf(GDKout,"%s\n",txt[i]); #endif if ( txt[i]) totlen += len[i] = (int)strlen(txt[i]); } ps = GDKmalloc(totlen + mb->stop + 1); if( ps == NULL) GDKerror("mal2str: " MAL_MALLOC_FAIL); totlen = 0; for (i = first; i < last; i++) { if( txt[i]){ if( ps){ strncpy(ps + totlen, txt[i], len[i]); ps[totlen + len[i]] = '\n'; ps[totlen + len[i] + 1] = 0; totlen += len[i] + 1; } GDKfree(txt[i]); } } GDKfree(len); GDKfree(txt); return ps; }
static void monet5_freecode(int clientid, backend_code code, backend_stack stk, int nr, char *name) { str msg; (void) code; (void) stk; (void) nr; (void) clientid; msg = SQLCacheRemove(MCgetClient(clientid), name); if (msg) GDKfree(msg); /* do something with error? */ #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#monet5_free:%d\n", nr); #endif }
str SQLCacheRemove(Client c, str nme) { Symbol s; #ifdef _SQL_CACHE_DEBUG mnstr_printf(GDKout, "#SQLCacheRemove %s\n", nme); #endif s = findSymbolInModule(c->nspace, nme); if (s == NULL) throw(MAL, "cache.remove", "internal error, symbol missing\n"); if (getInstrPtr(s->def, 0)->token == FACTORYsymbol) shutdownFactoryByName(c, c->nspace, nme); else deleteSymbol(c->nspace, s); return MAL_SUCCEED; }
str SQLexitClient(Client c) { #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#SQLexitClient\n"); #endif if (SQLinitialized == FALSE) throw(SQL, "SQLexitClient", "Catalogue not available"); if (c->sqlcontext) { backend *be = NULL; mvc *m = NULL; if (c->sqlcontext == NULL) throw(SQL, "SQLexitClient", "MVC catalogue not available"); be = (backend *) c->sqlcontext; m = be->mvc; assert(m->session); if (m->session->auto_commit && m->session->active) { if (mvc_status(m) >= 0 && mvc_commit(m, 0, NULL) < 0) (void) handle_error(m, c->fdout, 0); } if (m->session->active) { RECYCLEdrop(0); mvc_rollback(m, 0, NULL); } res_tables_destroy(m->results); m->results = NULL; mvc_destroy(m); backend_destroy(be); c->state[MAL_SCENARIO_OPTIMIZE] = NULL; c->state[MAL_SCENARIO_PARSER] = NULL; c->sqlcontext = NULL; } c->state[MAL_SCENARIO_READER] = NULL; return MAL_SUCCEED; }
/* #define _SQL_READER_DEBUG */ str SQLreader(Client c) { int go = TRUE; int more = TRUE; int commit_done = FALSE; backend *be = (backend *) c->sqlcontext; bstream *in = c->fdin; int language = -1; mvc *m = NULL; int blocked = isa_block_stream(in->s); if (SQLinitialized == FALSE) { c->mode = FINISHCLIENT; return NULL; } if (!be || c->mode <= FINISHCLIENT) { #ifdef _SQL_READER_DEBUG mnstr_printf(GDKout, "#SQL client finished\n"); #endif c->mode = FINISHCLIENT; return NULL; } #ifdef _SQL_READER_DEBUG mnstr_printf(GDKout, "#SQLparser: start reading SQL %s %s\n", (be->console ? " from console" : ""), (blocked ? "Blocked read" : "")); #endif language = be->language; /* 'S' for SQL, 'D' from debugger */ m = be->mvc; m->errstr[0] = 0; /* * Continue processing any left-over input from the previous round. */ #ifdef _SQL_READER_DEBUG mnstr_printf(GDKout, "#pos %d len %d eof %d \n", in->pos, in->len, in->eof); #endif /* * Distinguish between console reading and mclient connections. * The former comes with readline functionality. */ while (more) { more = FALSE; /* Different kinds of supported statements sequences A; -- single line s A \n B; -- multi line S A; B; -- compound single block s A; -- many multi line B \n C; -- statements in one block S */ /* auto_commit on end of statement */ if (m->scanner.mode == LINE_N && !commit_done) { go = SQLautocommit(c, m); commit_done = TRUE; } if (go && in->pos >= in->len) { ssize_t rd; if (c->bak) { #ifdef _SQL_READER_DEBUG mnstr_printf(GDKout, "#Switch to backup stream\n"); #endif in = c->fdin; blocked = isa_block_stream(in->s); m->scanner.rs = c->fdin; c->fdin->pos += c->yycur; c->yycur = 0; } if (in->eof || !blocked) { language = (be->console) ? 'S' : 0; /* The rules of auto_commit require us to finish and start a transaction on the start of a new statement (s A;B; case) */ if (!(m->emod & mod_debug) && !commit_done) { go = SQLautocommit(c, m); commit_done = TRUE; } if (go && ((!blocked && mnstr_write(c->fdout, c->prompt, c->promptlength, 1) != 1) || mnstr_flush(c->fdout))) { go = FALSE; break; } in->eof = 0; } if (in->buf == NULL) { more = FALSE; go = FALSE; } else if (go && (rd = bstream_next(in)) <= 0) { #ifdef _SQL_READER_DEBUG mnstr_printf(GDKout, "#rd %d language %d eof %d\n", rd, language, in->eof); #endif if (be->language == 'D' && in->eof == 0) return 0; if (rd == 0 && language !=0 && in->eof && !be->console) { /* we hadn't seen the EOF before, so just try again (this time with prompt) */ more = TRUE; continue; } go = FALSE; break; } else if (go && !be->console && language == 0) { if (in->buf[in->pos] == 's' && !in->eof) { while ((rd = bstream_next(in)) > 0) ; } be->language = in->buf[in->pos++]; if (be->language == 's') { be->language = 'S'; m->scanner.mode = LINE_1; } else if (be->language == 'S') { m->scanner.mode = LINE_N; } } #ifdef _SQL_READER_DEBUG mnstr_printf(GDKout, "#SQL blk:%s\n", in->buf + in->pos); #endif } } if ( (c->stimeout && (GDKusec() - c->session) > c->stimeout) || !go || (strncmp(CURRENT(c), "\\q", 2) == 0)) { in->pos = in->len; /* skip rest of the input */ c->mode = FINISHCLIENT; return NULL; } return 0; }
str SQLinitClient(Client c) { mvc *m; str schema; str msg = MAL_SUCCEED; backend *be; bstream *bfd = NULL; stream *fd = NULL; static int maybeupgrade = 1; #ifdef _SQL_SCENARIO_DEBUG mnstr_printf(GDKout, "#SQLinitClient\n"); #endif if (SQLinitialized == 0 && (msg = SQLprelude(NULL)) != MAL_SUCCEED) return msg; MT_lock_set(&sql_contextLock); /* * Based on the initialization return value we can prepare a SQLinit * string with all information needed to initialize the catalog * based on the mandatory scripts to be executed. */ if (sqlinit) { /* add sqlinit to the fdin stack */ buffer *b = (buffer *) GDKmalloc(sizeof(buffer)); size_t len = strlen(sqlinit); bstream *fdin; buffer_init(b, _STRDUP(sqlinit), len); fdin = bstream_create(buffer_rastream(b, "si"), b->len); bstream_next(fdin); MCpushClientInput(c, fdin, 0, ""); } if (c->sqlcontext == 0) { m = mvc_create(c->idx, 0, SQLdebug, c->fdin, c->fdout); global_variables(m, "monetdb", "sys"); if (isAdministrator(c) || strcmp(c->scenario, "msql") == 0) /* console should return everything */ m->reply_size = -1; be = (void *) backend_create(m, c); } else { be = c->sqlcontext; m = be->mvc; mvc_reset(m, c->fdin, c->fdout, SQLdebug, NR_GLOBAL_VARS); backend_reset(be); } if (m->session->tr) reset_functions(m->session->tr); /* pass through credentials of the user if not console */ schema = monet5_user_set_def_schema(m, c->user); if (!schema) { _DELETE(schema); throw(PERMD, "SQLinitClient", "08004!schema authorization error"); } _DELETE(schema); /*expect SQL text first */ be->language = 'S'; /* Set state, this indicates an initialized client scenario */ c->state[MAL_SCENARIO_READER] = c; c->state[MAL_SCENARIO_PARSER] = c; c->state[MAL_SCENARIO_OPTIMIZE] = c; c->sqlcontext = be; initSQLreferences(); /* initialize the database with predefined SQL functions */ if (SQLnewcatalog == 0) { /* check whether table sys.systemfunctions exists: if * it doesn't, this is probably a restart of the * server after an incomplete initialization */ sql_schema *s = mvc_bind_schema(m, "sys"); sql_table *t = s ? mvc_bind_table(m, s, "systemfunctions") : NULL; if (t == NULL) SQLnewcatalog = 1; } if (SQLnewcatalog > 0) { char path[PATHLENGTH]; str fullname; SQLnewcatalog = 0; maybeupgrade = 0; snprintf(path, PATHLENGTH, "createdb"); slash_2_dir_sep(path); fullname = MSP_locate_sqlscript(path, 1); if (fullname) { str filename = fullname; str p, n; fprintf(stdout, "# SQL catalog created, loading sql scripts once\n"); do { p = strchr(filename, PATH_SEP); if (p) *p = '\0'; if ((n = strrchr(filename, DIR_SEP)) == NULL) { n = filename; } else { n++; } fprintf(stdout, "# loading sql script: %s\n", n); fd = open_rastream(filename); if (p) filename = p + 1; if (fd) { size_t sz; sz = getFileSize(fd); if (sz > (size_t) 1 << 29) { mnstr_destroy(fd); msg = createException(MAL, "createdb", "file %s too large to process", filename); } else { bfd = bstream_create(fd, sz == 0 ? (size_t) (128 * BLOCK) : sz); if (bfd && bstream_next(bfd) >= 0) msg = SQLstatementIntern(c, &bfd->buf, "sql.init", TRUE, FALSE, NULL); bstream_destroy(bfd); } if (m->sa) sa_destroy(m->sa); m->sa = NULL; if (msg) p = NULL; } } while (p); GDKfree(fullname); } else fprintf(stderr, "!could not read createdb.sql\n"); } else { /* handle upgrades */ if (!m->sa) m->sa = sa_create(); if (maybeupgrade) SQLupgrades(c,m); maybeupgrade = 0; } MT_lock_unset(&sql_contextLock); fflush(stdout); fflush(stderr); /* send error from create scripts back to the first client */ if (msg) { error(c->fdout, msg); handle_error(m, c->fdout, 0); sqlcleanup(m, mvc_status(m)); } return msg; }
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 {
/* Sends command for database to merovingian listening at host and port. * If host is a path, and port is -1, a UNIX socket connection for host * is opened. The response of merovingian is returned as a malloced * string. If wait is set to a non-zero value, this function will only * return after it has seen an EOF from the server. This is useful with * multi-line responses, but can lock up for single line responses where * the server allows pipelining (and hence doesn't close the * connection). */ char* control_send( char** ret, char* host, int port, char* database, char* command, char wait, char* pass) { char sbuf[8096]; char rbuf[8096]; char *buf; int sock = -1; ssize_t len; stream *fdin = NULL; stream *fdout = NULL; *ret = NULL; /* gets overwritten in case of success */ if (port == -1) { struct sockaddr_un server; /* UNIX socket connect */ if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot open connection: %s", strerror(errno)); return(strdup(sbuf)); } memset(&server, 0, sizeof(struct sockaddr_un)); server.sun_family = AF_UNIX; strncpy(server.sun_path, host, sizeof(server.sun_path) - 1); if (connect(sock, (SOCKPTR) &server, sizeof(struct sockaddr_un)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot connect: %s", strerror(errno)); close(sock); return(strdup(sbuf)); } } else { struct sockaddr_in server; struct hostent *hp; char ver = 0; char *p; /* TCP socket connect */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot open connection: %s", strerror(errno)); return(strdup(sbuf)); } hp = gethostbyname(host); if (hp == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot lookup hostname: %s", hstrerror(h_errno)); close(sock); return(strdup(sbuf)); } memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = hp->h_addrtype; memcpy(&server.sin_addr, hp->h_addr_list[0], hp->h_length); server.sin_port = htons((unsigned short) (port & 0xFFFF)); if (connect(sock, (SOCKPTR) &server, sizeof(struct sockaddr_in)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot connect: %s", strerror(errno)); close(sock); return(strdup(sbuf)); } /* try reading length */ len = recv(sock, rbuf, 2, 0); if (len == 2) len += recv(sock, rbuf + len, sizeof(rbuf) - len - 1, 0); /* perform login ritual */ if (len <= 2) { snprintf(sbuf, sizeof(sbuf), "no response from monetdbd"); close(sock); return(strdup(sbuf)); } rbuf[len] = 0; /* we only understand merovingian:1 and :2 (backwards compat * <=Aug2011) and mapi v9 on merovingian */ if (strncmp(rbuf, "merovingian:1:", strlen("merovingian:1:")) == 0) { buf = rbuf + strlen("merovingian:1:"); ver = 1; } else if (strncmp(rbuf, "merovingian:2:", strlen("merovingian:2:")) == 0) { buf = rbuf + strlen("merovingian:2:"); ver = 2; } else if (strstr(rbuf + 2, ":merovingian:9:") != NULL) { buf = rbuf + 2; ver = 9; fdin = block_stream(socket_rastream(sock, "client in")); fdout = block_stream(socket_wastream(sock, "client out")); } else { if (len > 2 && (strstr(rbuf + 2, ":BIG:") != NULL || strstr(rbuf + 2, ":LIT:") != NULL)) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "server looks like a mapi server, " "are you connecting to an mserver directly " "instead of monetdbd?"); } else { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "unsupported monetdbd server"); } close(sock); return(strdup(sbuf)); } switch (ver) { case 1: case 2: /* we never really used the mode specifier of v2 */ p = strchr(buf, ':'); if (p != NULL) *p = '\0'; p = control_hash(pass, buf); len = snprintf(sbuf, sizeof(sbuf), "%s%s\n", p, ver == 2 ? ":control" : ""); len = send(sock, sbuf, len, 0); free(p); if (len == -1) { close(sock); return(strdup("cannot send challenge response to server")); } break; case 9: { char *chal = NULL; char *algos = NULL; char *shash = NULL; char *phash = NULL; char *algsv[] = { "RIPEMD160", "SHA256", "SHA1", "MD5", NULL }; char **algs = algsv; /* buf at this point looks like * "challenge:servertype:protover:algos:endian:hash:" */ chal = buf; /* chal */ p = strchr(chal, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* servertype */ p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* protover */ p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* algos */ algos = p; p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* endian */ p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* hash */ shash = p; p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p = '\0'; /* we first need to hash our password in the form the * server stores it too */ if (strcmp(shash, "RIPEMD160") == 0) { phash = mcrypt_RIPEMD160Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA512") == 0) { phash = mcrypt_SHA512Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA384") == 0) { phash = mcrypt_SHA384Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA256") == 0) { phash = mcrypt_SHA256Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA224") == 0) { phash = mcrypt_SHA224Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA1") == 0) { phash = mcrypt_SHA1Sum(pass, strlen(pass)); } else if (strcmp(shash, "MD5") == 0) { phash = mcrypt_MD5Sum(pass, strlen(pass)); } else { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "monetdbd server requires unknown hash: %s", shash); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } /* now hash the password hash with the provided * challenge */ for (; *algs != NULL; algs++) { /* TODO: make this actually obey the separation by * commas, and only allow full matches */ if (strstr(algos, *algs) != NULL) { p = mcrypt_hashPassword(*algs, phash, chal); if (p == NULL) continue; mnstr_printf(fdout, "BIG:monetdb:{%s}%s:control:merovingian:\n", *algs, p); mnstr_flush(fdout); free(p); break; } } free(phash); if (p == NULL) { /* the server doesn't support what we can */ snprintf(sbuf, sizeof(sbuf), "cannot connect: " "unsupported hash algoritms: %s", algos); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } } } if (fdin != NULL) { /* stream.h is sooo broken :( */ memset(rbuf, '\0', sizeof(rbuf)); if ((len = mnstr_read_block(fdin, rbuf, sizeof(rbuf) - 1, 1)) < 0) { close_stream(fdout); close_stream(fdin); return(strdup("no response from monetdbd after login")); } rbuf[len - 1] = '\0'; } else { if ((len = recv(sock, rbuf, sizeof(rbuf), 0)) <= 0) { close(sock); return(strdup("no response from monetdbd after login")); } rbuf[len - 1] = '\0'; } if (strcmp(rbuf, "=OK") != 0 && strcmp(rbuf, "OK") != 0) { buf = rbuf; if (*buf == '!') buf++; if (fdin != NULL) { close_stream(fdout); close_stream(fdin); } else { close(sock); } return(strdup(buf)); } } if (fdout != NULL) { mnstr_printf(fdout, "%s %s\n", database, command); mnstr_flush(fdout); } else { len = snprintf(sbuf, sizeof(sbuf), "%s %s\n", database, command); if (send(sock, sbuf, len, 0) == -1) { close(sock); return(strdup("failed to send control command to server")); } } if (wait != 0) { size_t buflen = sizeof(sbuf); size_t bufpos = 0; char *bufp; bufp = buf = malloc(sizeof(char) * buflen); if (buf == NULL) { if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } return(strdup("failed to allocate memory")); } while (1) { if (fdin != NULL) { /* stream.h is sooo broken :( */ memset(buf + bufpos, '\0', buflen - bufpos); len = mnstr_read_block(fdin, buf + bufpos, buflen - bufpos - 1, 1); if (len >= 0) len = strlen(buf + bufpos); } else { len = recv(sock, buf + bufpos, buflen - bufpos, 0); } if (len <= 0) break; if ((size_t)len == buflen - bufpos) { buflen *= 2; bufp = realloc(buf, sizeof(char) * buflen); if (bufp == NULL) { free(buf); if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } return(strdup("failed to allocate more memory")); } buf = bufp; } bufpos += (size_t)len; } if (bufpos == 0) { if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } free(buf); return(strdup("incomplete response from monetdbd")); } buf[bufpos - 1] = '\0'; if (fdin) { /* strip out protocol = */ memmove(bufp, bufp + 1, strlen(bufp + 1) + 1); while ((bufp = strstr(bufp, "\n=")) != NULL) memmove(bufp + 1, bufp + 2, strlen(bufp + 2) + 1); } *ret = buf; } else { if (fdin != NULL) { if (mnstr_read_block(fdin, rbuf, sizeof(rbuf) - 1, 1) < 0) { close_stream(fdin); close_stream(fdout); return(strdup("incomplete response from monetdbd")); } rbuf[strlen(rbuf) - 1] = '\0'; *ret = strdup(rbuf + 1); } else { if ((len = recv(sock, rbuf, sizeof(rbuf), 0)) <= 0) { close(sock); return(strdup("incomplete response from monetdbd")); } rbuf[len - 1] = '\0'; *ret = strdup(rbuf); } } if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } return(NULL); }
str SQLparser(Client c) { bstream *in = c->fdin; stream *out = c->fdout; str msg = NULL; backend *be; mvc *m; int oldvtop, oldstop; int pstatus = 0; int err = 0, opt = 0; be = (backend *) c->sqlcontext; if (be == 0) { /* tell the client */ mnstr_printf(out, "!SQL state descriptor missing, aborting\n"); mnstr_flush(out); /* leave a message in the log */ fprintf(stderr, "SQL state descriptor missing, cannot handle client!\n"); /* stop here, instead of printing the exception below to the * client in an endless loop */ c->mode = FINISHCLIENT; throw(SQL, "SQLparser", "State descriptor missing"); } oldvtop = c->curprg->def->vtop; oldstop = c->curprg->def->stop; be->vtop = oldvtop; #ifdef _SQL_PARSER_DEBUG mnstr_printf(GDKout, "#SQL compilation \n"); printf("debugger? %d(%d)\n", (int) be->mvc->emode, (int) be->mvc->emod); #endif m = be->mvc; m->type = Q_PARSE; SQLtrans(m); pstatus = m->session->status; /* sqlparse needs sql allocator to be available. It can be NULL at * this point if this is a recursive call. */ if (!m->sa) m->sa = sa_create(); m->emode = m_normal; m->emod = mod_none; if (be->language == 'X') { int n = 0, v, off, len; if (strncmp(in->buf + in->pos, "export ", 7) == 0) n = sscanf(in->buf + in->pos + 7, "%d %d %d", &v, &off, &len); if (n == 2 || n == 3) { mvc_export_chunk(be, out, v, off, n == 3 ? len : m->reply_size); in->pos = in->len; /* HACK: should use parsed length */ return MAL_SUCCEED; } if (strncmp(in->buf + in->pos, "close ", 6) == 0) { res_table *t; v = (int) strtol(in->buf + in->pos + 6, NULL, 0); t = res_tables_find(m->results, v); if (t) m->results = res_tables_remove(m->results, t); in->pos = in->len; /* HACK: should use parsed length */ return MAL_SUCCEED; } if (strncmp(in->buf + in->pos, "release ", 8) == 0) { cq *q = NULL; v = (int) strtol(in->buf + in->pos + 8, NULL, 0); if ((q = qc_find(m->qc, v)) != NULL) qc_delete(m->qc, q); in->pos = in->len; /* HACK: should use parsed length */ return MAL_SUCCEED; } if (strncmp(in->buf + in->pos, "auto_commit ", 12) == 0) { int commit; v = (int) strtol(in->buf + in->pos + 12, NULL, 10); commit = (!m->session->auto_commit && v); m->session->auto_commit = (v) != 0; m->session->ac_on_commit = m->session->auto_commit; if (m->session->active) { if (commit && mvc_commit(m, 0, NULL) < 0) { mnstr_printf(out, "!COMMIT: commit failed while " "enabling auto_commit\n"); msg = createException(SQL, "SQLparser", "Xauto_commit (commit) failed"); } else if (!commit && mvc_rollback(m, 0, NULL) < 0) { RECYCLEdrop(0); mnstr_printf(out, "!COMMIT: rollback failed while " "disabling auto_commit\n"); msg = createException(SQL, "SQLparser", "Xauto_commit (rollback) failed"); } } in->pos = in->len; /* HACK: should use parsed length */ if (msg != NULL) goto finalize; return MAL_SUCCEED; } if (strncmp(in->buf + in->pos, "reply_size ", 11) == 0) { v = (int) strtol(in->buf + in->pos + 11, NULL, 10); if (v < -1) { msg = createException(SQL, "SQLparser", "reply_size cannot be negative"); goto finalize; } m->reply_size = v; in->pos = in->len; /* HACK: should use parsed length */ return MAL_SUCCEED; } if (strncmp(in->buf + in->pos, "sizeheader", 10) == 0) { v = (int) strtol(in->buf + in->pos + 10, NULL, 10); m->sizeheader = v != 0; in->pos = in->len; /* HACK: should use parsed length */ return MAL_SUCCEED; } if (strncmp(in->buf + in->pos, "quit", 4) == 0) { c->mode = FINISHCLIENT; return MAL_SUCCEED; } mnstr_printf(out, "!unrecognized X command: %s\n", in->buf + in->pos); msg = createException(SQL, "SQLparser", "unrecognized X command"); goto finalize; } if (be->language !='S') { mnstr_printf(out, "!unrecognized language prefix: %ci\n", be->language); msg = createException(SQL, "SQLparser", "unrecognized language prefix: %c", be->language); goto finalize; } if ((err = sqlparse(m)) || /* Only forget old errors on transaction boundaries */ (mvc_status(m) && m->type != Q_TRANS) || !m->sym) { if (!err &&m->scanner.started) /* repeat old errors, with a parsed query */ err = mvc_status(m); if (err) { msg = createException(PARSE, "SQLparser", "%s", m->errstr); handle_error(m, c->fdout, pstatus); } sqlcleanup(m, err); goto finalize; } assert(m->session->schema != NULL); /* * We have dealt with the first parsing step and advanced the input reader * to the next statement (if any). * Now is the time to also perform the semantic analysis, optimize and * produce code. */ be->q = NULL; if (m->emode == m_execute) { assert(m->sym->data.lval->h->type == type_int); be->q = qc_find(m->qc, m->sym->data.lval->h->data.i_val); if (!be->q) { err = -1; mnstr_printf(out, "!07003!EXEC: no prepared statement with id: %d\n", m->sym->data.lval->h->data.i_val); msg = createException(SQL, "PREPARE", "no prepared statement with id: %d", m->sym->data.lval->h->data.i_val); handle_error(m, c->fdout, pstatus); sqlcleanup(m, err); goto finalize; } else if (be->q->type != Q_PREPARE) { err = -1; mnstr_printf(out, "!07005!EXEC: given handle id is not for a " "prepared statement: %d\n", m->sym->data.lval->h->data.i_val); msg = createException(SQL, "PREPARE", "is not a prepared statement: %d", m->sym->data.lval->h->data.i_val); handle_error(m, c->fdout, pstatus); sqlcleanup(m, err); goto finalize; } m->emode = m_inplace; scanner_query_processed(&(m->scanner)); } else if (caching(m) && cachable(m, NULL) && m->emode != m_prepare && (be->q = qc_match(m->qc, m->sym, m->args, m->argc, m->scanner.key ^ m->session->schema->base.id)) != NULL) { // look for outdated plans if ( OPTmitosisPlanOverdue(c, be->q->name) ){ msg = SQLCacheRemove(c, be->q->name); qc_delete(be->mvc->qc, be->q); goto recompilequery; } if (m->emod & mod_debug) SQLsetDebugger(c, m, TRUE); if (m->emod & mod_trace) SQLsetTrace(be, c, TRUE); if (!(m->emod & (mod_explain | mod_debug | mod_trace | mod_dot))) m->emode = m_inplace; scanner_query_processed(&(m->scanner)); } else { sql_rel *r; stmt *s; recompilequery: r = sql_symbol2relation(m, m->sym); s = sql_relation2stmt(m, r); if (s == 0 || (err = mvc_status(m) && m->type != Q_TRANS)) { msg = createException(PARSE, "SQLparser", "%s", m->errstr); handle_error(m, c->fdout, pstatus); sqlcleanup(m, err); goto finalize; } assert(s); /* generate the MAL code */ if (m->emod & mod_trace) SQLsetTrace(be, c, TRUE); if (m->emod & mod_debug) SQLsetDebugger(c, m, TRUE); if (!caching(m) || !cachable(m, s)) { scanner_query_processed(&(m->scanner)); if (backend_callinline(be, c, s, 0) == 0) { opt = 1; } else { err = 1; } } else { /* generate a factory instantiation */ be->q = qc_insert(m->qc, m->sa, /* the allocator */ r, /* keep relational query */ m->sym, /* the sql symbol tree */ m->args, /* the argument list */ m->argc, m->scanner.key ^ m->session->schema->base.id, /* the statement hash key */ m->emode == m_prepare ? Q_PREPARE : m->type, /* the type of the statement */ sql_escape_str(QUERY(m->scanner))); scanner_query_processed(&(m->scanner)); be->q->code = (backend_code) backend_dumpproc(be, c, be->q, s); if (!be->q->code) err = 1; be->q->stk = 0; /* passed over to query cache, used during dumpproc */ m->sa = NULL; m->sym = NULL; /* register name in the namespace */ be->q->name = putName(be->q->name, strlen(be->q->name)); if (m->emode == m_normal && m->emod == mod_none) m->emode = m_inplace; } } if (err) m->session->status = -10; if (err == 0) { if (be->q) { if (m->emode == m_prepare) err = mvc_export_prepare(m, c->fdout, be->q, ""); else if (m->emode == m_inplace) { /* everything ready for a fast call */ } else { /* call procedure generation (only in cache mode) */ backend_call(be, c, be->q); } } /* In the final phase we add any debugging control */ if (m->emod & mod_trace) SQLsetTrace(be, c, FALSE); if (m->emod & mod_debug) SQLsetDebugger(c, m, FALSE); /* * During the execution of the query exceptions can be raised. * The default action is to print them out at the end of the * query block. */ pushEndInstruction(c->curprg->def); chkTypes(c->fdout, c->nspace, c->curprg->def, TRUE); /* resolve types */ if (opt) { MalBlkPtr mb = c->curprg->def; trimMalBlk(mb); chkProgram(c->fdout, c->nspace, mb); addOptimizers(c, mb, "default_pipe"); msg = optimizeMALBlock(c, mb); if (msg != MAL_SUCCEED) { sqlcleanup(m, err); goto finalize; } c->curprg->def = mb; } //printFunction(c->fdout, c->curprg->def, 0, LIST_MAL_ALL); /* we know more in this case than chkProgram(c->fdout, c->nspace, c->curprg->def); */ if (c->curprg->def->errors) { showErrors(c); /* restore the state */ MSresetInstructions(c->curprg->def, oldstop); freeVariables(c, c->curprg->def, c->glb, oldvtop); c->curprg->def->errors = 0; msg = createException(PARSE, "SQLparser", "Semantic errors"); } } finalize: if (msg) sqlcleanup(m, 0); return msg; }
/* * The generic solution to the multiplex operators is to translate * them to a MAL loop. * The call optimizer.multiplex(MOD,FCN,A1,...An) introduces the following code * structure: * * @verbatim * A1rev:=bat.reverse(A1); * resB:= bat.new(A1); * barrier (h,t):= iterator.new(A1); * $1:= algebra.fetch(A1,h); * $2:= A2; # in case of constant? * ... * cr:= MOD.FCN($1,...,$n); * y:=algebra.fetch(A1rev,h); * bat.insert(resB,y,cr); * redo (h,t):= iterator.next(A1); * end h; * @end verbatim * * The algorithm consists of two phases: phase one deals with * collecting the relevant information, phase two is the actual * code construction. */ static str OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i = 2, resB, iter = 0, cr; int hvar, tvar; int x, y; str mod, fcn; int *alias; InstrPtr q; int ht, tt; (void) cntxt; (void) stk; ht = getHeadType(getArgType(mb, pci, 0)); if (ht != TYPE_oid) throw(MAL, "optimizer.multiplex", "Target head type is missing"); tt = getTailType(getArgType(mb, pci, 0)); if (tt== TYPE_any) throw(MAL, "optimizer.multiplex", "Target tail type is missing"); if (isAnyExpression(getArgType(mb, pci, 0))) throw(MAL, "optimizer.multiplex", "Target type is missing"); mod = VALget(&getVar(mb, getArg(pci, 1))->value); mod = putName(mod,strlen(mod)); fcn = VALget(&getVar(mb, getArg(pci, 2))->value); fcn = putName(fcn,strlen(fcn)); /* search the iterator bat */ for (i = 3; i < pci->argc; i++) if (isaBatType(getArgType(mb, pci, i))) { iter = getArg(pci, i); if (getHeadType(getVarType(mb,iter)) != TYPE_oid) throw(MAL, "optimizer.multiplex", "Iterator BAT is not OID-headed"); break; } if( i == pci->argc) throw(MAL, "optimizer.multiplex", "Iterator BAT type is missing"); OPTDEBUGmultiplex { mnstr_printf(cntxt->fdout,"#calling the optimize multiplex script routine\n"); printFunction(cntxt->fdout,mb, 0, LIST_MAL_ALL ); mnstr_printf(cntxt->fdout,"#multiplex against operator %d %s\n",iter, getTypeName(getVarType(mb,iter))); printInstruction(cntxt->fdout,mb, 0, pci,LIST_MAL_ALL); } /* * Beware, the operator constant (arg=1) is passed along as well, * because in the end we issue a recursive function call that should * find the actual arguments at the proper place of the callee. */ alias= (int*) GDKmalloc(sizeof(int) * pci->maxarg); if (alias == NULL) return NULL; /* x := bat.reverse(A1); */ x = newTmpVariable(mb, newBatType(getTailType(getVarType(mb,iter)), getHeadType(getVarType(mb,iter)))); q = newFcnCall(mb, batRef, reverseRef); getArg(q, 0) = x; q = pushArgument(mb, q, iter); /* resB := new(refBat) */ q = newFcnCall(mb, batRef, newRef); resB = getArg(q, 0); setVarType(mb, getArg(q, 0), newBatType(ht, tt)); q = pushType(mb, q, ht); q = pushType(mb, q, tt); /* barrier (h,r) := iterator.new(refBat); */ q = newFcnCall(mb, iteratorRef, newRef); q->barrier = BARRIERsymbol; hvar = newTmpVariable(mb, TYPE_any); getArg(q,0) = hvar; tvar = newTmpVariable(mb, TYPE_any); q= pushReturn(mb, q, tvar); (void) pushArgument(mb,q,iter); /* $1:= algebra.fetch(Ai,h) or constant */ alias[i] = tvar; for (i++; i < pci->argc; i++) if (isaBatType(getArgType(mb, pci, i))) { q = newFcnCall(mb, algebraRef, "fetch"); alias[i] = newTmpVariable(mb, getTailType(getArgType(mb, pci, i))); getArg(q, 0) = alias[i]; q= pushArgument(mb, q, getArg(pci, i)); (void) pushArgument(mb, q, hvar); } /* cr:= mod.CMD($1,...,$n); */ q = newFcnCall(mb, mod, fcn); cr = getArg(q, 0) = newTmpVariable(mb, TYPE_any); for (i = 3; i < pci->argc; i++) if (isaBatType(getArgType(mb, pci, i))) { q= pushArgument(mb, q, alias[i]); } else { q = pushArgument(mb, q, getArg(pci, i)); } /* y := algebra.fetch(x,h); */ y = newTmpVariable(mb, getHeadType(getVarType(mb,iter))); q = newFcnCall(mb, algebraRef, "fetch"); getArg(q, 0) = y; q = pushArgument(mb, q, x); q = pushArgument(mb, q, hvar); /* insert(resB,h,cr); not append(resB, cr); the head type (oid) may dynamically change */ q = newFcnCall(mb, batRef, insertRef); q= pushArgument(mb, q, resB); q= pushArgument(mb, q, y); (void) pushArgument(mb, q, cr); /* redo (h,r):= iterator.next(refBat); */ q = newFcnCall(mb, iteratorRef, nextRef); q->barrier = REDOsymbol; getArg(q,0) = hvar; q= pushReturn(mb, q, tvar); (void) pushArgument(mb,q,iter); q = newAssignment(mb); q->barrier = EXITsymbol; getArg(q,0) = hvar; (void) pushReturn(mb, q, tvar); q = newAssignment(mb); getArg(q, 0) = getArg(pci, 0); (void) pushArgument(mb, q, resB); GDKfree(alias); return MAL_SUCCEED; }
static void mal_help_display(char **msg, int a, int b){ int i; (void) msg; (void) a; (void) b; for(i=0;i<a; i++) mnstr_printf(GDKout,"%s\n",msg[i]); }
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 OPTpushselectImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, limit, slimit, actions=0, *vars, push_down_delta = 0, nr_topn = 0, nr_likes = 0; InstrPtr p, *old; subselect_t subselects; memset(&subselects, 0, sizeof(subselects)); if( mb->errors) return 0; OPTDEBUGpushselect mnstr_printf(cntxt->fdout,"#Push select optimizer started\n"); (void) stk; (void) pci; vars= (int*) GDKzalloc(sizeof(int)* mb->vtop); if( vars == NULL) return 0; limit = mb->stop; slimit= mb->ssize; old = mb->stmt; /* check for bailout conditions */ for (i = 1; i < limit; i++) { int lastbat; p = old[i]; for (j = 0; j<p->retc; j++) { int res = getArg(p, j); vars[res] = i; } if (getModuleId(p) == algebraRef && (getFunctionId(p) == tintersectRef || getFunctionId(p) == tinterRef || getFunctionId(p) == tdifferenceRef || getFunctionId(p) == tdiffRef)) { GDKfree(vars); return 0; } if (getModuleId(p) == algebraRef && getFunctionId(p) == sliceRef) nr_topn++; if (isLikeOp(p)) nr_likes++; if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef) push_down_delta++; if (getModuleId(p) == sqlRef && getFunctionId(p) == tidRef) { /* rewrite equal table ids */ int sname = getArg(p, 2), tname = getArg(p, 3), s; for (s = 0; s < subselects.nr; s++) { InstrPtr q = old[vars[subselects.tid[s]]]; int Qsname = getArg(q, 2), Qtname = getArg(q, 3); if (no_updates(old, vars, getArg(q,1), getArg(p,1)) && ((sname == Qsname && tname == Qtname) || (0 && strcmp(getVarConstant(mb, sname).val.sval, getVarConstant(mb, Qsname).val.sval) == 0 && strcmp(getVarConstant(mb, tname).val.sval, getVarConstant(mb, Qtname).val.sval) == 0))) { clrFunction(p); p->retc = 1; p->argc = 2; getArg(p, 1) = getArg(q, 0); break; } } } lastbat = lastbat_arg(mb, p); if (isSubSelect(p) && p->retc == 1 && /* no cand list */ getArgType(mb, p, lastbat) != newBatType(TYPE_oid, TYPE_oid)) { int i1 = getArg(p, 1), tid = 0; InstrPtr q = old[vars[i1]]; /* find the table ids */ while(!tid) { if (getModuleId(q) == algebraRef && getFunctionId(q) == leftfetchjoinRef) { int i1 = getArg(q, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); if (s->argc == 2 && s->retc == 1) { int i1 = getArg(s, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); } break; } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { int i1 = getArg(q, 1); q = old[vars[i1]]; } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { int i2 = getArg(q, 2); q = old[vars[i2]]; } else { break; } } if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { GDKfree(vars); return 0; } } /* left hand side */ if ( (GDKdebug & (1<<15)) && isMatJoinOp(p) && p->retc == 2) { int i1 = getArg(p, 2), tid = 0; InstrPtr q = old[vars[i1]]; /* find the table ids */ while(!tid) { if (getModuleId(q) == algebraRef && getFunctionId(q) == leftfetchjoinRef) { int i1 = getArg(q, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); break; } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { int i1 = getArg(q, 1); q = old[vars[i1]]; } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { int i2 = getArg(q, 2); q = old[vars[i2]]; } else { break; } } if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { GDKfree(vars); return 0; } } /* right hand side */ if ( (GDKdebug & (1<<15)) && isMatJoinOp(p) && p->retc == 2) { int i1 = getArg(p, 3), tid = 0; InstrPtr q = old[vars[i1]]; /* find the table ids */ while(!tid) { if (getModuleId(q) == algebraRef && getFunctionId(q) == leftfetchjoinRef) { int i1 = getArg(q, 1); InstrPtr s = old[vars[i1]]; if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) tid = getArg(q, 1); break; } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { int i1 = getArg(q, 1); q = old[vars[i1]]; } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { int i2 = getArg(q, 2); q = old[vars[i2]]; } else { break; } } if (tid && subselect_add(&subselects, tid, getArg(p, 1)) < 0) { GDKfree(vars); return 0; } } } if ((!subselects.nr && !nr_topn && !nr_likes) || newMalBlkStmt(mb, mb->ssize) <0 ) { GDKfree(vars); return 0; } pushInstruction(mb,old[0]); for (i = 1; i < limit; i++) { p = old[i]; /* rewrite batalgebra.like + subselect -> likesubselect */ if (getModuleId(p) == algebraRef && p->retc == 1 && getFunctionId(p) == subselectRef) { int var = getArg(p, 1); InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ if (isLikeOp(q)) { /* TODO check if getArg(p, 3) value == TRUE */ InstrPtr r = newInstruction(mb, ASSIGNsymbol); int has_cand = (getArgType(mb, p, 2) == newBatType(TYPE_oid, TYPE_oid)); int a, anti = (getFunctionId(q)[0] == 'n'), ignore_case = (getFunctionId(q)[anti?4:0] == 'i'); setModuleId(r, algebraRef); setFunctionId(r, likesubselectRef); getArg(r,0) = getArg(p,0); r = pushArgument(mb, r, getArg(q, 1)); if (has_cand) r = pushArgument(mb, r, getArg(p, 2)); for(a = 2; a<q->argc; a++) r = pushArgument(mb, r, getArg(q, a)); if (r->argc < (4+has_cand)) r = pushStr(mb, r, ""); /* default esc */ if (r->argc < (5+has_cand)) r = pushBit(mb, r, ignore_case); if (r->argc < (6+has_cand)) r = pushBit(mb, r, anti); freeInstruction(p); p = r; actions++; } } /* inject table ids into subselect * s = subselect(c, C1..) => subselect(c, t, C1..) */ if (isSubSelect(p) && p->retc == 1) { int tid = 0; if ((tid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { int lastbat = lastbat_arg(mb, p); if (getArgType(mb, p, lastbat) == TYPE_bat) /* empty candidate list bat_nil */ getArg(p, lastbat) = tid; else p = PushArgument(mb, p, tid, lastbat+1); /* make sure to resolve again */ p->token = ASSIGNsymbol; p->typechk = TYPE_UNKNOWN; p->fcn = NULL; p->blk = NULL; actions++; } } else if ( (GDKdebug & (1<<15)) && isMatJoinOp(p) && p->retc == 2 && !(getFunctionId(p) == joinRef && p->argc > 4) ) { int ltid = 0, rtid = 0, done = 0; int range = 0; if(getFunctionId(p) == joinRef) range = (p->argc >= 4); if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0 && (rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { p = PushArgument(mb, p, ltid, 4+range); p = PushArgument(mb, p, rtid, 5+range); done = 1; } else if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { p = PushArgument(mb, p, ltid, 4+range); p = PushNil(mb, p, 5+range, TYPE_bat); done = 1; } else if ((rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { p = PushNil(mb, p, 4+range, TYPE_bat); p = PushArgument(mb, p, rtid, 5+range); done = 1; } if (done) { if(getFunctionId(p) == antijoinRef) p = pushInt(mb, p, JOIN_NE); p = pushBit(mb, p, FALSE); /* do not match nils */ p = pushNil(mb, p, TYPE_lng); /* no estimate */ /* TODO join* -> subjoin* */ if(getFunctionId(p) == joinRef) getFunctionId(p) = subjoinRef; else if(getFunctionId(p) == antijoinRef) getFunctionId(p) = subthetajoinRef; else if(getFunctionId(p) == thetajoinRef) getFunctionId(p) = subthetajoinRef; else if(getFunctionId(p) == bandjoinRef) getFunctionId(p) = subbandjoinRef; /* make sure to resolve again */ p->token = ASSIGNsymbol; p->typechk = TYPE_UNKNOWN; p->fcn = NULL; p->blk = NULL; actions++; } } /* Leftfetchjoins involving rewriten table ids need to be flattend * l = leftfetchjoin(t, c); => l = c; * and * l = leftfetchjoin(s, ntids); => l = s; */ else if (getModuleId(p) == algebraRef && getFunctionId(p) == leftfetchjoinRef) { int var = getArg(p, 1); if (subselect_find_subselect(&subselects, var) > 0) { InstrPtr q = newAssignment(mb); getArg(q, 0) = getArg(p, 0); (void) pushArgument(mb, q, getArg(p, 2)); actions++; freeInstruction(p); continue; } else { /* deletes/updates use table ids */ int var = getArg(p, 2); InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ if (q->token == ASSIGNsymbol) { var = getArg(q, 1); q = mb->stmt[vars[var]]; } if (subselect_find_subselect(&subselects, var) > 0) { InstrPtr qq = newAssignment(mb); /* TODO: check result */ getArg(qq, 0) = getArg(p, 0); (void) pushArgument(mb, qq, getArg(p, 1)); actions++; freeInstruction(p); continue; } /* c = sql.delta(b,uid,uval,ins); * l = leftfetchjoin(x, c); * into * l = sql.projectdelta(x,b,uid,uval,ins); */ else if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef && q->argc == 5) { q = copyInstruction(q); setFunctionId(q, projectdeltaRef); getArg(q, 0) = getArg(p, 0); q = PushArgument(mb, q, getArg(p, 1), 1); freeInstruction(p); p = q; actions++; } } } pushInstruction(mb,p); } for (; i<limit; i++) if (old[i]) pushInstruction(mb,old[i]); for (; i<slimit; i++) if (old[i]) freeInstruction(old[i]); GDKfree(old); if (!push_down_delta) { GDKfree(vars); return actions; } /* now push selects through delta's */ limit = mb->stop; slimit= mb->ssize; old = mb->stmt; if (newMalBlkStmt(mb, mb->stop+(5*push_down_delta)) <0 ) { mb->stmt = old; GDKfree(vars); return actions; } pushInstruction(mb,old[0]); for (i = 1; i < limit; i++) { int lastbat; p = old[i]; for (j = 0; j<p->retc; j++) { int res = getArg(p, j); vars[res] = i; } /* push subslice under projectdelta */ if (isSlice(p) && p->retc == 1) { int var = getArg(p, 1); InstrPtr q = old[vars[var]]; if (getModuleId(q) == sqlRef && getFunctionId(q) == projectdeltaRef) { InstrPtr r = copyInstruction(p); InstrPtr s = copyInstruction(q); ValRecord cst; /* slice the candidates */ setFunctionId(r, sliceRef); getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(r, 1) = getArg(s, 1); cst.vtype = getArgType(mb, r, 2); cst.val.wval = 0; getArg(r, 2) = defConstant(mb, cst.vtype, &cst); /* start from zero */ pushInstruction(mb,r); /* dummy result for the old q, will be removed by deadcode optimizer */ getArg(q, 0) = newTmpVariable(mb, getArgType(mb, q, 0)); getArg(s, 1) = getArg(r, 0); /* use result of subslice */ pushInstruction(mb, s); } } /* c = delta(b, uid, uvl, ins) * s = subselect(c, C1..) * * nc = subselect(b, C1..) * ni = subselect(ins, C1..) * nu = subselect(uvl, C1..) * s = subdelta(nc, uid, nu, ni); * * doesn't handle Xsubselect(x, .. z, C1.. cases) ie multicolumn selects */ lastbat = lastbat_arg(mb, p); if (isSubSelect(p) && p->retc == 1 && lastbat == 2) { int var = getArg(p, 1); InstrPtr q = old[vars[var]]; if (q->token == ASSIGNsymbol) { var = getArg(q, 1); q = old[vars[var]]; } if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef) { InstrPtr r = copyInstruction(p); InstrPtr s = copyInstruction(p); InstrPtr t = copyInstruction(p); InstrPtr u = copyInstruction(q); getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(r, 1) = getArg(q, 1); /* column */ pushInstruction(mb,r); getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(s, 1) = getArg(q, 3); /* updates */ s = ReplaceWithNil(mb, s, 2, TYPE_bat); /* no candidate list */ setArgType(mb, s, 2, newBatType(TYPE_oid,TYPE_oid)); /* make sure to resolve again */ s->token = ASSIGNsymbol; s->typechk = TYPE_UNKNOWN; s->fcn = NULL; s->blk = NULL; pushInstruction(mb,s); getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_oid, TYPE_oid)); getArg(t, 1) = getArg(q, 4); /* inserts */ pushInstruction(mb,t); setFunctionId(u, subdeltaRef); getArg(u, 0) = getArg(p,0); getArg(u, 1) = getArg(r,0); getArg(u, 2) = getArg(p,2); /* pre-cands */ getArg(u, 3) = getArg(q,2); /* update ids */ getArg(u, 4) = getArg(s,0); u = pushArgument(mb, u, getArg(t,0)); pushInstruction(mb,u); freeInstruction(p); continue; } } pushInstruction(mb,p); } for (; i<limit; i++) if (old[i]) pushInstruction(mb,old[i]); GDKfree(vars); GDKfree(old); return actions; }
int main(int argc, char **av) { char *prog = *av; opt *set = NULL; int idx = 0, grpdebug = 0, debug = 0, setlen = 0, listing = 0, i = 0; str dbinit = NULL; str err = MAL_SUCCEED; char prmodpath[1024]; char *modpath = NULL; char *binpath = NULL; str *monet_script; static struct option long_options[] = { { "config", 1, 0, 'c' }, { "dbpath", 1, 0, 0 }, { "dbinit", 1, 0, 0 }, { "debug", 2, 0, 'd' }, { "help", 0, 0, '?' }, { "version", 0, 0, 0 }, { "readonly", 0, 0, 'r' }, { "set", 1, 0, 's' }, { "threads", 0, 0, 0 }, { "memory", 0, 0, 0 }, { "properties", 0, 0, 0 }, { "io", 0, 0, 0 }, { "transactions", 0, 0, 0 }, { "trace", 2, 0, 't' }, { "modules", 0, 0, 0 }, { "algorithms", 0, 0, 0 }, { "optimizers", 0, 0, 0 }, { "performance", 0, 0, 0 }, #if 0 { "xproperties", 0, 0, 0 }, #endif { "forcemito", 0, 0, 0 }, { "heaps", 0, 0, 0 }, { 0, 0, 0, 0 } }; #if defined(_MSC_VER) && defined(__cplusplus) set_terminate(mserver_abort); #endif if (setlocale(LC_CTYPE, "") == NULL) { GDKfatal("cannot set locale\n"); } #ifdef HAVE_MALLOPT if (malloc_init) { /* for (Red Hat) Linux (6.2) unused and ignored at least as of glibc-2.1.3-15 */ /* for (Red Hat) Linux (8) used at least as of glibc-2.2.93-5 */ if (mallopt(M_MXFAST, 192)) { fprintf(stderr, "!monet: mallopt(M_MXFAST,192) fails.\n"); } #ifdef M_BLKSZ if (mallopt(M_BLKSZ, 8 * 1024)) { fprintf(stderr, "!monet: mallopt(M_BLKSZ,8*1024) fails.\n"); } #endif } malloc_init = 0; #else (void) malloc_init; /* still unused */ #endif if (getcwd(monet_cwd, PATHLENGTH - 1) == NULL) { perror("pwd"); GDKfatal("monet_init: could not determine current directory\n"); } /* retrieve binpath early (before monet_init) because some * implementations require the working directory when the binary was * called */ binpath = get_bin_path(); if (!(setlen = mo_builtin_settings(&set))) usage(prog, -1); setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_single_user", "yes"); for (;;) { int option_index = 0; int c = getopt_long(argc, av, "c:d::rs:t::?", long_options, &option_index); if (c == -1) break; switch (c) { case 0: if (strcmp(long_options[option_index].name, "dbpath") == 0) { size_t optarglen = strlen(optarg); /* remove trailing directory separator */ while (optarglen > 0 && (optarg[optarglen - 1] == '/' || optarg[optarglen - 1] == '\\')) optarg[--optarglen] = '\0'; setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_dbpath", optarg); break; } if (strcmp(long_options[option_index].name, "dbinit") == 0) { if (dbinit) fprintf(stderr, "#warning: ignoring multiple --dbinit argument\n"); else dbinit = optarg; break; } if (strcmp(long_options[option_index].name, "version") == 0) { monet_version(); exit(0); } /* debugging options */ if (strcmp(long_options[option_index].name, "properties") == 0) { grpdebug |= GRPproperties; break; } if (strcmp(long_options[option_index].name, "algorithms") == 0) { grpdebug |= GRPalgorithms; break; } if (strcmp(long_options[option_index].name, "optimizers") == 0) { grpdebug |= GRPoptimizers; break; } #if 0 if (strcmp(long_options[option_index].name, "xproperties") == 0) { grpdebug |= GRPxproperties; break; } #endif if (strcmp(long_options[option_index].name, "forcemito") == 0) { grpdebug |= GRPforcemito; break; } if (strcmp(long_options[option_index].name, "performance") == 0) { grpdebug |= GRPperformance; break; } if (strcmp(long_options[option_index].name, "io") == 0) { grpdebug |= GRPio; break; } if (strcmp(long_options[option_index].name, "memory") == 0) { grpdebug |= GRPmemory; break; } if (strcmp(long_options[option_index].name, "modules") == 0) { grpdebug |= GRPmodules; break; } if (strcmp(long_options[option_index].name, "transactions") == 0) { grpdebug |= GRPtransactions; break; } if (strcmp(long_options[option_index].name, "threads") == 0) { grpdebug |= GRPthreads; break; } if (strcmp(long_options[option_index].name, "trace") == 0) { mal_trace = optarg? optarg:"ISTest"; break; } if (strcmp(long_options[option_index].name, "heaps") == 0) { grpdebug |= GRPheaps; break; } usage(prog, -1); /* not reached */ case 'c': setlen = mo_add_option(&set, setlen, opt_cmdline, "config", optarg); break; case 'd': if (optarg) { debug |= strtol(optarg, NULL, 10); } else { debug |= 1; } break; case 'r': setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_readonly", "yes"); break; case 's': { /* should add option to a list */ char *tmp = strchr(optarg, '='); if (tmp) { *tmp = '\0'; setlen = mo_add_option(&set, setlen, opt_cmdline, optarg, tmp + 1); } else fprintf(stderr, "ERROR: wrong format %s\n", optarg); } break; case 't': mal_trace = optarg? optarg:"ISTest"; break; case '?': /* a bit of a hack: look at the option that the current `c' is based on and see if we recognize it: if -? or --help, exit with 0, else with -1 */ usage(prog, strcmp(av[optind - 1], "-?") == 0 || strcmp(av[optind - 1], "--help") == 0 ? 0 : -1); default: fprintf(stderr, "ERROR: getopt returned character " "code '%c' 0%o\n", c, c); usage(prog, -1); } } if (!(setlen = mo_system_config(&set, setlen))) usage(prog, -1); if (debug || grpdebug) { long_str buf; if (debug) mo_print_options(set, setlen); debug |= grpdebug; /* add the algorithm tracers */ snprintf(buf, sizeof(long_str) - 1, "%d", debug); setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_debug", buf); } #ifdef RDEBUG printf("parameter ok\n"); #endif monet_script = (str *) malloc(sizeof(str) * (argc + 1)); if (monet_script) { monet_script[idx] = NULL; while (optind < argc) { monet_script[idx] = absolute_path(av[optind]); monet_script[idx + 1] = NULL; optind++; idx++; } } if (monet_init(set, setlen) == 0) { mo_free_options(set, setlen); return 0; } mo_free_options(set, setlen); #ifdef RDEBUG printf("monet_init ok\n"); #endif GDKsetenv("monet_version", VERSION); GDKsetenv("monet_release", MONETDB_RELEASE); if ((modpath = GDKgetenv("monet_mod_path")) == NULL) { /* start probing based on some heuristics given the binary * location: * bin/mserver5 -> ../ * libX/monetdb5/lib/ * probe libX = lib, lib32, lib64, lib/64 */ char *libdirs[] = { "lib", "lib64", "lib/64", "lib32", NULL }; size_t i; struct stat sb; if (binpath != NULL) { char *p = strrchr(binpath, DIR_SEP); if (p != NULL) *p = '\0'; p = strrchr(binpath, DIR_SEP); if (p != NULL) { *p = '\0'; for (i = 0; libdirs[i] != NULL; i++) { snprintf(prmodpath, sizeof(prmodpath), "%s%c%s%cmonetdb5", binpath, DIR_SEP, libdirs[i], DIR_SEP); if (stat(prmodpath, &sb) == 0) { modpath = prmodpath; break; } } } else { printf("#warning: unusable binary location, " "please use --set monet_mod_path=/path/to/... to " "allow finding modules\n"); fflush(NULL); } } else { printf("#warning: unable to determine binary location, " "please use --set monet_mod_path=/path/to/... to " "allow finding modules\n"); fflush(NULL); } if (modpath != NULL) GDKsetenv("monet_mod_path", modpath); } #ifdef RDEBUG printf("modpath ok\n"); #endif /* configure sabaoth to use the right dbpath and active database */ msab_dbpathinit(GDKgetenv("gdk_dbpath")); /* wipe out all cruft, if left over */ if ((err = msab_wildRetreat()) != NULL) { /* just swallow the error */ free(err); } /* From this point, the server should exit cleanly. Discussion: * even earlier? Sabaoth here registers the server is starting up. */ if ((err = msab_registerStarting()) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } #ifdef RDEBUG printf("some stuff\n"); #endif #ifdef HAVE_SIGACTION { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; if ( sigaction(SIGINT, &sa, NULL) == -1 || sigaction(SIGQUIT, &sa, NULL) == -1 || sigaction(SIGTERM, &sa, NULL) == -1) { fprintf(stderr, "!unable to create signal handlers\n"); } } #else signal(SIGINT, handler); #ifdef SIGQUIT signal(SIGQUIT, handler); #endif signal(SIGTERM, handler); #endif { str lang = "mal"; /* we inited mal before, so publish its existence */ if ((err = msab_marchScenario(lang)) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } } #ifdef RDEBUG printf("scenario ok\n"); #endif { /* unlock the vault, first see if we can find the file which * holds the secret */ char secret[1024]; char *secretp = secret; FILE *secretf; size_t len; if (GDKgetenv("monet_vault_key") == NULL) { /* use a default (hard coded, non safe) key */ snprintf(secret, sizeof(secret), "%s", "Xas632jsi2whjds8"); } else { if ((secretf = fopen(GDKgetenv("monet_vault_key"), "r")) == NULL) { snprintf(secret, sizeof(secret), "unable to open vault_key_file %s: %s", GDKgetenv("monet_vault_key"), strerror(errno)); /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", secret); } len = fread(secret, 1, sizeof(secret), secretf); secret[len] = '\0'; len = strlen(secret); /* secret can contain null-bytes */ if (len == 0) { snprintf(secret, sizeof(secret), "vault key has zero-length!"); /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", secret); } else if (len < 5) { fprintf(stderr, "#warning: your vault key is too short " "(" SZFMT "), enlarge your vault key!\n", len); } fclose(secretf); } if ((err = AUTHunlockVault(&secretp)) != MAL_SUCCEED) { /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", err); } } /* make sure the authorisation BATs are loaded */ if ((err = AUTHinitTables()) != MAL_SUCCEED) { /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", err); } #ifdef RDEBUG printf("vaultkey ok\n"); #endif if (mal_init()) { /* don't show this as a crash */ msab_registerStop(); return 0; } #ifdef RDEBUG printf("mal_init ok\n"); #endif #if (0) if (!loadLibrary("lib_leaker", TRUE)) return 42; #endif #ifdef RDEBUG printf("lib_leaker ok\n"); #endif if (GDKgetenv("mal_listing")) sscanf(GDKgetenv("mal_listing"), "%d", &listing); MSinitClientPrg(mal_clients, "user", "main"); if (dbinit == NULL) dbinit = GDKgetenv("dbinit"); if (dbinit) callString(mal_clients, dbinit, listing); #ifdef RDEBUG printf("MSinitClientPrg ok\n"); #endif emergencyBreakpoint(); if ((err = compileOptimizer(mal_clients, "leaker_pipe")) != MAL_SUCCEED) mnstr_printf(mal_clients->fdout, "OPT_COMPILE: %s\n", err); //callString(mal_clients, "sql.start();\n", 0); if (monet_script) for (i = 0; monet_script[i]; i++) { str msg = evalFile(mal_clients, monet_script[i], listing); /* check for internal exception message to terminate */ if (msg) { if (strcmp(msg, "MALException:client.quit:Server stopped.") == 0) mal_exit(); fprintf(stderr, "#%s: %s\n", monet_script[i], msg); GDKfree(msg); } GDKfree(monet_script[i]); monet_script[i] = 0; } if ((err = msab_registerStarted()) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } if (monet_script) free(monet_script); MSserveClient(mal_clients); /* mal_exit calls MT_global_exit, so statements after this call will * never get reached */ mal_exit(); return 0; }
char * getConsoleInput(Client c, const char *prompt, int linemode, int exit_on_error) { char *line = NULL; char *buf = NULL; size_t length; (void) exit_on_error; (void) linemode; do { #ifdef HAVE_LIBREADLINE if (prompt) { if (buf) free(buf); buf = readline(prompt); /* add a newline to the end since that makes further processing easier */ if (buf) { add_history(buf); length = strlen(buf); buf = realloc(buf, length + 2); if( buf == NULL){ GDKerror("getConsoleInput: " MAL_MALLOC_FAIL); return NULL; } buf[length++] = '\n'; buf[length] = 0; } line = buf; } else #endif { #ifndef HAVE_LIBREADLINE if (prompt) { fputs(prompt, stdout); fflush(stdout); } #endif if (buf == NULL) { buf= malloc(BUFSIZ); if( buf == NULL){ GDKerror("getConsoleInput: " MAL_MALLOC_FAIL); return NULL; } } line = fgets(buf, BUFSIZ, stdin); } if (line == NULL) { /* end of file */ if (buf) free(buf); return NULL; } else length = strlen(line); if (length > 0 ) { /* test for special commands */ while (length > 0 && (*line & ~0x7F) == 0 && isspace((int) *line)) { line++; length--; } /* in the switch, use continue if the line was processed, use break to send to parser */ switch (*line) { case '\0': /* empty line */ break; case '\\': switch (line[1]) { case 'q': free(buf); return NULL; default: break; } line= NULL; break; case '<': /* read commands from file */ if (line[length - 1] == '\n') line[--length] = 0; if (line[length - 1] == '\r') line[--length] = 0; /* doFile(mid, line + 1, 0);*/ line= NULL; continue; case '>': /* redirect output to file */ line++; length--; if (line[length - 1] == '\n') line[--length] = 0; if (line[length - 1] == '\r') line[--length] = 0; if (c->fdout && c->fdout != GDKout && c->fdout != GDKerr){ close_stream(c->fdout); c->fdout= 0; } if (length == 0 || strcmp(line, "stdout") == 0) c->fdout = GDKout; else if (strcmp(line, "stderr") == 0) c->fdout = GDKerr; else if ((c->fdout = open_wastream(line)) == NULL) { c->fdout = GDKout; mnstr_printf(GDKerr, "Cannot open %s\n", line); } line = NULL; continue; #ifdef HAVE_LIBREADLINE case '!': { char *nl; int i; if(line[1]=='\n') { for(i=0; i< history_length; i++){ nl= history_get(i)? history_get(i)->line:0; if( nl) mnstr_printf(c->fdout, "%d %s\n", i, nl); } line = NULL; } else if( history_expand(line,&nl) ==1 ) { mnstr_printf(c->fdout,"#%s",nl); line= nl; } else line= NULL; } continue; #endif case '?': if( line[1] && line[1]!='\n'){ showHelp( c->nspace,line+1, c->fdout); } else showCommands(); line= NULL; continue; } /* make sure we return a pointer that can (and should) be freed by the caller */ if (line) line = buf; } } while (line == NULL); return line; }
int main(int argc, char **argv) { int port = 0; char *user = NULL; char *passwd = NULL; char *host = NULL; char *dbname = NULL; int trace = 0; int describe = 0; int functions = 0; int useinserts = 0; int c; Mapi mid; int quiet = 0; stream *out; char user_set_as_flag = 0; char *table = NULL; static struct option long_options[] = { {"host", 1, 0, 'h'}, {"port", 1, 0, 'p'}, {"database", 1, 0, 'd'}, {"describe", 0, 0, 'D'}, {"functions", 0, 0, 'f'}, {"table", 1, 0, 't'}, {"inserts", 0, 0, 'N'}, {"Xdebug", 0, 0, 'X'}, {"user", 1, 0, 'u'}, {"quiet", 0, 0, 'q'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; parse_dotmonetdb(&user, &passwd, NULL, NULL, NULL, NULL); while ((c = getopt_long(argc, argv, "h:p:d:Dft:NXu:q?", long_options, NULL)) != -1) { switch (c) { case 'u': if (user) free(user); user = strdup(optarg); user_set_as_flag = 1; break; case 'h': host = optarg; break; case 'p': assert(optarg != NULL); port = atoi(optarg); break; case 'd': dbname = optarg; break; case 'D': describe = 1; break; case 'N': useinserts = 1; break; case 'f': if (table) usage(argv[0], -1); functions = 1; break; case 't': if (table || functions) usage(argv[0], -1); table = optarg; break; case 'q': quiet = 1; break; case 'X': trace = MAPI_TRACE; break; case '?': /* a bit of a hack: look at the option that the current `c' is based on and see if we recognize it: if -? or --help, exit with 0, else with -1 */ usage(argv[0], strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0 ? 0 : -1); default: usage(argv[0], -1); } } if (optind == argc - 1) dbname = argv[optind]; else if (optind != argc) usage(argv[0], -1); /* when config file would provide defaults */ if (user_set_as_flag) passwd = NULL; if (user == NULL) user = simple_prompt("user", BUFSIZ, 1, prompt_getlogin()); if (passwd == NULL) passwd = simple_prompt("password", BUFSIZ, 0, NULL); mid = mapi_connect(host, port, user, passwd, "sql", dbname); if (user) free(user); if (passwd) free(passwd); if (mid == NULL) { fprintf(stderr, "failed to allocate Mapi structure\n"); exit(2); } if (mapi_error(mid)) { mapi_explain(mid, stderr); exit(2); } if (!quiet) { char *motd = mapi_get_motd(mid); if (motd) fprintf(stderr, "%s", motd); } mapi_trace(mid, trace); mapi_cache_limit(mid, 10000); out = file_wastream(stdout, "stdout"); if (out == NULL) { fprintf(stderr, "failed to allocate stream\n"); exit(2); } if (!quiet) { char buf[27]; time_t t = time(0); char *p; #ifdef HAVE_CTIME_R3 ctime_r(&t, buf, sizeof(buf)); #else #ifdef HAVE_CTIME_R ctime_r(&t, buf); #else strncpy(buf, ctime(&t), sizeof(buf)); #endif #endif if ((p = strrchr(buf, '\n')) != NULL) *p = 0; mnstr_printf(out, "-- msqldump %s %s%s %s\n", describe ? "describe" : "dump", functions ? "functions" : table ? "table " : "database", table ? table : "", buf); dump_version(mid, out, "--"); } if (functions) c = dump_functions(mid, out, NULL, NULL); else if (table) c = dump_table(mid, NULL, table, out, describe, 1, useinserts); else c = dump_database(mid, out, describe, useinserts); mnstr_flush(out); mapi_destroy(mid); if (mnstr_errnr(out)) { fprintf(stderr, "%s: %s", argv[0], mnstr_error(out)); return 1; } mnstr_destroy(out); return c; }