]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
CLI enhancement: Add the ".eqp full" option, that shows both the EXPLAIN
authordrh <drh@noemail.net>
Fri, 15 Apr 2016 15:03:27 +0000 (15:03 +0000)
committerdrh <drh@noemail.net>
Fri, 15 Apr 2016 15:03:27 +0000 (15:03 +0000)
QUERY PLAN and the EXPLAIN output for each command run.  Also disable
any ".wheretrace" and ".selecttrace" when showing EQP output.

FossilOrigin-Name: 3e217d6265ecd16db783bed7ce1d9d0f9c4828bb

manifest
manifest.uuid
src/shell.c

index dadfc369454cbb98ddcb1e134707fe893be82fbf..c039180bbfed0bb0a9e4b3dffb8c9d0630cda39a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C In\sthe\sICU\sextension\stoupper()\sand\stolower()\sSQL\sfunctions,\savoid\scalling\su_strToUpper()\sor\su_strToLower()\sa\ssecond\stime\sif\sthe\sbuffer\spassed\sto\sthe\sfirst\sinvocation\sturns\sout\sto\sbe\slarge\senough.
-D 2016-04-14T17:29:13.982
+C CLI\senhancement:\s\sAdd\sthe\s".eqp\sfull"\soption,\sthat\sshows\sboth\sthe\sEXPLAIN\nQUERY\sPLAN\sand\sthe\sEXPLAIN\soutput\sfor\seach\scommand\srun.\s\sAlso\sdisable\nany\s".wheretrace"\sand\s".selecttrace"\swhen\sshowing\sEQP\soutput.
+D 2016-04-15T15:03:27.144
 F Makefile.in eba680121821b8a60940a81454316f47a341487a
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836
@@ -376,7 +376,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
 F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20
 F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
 F src/select.c 30217121bdf6b587462150b8ee9e1467f7a6036b
-F src/shell.c ebcdf99f3e7c7409bd463eae443f1bd01e3e2d02
+F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6
 F src/sqlite.h.in 64eb70a3b309751bebf73a5552a51244f68f0ea5
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
@@ -1482,7 +1482,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7b7a69d098f7581a43b818c251717c2450b797de
-R a8b6237f5057a202cac6f8ad76568fb8
-U dan
-Z 7154ea80cb4b14d420b76956f5072d2e
+P d23e581351fb8eea28e7b13b3dcadfc817c3a05f
+R e880e1f26ac9fef78137656188a6e0aa
+U drh
+Z dc2294cde78bca18f07e3e2fb59a4dd5
index b44499e23c17a8889ab3d1f74487854b56b86e5c..453393af12087ce826ead2e3270532b36a25b068 100644 (file)
@@ -1 +1 @@
-d23e581351fb8eea28e7b13b3dcadfc817c3a05f
\ No newline at end of file
+3e217d6265ecd16db783bed7ce1d9d0f9c4828bb
\ No newline at end of file
index 4744b91dddd798fddfd1a336d5733130f8ac93cc..5148177372eba42a04006f15344f3d8f1b0f379c 100644 (file)
@@ -1733,7 +1733,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
     if( str_in_array(zOp, azGoto) && p2op<p->nIndent
      && (abYield[p2op] || sqlite3_column_int(pSql, 2))
     ){
-      for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
+      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
     }
   }
 
@@ -1752,6 +1752,104 @@ static void explain_data_delete(ShellState *p){
   p->iIndent = 0;
 }
 
