static void sa_reverse_test(void) { printsln((String)__func__); Array ac, ex; ac = sa_of_string("1, 2, 3"); ex = sa_of_string("3, 2, 1"); a_reverse(ac); sa_check_expect(ac, ex); sa_free(ac); sa_free(ex); ac = sa_of_string("1, 2, 3, 4"); ex = sa_of_string("4, 3, 2, 1"); a_reverse(ac); sa_check_expect(ac, ex); sa_free(ac); sa_free(ex); ac = sa_create(0, ""); ex = sa_create(0, ""); a_reverse(ac); sa_check_expect(ac, ex); a_free(ac); a_free(ex); ac = sa_create(0, "x"); ex = sa_create(0, "x"); a_reverse(ac); sa_check_expect(ac, ex); a_free(ac); a_free(ex); }
static void a_concat_test(void) { printsln((String)__func__); Array a1, a2, ac, ex; a1 = sa_of_string("10, 20, 30"); a2 = sa_of_string("1, 2, 3"); ac = a_concat(a1, a2); ex = sa_of_string("10, 20, 30, 1, 2, 3"); sa_check_expect(ac, ex); sa_free(a1); sa_free(a2); a_free(ac); sa_free(ex); a1 = sa_of_string("10, 20, 30"); a2 = sa_create(0, ""); ac = a_concat(a1, a2); ex = sa_of_string("10, 20, 30"); sa_check_expect(ac, ex); sa_free(a1); a_free(a2); a_free(ac); sa_free(ex); a1 = sa_create(0, ""); a2 = sa_of_string("10, 20, 30"); ac = a_concat(a1, a2); ex = sa_of_string("10, 20, 30"); sa_check_expect(ac, ex); a_free(a1); sa_free(a2); a_free(ac); sa_free(ex); a1 = sa_create(0, ""); a2 = sa_create(0, ""); ac = a_concat(a1, a2); ex = sa_create(0, ""); sa_check_expect(ac, ex); a_free(a1); a_free(a2); a_free(ac); a_free(ex); }
static void sa_of_string_test(void) { printsln((String)__func__); Array ac, ex; ac = sa_of_string("1, 2, 3"); ex = sa_create(3, ""); sa_set(ex, 0, "1"); sa_set(ex, 1, "2"); sa_set(ex, 2, "3"); sa_check_expect(ac, ex); sa_free(ac); ac = sa_of_string("1 , 2, 3 "); sa_set(ex, 0, "1 "); sa_set(ex, 1, "2"); sa_set(ex, 2, "3 "); sa_check_expect(ac, ex); sa_free(ac); a_free(ex); ac = sa_of_string("1 , 2"); ex = sa_create(2, ""); sa_set(ex, 0, "1 "); sa_set(ex, 1, "2"); sa_check_expect(ac, ex); sa_free(ac); a_free(ex); ac = sa_of_string(""); ex = sa_create(1, ""); sa_check_expect(ac, ex); sa_free(ac); a_free(ex); ac = sa_of_string("123"); ex = sa_create(1, "123"); sa_check_expect(ac, ex); sa_free(ac); a_free(ex); }
static void sa_create_test(void) { printsln((String)__func__); Array array; array = sa_create(3, ""); String a1[] = { "", "", "" }; sa_check_expect_file_line(__FILE__, __func__, __LINE__, array, a1, 3); a_free(array); array = sa_create(5, "x"); String a2[] = { "x", "x", "x", "x", "x" }; sa_check_expect_file_line(__FILE__, __func__, __LINE__, array, a2, 5); a_free(array); array = sa_create(1, "y"); String a3[] = { "y" }; sa_check_expect_file_line(__FILE__, __func__, __LINE__, array, a3, 1); a_free(array); array = sa_create(0, "z"); String a4[] = { }; sa_check_expect_file_line(__FILE__, __func__, __LINE__, array, a4, 0); a_free(array); }
static void a_sub_test(void) { printsln((String)__func__); Array array, array2, sub; array = sa_of_string("1, 2, 3, 4"); sub = a_sub(array, 0, a_length(array)); sa_check_expect(array, sub); a_free(sub); sub = a_sub(array, -1, a_length(array) + 1); sa_check_expect(array, sub); a_free(sub); array2 = sa_of_string("2, 3, 4"); // sa_println(array2); // printiln(a_length(array2)); sub = a_sub(array, 1, a_length(array)); sa_check_expect(array2, sub); sa_free(array2); a_free(sub); array2 = sa_of_string("2, 3"); sub = a_sub(array, 1, a_length(array) - 1); sa_check_expect(array2, sub); sa_free(array2); a_free(sub); array2 = sa_create(0, ""); sub = a_sub(array, 1, 1); sa_check_expect(array2, sub); a_free(sub); sub = a_sub(array, 2, 1); sa_check_expect(array2, sub); sa_free(array2); a_free(sub); sa_free(array); }
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; }
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; }
void mvc_reset(mvc *m, bstream *rs, stream *ws, int debug, int globalvars) { int i; sql_trans *tr; if (mvc_debug) fprintf(stderr, "#mvc_reset\n"); tr = m->session->tr; if (tr && tr->parent) { assert(m->session->active == 0); store_lock(); while (tr->parent->parent != NULL) tr = sql_trans_destroy(tr); store_unlock(); } if (tr) sql_session_reset(m->session, 1 /*autocommit on*/); if (m->sa) m->sa = sa_reset(m->sa); else m->sa = sa_create(); m->errstr[0] = '\0'; m->params = NULL; /* reset topvars to the set of global variables */ stack_pop_until(m, globalvars); m->frame = 1; m->argc = 0; m->sym = NULL; m->rowcnt = m->last_id = m->role_id = m->user_id = -1; m->emode = m_normal; m->emod = mod_none; if (m->reply_size != 100) stack_set_number(m, "reply_size", 100); m->reply_size = 100; if (m->timezone != 0) stack_set_number(m, "current_timezone", 0); m->timezone = 0; if (m->debug != debug) stack_set_number(m, "debug", debug); m->debug = debug; if (m->cache != DEFAULT_CACHESIZE) stack_set_number(m, "cache", DEFAULT_CACHESIZE); m->cache = DEFAULT_CACHESIZE; m->caching = m->cache; if (m->history != 0) stack_set_number(m, "history", 0); m->history = 0; m->label = 0; m->cascade_action = NULL; m->type = Q_PARSE; m->pushdown = 1; for(i=0;i<MAXSTATS;i++) m->opt_stats[i] = 0; m->result_id = 0; m->results = NULL; scanner_init(&m->scanner, rs, ws); }
int mvc_init(int debug, store_type store, int ro, int su, backend_stack stk) { int first = 0; logger_settings *log_settings = (struct logger_settings *) GDKmalloc(sizeof(struct logger_settings)); /* Set the default WAL directory. "sql_logs" by default */ log_settings->logdir = "sql_logs"; /* Get and pass on the WAL directory location, if set */ if (GDKgetenv("gdk_logdir") != NULL) { log_settings->logdir = GDKgetenv("gdk_logdir"); } /* Get and pass on the shared WAL directory location, if set */ log_settings->shared_logdir = GDKgetenv("gdk_shared_logdir"); /* Get and pass on the shared WAL drift threshold, if set. * -1 by default, meaning it should be ignored, since it is not set */ log_settings->shared_drift_threshold = GDKgetenv_int("gdk_shared_drift_threshold", -1); /* Get and pass on the flag how many WAL files should be preserved. * 0 by default - keeps only the current WAL file. */ log_settings->keep_persisted_log_files = GDKgetenv_int("gdk_keep_persisted_log_files", 0); mvc_debug = debug&4; if (mvc_debug) { fprintf(stderr, "#mvc_init logdir %s\n", log_settings->logdir); fprintf(stderr, "#mvc_init keep_persisted_log_files %d\n", log_settings->keep_persisted_log_files); if (log_settings->shared_logdir != NULL) { fprintf(stderr, "#mvc_init shared_logdir %s\n", log_settings->shared_logdir); } fprintf(stderr, "#mvc_init shared_drift_threshold %d\n", log_settings->shared_drift_threshold); } keyword_init(); scanner_init_keywords(); if ((first = store_init(debug, store, ro, su, log_settings, stk)) < 0) { fprintf(stderr, "!mvc_init: unable to create system tables\n"); return -1; } if (first || catalog_version) { sql_schema *s; sql_table *t; mvc *m = mvc_create(0, stk, 0, NULL, NULL); m->sa = sa_create(); /* disable caching */ m->caching = 0; /* disable history */ m->history = 0; /* disable size header */ m->sizeheader = 0; mvc_trans(m); s = m->session->schema = mvc_bind_schema(m, "sys"); assert(m->session->schema != NULL); if (!first) { t = mvc_bind_table(m, s, "tables"); mvc_drop_table(m, s, t, 0); t = mvc_bind_table(m, s, "columns"); mvc_drop_table(m, s, t, 0); } t = mvc_create_view(m, s, "tables", SQL_PERSIST, "SELECT \"id\", \"name\", \"schema_id\", \"query\", CAST(CASE WHEN \"system\" THEN \"type\" + 10 /* system table/view */ ELSE (CASE WHEN \"commit_action\" = 0 THEN \"type\" /* table/view */ ELSE \"type\" + 20 /* global temp table */ END) END AS SMALLINT) AS \"type\", \"system\", \"commit_action\", \"access\", CASE WHEN (NOT \"system\" AND \"commit_action\" > 0) THEN 1 ELSE 0 END AS \"temporary\" FROM \"sys\".\"_tables\" WHERE \"type\" <> 2 UNION ALL SELECT \"id\", \"name\", \"schema_id\", \"query\", CAST(\"type\" + 30 /* local temp table */ AS SMALLINT) AS \"type\", \"system\", \"commit_action\", \"access\", 1 AS \"temporary\" FROM \"tmp\".\"_tables\";", 1); mvc_create_column_(m, t, "id", "int", 32); mvc_create_column_(m, t, "name", "varchar", 1024); mvc_create_column_(m, t, "schema_id", "int", 32); mvc_create_column_(m, t, "query", "varchar", 2048); mvc_create_column_(m, t, "type", "smallint", 16); mvc_create_column_(m, t, "system", "boolean", 1); mvc_create_column_(m, t, "commit_action", "smallint", 16); mvc_create_column_(m, t, "access", "smallint", 16); mvc_create_column_(m, t, "temporary", "smallint", 16); if (!first) { int pub = ROLE_PUBLIC; int p = PRIV_SELECT; int zero = 0; sql_table *privs = find_sql_table(s, "privileges"); table_funcs.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero); } t = mvc_create_view(m, s, "columns", SQL_PERSIST, "SELECT * FROM (SELECT p.* FROM \"sys\".\"_columns\" AS p UNION ALL SELECT t.* FROM \"tmp\".\"_columns\" AS t) AS columns;", 1); mvc_create_column_(m, t, "id", "int", 32); mvc_create_column_(m, t, "name", "varchar", 1024); mvc_create_column_(m, t, "type", "varchar", 1024); mvc_create_column_(m, t, "type_digits", "int", 32); mvc_create_column_(m, t, "type_scale", "int", 32); mvc_create_column_(m, t, "table_id", "int", 32); mvc_create_column_(m, t, "default", "varchar", 2048); mvc_create_column_(m, t, "null", "boolean", 1); mvc_create_column_(m, t, "number", "int", 32); mvc_create_column_(m, t, "storage", "varchar", 2048); if (!first) { int pub = ROLE_PUBLIC; int p = PRIV_SELECT; int zero = 0; sql_table *privs = find_sql_table(s, "privileges"); table_funcs.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero); } else { sql_create_env(m, s); sql_create_privileges(m, s); } s = m->session->schema = mvc_bind_schema(m, "tmp"); assert(m->session->schema != NULL); if (mvc_commit(m, 0, NULL) < 0) { fprintf(stderr, "!mvc_init: unable to commit system tables\n"); return -1; } mvc_destroy(m); } return first; }
/* * 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; }