int SQLautocommit(Client c, mvc *m) { if (m->session->auto_commit && m->session->active) { if (mvc_status(m) < 0) { RECYCLEdrop(0); mvc_rollback(m, 0, NULL); } else if (mvc_commit(m, 0, NULL) < 0) { return handle_error(m, c->fdout, 0); } } return TRUE; }
/* release all savepoints up including the given named savepoint * but keep the current changes. * */ int mvc_release(mvc *m, const char *name) { int ok = SQL_OK; int res = Q_TRANS; sql_trans *tr = m->session->tr; assert(tr); assert(m->session->active); /* only release active transactions */ if (mvc_debug) fprintf(stderr, "#mvc_release %s\n", (name) ? name : ""); if (!name) mvc_rollback(m, 0, name); while (tr && (!tr->name || strcmp(tr->name, name) != 0)) tr = tr->parent; if (!tr || !tr->name || strcmp(tr->name, name) != 0) { (void)sql_error(m, 010, "release savepoint %s doesn't exists", name); m->session->status = -1; return -1; } tr = m->session->tr; store_lock(); while (ok == SQL_OK && (!tr->name || strcmp(tr->name, name) != 0)) { /* commit all intermediate savepoints */ if (sql_trans_commit(tr) != SQL_OK) GDKfatal("release savepoints should not fail"); tr = sql_trans_destroy(tr); } tr->name = NULL; store_unlock(); m->session->tr = tr; m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name); m->type = res; return res; }
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; }
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; }
int mvc_commit(mvc *m, int chain, const char *name) { sql_trans *cur, *tr = m->session->tr; int ok = SQL_OK;//, wait = 0; assert(tr); assert(m->session->active); /* only commit an active transaction */ if (mvc_debug) fprintf(stderr, "#mvc_commit %s\n", (name) ? name : ""); if (m->session->status < 0) { (void)sql_error(m, 010, "40000!COMMIT: transaction is aborted, will ROLLBACK instead"); mvc_rollback(m, chain, name); return -1; } /* savepoint then simply make a copy of the current transaction */ if (name && name[0] != '\0') { sql_trans *tr = m->session->tr; if (mvc_debug) fprintf(stderr, "#mvc_savepoint\n"); store_lock(); m->session->tr = sql_trans_create(m->session->stk, tr, name); store_unlock(); m->type = Q_TRANS; if (m->qc) /* clean query cache, protect against concurrent access on the hash tables (when functions already exists, concurrent mal will build up the hash (not copied in the trans dup)) */ qc_clean(m->qc); m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name); if (mvc_debug) fprintf(stderr, "#mvc_commit %s done\n", name); return 0; } /* first release all intermediate savepoints */ cur = tr; tr = tr->parent; if (tr->parent) { store_lock(); while (tr->parent != NULL && ok == SQL_OK) { tr = sql_trans_destroy(tr); } store_unlock(); } cur -> parent = tr; tr = cur; store_lock(); /* if there is nothing to commit reuse the current transaction */ if (tr->wtime == 0) { if (!chain) sql_trans_end(m->session); m->type = Q_TRANS; if (mvc_debug) fprintf(stderr, "#mvc_commit %s done\n", (name) ? name : ""); store_unlock(); return 0; } /* while (tr->schema_updates && store_nr_active > 1) { store_unlock(); MT_sleep_ms(100); wait += 100; if (wait > 1000) { (void)sql_error(m, 010, "40000!COMMIT: transaction is aborted because of DDL concurrency conflicts, will ROLLBACK instead"); mvc_rollback(m, chain, name); return -1; } store_lock(); } * */ /* validation phase */ if (sql_trans_validate(tr)) { if ((ok = sql_trans_commit(tr)) != SQL_OK) { char *msg = sql_message("40000!COMMIT: transaction commit failed (perhaps your disk is full?) exiting (kernel error: %s)", GDKerrbuf); GDKfatal("%s", msg); _DELETE(msg); } } else { store_unlock(); (void)sql_error(m, 010, "40000!COMMIT: transaction is aborted because of concurrency conflicts, will ROLLBACK instead"); mvc_rollback(m, chain, name); return -1; } sql_trans_end(m->session); if (chain) sql_trans_begin(m->session); store_unlock(); m->type = Q_TRANS; if (mvc_debug) fprintf(stderr, "#mvc_commit %s done\n", (name) ? name : ""); return ok; }
str monet5_user_set_def_schema(mvc *m, oid user) { oid rid; sqlid schema_id; sql_schema *sys = NULL; sql_table *user_info = NULL; sql_column *users_name = NULL; sql_column *users_schema = NULL; sql_table *schemas = NULL; sql_column *schemas_name = NULL; sql_column *schemas_id = NULL; sql_table *auths = NULL; sql_column *auths_name = NULL; void *p = 0; str schema = NULL; str username = NULL; if (m->debug &1) fprintf(stderr, "monet5_user_set_def_schema " OIDFMT "\n", user); mvc_trans(m); sys = find_sql_schema(m->session->tr, "sys"); user_info = find_sql_table(sys, "db_user_info"); users_name = find_sql_column(user_info, "name"); users_schema = find_sql_column(user_info, "default_schema"); rid = table_funcs.column_find_row(m->session->tr, users_name, username, NULL); if (!is_oid_nil(rid)) p = table_funcs.column_find_value(m->session->tr, users_schema, rid); assert(p); schema_id = *(sqlid *) p; _DELETE(p); schemas = find_sql_table(sys, "schemas"); schemas_name = find_sql_column(schemas, "name"); schemas_id = find_sql_column(schemas, "id"); auths = find_sql_table(sys, "auths"); auths_name = find_sql_column(auths, "name"); rid = table_funcs.column_find_row(m->session->tr, schemas_id, &schema_id, NULL); if (!is_oid_nil(rid)) schema = table_funcs.column_find_value(m->session->tr, schemas_name, rid); /* only set schema if user is found */ rid = table_funcs.column_find_row(m->session->tr, auths_name, username, NULL); if (!is_oid_nil(rid)) { sql_column *auths_id = find_sql_column(auths, "id"); int id; p = table_funcs.column_find_value(m->session->tr, auths_id, rid); id = *(int *) p; _DELETE(p); m->user_id = m->role_id = id; } else { schema = NULL; } if (!schema || !mvc_set_schema(m, schema)) { if (m->session->active) mvc_rollback(m, 0, NULL); return NULL; } /* reset the user and schema names */ if(!stack_set_string(m, "current_schema", schema) || !stack_set_string(m, "current_user", username) || !stack_set_string(m, "current_role", username)) { schema = NULL; } GDKfree(username); mvc_rollback(m, 0, NULL); return schema; }