]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add auto-explain mode to the command-line shell. Default on. Auto-explain
authordrh <drh@noemail.net>
Tue, 9 Feb 2016 18:39:25 +0000 (18:39 +0000)
committerdrh <drh@noemail.net>
Tue, 9 Feb 2016 18:39:25 +0000 (18:39 +0000)
tries to automatically detect EXPLAIN queries and format them appropriately.

FossilOrigin-Name: 1d62aa6b315df47cafb33da7ca79d3386a2fdd48

manifest
manifest.uuid
src/shell.c

index 972cf743530c9f535f7363494c546beac34cc6c9..4e297feee85414be75aad6fd89b6499c26446267 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sMSVC\smakefile\soptions\sthat\senable\scontrol-flow\sguard.
-D 2016-02-09T18:28:20.640
+C Add\sauto-explain\smode\sto\sthe\scommand-line\sshell.\s\sDefault\son.\s\sAuto-explain\ntries\sto\sautomatically\sdetect\sEXPLAIN\squeries\sand\sformat\sthem\sappropriately.
+D 2016-02-09T18:39:25.001
 F Makefile.in 95ea52e9c02962e31f986fe8ea5805104c84f94b
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 0fe3b22f8e29bcde0533ada7957a5f15835d797a
@@ -349,7 +349,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
 F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c
 F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
 F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d
