Changeset: 19da1b518a1c for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=19da1b518a1c
Modified Files:
monetdb5/mal/mal_function.c
monetdb5/modules/mal/mdb.mx
sql/backends/monet5/sql_scenario.c
sql/server/sql_mvc.h
sql/server/sql_parser.y
sql/server/sql_scan.c
sql/storage/bat/bat_storage.c
Branch: default
Log Message:
SQL: implemented DOT prefix for SQL queries
Like the EXPLAIN prefix, the DOT prefix shows the flow dependencies of
the MAL plan backing the SQL query in dot compatible format. Use
mclient -ftab to pipe output directly to graphviz.
diffs (truncated from 455 to 300 lines):
diff --git a/monetdb5/mal/mal_function.c b/monetdb5/mal/mal_function.c
--- a/monetdb5/mal/mal_function.c
+++ b/monetdb5/mal/mal_function.c
@@ -593,7 +593,6 @@ listFunction(stream *fd, MalBlkPtr mb, M
if (flg & LIST_MAPI) {
size_t len = 0;
str ps;
- /* a bit dirty, but only here we have the number of lines */
mnstr_printf(fd, "&1 0 %d 1 %d\n", /* type id rows columns
tuples */
mb->stop, mb->stop);
mnstr_printf(fd, "%% .explain # table_name\n");
@@ -608,7 +607,7 @@ listFunction(stream *fd, MalBlkPtr mb, M
GDKfree(ps);
}
}
- mnstr_printf(fd, "%% " SZFMT " # length\n", len); /*
unknown */
+ mnstr_printf(fd, "%% " SZFMT " # length\n", len);
}
for (i = first; i < first +size && i < mb->stop; i++)
printInstruction(fd, mb, stk, getInstrPtr(mb, i), flg);
@@ -953,6 +952,7 @@ void chkDeclarations(MalBlkPtr mb){
}
GDKfree(decl);
}
+
/*
* Data flow analysis.
* Flow graph display is handy for debugging and analysis.
@@ -962,29 +962,29 @@ static void
showOutFlow(MalBlkPtr mb, int pc, int varid, stream *f)
{
InstrPtr p;
- int i, k,found;
-
+ int i, k, found;
for (i = pc + 1; i < mb->stop - 1; i++) {
p = getInstrPtr(mb, i);
- found=0;
+ found = 0;
for (k = 0; k < p->argc; k++) {
- if (p->argv[k] == varid ){
+ if (p->argv[k] == varid) {
mnstr_printf(f, "n%d -> n%d\n", pc, i);
found++;
}
}
/* stop as soon you find a re-assignment */
for (k = 0; k < p->retc; k++) {
- if (getArg(p,k) == varid)
+ if (getArg(p, k) == varid)
i = mb->stop;
}
/* or a side-effect usage */
- if( found &&
- (p->retc== 0 || getArgType(mb,p,0)== TYPE_void) )
- i = mb->stop;
+ if (found &&
+ (p->retc == 0 || getArgType(mb, p, 0) == TYPE_void))
+ i = mb->stop;
}
}
+
static void
showInFlow(MalBlkPtr mb, int pc, int varid, stream *f)
{
@@ -992,13 +992,13 @@ showInFlow(MalBlkPtr mb, int pc, int var
int i, k;
/* find last use, needed for operations with side effects */
- for (i = pc -1; i >= 0; i-- ){
+ for (i = pc - 1; i >= 0; i--) {
p = getInstrPtr(mb, i);
for (k = 0; k < p->argc; k++)
- if (p->argv[k] == varid )
- mnstr_printf(f, "n%d -> n%d\n",i, pc);
- return;
- }
+ if (p->argv[k] == varid)
+ mnstr_printf(f, "n%d -> n%d\n", i, pc);
+ return;
+ }
}
/*
@@ -1010,8 +1010,8 @@ showFlowDetails(MalBlkPtr mb, MalStkPtr
{
str s, msg;
- (void) stk; /* fool the compiler */
- msg = instruction2str(mb,stk, p, LIST_MAL_DEBUG);
+ (void) stk; /* fool the compiler */
+ msg = instruction2str(mb, stk, p, LIST_MAL_DEBUG);
mnstr_printf(f, "n%d [fontsize=8, shape=box, label=\"", pc);
for (s = msg; *s; s++)
if (*s == '"')
@@ -1028,43 +1028,83 @@ showFlowGraph(MalBlkPtr mb, MalStkPtr st
stream *f;
InstrPtr p;
int i, k;
+ char mapimode = 0;
+ buffer *bufstr = NULL;
- (void) stk; /* fool the compiler */
+ (void) stk; /* fool the compiler */
- if (idcmp(fname, "stdout") == 0)
+ if (idcmp(fname, "stdout") == 0) {
f = GDKout;
- else
+ } else if (idcmp(fname, "stdout-mapi") == 0) {
+ bufstr = buffer_create(8096);
+ f = buffer_wastream(bufstr, "bufstr_write");
+ mapimode = 1;
+ } else {
f = open_wastream(fname);
+ }
p = getInstrPtr(mb, 0);
- mnstr_printf(f, "digraph %s{\n", getFunctionId(p));
+ mnstr_printf(f, "digraph %s {\n", getFunctionId(p));
p = getInstrPtr(mb, 0);
showFlowDetails(mb, stk, p, 0, f);
for (k = p->retc; k < p->argc; k++) {
showOutFlow(mb, 0, p->argv[k], f);
}
- for (i = 1; i < mb->stop ; i++) {
+ for (i = 1; i < mb->stop; i++) {
p = getInstrPtr(mb, i);
showFlowDetails(mb, stk, p, i, f);
for (k = 0; k < p->retc; k++)
- showOutFlow(mb, i, p->argv[k], f);
+ showOutFlow(mb, i, p->argv[k], f);
- if( p->retc== 0 || getArgType(mb,p,0)== TYPE_void) /* assume
side effects */
- for (k = p->retc; k < p->argc; k++)
- if (getArgType(mb,p,k) != TYPE_void &&
- !isVarConstant(mb,getArg(p,k)))
- showOutFlow(mb, i, p->argv[k], f);
+ if (p->retc == 0 || getArgType(mb, p, 0) == TYPE_void) /*
assume side effects */
+ for (k = p->retc; k < p->argc; k++)
+ if (getArgType(mb, p, k) != TYPE_void &&
+ !isVarConstant(mb, getArg(p, k)))
+ showOutFlow(mb, i, p->argv[k], f);
- if( getFunctionId(p)== 0)
- for (k =0; k< p->retc; k++)
- if( getArgType(mb,p,k) != TYPE_void)
+ if (getFunctionId(p) == 0)
+ for (k = 0; k < p->retc; k++)
+ if (getArgType(mb, p, k) != TYPE_void)
showInFlow(mb, i, p->argv[k], f);
- if ( p->token == ENDsymbol)
+ if (p->token == ENDsymbol)
break;
}
mnstr_printf(f, "}\n");
- if (f != GDKout)
+
+ if (mapimode == 1) {
+ size_t maxlen = 0;
+ size_t rows = 0;
+ str buf = buffer_get_buf(bufstr);
+ str line, oline;
+
+ /* calculate width of column, and the number of tuples */
+ oline = buf;
+ while ((line = strchr(oline, '\n')) != NULL) {
+ if ((size_t) (line - oline) > maxlen)
+ maxlen = line - oline;
+ rows++;
+ oline = line + 1;
+ } /* see printf before this mapimode if, last line ends with \n
*/
+
+ /* write mapi header */
+ mnstr_printf(GDKout, "&1 0 " SZFMT " 1 " SZFMT "\n",
+ /* type id rows columns tuples */ rows, rows);
+ mnstr_printf(GDKout, "%% .dot # table_name\n");
+ mnstr_printf(GDKout, "%% dot # name\n");
+ mnstr_printf(GDKout, "%% clob # type\n");
+ mnstr_printf(GDKout, "%% " SZFMT " # length\n", maxlen);
+ oline = buf;
+ while ((line = strchr(oline, '\n')) != NULL) {
+ *line++ = '\0';
+ mnstr_printf(GDKout, "=%s\n", oline);
+ oline = line;
+ }
+ free(buf);
mnstr_close(f);
+ buffer_destroy(bufstr);
+ } else if (f != GDKout) {
+ mnstr_close(f);
+ }
}
diff --git a/monetdb5/modules/mal/mdb.mx b/monetdb5/modules/mal/mdb.mx
--- a/monetdb5/modules/mal/mdb.mx
+++ b/monetdb5/modules/mal/mdb.mx
@@ -179,6 +179,10 @@ pattern trap():void
address mdbTrap
comment "A suspended process for debugging.";
+pattern dot(s:str):void
+address MDBshowFlowGraph
+comment "Dump the data flow of the current routine in a format recognizable by
the command 'dot' to the file s";
+
pattern dot(M:str,F:str,s:str):void
address MDBshowFlowGraph
comment "Dump the data flow of the function
@@ -906,24 +910,34 @@ MDBshowFlowGraph(Client cntxt, MalBlkPtr
Symbol s = NULL;
(void)cntxt;
+
if (stk != 0) {
- modnme = *(str*) getArgReference(stk, p, 1);
- fcnnme = *(str*) getArgReference(stk, p, 2);
- fname = *(str*) getArgReference(stk, p, 3);
+ if (p->argc == 2) {
+ modnme = fcnnme = NULL;
+ fname = *(str*) getArgReference(stk, p, 1);
+ } else {
+ modnme = *(str*) getArgReference(stk, p, 1);
+ fcnnme = *(str*) getArgReference(stk, p, 2);
+ fname = *(str*) getArgReference(stk, p, 3);
+ }
} else {
modnme = getArgDefault(mb, p, 1);
fcnnme = getArgDefault(mb, p, 2);
fname = getArgDefault(mb, p, 3);
}
- s = findSymbol(cntxt->nspace, putName(modnme,strlen(modnme)),
putName(fcnnme, strlen(fcnnme)));
+ if (modnme != NULL) {
+ s = findSymbol(cntxt->nspace, putName(modnme,strlen(modnme)),
putName(fcnnme, strlen(fcnnme)));
- if (s == NULL) {
- char buf[1024];
- snprintf(buf,1024, "Could not find %s.%s\n", modnme, fcnnme);
- throw(MAL, "mdb.dot", "%s", buf);
+ if (s == NULL) {
+ char buf[1024];
+ snprintf(buf,1024, "Could not find %s.%s\n", modnme,
fcnnme);
+ throw(MAL, "mdb.dot", "%s", buf);
+ }
+ showFlowGraph(s->def, stk, fname);
+ } else {
+ showFlowGraph(mb, stk, fname);
}
- showFlowGraph(s->def, stk, fname);
return MAL_SUCCEED;
}
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
@@ -1176,8 +1176,17 @@ SQLshowPlan(Client c)
newStmt(c->curprg->def, "mdb", "listMapi");
}
+static void
+SQLshowDot(Client c)
+{
+ InstrPtr q;
+ /* we should determine rendering requirements first */
+ /* FIXME: unify this with direct showFlowGraph() calls as used below */
+ q = newStmt(c->curprg->def, "mdb", "dot");
+ q = pushStr(c->curprg->def, q, "stdout-mapi");
+}
+
/*
- * @-
* The core part of the SQL interface, parse the query and
* prepare the intermediate code.
*/
@@ -1368,7 +1377,8 @@ SQLparser(Client c)
SQLsetDebugger(c, m, TRUE);
if (m->emod & mod_trace)
SQLsetTrace(be, c, TRUE);
- if (m->emode != m_explain && !(m->emod & (mod_debug |
mod_trace)))
+ if (m->emode != m_explain && m->emode != m_dot &&
+ !(m->emod & (mod_debug | mod_trace)))
m->emode = m_inplace;
scanner_query_processed(&(m->scanner));
} else {
@@ -1385,11 +1395,13 @@ SQLparser(Client c)
/* generate and call the MAL code */
if (m->emode == m_explain)
SQLshowPlan(c);
+ if (m->emode == m_dot)
+ SQLshowDot(c);
if (m->emod & mod_trace)
SQLsetTrace(be, c, TRUE);
if (m->emod & mod_debug)
SQLsetDebugger(c, m, TRUE);
- if ((m->emode != m_inplace && m->emode != m_prepare && m->emode
!= m_prepareresult && !m->caching && m->emode != m_explain) || s->type ==
st_none || m->type == Q_TRANS) {
+ if ((m->emode != m_inplace && m->emode != m_prepare && m->emode
!= m_prepareresult && !m->caching && m->emode != m_explain && m->emode !=
m_dot) || s->type == st_none || m->type == Q_TRANS) {
InstrPtr p;
MalBlkPtr curBlk;
_______________________________________________
Checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list