+/*
+** Disable and restore .wheretrace and .selecttrace settings.
+*/
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+extern int sqlite3SelectTrace;
+static int savedSelectTrace;
+#endif
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+extern int sqlite3WhereTrace;
+static int savedWhereTrace;
+#endif
+static void disable_debug_trace_modes(void){
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+  savedSelectTrace = sqlite3SelectTrace;
+  sqlite3SelectTrace = 0;
+#endif
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+  savedWhereTrace = sqlite3WhereTrace;
+  sqlite3WhereTrace = 0;
+#endif
+}
+static void restore_debug_trace_modes(void){
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+  sqlite3SelectTrace = savedSelectTrace;
+#endif
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+  sqlite3WhereTrace = savedWhereTrace;
+#endif
+}
+
+/*
+** Run a prepared statement
+*/
+static void exec_prepared_stmt(
+  ShellState *pArg,                                /* Pointer to ShellState */
+  sqlite3_stmt *pStmt,                             /* Statment to run */
+  int (*xCallback)(void*,int,char**,char**,int*)   /* Callback function */
+){
+  int rc;
+
+  /* perform the first step.  this will tell us if we
+  ** have a result set or not and how wide it is.
+  */
+  rc = sqlite3_step(pStmt);
+  /* if we have a result set... */
+  if( SQLITE_ROW == rc ){
+    /* if we have a callback... */
+    if( xCallback ){
+      /* allocate space for col name ptr, value ptr, and type */
+      int nCol = sqlite3_column_count(pStmt);
+      void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
+      if( !pData ){
+        rc = SQLITE_NOMEM;
+      }else{
+        char **azCols = (char **)pData;      /* Names of result columns */
+        char **azVals = &azCols[nCol];       /* Results */
+        int *aiTypes = (int *)&azVals[nCol]; /* Result types */
+        int i, x;
+        assert(sizeof(int) <= sizeof(char *));
+        /* save off ptrs to column names */
+        for(i=0; i<nCol; i++){
+          azCols[i] = (char *)sqlite3_column_name(pStmt, i);
+        }
+        do{
+          /* 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->cMode==MODE_Insert ){
+              azVals[i] = "";
+            }else{
+              azVals[i] = (char*)sqlite3_column_text(pStmt, i);
+            }
+            if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
+              rc = SQLITE_NOMEM;
+              break; /* from for */
+            }
+          } /* end for */
+
+          /* if data and types extracted successfully... */
+          if( SQLITE_ROW == rc ){
+            /* call the supplied callback with the result row data */
+            if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
+              rc = SQLITE_ABORT;
+            }else{
+              rc = sqlite3_step(pStmt);
+            }
+          }
+        } while( SQLITE_ROW == rc );
+        sqlite3_free(pData);
+      }
+    }else{
+      do{
+        rc = sqlite3_step(pStmt);
+      } while( rc == SQLITE_ROW );
+    }
+  }
+}
+
 /*
 ** Execute a statement or set of statements.  Print
 ** any result rows/columns depending on the current mode
@@ -1779,6 +1877,7 @@ static int shell_exec(
   }
 
   while( zSql[0] && (SQLITE_OK == rc) ){
+    static const char *zStmtSql;
     rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
     if( SQLITE_OK != rc ){
       if( pzErrMsg ){
@@ -1791,6 +1890,8 @@ static int shell_exec(
         while( IsSpace(zSql[0]) ) zSql++;
         continue;
       }
+      zStmtSql = sqlite3_sql(pStmt);
+      while( IsSpace(zStmtSql[0]) ) zStmtSql++;
 
       /* save off the prepared statment handle and reset row count */
       if( pArg ){
@@ -1800,15 +1901,15 @@ static int shell_exec(
 
       /* echo the sql statement if echo on */
       if( pArg && pArg->echoOn ){
-        const char *zStmtSql = sqlite3_sql(pStmt);
         utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
       }
 
       /* Show the EXPLAIN QUERY PLAN if .eqp is on */
-      if( pArg && pArg->autoEQP ){
+      if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
         sqlite3_stmt *pExplain;
-        char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
-                                     sqlite3_sql(pStmt));
+        char *zEQP;
+        disable_debug_trace_modes();
+        zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
         rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
         if( rc==SQLITE_OK ){
           while( sqlite3_step(pExplain)==SQLITE_ROW ){
@@ -1820,13 +1921,27 @@ static int shell_exec(
         }
         sqlite3_finalize(pExplain);
         sqlite3_free(zEQP);
+        if( pArg->autoEQP>=2 ){
+          /* Also do an EXPLAIN for ".eqp full" mode */
+          zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
+          rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+          if( rc==SQLITE_OK ){
+            pArg->cMode = MODE_Explain;
+            explain_data_prepare(pArg, pExplain);
+            exec_prepared_stmt(pArg, pExplain, xCallback);
+            explain_data_delete(pArg);
+          }
+          sqlite3_finalize(pExplain);
+          sqlite3_free(zEQP);
+        }
+        restore_debug_trace_modes();
       }
 
       if( pArg ){
         pArg->cMode = pArg->mode;
         if( pArg->autoExplain
          && sqlite3_column_count(pStmt)==8
-         && sqlite3_strlike("%EXPLAIN%", sqlite3_sql(pStmt),0)==0
+         && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
         ){
           pArg->cMode = MODE_Explain;
         }
@@ -1838,63 +1953,7 @@ static int shell_exec(
         }
       }
 
-      /* perform the first step.  this will tell us if we
-      ** have a result set or not and how wide it is.
-      */
-      rc = sqlite3_step(pStmt);
-      /* if we have a result set... */
-      if( SQLITE_ROW == rc ){
-        /* if we have a callback... */
-        if( xCallback ){
-          /* allocate space for col name ptr, value ptr, and type */
-          int nCol = sqlite3_column_count(pStmt);
-          void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
-          if( !pData ){
-            rc = SQLITE_NOMEM;
-          }else{
-            char **azCols = (char **)pData;      /* Names of result columns */
-            char **azVals = &azCols[nCol];       /* Results */
-            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
-            int i, x;
-            assert(sizeof(int) <= sizeof(char *));
-            /* save off ptrs to column names */
-            for(i=0; i<nCol; i++){
-              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
-            }
-            do{
-              /* 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->cMode==MODE_Insert ){
-                  azVals[i] = "";
-                }else{
-                  azVals[i] = (char*)sqlite3_column_text(pStmt, i);
-                }
-                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
-                  rc = SQLITE_NOMEM;
-                  break; /* from for */
-                }
-              } /* end for */
-
-              /* if data and types extracted successfully... */
-              if( SQLITE_ROW == rc ){
-                /* call the supplied callback with the result row data */
-                if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
-                  rc = SQLITE_ABORT;
-                }else{
-                  rc = sqlite3_step(pStmt);
-                }
-              }
-            } while( SQLITE_ROW == rc );
-            sqlite3_free(pData);
-          }
-        }else{
-          do{
-            rc = sqlite3_step(pStmt);
-          } while( rc == SQLITE_ROW );
-        }
-      }
-
+      exec_prepared_stmt(pArg, pStmt, xCallback);
       explain_data_delete(pArg);
 
       /* print usage stats if stats on */
