str bstream_create_wrapwrap(Bstream *Bs, Stream *S, int *bufsize) { if ((*(bstream **)Bs = bstream_create(*(stream **)S, (size_t)*bufsize)) == NULL) throw(IO, "bstreams.create", "failed to create block stream"); return MAL_SUCCEED; }
Client MCinitClientRecord(Client c, oid user, bstream *fin, stream *fout) { str prompt; c->user = user; c->username = 0; c->scenario = NULL; c->oldscenario = NULL; c->srcFile = NULL; c->blkmode = 0; c->fdin = fin ? fin : bstream_create(GDKin, 0); c->yycur = 0; c->bak = NULL; c->listing = 0; c->fdout = fout ? fout : GDKstdout; c->mdb = 0; c->history = 0; c->curprg = c->backup = 0; c->glb = 0; /* remove garbage from previous connection */ if (c->nspace) { freeModule(c->nspace); c->nspace = 0; } c->father = NULL; c->login = c->lastcmd = time(0); //c->active = 0; c->session = GDKusec(); c->qtimeout = 0; c->stimeout = 0; c->stage = 0; c->itrace = 0; c->debugOptimizer = c->debugScheduler = 0; c->flags = MCdefault; c->errbuf = 0; prompt = !fin ? GDKgetenv("monet_prompt") : PROMPT1; c->prompt = GDKstrdup(prompt); c->promptlength = strlen(prompt); c->actions = 0; c->totaltime = 0; /* create a recycler cache */ c->exception_buf_initialized = 0; c->error_row = c->error_fld = c->error_msg = c->error_input = NULL; (void) AUTHgetUsername(&c->username, c); MT_sema_init(&c->s, 0, "Client->s"); return c; }
Client MCinitClientRecord(Client c, oid user, bstream *fin, stream *fout) { str prompt; c->user = user; c->scenario = NULL; c->oldscenario = NULL; c->srcFile = NULL; c->blkmode = 0; c->fdin = fin ? fin : bstream_create(GDKin, 0); c->yycur = 0; c->bak = NULL; c->listing = 0; c->fdout = fout ? fout : GDKstdout; c->mdb = 0; c->history = 0; c->curprg = c->backup = 0; c->glb = 0; /* remove garbage from previous connection */ if (c->nspace) { freeModule(c->nspace); c->nspace = 0; } c->father = NULL; c->login = c->lastcmd = time(0); c->qtimeout = 0; c->stimeout = 0; c->stage = 0; c->itrace = 0; c->debugOptimizer = c->debugScheduler = 0; c->flags = MCdefault; c->timer = 0; c->memory = 0; c->errbuf = 0; prompt = !fin ? GDKgetenv("monet_prompt") : PROMPT1; c->prompt = GDKstrdup(prompt); c->promptlength = strlen(prompt); c->actions = 0; c->totaltime = 0; c->rcc = (RecPtr) GDKzalloc(sizeof(RecStat)); c->rcc->curQ = -1; c->exception_buf_initialized = 0; MT_sema_init(&c->s, 0, "MCinitClient"); return c; }
/* * Locate a file with SQL commands and execute it. For the time being a 1MB * file limit is implicitly imposed. If the file can not be located in the * script library, we assume it is sufficiently self descriptive. * (Respecting the file system context where the call is executed ) */ str SQLinclude(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { stream *fd; bstream *bfd; str *name = getArgReference_str(stk, pci, 1); str msg = MAL_SUCCEED, fullname; str *expr; mvc *m; size_t sz; fullname = MSP_locate_sqlscript(*name, 0); if (fullname == NULL) fullname = *name; fd = open_rastream(fullname); if (mnstr_errnr(fd) == MNSTR_OPEN_ERROR) { mnstr_destroy(fd); throw(MAL, "sql.include", "could not open file: %s\n", *name); } sz = getFileSize(fd); if (sz > (size_t) 1 << 29) { mnstr_destroy(fd); throw(MAL, "sql.include", "file %s too large to process", fullname); } bfd = bstream_create(fd, sz == 0 ? (size_t) (128 * BLOCK) : sz); if (bstream_next(bfd) < 0) { bstream_destroy(bfd); throw(MAL, "sql.include", "could not read %s\n", *name); } expr = &bfd->buf; msg = SQLstatementIntern(cntxt, expr, "sql.include", TRUE, FALSE, NULL); bstream_destroy(bfd); m = ((backend *) cntxt->sqlcontext)->mvc; if (m->sa) sa_destroy(m->sa); m->sa = NULL; (void) mb; return msg; }
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; }
/* * BEWARE: SQLstatementIntern only commits after all statements found * in expr are executed, when autocommit mode is enabled. * * The tricky part for this statement is to ensure that the SQL statement * is executed within the client context specified. This leads to context juggling. */ str SQLstatementIntern(Client c, str *expr, str nme, int execute, bit output, res_table **result) { int status = 0; int err = 0; mvc *o, *m; int ac, sizevars, topvars; sql_var *vars; int oldvtop, oldstop = 1; buffer *b; char *n; stream *buf; str msg = MAL_SUCCEED; backend *be, *sql = (backend *) c->sqlcontext; size_t len = strlen(*expr); #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#SQLstatement:%s\n", *expr); #endif if (!sql) { msg = SQLinitEnvironment(c, NULL, NULL, NULL); sql = (backend *) c->sqlcontext; } if (msg){ GDKfree(msg); throw(SQL, "SQLstatement", "Catalogue not available"); } initSQLreferences(); m = sql->mvc; ac = m->session->auto_commit; o = MNEW(mvc); if (!o) throw(SQL, "SQLstatement", "Out of memory"); *o = *m; /* create private allocator */ m->sa = NULL; SQLtrans(m); status = m->session->status; m->type = Q_PARSE; be = sql; sql = backend_create(m, c); sql->output_format = be->output_format; m->qc = NULL; m->caching = 0; m->user_id = m->role_id = USER_MONETDB; if (result) m->reply_size = -2; /* do not cleanup, result tables */ /* mimick a client channel on which the query text is received */ b = (buffer *) GDKmalloc(sizeof(buffer)); n = GDKmalloc(len + 1 + 1); strncpy(n, *expr, len); n[len] = '\n'; n[len + 1] = 0; len++; buffer_init(b, n, len); buf = buffer_rastream(b, "sqlstatement"); scanner_init(&m->scanner, bstream_create(buf, b->len), NULL); m->scanner.mode = LINE_N; bstream_next(m->scanner.rs); m->params = NULL; m->argc = 0; m->session->auto_commit = 0; if (!m->sa) m->sa = sa_create(); /* * System has been prepared to parse it and generate code. * Scan the complete string for SQL statements, stop at the first error. */ c->sqlcontext = sql; while (msg == MAL_SUCCEED && m->scanner.rs->pos < m->scanner.rs->len) { sql_rel *r; stmt *s; MalStkPtr oldglb = c->glb; if (!m->sa) m->sa = sa_create(); m->sym = NULL; if ((err = sqlparse(m)) || /* Only forget old errors on transaction boundaries */ (mvc_status(m) && m->type != Q_TRANS) || !m->sym) { if (!err) err = mvc_status(m); if (*m->errstr) msg = createException(PARSE, "SQLparser", "%s", m->errstr); *m->errstr = 0; sqlcleanup(m, err); execute = 0; if (!err) continue; assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } /* * 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. * We don't search the cache for a previous incarnation yet. */ MSinitClientPrg(c, "user", nme); oldvtop = c->curprg->def->vtop; oldstop = c->curprg->def->stop; r = sql_symbol2relation(m, m->sym); s = sql_relation2stmt(m, r); #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#SQLstatement:\n"); #endif scanner_query_processed(&(m->scanner)); if (s == 0 || (err = mvc_status(m))) { msg = createException(PARSE, "SQLparser", "%s", m->errstr); handle_error(m, c->fdout, status); sqlcleanup(m, err); /* restore the state */ MSresetInstructions(c->curprg->def, oldstop); freeVariables(c, c->curprg->def, c->glb, oldvtop); c->curprg->def->errors = 0; assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } /* generate MAL code */ if (backend_callinline(sql, c, s, 1) == 0) addQueryToCache(c); else err = 1; if (err ||c->curprg->def->errors) { /* restore the state */ MSresetInstructions(c->curprg->def, oldstop); freeVariables(c, c->curprg->def, c->glb, oldvtop); c->curprg->def->errors = 0; msg = createException(SQL, "SQLparser", "Errors encountered in query"); assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#result of sql.eval()\n"); printFunction(c->fdout, c->curprg->def, 0, c->listing); #endif if (execute) { MalBlkPtr mb = c->curprg->def; if (!output) sql->out = NULL; /* no output */ msg = runMAL(c, mb, 0, 0); MSresetInstructions(mb, oldstop); freeVariables(c, mb, NULL, oldvtop); } sqlcleanup(m, 0); if (!execute) { assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#parse/execute result %d\n", err); #endif assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; } if (m->results && result) { /* return all results sets */ *result = m->results; m->results = NULL; } /* * We are done; a MAL procedure resides in the cache. */ endofcompile: if (execute) MSresetInstructions(c->curprg->def, 1); c->sqlcontext = be; backend_destroy(sql); GDKfree(n); GDKfree(b); bstream_destroy(m->scanner.rs); if (m->sa) sa_destroy(m->sa); m->sa = NULL; m->sym = NULL; /* variable stack maybe resized, ie we need to keep the new stack */ status = m->session->status; sizevars = m->sizevars; topvars = m->topvars; vars = m->vars; *m = *o; _DELETE(o); m->sizevars = sizevars; m->topvars = topvars; m->vars = vars; m->session->status = status; m->session->auto_commit = ac; return msg; }
static Client MCinitClientRecord(Client c, oid user, bstream *fin, stream *fout) { const char *prompt; c->user = user; c->username = 0; c->scenario = NULL; c->oldscenario = NULL; c->srcFile = NULL; c->blkmode = 0; c->fdin = fin ? fin : bstream_create(GDKin, 0); if ( c->fdin == NULL){ MT_lock_set(&mal_contextLock); c->mode = FREECLIENT; MT_lock_unset(&mal_contextLock); showException(GDKout, MAL, "initClientRecord", MAL_MALLOC_FAIL); return NULL; } c->yycur = 0; c->bak = NULL; c->listing = 0; c->fdout = fout ? fout : GDKstdout; c->mdb = 0; c->history = 0; c->curprg = c->backup = 0; c->glb = 0; /* remove garbage from previous connection * be aware, a user can introduce several modules * that should be freed to avoid memory leaks */ c->usermodule = c->curmodule = 0; c->father = NULL; c->login = c->lastcmd = time(0); //c->active = 0; c->session = GDKusec(); c->qtimeout = 0; c->stimeout = 0; c->itrace = 0; c->flags = 0; c->errbuf = 0; prompt = !fin ? GDKgetenv("monet_prompt") : PROMPT1; c->prompt = GDKstrdup(prompt); if ( c->prompt == NULL){ if (fin == NULL) { c->fdin->s = NULL; bstream_destroy(c->fdin); MT_lock_set(&mal_contextLock); c->mode = FREECLIENT; MT_lock_unset(&mal_contextLock); } showException(GDKout, MAL, "initClientRecord", MAL_MALLOC_FAIL); return NULL; } c->promptlength = strlen(prompt); c->actions = 0; c->exception_buf_initialized = 0; c->error_row = c->error_fld = c->error_msg = c->error_input = NULL; c->wlc_kind = 0; c->wlc = NULL; #ifndef HAVE_EMBEDDED /* no authentication in embedded mode */ { str msg = AUTHgetUsername(&c->username, c); if (msg) /* shouldn't happen */ freeException(msg); } #endif c->blocksize = BLOCK; c->protocol = PROTOCOL_9; c->filetrans = false; c->query = NULL; char name[16]; snprintf(name, sizeof(name), "Client%d->s", (int) (c - mal_clients)); MT_sema_init(&c->s, 0, name); return c; }