Changeset: fb5890189fc7 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=fb5890189fc7 Modified Files: sql/backends/monet5/sql.c sql/backends/monet5/sql.h sql/backends/monet5/sql.mal sql/backends/monet5/sql_gencode.c sql/backends/monet5/sql_scenario.c sql/backends/monet5/sql_session.mal sql/backends/monet5/sql_upgrades.c sql/scripts/22_clients.sql sql/server/sql_qc.c sql/server/sql_qc.h Branch: default Log Message:
Added table returning function and view "prepared_statements", which depicts the available session's prepared statements. Some minor notes: - Added "created" field to the query cache struct with the timestamp of the query's creation. - The "codestring" field is no longer escaped, so the prepared statement query can be viewed as raw at the "prepared_statements" view. - Later we can the possibility for the monetdb user to view all the server's prepared statements. However this requires to add authentication to the query cache and a global lock I think. diffs (truncated from 371 to 300 lines): diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c --- a/sql/backends/monet5/sql.c +++ b/sql/backends/monet5/sql.c @@ -5277,3 +5277,85 @@ SQLhot_snapshot(void *ret, const str *ta else throw(SQL, "sql.hot_snapshot", GDK_EXCEPTION); } + +str +SQLsession_prepared_statements(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) +{ + BAT *sessionid, *user, *statementid, *statement, *created; + bat *sid = getArgReference_bat(stk,pci,0); + bat *u = getArgReference_bat(stk,pci,1); + bat *i = getArgReference_bat(stk,pci,2); + bat *s = getArgReference_bat(stk,pci,3); + bat *c = getArgReference_bat(stk,pci,4); + str msg = MAL_SUCCEED, usr; + mvc *sql = NULL; + cq *q = NULL; + + (void) stk; + (void) pci; + if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL) + return msg; + if ((msg = checkSQLContext(cntxt)) != NULL) + return msg; + + assert(sql->qc); + + sessionid = COLnew(0, TYPE_int, 256, TRANSIENT); + user = COLnew(0, TYPE_str, 256, TRANSIENT); + statementid = COLnew(0, TYPE_int, 256, TRANSIENT); + statement = COLnew(0, TYPE_str, 256, TRANSIENT); + created = COLnew(0, TYPE_timestamp, 256, TRANSIENT); + if (sessionid == NULL || user == NULL || statementid == NULL || statement == NULL || created == NULL) { + msg = createException(SQL, "sql.session_prepared_statements", SQLSTATE(HY001) MAL_MALLOC_FAIL); + goto bailout; + } + + for (q = sql->qc->q; q; q = q->next) { + if (q->prepared) { + gdk_return bun_res; + if (BUNappend(sessionid, &(cntxt->idx), false) != GDK_SUCCEED) { + msg = createException(SQL, "sql.session_prepared_statements", SQLSTATE(HY001) MAL_MALLOC_FAIL); + goto bailout; + } + + msg = AUTHgetUsername(&usr, cntxt); + if (msg != MAL_SUCCEED) + goto bailout; + bun_res = BUNappend(user, usr, false); + GDKfree(usr); + if (bun_res != GDK_SUCCEED) { + msg = createException(SQL, "sql.session_prepared_statements", SQLSTATE(HY001) MAL_MALLOC_FAIL); + goto bailout; + } + + if (BUNappend(statementid, &(q->id), false) != GDK_SUCCEED) { + msg = createException(SQL, "sql.session_prepared_statements", SQLSTATE(HY001) MAL_MALLOC_FAIL); + goto bailout; + } + if (BUNappend(statement, q->codestring, false) != GDK_SUCCEED) { + msg = createException(SQL, "sql.session_prepared_statements", SQLSTATE(HY001) MAL_MALLOC_FAIL); + goto bailout; + } + if (BUNappend(created, &(q->created), false) != GDK_SUCCEED) { + msg = createException(SQL, "sql.session_prepared_statements", SQLSTATE(HY001) MAL_MALLOC_FAIL); + goto bailout; + } + } + } + +bailout: + if (msg) { + BBPreclaim(sessionid); + BBPreclaim(user); + BBPreclaim(statementid); + BBPreclaim(statement); + BBPreclaim(created); + } else { + BBPkeepref(*sid = sessionid->batCacheid); + BBPkeepref(*u = user->batCacheid); + BBPkeepref(*i = statementid->batCacheid); + BBPkeepref(*s = statement->batCacheid); + BBPkeepref(*c = created->batCacheid); + } + return msg; +} diff --git a/sql/backends/monet5/sql.h b/sql/backends/monet5/sql.h --- a/sql/backends/monet5/sql.h +++ b/sql/backends/monet5/sql.h @@ -312,4 +312,6 @@ sql5_export str SQLsuspend_log_flushing( sql5_export str SQLresume_log_flushing(void *ret); sql5_export str SQLhot_snapshot(void *ret, const str *tarfile); +sql5_export str SQLsession_prepared_statements(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); + #endif /* _SQL_H */ diff --git a/sql/backends/monet5/sql.mal b/sql/backends/monet5/sql.mal --- a/sql/backends/monet5/sql.mal +++ b/sql/backends/monet5/sql.mal @@ -603,6 +603,10 @@ address SYSMONstop; pattern sysmon_stop(tag:lng) address SYSMONstop; +pattern prepared_statements()(sessionid:bat[:int], user:bat[:str], statementid:bat[:int], statementt:bat[:str], createdd:bat[:timestamp]) +address SQLsession_prepared_statements +comment "Available prepared statements in the current session"; + pattern copy_rejects() (rowid:bat[:lng], fldid:bat[:int], msg:bat[:str], inp:bat[:str]) address COPYrejects; pattern copy_rejects_clear() diff --git a/sql/backends/monet5/sql_gencode.c b/sql/backends/monet5/sql_gencode.c --- a/sql/backends/monet5/sql_gencode.c +++ b/sql/backends/monet5/sql_gencode.c @@ -742,8 +742,8 @@ backend_dumpproc(backend *be, Client c, MalBlkPtr mb = 0; Symbol curPrg = 0, backup = NULL; InstrPtr curInstr = 0; - int argc = 0; - char arg[IDLENGTH]; + int argc = 0, res; + char arg[IDLENGTH], *escaped_q = NULL; node *n; backup = c->curprg; @@ -806,7 +806,15 @@ backend_dumpproc(backend *be, Client c, } } - if (backend_dumpstmt(be, mb, r, 1, 1, be->q?be->q->codestring:NULL) < 0) + if (be->q) { + if (!(escaped_q = sql_escape_str(be->q->codestring))) { + sql_error(m, 001, SQLSTATE(HY013) MAL_MALLOC_FAIL); + goto cleanup; + } + } + res = backend_dumpstmt(be, mb, r, 1, 1, escaped_q); + GDKfree(escaped_q); + if (res < 0) goto cleanup; if (cq) { 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 @@ -1276,25 +1276,23 @@ SQLparser(Client c) else opt = 1; } else { /* Add the query tree to the SQL query cache - * and bake a MAL program for it. - */ - char *escaped_q; - char qname[IDLENGTH]; + * and bake a MAL program for it. */ + char *q_copy = GDKstrdup(q), qname[IDLENGTH]; + 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 (!q_copy) { err = 1; msg = createException(PARSE, "SQLparser", SQLSTATE(HY001) MAL_MALLOC_FAIL); } else { be->q = qc_insert(m->qc, m->sa, /* the allocator */ r, /* keep relational query */ - qname, /* its MAL name) */ + qname, /* its MAL name */ 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->type, /* the type of the statement */ - escaped_q, + q_copy, m->no_mitosis, m->emode == m_prepare); } diff --git a/sql/backends/monet5/sql_session.mal b/sql/backends/monet5/sql_session.mal --- a/sql/backends/monet5/sql_session.mal +++ b/sql/backends/monet5/sql_session.mal @@ -1,40 +1,39 @@ module sql; -pattern sql.setquerytimeout(n:int):void + +pattern sql.setquerytimeout(n:int):void address SQLqueryTimeout; -pattern sql.setquerytimeout(sid:bte, n:int):void +pattern sql.setquerytimeout(sid:bte, n:int):void address SQLqueryTimeout; -pattern sql.setquerytimeout(sid:sht, n:int):void +pattern sql.setquerytimeout(sid:sht, n:int):void address SQLqueryTimeout; -pattern sql.setquerytimeout(sid:int, n:int):void +pattern sql.setquerytimeout(sid:int, n:int):void address SQLqueryTimeout comment "A query is aborted after q seconds (q=0 means run undisturbed)."; - -pattern sql.setsessiontimeout(n:int):void + +pattern sql.setsessiontimeout(n:int):void address SQLsessionTimeout; -pattern sql.setsessiontimeout(sid:bte, n:int):void +pattern sql.setsessiontimeout(sid:bte, n:int):void address SQLsessionTimeout; -pattern sql.setsessiontimeout(sid:sht, n:int):void +pattern sql.setsessiontimeout(sid:sht, n:int):void address SQLsessionTimeout; -pattern sql.setsessiontimeout(sid:int, n:int):void +pattern sql.setsessiontimeout(sid:int, n:int):void address SQLsessionTimeout comment "Set the session timeout for a particulat session id"; -pattern sql.setoptimizer(opt:str):void +pattern sql.setoptimizer(opt:str):void address SQLsetoptimizer; -pattern sql.setoptimizer(sid:int, opt:str):void +pattern sql.setoptimizer(sid:int, opt:str):void address SQLsetoptimizer comment "Set the session optimizer"; - -pattern sql.setworkerlimit(n:int):void + +pattern sql.setworkerlimit(n:int):void address SQLsetworkerlimit; -pattern sql.setworkerlimit(sid:int, n:int):void +pattern sql.setworkerlimit(sid:int, n:int):void address SQLsetworkerlimit comment "Limit the number of worker threads per query"; -pattern sql.setmemorylimit(n:int):void +pattern sql.setmemorylimit(n:int):void address SQLsetmemorylimit; -pattern sql.setmemorylimit(sid:sht, n:int):void +pattern sql.setmemorylimit(sid:sht, n:int):void address SQLsetmemorylimit comment "Limit the memory claim in MB per query"; - - diff --git a/sql/backends/monet5/sql_upgrades.c b/sql/backends/monet5/sql_upgrades.c --- a/sql/backends/monet5/sql_upgrades.c +++ b/sql/backends/monet5/sql_upgrades.c @@ -2440,11 +2440,22 @@ sql_update_default(Client c, mvc *sql, c " external name clients.stopsession;\n"); pos += snprintf(buf + pos, bufsize - pos, + "create function sys.prepared_statements()\n" + "returns table(\n" + "\"sessionid\" int,\n" + "\"user\" string,\n" + "\"statementid\" int,\n" + "\"statement\" string,\n" + "\"created\" timestamp)\n" + " external name sql.prepared_statements;\n" + "create view sys.prepared_statements as select * from sys.prepared_statements();\n"); + + pos += snprintf(buf + pos, bufsize - pos, "update sys.functions set system = true where schema_id = (select id from sys.schemas where name = 'sys')" - " and name = 'sessions' and type = %d;\n", (int) F_UNION); + " and name in ('sessions', 'prepared_statements') and type = %d;\n", (int) F_UNION); pos += snprintf(buf + pos, bufsize - pos, "update sys._tables set system = true where schema_id = (select id from sys.schemas where name = 'sys')" - " and name = 'sessions';\n"); + " and name in ('sessions', 'prepared_statements');\n"); pos += snprintf(buf + pos, bufsize - pos, "update sys.functions set system = true where schema_id = (select id from sys.schemas where name = 'sys')" " and name in ('setoptimizer', 'setquerytimeout', 'setsessiontimeout', 'setworkerlimit', 'setmemorylimit', 'setoptimizer', 'stopsession') and type = %d;\n", (int) F_PROC); diff --git a/sql/scripts/22_clients.sql b/sql/scripts/22_clients.sql --- a/sql/scripts/22_clients.sql +++ b/sql/scripts/22_clients.sql @@ -81,3 +81,18 @@ create procedure sys.stopsession("sessio create procedure sys.setprinttimeout("timeout" integer) external name clients.setprinttimeout; + +-- session's prepared statements +create function sys.prepared_statements() +returns table( + "sessionid" int, + "user" string, + "statementid" int, + "statement" string, + "created" timestamp +) +external name sql.prepared_statements; +grant execute on function sys.prepared_statements to public; + +create view sys.prepared_statements as select * from sys.prepared_statements(); +grant select on sys.prepared_statements to public; diff --git a/sql/server/sql_qc.c b/sql/server/sql_qc.c --- a/sql/server/sql_qc.c +++ b/sql/server/sql_qc.c @@ -41,6 +41,7 @@ #include "sql_qc.h" #include "sql_mvc.h" #include "sql_atom.h" +#include "mtime.h" qc * _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list