Changeset: 633c63b5ecb7 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=633c63b5ecb7 Modified Files: sql/backends/monet5/sql_execute.c sql/backends/monet5/sql_scenario.c sql/backends/monet5/sql_upgrades.c sql/scripts/51_sys_schema_extension.sql sql/server/sql_mvc.c sql/server/sql_mvc.h sql/server/sql_parser.y sql/server/sql_qc.c sql/server/sql_qc.h sql/server/sql_scan.c Branch: default Log Message:
Introducing deallocate statements, which allow users to close a prepared statement via SQL: DEALLOC[ATE] [PREPARE] { number | ALL } diffs (truncated from 552 to 300 lines): diff --git a/sql/backends/monet5/sql_execute.c b/sql/backends/monet5/sql_execute.c --- a/sql/backends/monet5/sql_execute.c +++ b/sql/backends/monet5/sql_execute.c @@ -763,7 +763,7 @@ SQLengineIntern(Client c, backend *be) cleanup_engine: if (m->type == Q_SCHEMA && m->qc != NULL) - qc_clean(m->qc); + qc_clean(m->qc, false); if (msg) { /* don't print exception decoration, just the message */ /* diff --git a/sql/backends/monet5/sql_scenario.c b/sql/backends/monet5/sql_scenario.c --- a/sql/backends/monet5/sql_scenario.c +++ b/sql/backends/monet5/sql_scenario.c @@ -217,7 +217,7 @@ SQLepilogue(void *ret) } #define SQLglobal(name, val, failure) \ - if(!stack_push_var(sql, name, &ctype) || !stack_set_var(sql, name, VALset(&src, ctype.type->localtype, (char*)(val)))) \ + if (!stack_push_var(sql, name, &ctype) || !stack_set_var(sql, name, VALset(&src, ctype.type->localtype, (char*)(val)))) \ failure--; #define NR_GLOBAL_VARS 9 @@ -286,17 +286,17 @@ SQLprepareClient(Client c, int login) c->getquery = SQLgetquery; if (c->sqlcontext == 0) { m = mvc_create(c->idx, 0, SQLdebug, c->fdin, c->fdout); - if( m == NULL) { + if (m == NULL) { throw(SQL,"sql.initClient",SQLSTATE(HY001) MAL_MALLOC_FAIL); } - if(global_variables(m, "monetdb", "sys") < 0) { + if (global_variables(m, "monetdb", "sys") < 0) { mvc_destroy(m); throw(SQL,"sql.initClient",SQLSTATE(HY001) MAL_MALLOC_FAIL); } if (c->scenario && strcmp(c->scenario, "msql") == 0) m->reply_size = -1; be = (void *) backend_create(m, c); - if( be == NULL) { + if ( be == NULL) { mvc_destroy(m); throw(SQL,"sql.initClient", SQLSTATE(HY001) MAL_MALLOC_FAIL); } @@ -306,10 +306,10 @@ SQLprepareClient(Client c, int login) /* Only reset if there is no active transaction which * can happen when we combine sql.init with msql. */ - if(m->session->tr->active) { + if (m->session->tr->active) { return NULL; } - if(mvc_reset(m, c->fdin, c->fdout, SQLdebug, NR_GLOBAL_VARS) < 0) { + if (mvc_reset(m, c->fdin, c->fdout, SQLdebug, NR_GLOBAL_VARS) < 0) { throw(SQL,"sql.initClient", SQLSTATE(HY001) MAL_MALLOC_FAIL); } backend_reset(be); @@ -364,9 +364,9 @@ SQLresetClient(Client c) c->sqlcontext = NULL; } c->state[MAL_SCENARIO_READER] = NULL; - if(other && !msg) + if (other && !msg) msg = other; - else if(other && msg) + else if (other && msg) freeException(other); return msg; } @@ -420,7 +420,7 @@ SQLinit(Client c) stream *buf; bstream *fdin; - if( b == NULL || cbuf == NULL) { + if ( b == NULL || cbuf == NULL) { MT_lock_unset(&sql_contextLock); GDKfree(b); GDKfree(cbuf); @@ -429,21 +429,21 @@ SQLinit(Client c) buffer_init(b, cbuf, len); buf = buffer_rastream(b, "si"); - if( buf == NULL) { + if ( buf == NULL) { MT_lock_unset(&sql_contextLock); buffer_destroy(b); throw(SQL,"sql.init",SQLSTATE(HY001) MAL_MALLOC_FAIL); } fdin = bstream_create(buf, b->len); - if( fdin == NULL) { + if ( fdin == NULL) { MT_lock_unset(&sql_contextLock); buffer_destroy(b); throw(SQL,"sql.init",SQLSTATE(HY001) MAL_MALLOC_FAIL); } bstream_next(fdin); - if( MCpushClientInput(c, fdin, 0, "") < 0) + if ( MCpushClientInput(c, fdin, 0, "") < 0) fprintf(stderr, "SQLinit:Could not switch client input stream"); } if ((msg = SQLprepareClient(c, 0)) != NULL) { @@ -614,7 +614,7 @@ SQLinit(Client c) throw(SQL, "SQLinit", SQLSTATE(42000) "Starting idle manager failed"); } } - if( wlc_state == WLC_STARTUP) + if ( wlc_state == WLC_STARTUP) return WLCinit(); return MAL_SUCCEED; } @@ -629,14 +629,14 @@ handle_error(mvc *m, int pstatus, str ms /* transaction already broken */ if (m->type != Q_TRANS && pstatus < 0) { new = createException(SQL,"sql.execute",TRANS_ABORTED); - } else if( GDKerrbuf && GDKerrbuf[0]){ + } else if ( GDKerrbuf && GDKerrbuf[0]){ new = GDKstrdup(GDKerrbuf); GDKerrbuf[0] = 0; - } else if( *m->errstr){ + } else if ( *m->errstr){ new = GDKstrdup(m->errstr); m->errstr[0] = 0; } - if( new && msg){ + if ( new && msg){ newmsg = GDKzalloc( strlen(msg) + strlen(new) + 64); if (newmsg == NULL) { newmsg = createException(SQL, "sql.execute", SQLSTATE(HY001) MAL_MALLOC_FAIL); @@ -648,10 +648,10 @@ handle_error(mvc *m, int pstatus, str ms freeException(new); freeException(msg); } else - if( msg) + if ( msg) newmsg = msg; else - if( new) + if ( new) newmsg = new; return newmsg; } @@ -793,7 +793,7 @@ SQLcompile(Client cntxt, MalBlkPtr mb, M *ret = NULL; if ((msg = SQLstatementIntern(cntxt, expr, "SQLcompile", FALSE, FALSE, NULL)) != MAL_SUCCEED) return msg; - if((*ret = _STRDUP("SQLcompile")) == NULL) + if ((*ret = _STRDUP("SQLcompile")) == NULL) throw(SQL,"sql.compile",SQLSTATE(HY001) MAL_MALLOC_FAIL); return MAL_SUCCEED; } @@ -828,7 +828,7 @@ SQLinclude(Client cntxt, MalBlkPtr mb, M close_stream(fd); throw(MAL, "sql.include", SQLSTATE(42000) "file %s too large to process", fullname); } - if((bfd = bstream_create(fd, sz == 0 ? (size_t) (128 * BLOCK) : sz)) == NULL) { + if ((bfd = bstream_create(fd, sz == 0 ? (size_t) (128 * BLOCK) : sz)) == NULL) { close_stream(fd); throw(MAL, "sql.include", SQLSTATE(HY001) MAL_MALLOC_FAIL); } @@ -1031,7 +1031,7 @@ cachable(mvc *m, sql_rel *r) if (m->type == Q_TRANS ) /* m->type == Q_SCHEMA || cachable to make sure we have trace on alter statements */ return 0; /* we don't store queries with a large footprint */ - if(r && sa_size(m->sa) > MAX_QUERY) + if (r && sa_size(m->sa) > MAX_QUERY) return 0; return 1; } @@ -1052,7 +1052,7 @@ SQLparser(Client c) mvc *m; int oldvtop, oldstop; int pstatus = 0; - int err = 0, opt = 0; + int err = 0, opt = 0, preparedid = -1; char *q = NULL; be = (backend *) c->sqlcontext; @@ -1210,34 +1210,49 @@ SQLparser(Client c) if (q == NULL) { err = 1; msg = createException(PARSE, "SQLparser", SQLSTATE(HY001) MAL_MALLOC_FAIL); - } else 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; - msg = createException(SQL, "EXEC", SQLSTATE(07003) "No prepared statement with id: %d\n", m->sym->data.lval->h->data.i_val); - *m->errstr = 0; - msg = handle_error(m, pstatus, msg); - sqlcleanup(m, err); - goto finalize; - } else if (!be->q->prepared) { - err = -1; - msg = createException(SQL, "EXEC", SQLSTATE(07005) "Given handle id is not for a " "prepared statement: %d\n", m->sym->data.lval->h->data.i_val); - *m->errstr = 0; - msg = handle_error(m, pstatus, msg); - sqlcleanup(m, err); - goto finalize; + } else if (m->emode == m_execute || m->emode == m_deallocate) { + if (m->emode == m_execute) { + assert(m->sym->data.lval->h->type == type_int); + preparedid = m->sym->data.lval->h->data.i_val; + + assert(preparedid >= 0); + be->q = qc_find(m->qc, preparedid); + } else { /* m_deallocate case */ + AtomNode *an = (AtomNode *) m->sym; + assert(m->sym->type == type_symbol && an->a->data.vtype == TYPE_int); + preparedid = an->a->data.val.ival; + + if (preparedid > -1) /* The -1 case represents the deallocate the entire query cache */ + be->q = qc_find(m->qc, preparedid); } - m->type = be->q->type; + + if (preparedid > -1) { + const char *mode = (m->emode == m_execute) ? "EXEC" : "DEALLOC"; + if (!be->q) { + err = -1; + msg = createException(SQL, mode, SQLSTATE(07003) "No prepared statement with id: %d\n", preparedid); + *m->errstr = 0; + msg = handle_error(m, pstatus, msg); + sqlcleanup(m, err); + goto finalize; + } else if (!be->q->prepared) { + err = -1; + msg = createException(SQL, mode, SQLSTATE(07005) "Given handle id is not for a prepared statement: %d\n", preparedid); + *m->errstr = 0; + msg = handle_error(m, pstatus, msg); + sqlcleanup(m, err); + goto finalize; + } + } + + m->type = (m->emode == m_execute) ? be->q->type : Q_SCHEMA; /* TODO DEALLOCATE statements don't fit for Q_SCHEMA */ scanner_query_processed(&(m->scanner)); } else if (caching(m) && cachable(m, NULL) && m->emode != m_prepare && (be->q = qc_match(m->qc, m, m->sym, m->args, m->argc, m->scanner.key ^ m->session->schema->base.id)) != NULL) { /* query template was found in the query cache */ scanner_query_processed(&(m->scanner)); m->no_mitosis = be->q->no_mitosis; } else { - sql_rel *r; - - r = sql_symbol2relation(m, m->sym); + sql_rel *r = sql_symbol2relation(m, m->sym); if (!r || (err = mvc_status(m) && m->type != Q_TRANS && *m->errstr)) { if (strlen(m->errstr) > 6 && m->errstr[5] == '!') @@ -1268,7 +1283,7 @@ SQLparser(Client c) be->q = NULL; (void) snprintf(qname, IDLENGTH, "%c%d_%d", (m->emode == m_prepare?'p':'s'), m->qc->id++, m->qc->clientid); escaped_q = sql_escape_str(q); - if(!escaped_q) { + if (!escaped_q) { err = 1; msg = createException(PARSE, "SQLparser", SQLSTATE(HY001) MAL_MALLOC_FAIL); } else { @@ -1283,7 +1298,7 @@ SQLparser(Client c) m->no_mitosis, m->emode == m_prepare); } - if(!be->q) { + if (!be->q) { err = 1; msg = createException(PARSE, "SQLparser", SQLSTATE(HY001) MAL_MALLOC_FAIL); } @@ -1298,7 +1313,7 @@ SQLparser(Client c) m->sym = NULL; /* register name in the namespace */ be->q->name = putName(be->q->name); - if(!be->q->name) { + if (!be->q->name) { err = 1; msg = createException(PARSE, "SQLparser", SQLSTATE(HY001) MAL_MALLOC_FAIL); } @@ -1308,12 +1323,21 @@ SQLparser(Client c) m->session->status = -10; if (err == 0) { /* no parsing error encountered, finalize the code of the query wrapper */ - if (be->q) { - if (m->emode == m_prepare){ + if (m->emode == m_deallocate) { + assert(be->q || preparedid == -1); + if (be->q) { + qc_delete(m->qc, be->q); + } else { + qc_clean(m->qc, true); + } + /* For deallocate statements just export a simple output */ + err = mvc_export_operation(be, c->fdout, "", c->curprg->def->starttime, c->curprg->def->optimize); + } else if (be->q) { + if (m->emode == m_prepare) { /* For prepared queries, return a table with result set structure*/ /* optimize the code block and rename it */ err = mvc_export_prepare(m, c->fdout, be->q, ""); - } else if( m->emode == m_execute || m->emode == m_normal || m->emode == m_plan){ + } else if (m->emode == m_execute || m->emode == m_normal || m->emode == m_plan) { _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list