예제 #1
0
void
listModules(stream *out, Module s)
{
	while(s){
		mnstr_printf(out,"Unexpected module %s\n",  s->name);
		s= s->link;
	}
}
예제 #2
0
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);
}
예제 #3
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;
}
예제 #4
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;
}
예제 #5
0
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);
}
예제 #6
0
/*
 * 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;
}
예제 #7
0
// 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;
		}
	}
}
예제 #8
0
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;
}
예제 #9
0
파일: mdb.c 프로젝트: cswxu/monetdb-mcs
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;
}
예제 #10
0
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
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
파일: sensor.c 프로젝트: digideskio/monetdb
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;
}
예제 #14
0
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;
	}
}
예제 #15
0
파일: mal_listing.c 프로젝트: f7753/monetdb
/* 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;
}
예제 #16
0
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
}
예제 #17
0
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;
}
예제 #18
0
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;
}
예제 #19
0
/* #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;
}
예제 #20
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;
}
예제 #21
0
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 {
예제 #22
0
파일: control.c 프로젝트: f7753/monetdb
/* 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);
}
예제 #23
0
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;
}
예제 #24
0
/*
 * 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;
}
예제 #25
0
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]);
}
예제 #26
0
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;
}
예제 #27
0
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;
}
예제 #28
0
파일: client.c 프로젝트: lajus/monetinr
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;
}
예제 #29
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;
}
예제 #30
0
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;
}