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

Reply via email to