-F src/shell.c dcd7a83645ef2a58ee9c6d0ea4714d877d7835c4
+F src/shell.c eae68d3a7aff0f4195074d5f204dc2c219e748fd
 F src/sqlite.h.in cf22ad1d52dca2c9862d63833e581028119aab7e
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
@@ -1427,7 +1427,10 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 992282399cd2d1fc52ff5a1a4bff59f30b62899a
-R 339c4dc7dafb8a9f839919868c327cb9
-U mistachkin
-Z 87542794a9bfaf638d39bc9a323993e0
+P 51b6823f4c9376d549f572f5a33cac1e4c9783a2
+R 38fbc467636eda7f2b73a6fc60969ca8
+T *branch * auto-explain
+T *sym-auto-explain *
+T -sym-trunk *
+U drh
+Z 2feb45f9e3784b1a58bde6f86e718a1d
index 59daec470ff137097e59d51f3959e2ac56d4ba6d..6a13da9877b424de89d277fe0468ea4cffd55daf 100644 (file)
@@ -1 +1 @@
-51b6823f4c9376d549f572f5a33cac1e4c9783a2
\ No newline at end of file
+1d62aa6b315df47cafb33da7ca79d3386a2fdd48
\ No newline at end of file
index 3f8b22f4fa26465193b8e59d5ae694bb90a6fb0a..c45b28b999cf95403b4c5a2098331ff2cdffb492 100644 (file)
@@ -592,6 +592,7 @@ typedef struct ShellState ShellState;
 struct ShellState {
   sqlite3 *db;           /* The database */
   int echoOn;            /* True to echo input commands */
+  int autoExplain;       /* Automatically turn on .explain mode */
   int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
   int statsOn;           /* True to display memory stats before each finalize */
   int scanstatsOn;       /* True to display scan stats before each finalize */
@@ -603,6 +604,8 @@ struct ShellState {
   FILE *traceOut;        /* Output for sqlite3_trace() */
   int nErr;              /* Number of errors seen */
   int mode;              /* An output mode setting */
+  int cMode;             /* temporary output mode for the current query */
+  int normalMode;        /* Output mode before ".explain on" */
   int writableSchema;    /* True if PRAGMA writable_schema=ON */
   int showHeader;        /* True to show column names in List or Column mode */
   unsigned shellFlgs;    /* Various flags */
@@ -613,7 +616,6 @@ struct ShellState {
   int actualWidth[100];  /* Actual width of each column */
   char nullValue[20];    /* The text to print when a NULL comes back from
                          ** the database */
-  SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
   char outfile[FILENAME_MAX]; /* Filename for *out */
   const char *zDbFilename;    /* name of the database file */
   char *zFreeOnClose;         /* Filename to free when closing */
@@ -882,7 +884,7 @@ static int shell_callback(
   int i;
   ShellState *p = (ShellState*)pArg;
 
-  switch( p->mode ){
+  switch( p->cMode ){
     case MODE_Line: {
       int w = 5;
       if( azArg==0 ) break;
@@ -899,11 +901,24 @@ static int shell_callback(
     }
     case MODE_Explain:
     case MODE_Column: {
+      static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
+      const int *colWidth;
+      int showHdr;
+      char *rowSep;
+      if( p->cMode==MODE_Column ){
+        colWidth = p->colWidth;
+        showHdr = p->showHeader;
+        rowSep = p->rowSeparator;
+      }else{
+        colWidth = aExplainWidths;
+        showHdr = 1;
+        rowSep = "\n";
+      }
       if( p->cnt++==0 ){
         for(i=0; i<nArg; i++){
           int w, n;
           if( i<ArraySize(p->colWidth) ){
-            w = p->colWidth[i];
+            w = colWidth[i];
           }else{
             w = 0;
           }
@@ -916,17 +931,17 @@ static int shell_callback(
           if( i<ArraySize(p->actualWidth) ){
             p->actualWidth[i] = w;
           }
-          if( p->showHeader ){
+          if( showHdr ){
             if( w<0 ){
               utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i],
-                      i==nArg-1 ? p->rowSeparator : "  ");
+                      i==nArg-1 ? rowSep : "  ");
             }else{
               utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i],
-                      i==nArg-1 ? p->rowSeparator : "  ");
+                      i==nArg-1 ? rowSep : "  ");
             }
           }
         }
-        if( p->showHeader ){
+        if( showHdr ){
           for(i=0; i<nArg; i++){
             int w;
             if( i<ArraySize(p->actualWidth) ){
@@ -938,7 +953,7 @@ static int shell_callback(
             utf8_printf(p->out,"%-*.*s%s",w,w,
                    "----------------------------------------------------------"
                    "----------------------------------------------------------",
-                    i==nArg-1 ? p->rowSeparator : "  ");
+                    i==nArg-1 ? rowSep : "  ");
           }
         }
       }
@@ -950,7 +965,7 @@ static int shell_callback(
         }else{
            w = 10;
         }
-        if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
+        if( p->cMode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
           w = strlen30(azArg[i]);
         }
         if( i==1 && p->aiIndent && p->pStmt ){
@@ -962,11 +977,11 @@ static int shell_callback(
         if( w<0 ){
           utf8_printf(p->out,"%*.*s%s",-w,-w,
               azArg[i] ? azArg[i] : p->nullValue,
-              i==nArg-1 ? p->rowSeparator : "  ");
+              i==nArg-1 ? rowSep : "  ");
         }else{
           utf8_printf(p->out,"%-*.*s%s",w,w,
               azArg[i] ? azArg[i] : p->nullValue,
-              i==nArg-1 ? p->rowSeparator : "  ");
+              i==nArg-1 ? rowSep : "  ");
         }
       }
       break;
@@ -986,7 +1001,7 @@ static int shell_callback(
         utf8_printf(p->out, "%s", z);
         if( i<nArg-1 ){
           utf8_printf(p->out, "%s", p->colSeparator);
-        }else if( p->mode==MODE_Semi ){
+        }else if( p->cMode==MODE_Semi ){
           utf8_printf(p->out, ";%s", p->rowSeparator);
         }else{
           utf8_printf(p->out, "%s", p->rowSeparator);
@@ -1614,10 +1629,20 @@ static int shell_exec(
         sqlite3_free(zEQP);
       }
 
-      /* If the shell is currently in ".explain" mode, gather the extra
-      ** data required to add indents to the output.*/
-      if( pArg && pArg->mode==MODE_Explain ){
-        explain_data_prepare(pArg, pStmt);
+      if( pArg ){
+        pArg->cMode = pArg->mode;
+        if( sqlite3_column_count(pStmt)==8
+         && sqlite3_strlike("%EXPLAIN%", sqlite3_sql(pStmt),0)==0
+         && sqlite3_strlike("%QUERY%", sqlite3_sql(pStmt),0)!=0
+        ){
+          pArg->cMode = MODE_Explain;
+        }
+      
+        /* If the shell is currently in ".explain" mode, gather the extra
+        ** data required to add indents to the output.*/
+        if( pArg->cMode==MODE_Explain ){
+          explain_data_prepare(pArg, pStmt);
+        }
       }
 
       /* perform the first step.  this will tell us if we
@@ -1647,7 +1672,7 @@ static int shell_exec(
               /* extract the data and data types */
               for(i=0; i<nCol; i++){
                 aiTypes[i] = x = sqlite3_column_type(pStmt, i);
-                if( x==SQLITE_BLOB && pArg && pArg->mode==MODE_Insert ){
+                if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
                   azVals[i] = "";
                 }else{
                   azVals[i] = (char*)sqlite3_column_text(pStmt, i);
@@ -1867,8 +1892,7 @@ static char zHelp[] =
   ".echo on|off           Turn command echo on or off\n"
   ".eqp on|off            Enable or disable automatic EXPLAIN QUERY PLAN\n"
   ".exit                  Exit this program\n"
-  ".explain ?on|off?      Turn output mode suitable for EXPLAIN on or off.\n"
-  "                         With no args, it turns EXPLAIN on.\n"
+  ".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"
   ".fullschema            Show schema and the content of sqlite_stat tables\n"
   ".headers on|off        Turn display of headers on or off\n"
   ".help                  Show this message\n"
@@ -2855,7 +2879,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     open_db(p, 0);
     memcpy(&data, p, sizeof(data));
     data.showHeader = 1;
-    data.mode = MODE_Column;
+    data.cMode = data.mode = MODE_Column;
     data.colWidth[0] = 3;
     data.colWidth[1] = 15;
     data.colWidth[2] = 58;
@@ -2950,37 +2974,24 @@ static int do_meta_command(char *zLine, ShellState *p){
   }else
 
   if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
-    int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
-    if(val == 1) {
-      if(!p->normalMode.valid) {
-        p->normalMode.valid = 1;
-        p->normalMode.mode = p->mode;
-        p->normalMode.showHeader = p->showHeader;
-        memcpy(p->normalMode.colWidth,p->colWidth,sizeof(p->colWidth));
+    int val = 1;
+    if( nArg>=2 ){
+      if( strcmp(azArg[1],"auto")==0 ){
+        val = 99;
+      }else{
+        val =  booleanValue(azArg[1]);
       }
-      /* We could put this code under the !p->explainValid
-      ** condition so that it does not execute if we are already in
-      ** explain mode. However, always executing it allows us an easy
-      ** was to reset to explain mode in case the user previously
-      ** did an .explain followed by a .width, .mode or .header
-      ** command.
-      */
+    }
+    if( val==1 && p->mode!=MODE_Explain ){
+      p->normalMode = p->mode;
       p->mode = MODE_Explain;
-      p->showHeader = 1;
-      memset(p->colWidth,0,sizeof(p->colWidth));
-      p->colWidth[0] = 4;                  /* addr */
-      p->colWidth[1] = 13;                 /* opcode */
-      p->colWidth[2] = 4;                  /* P1 */
-      p->colWidth[3] = 4;                  /* P2 */
-      p->colWidth[4] = 4;                  /* P3 */
-      p->colWidth[5] = 13;                 /* P4 */
-      p->colWidth[6] = 2;                  /* P5 */
-      p->colWidth[7] = 13;                  /* Comment */
-    }else if (p->normalMode.valid) {
-      p->normalMode.valid = 0;
-      p->mode = p->normalMode.mode;
-      p->showHeader = p->normalMode.showHeader;
-      memcpy(p->colWidth,p->normalMode.colWidth,sizeof(p->colWidth));
+      p->autoExplain = 0;
+    }else if( val==0 ){
+      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
+      p->autoExplain = 0;
+    }else if( val==99 ){
+      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
+      p->autoExplain = 1;
     }
   }else
 
@@ -2996,7 +3007,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     open_db(p, 0);
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
-    data.mode = MODE_Semi;
+    data.cMode = data.mode = MODE_Semi;
     rc = sqlite3_exec(p->db,
        "SELECT sql FROM"
        "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
@@ -3021,7 +3032,7 @@ static int do_meta_command(char *zLine, ShellState *p){
       raw_printf(p->out, "ANALYZE sqlite_master;\n");
       sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
                    callback, &data, &zErrMsg);
-      data.mode = MODE_Insert;
+      data.cMode = data.mode = MODE_Insert;
       data.zDestTable = "sqlite_stat1";
       shell_exec(p->db, "SELECT * FROM sqlite_stat1",
                  shell_callback, &data,&zErrMsg);
@@ -3253,7 +3264,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     open_db(p, 0);
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
-    data.mode = MODE_List;
+    data.cMode = data.mode = MODE_List;
     if( nArg==1 ){
       rc = sqlite3_exec(p->db,
         "SELECT name FROM sqlite_master "
@@ -3439,6 +3450,7 @@ static int do_meta_command(char *zLine, ShellState *p){
          "ascii column csv html insert line list tabs tcl\n");
       rc = 1;
     }
+    p->cMode = p->mode;
   }else
 
   if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
@@ -3628,7 +3640,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     open_db(p, 0);
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
-    data.mode = MODE_Semi;
+    data.cMode = data.mode = MODE_Semi;
     if( nArg==2 ){
       int i;
       for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
@@ -3776,7 +3788,8 @@ static int do_meta_command(char *zLine, ShellState *p){
     }
     utf8_printf(p->out, "%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
     utf8_printf(p->out, "%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
-    utf8_printf(p->out,"%9.9s: %s\n","explain",p->normalMode.valid?"on":"off");
+    utf8_printf(p->out, "%12.12s: %s\n","explain",
+         p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
     utf8_printf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
     utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
     utf8_printf(p->out, "%12.12s: ", "nullvalue");
@@ -4575,7 +4588,8 @@ static void usage(int showDetail){
 */
 static void main_init(ShellState *data) {
   memset(data, 0, sizeof(*data));
-  data->mode = MODE_List;
+  data->normalMode = data->cMode = data->mode = MODE_List;
+  data->autoExplain = 1;
   memcpy(data->colSeparator,SEP_Column, 2);
   memcpy(data->rowSeparator,SEP_Row, 2);
   data->showHeader = 0;
@@ -4908,6 +4922,7 @@ int SQLITE_CDECL main(int argc, char **argv){
       raw_printf(stderr,"Use -help for a list of options.\n");
       return 1;
     }
+    data.cMode = data.mode;
   }
 
   if( !readStdin ){