@@ -2084,7 +2143,7 @@ static char zHelp[] =
   "                         If TABLE specified, only dump tables matching\n"
   "                         LIKE pattern TABLE.\n"
   ".echo on|off           Turn command echo on or off\n"
-  ".eqp on|off            Enable or disable automatic EXPLAIN QUERY PLAN\n"
+  ".eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN\n"
   ".exit                  Exit this program\n"
   ".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"
   ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
@@ -3254,9 +3313,13 @@ static int do_meta_command(char *zLine, ShellState *p){
 
   if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
     if( nArg==2 ){
-      p->autoEQP = booleanValue(azArg[1]);
+      if( strcmp(azArg[1],"full")==0 ){
+        p->autoEQP = 2;
+      }else{
+        p->autoEQP = booleanValue(azArg[1]);
+      }
     }else{
-      raw_printf(stderr, "Usage: .eqp on|off\n");
+      raw_printf(stderr, "Usage: .eqp on|off|full\n");
       rc = 1;
     }
   }else
@@ -4017,7 +4080,6 @@ static int do_meta_command(char *zLine, ShellState *p){
 
 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
   if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
-    extern int sqlite3SelectTrace;
     sqlite3SelectTrace = integerValue(azArg[1]);
   }else
 #endif
@@ -4277,17 +4339,18 @@ static int do_meta_command(char *zLine, ShellState *p){
   }else
 
   if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
+    static const char *azBool[] = { "off", "on", "full", "unk" };
     int i;
     if( nArg!=1 ){
       raw_printf(stderr, "Usage: .show\n");
       rc = 1;
       goto meta_command_exit;
     }
-    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, "%12.12s: %s\n","echo", azBool[p->echoOn!=0]);
+    utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
     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","headers", azBool[p->showHeader!=0]);
     utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
     utf8_printf(p->out, "%12.12s: ", "nullvalue");
       output_c_string(p->out, p->nullValue);
@@ -4300,7 +4363,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     utf8_printf(p->out,"%12.12s: ", "rowseparator");
       output_c_string(p->out, p->rowSeparator);
       raw_printf(p->out, "\n");
-    utf8_printf(p->out, "%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
+    utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
     utf8_printf(p->out, "%12.12s: ", "width");
     for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
       raw_printf(p->out, "%d ", p->colWidth[i]);
@@ -4715,7 +4778,6 @@ static int do_meta_command(char *zLine, ShellState *p){
 
 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
   if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
-    extern int sqlite3WhereTrace;
     sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
   }else
 #endif
@@ -5383,6 +5445,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
       data.echoOn = 1;
     }else if( strcmp(z,"-eqp")==0 ){
       data.autoEQP = 1;
+    }else if( strcmp(z,"-eqpfull")==0 ){
+      data.autoEQP = 2;
     }else if( strcmp(z,"-stats")==0 ){
       data.statsOn = 1;
     }else if( strcmp(z,"-scanstats")==0 ){