seqbulk *seqbulk_create(sql_sequence *seq, BUN cnt) { seqbulk *sb = MNEW(seqbulk); store_sequence *s; node *n = NULL; if (!sb) return NULL; store_lock(); sb->seq = seq; sb->cnt = cnt; sb->save = 0; for ( n = sql_seqs->h; n; n = n ->next ) { s = n->data; if (s->seqid == seq->base.id) break; } if (!n) { s = sql_create_sequence(seq); if (!s) { _DELETE(sb); store_unlock(); return NULL; } list_append(sql_seqs, s); } else { s = n->data; } sb->internal_seq = s; return sb; }
mvc * mvc_create(int clientid, backend_stack stk, int debug, bstream *rs, stream *ws) { int i; mvc *m; m = ZNEW(mvc); if (mvc_debug) fprintf(stderr, "#mvc_create\n"); m->errstr[0] = '\0'; /* if an error exceeds the buffer we don't want garbage at the end */ m->errstr[ERRSIZE-1] = '\0'; m->qc = qc_create(clientid, 0); m->sa = NULL; m->params = NULL; m->sizevars = MAXPARAMS; m->vars = NEW_ARRAY(sql_var, m->sizevars); m->topvars = 0; m->frame = 1; m->use_views = 0; m->argmax = MAXPARAMS; m->args = NEW_ARRAY(atom*,m->argmax); m->argc = 0; m->sym = NULL; m->rowcnt = m->last_id = m->role_id = m->user_id = -1; m->timezone = 0; m->clientid = clientid; m->emode = m_normal; m->emod = mod_none; m->reply_size = 100; m->debug = debug; m->cache = DEFAULT_CACHESIZE; m->caching = m->cache; m->history = 0; m->label = 0; m->cascade_action = NULL; for(i=0;i<MAXSTATS;i++) m->opt_stats[i] = 0; store_lock(); m->session = sql_session_create(stk, 1 /*autocommit on*/); store_unlock(); m->type = Q_PARSE; m->pushdown = 1; m->result_id = 0; m->results = NULL; scanner_init(&m->scanner, rs, ws); return m; }
int mvc_rollback(mvc *m, int chain, const char *name) { int res = 0; sql_trans *tr = m->session->tr; if (mvc_debug) fprintf(stderr, "#mvc_rollback %s\n", (name) ? name : ""); assert(tr); assert(m->session->active); /* only abort an active transaction */ store_lock(); if (m->qc) qc_clean(m->qc); if (name && name[0] != '\0') { while (tr && (!tr->name || strcmp(tr->name, name) != 0)) tr = tr->parent; if (!tr) { (void)sql_error(m, 010, "ROLLBACK: no such savepoint: '%s'", name); m->session->status = -1; store_unlock(); return -1; } tr = m->session->tr; while (!tr->name || strcmp(tr->name, name) != 0) { /* make sure we do not reuse changed data */ if (tr->wtime) tr->status = 1; tr = sql_trans_destroy(tr); } m->session->tr = tr; /* restart at savepoint */ m->session->status = tr->status; if (tr->name) tr->name = NULL; m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name); } else if (tr->parent) { /* first release all intermediate savepoints */ while (tr->parent->parent != NULL) { tr = sql_trans_destroy(tr); } m->session-> tr = tr; /* make sure we do not reuse changed data */ if (tr->wtime) tr->status = 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_rollback %s done\n", (name) ? name : ""); return res; }
int seq_next_value(sql_sequence *seq, lng *val) { lng nr = 0; node *n = NULL; store_sequence *s; int save = 0; *val = 0; store_lock(); for ( n = sql_seqs->h; n; n = n ->next ) { s = n->data; if (s->seqid == seq->base.id) break; } if (!n) { s = sql_create_sequence(seq); if (!s) { store_unlock(); return 0; } list_append(sql_seqs, s); } else { s = n->data; if (s->called) s->cur += seq->increment; } /* handle min/max and cycle */ if ((seq->maxvalue && s->cur > seq->maxvalue) || (seq->minvalue && s->cur < seq->minvalue)) { if (seq->cycle) { /* cycle to the min value again */ s->cur = seq->minvalue; save = 1; } else { /* we're out of numbers */ store_unlock(); return 0; } } s->called = 1; nr = s->cur; *val = nr; if (save || nr == s->cached) { s->cached = nr + seq->cacheinc*seq->increment; sql_update_sequence_cache(seq, s->cached); store_unlock(); return 1; } assert(nr<s->cached); store_unlock(); return 1; }
void mvc_trans(mvc *m) { int schema_changed = 0, err = m->session->status; assert(!m->session->active); /* can only start a new transaction */ store_lock(); schema_changed = sql_trans_begin(m->session); if (m->qc && (schema_changed || m->qc->nr > m->cache || err)){ if (schema_changed || err) { int seqnr = m->qc->id; if (m->qc) qc_destroy(m->qc); m->qc = qc_create(m->clientid, seqnr); } else { /* clean all but the prepared statements */ qc_clean(m->qc); } } store_unlock(); }
int seq_get_value(sql_sequence *seq, lng *val) { node *n = NULL; store_sequence *s; *val = 0; store_lock(); for ( n = sql_seqs->h; n; n = n ->next ) { s = n->data; if (s->seqid == seq->base.id) break; } if (!n) { s = sql_create_sequence(seq); if (!s) { store_unlock(); return 0; } list_append(sql_seqs, s); } else { s = n->data; } *val = s->cur; if (s->called) *val += seq->increment; /* handle min/max and cycle */ if ((seq->maxvalue && *val > seq->maxvalue) || (seq->minvalue && *val < seq->minvalue)) { if (seq->cycle) { /* cycle to the min value again */ *val = seq->minvalue; } else { /* we're out of numbers */ store_unlock(); return 0; } } store_unlock(); return 1; }
/* 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; }
void mvc_destroy(mvc *m) { sql_trans *tr; if (mvc_debug) fprintf(stderr, "#mvc_destroy\n"); tr = m->session->tr; if (tr) { store_lock(); if (m->session->active) sql_trans_end(m->session); while (tr->parent) tr = sql_trans_destroy(tr); m->session->tr = NULL; store_unlock(); } sql_session_destroy(m->session); stack_pop_until(m, 0); _DELETE(m->vars); if (m->scanner.log) /* close and destroy stream */ close_stream(m->scanner.log); if (m->sa) sa_destroy(m->sa); m->sa = NULL; if (m->qc) qc_destroy(m->qc); m->qc = NULL; _DELETE(m->args); m->args = NULL; _DELETE(m); }
/* release all savepoints up including the given named savepoint * but keep the current changes. * */ int mvc_release(mvc *m, char *name) { int ok = SQL_OK; int res = Q_TRANS; sql_trans *tr = m->session->tr; sql_trans *cur = tr; assert(tr); assert(m->session->active); /* only release active transactions */ if (mvc_debug) fprintf(stderr, "#mvc_release %s\n", (name) ? 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; tr = tr->parent; store_lock(); while (ok == SQL_OK && (!tr->name || strcmp(tr->name, name) != 0)) { tr = sql_trans_destroy(tr); } if (tr->name && strcmp(tr->name, name) == 0) { tr = sql_trans_destroy(tr); } store_unlock(); cur -> parent = tr; m->type = res; return res; }
int seq_restart(sql_sequence *seq, lng start) { node *n = NULL; store_sequence *s; store_lock(); for ( n = sql_seqs->h; n; n = n ->next ) { s = n->data; if (s->seqid == seq->base.id) break; } if (!n) { s = sql_create_sequence(seq); if (!s) { store_unlock(); return 0; } list_append(sql_seqs, s); } else { s = n->data; } s->called = 0; s->cur = start; s->cached = start; /* handle min/max and cycle */ if ((seq->maxvalue && s->cur > seq->maxvalue) || (seq->minvalue && s->cur < seq->minvalue)) { /* we're out of numbers */ store_unlock(); return 0; } sql_update_sequence_cache(seq, s->cached); store_unlock(); return 1; }
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_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; }