]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Improvements to columnar output in the CLI. Columns automatically expand
authordrh <drh@noemail.net>
Fri, 29 May 2020 16:15:58 +0000 (16:15 +0000)
committerdrh <drh@noemail.net>
Fri, 29 May 2020 16:15:58 +0000 (16:15 +0000)
to contain the largest row.

FossilOrigin-Name: 4e1db8e9a9ee370a398f13fd8546a520111b8cfb84460389535b5bc5bd9f4f82

manifest
manifest.uuid
src/shell.c.in

index edf9e43a801fb0bcf391606e0290524679d2d24c..d4109e2ff93e82499f4b3e8ddc0cd6d06130ec79 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Space\sto\shold\sthe\s".width"\sof\scolumns\sin\sthe\sCLI\sis\snow\sobtained\sfrom\nmalloc()\sand\shence\sis\snot\slimited\sin\sthe\snumber\sof\scolumns\ssupported.
-D 2020-05-29T14:38:43.840
+C Improvements\sto\scolumnar\soutput\sin\sthe\sCLI.\s\sColumns\sautomatically\sexpand\nto\scontain\sthe\slargest\srow.
+D 2020-05-29T16:15:58.318
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -534,7 +534,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c c2008519a0654f1e7490e9281ed0397d0f14bb840d81f0b96946248afcbdb25d
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c 39a00a8bc89596dfb37c16afcbb1d33de5085b9963564b58aafe1566d08c0881
-F src/shell.c.in 77530a909ab0e8e44c7797993b0f3143e95226380bc5f311158ad3e3209abf28
+F src/shell.c.in 9675df5f6be969309421509eef9c49a20179e5c4df8770f2d62edd41a9dee339
 F src/sqlite.h.in 74342b41e9d68ff9e56b192009046f8dd0aa2bd76ce1a588f330de614ba61de7
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
@@ -1866,7 +1866,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 af28bff91ad7e2d69db0052323c9c05c75a41d4134974bd1305f1c4f579d3558
-R 7199cbe7bb1c2e7279bcd8d792b04d19
+P 445ed5dab2c26e9f4a7fb5277abdba3359d23cf5318cfd0d8322162d9616ee7a
+R 5cd70920783d10744759d8e97b9aed09
 U drh
-Z e4dd532cb0e0bd045df8215b6bacef2f
+Z 0a5f6eacc5288734a9f57cf18ebe2785
index 589b69c5fc72c95bcd4fa296b93d77a1025e1609..cbe0de7cd31254c906928a1286c97a9f42747e72 100644 (file)
@@ -1 +1 @@
-445ed5dab2c26e9f4a7fb5277abdba3359d23cf5318cfd0d8322162d9616ee7a
\ No newline at end of file
+4e1db8e9a9ee370a398f13fd8546a520111b8cfb84460389535b5bc5bd9f4f82
\ No newline at end of file
index 299670755d2734ccc292470519a72d29051a492e..e4883c1474310579927b7c8ad2fabced06100ee1 100644 (file)
@@ -1945,15 +1945,8 @@ static void print_row_separator(
 ){
   int i;
   for(i=0; i<nArg; i++){
-    int w;
-    if( i<ArraySize(p->actualWidth) ){
-      w = p->actualWidth[i];
-      if( w<0 ) w = -w;
-    }else{
-       w = 10;
-    }
     fputs(zSep, p->out);
-    print_dashes(p->out, w+2);
+    print_dashes(p->out, p->actualWidth[i]+2);
   }
   fputs(zSep, p->out);
   fputs("\n", p->out);
@@ -1989,125 +1982,32 @@ static int shell_callback(
       }
       break;
     }
-    case MODE_Table:
-    case MODE_Markdown:
-    case MODE_Explain:
-    case MODE_Column: {
-      int showHdr;
-      char *rowSep;
-      char *colSep;
-      char *rowStart;
-      if( p->cMode==MODE_Column ){
-        showHdr = p->showHeader;
-        rowSep = p->rowSeparator;
-        colSep = "  ";
-        rowStart = "";
-      }else if( p->cMode==MODE_Explain ){
-        showHdr = 1;
-        rowSep = SEP_Row;
-        colSep = "  ";
-        rowStart = "";
-      }else{
-        showHdr = 1;
-        rowSep = " |\n";
-        colSep = " | ";
-        rowStart = "| ";
+    case MODE_Explain: {
+      static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
+      if( nArg>ArraySize(aExplainWidth) ){
+        nArg = ArraySize(aExplainWidth);
       }
-
       if( p->cnt++==0 ){
-        /* Compute column widths in p->actualWidth[] when the first row
-        ** is seen.  The width of each column is either the defined
-        ** width in p->colWidth[], or if p->colWidth[i]==0, then the
-        ** width is the larger of the width of the first row and the
-        ** column name. */
-        static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
-        const int *colWidth;
-        int nWidth;
-        if( p->cMode==MODE_Explain ){
-          colWidth = aExplainWidths;
-          nWidth = ArraySize(aExplainWidths);
-        }else{
-          colWidth = p->colWidth;
-          nWidth = p->nWidth;
-        }
         for(i=0; i<nArg; i++){
-          int w, n;
-          if( i<nWidth ){
-            w = colWidth[i];
-          }else{
-            w = 0;
-          }
-          if( w==0 ){
-            w = strlenChar(azCol[i] ? azCol[i] : "");
-            if( w<10 ) w = 10;
-            n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
-            if( w<n ) w = n;
-          }
-          if( i<ArraySize(p->actualWidth) ){
-            p->actualWidth[i] = w;
-          }
-        }
-        if( p->cMode==MODE_Table ){
-          print_row_separator(p, nArg, "+");
-        }
-        if( showHdr ){
-          fputs(rowStart, p->out);
-          for(i=0; i<nArg; i++){
-            int w;
-            if( i<ArraySize(p->actualWidth) ){
-               w = p->actualWidth[i];
-               if( w<0 ) w = -w;
-            }else{
-               w = 10;
-            }
-            utf8_width_print(p->out, w, azCol[i]);
-            fputs(i==nArg-1 ? rowSep : colSep, p->out);
-          }
-          for(i=0; i<nArg; i++){
-            int w;
-            if( i<ArraySize(p->actualWidth) ){
-               w = p->actualWidth[i];
-               if( w<0 ) w = -w;
-            }else{
-               w = 10;
-            }
-            if( p->cMode==MODE_Table || p->cMode==MODE_Markdown ){
-              char *zX = p->cMode==MODE_Markdown ? "|" : "+";
-              fputs(zX, p->out);
-              print_dashes(p->out, w+2);
-              if( i==nArg-1 ){
-                fputs(zX, p->out);
-                fputs("\n", p->out);
-              }
-            }else{
-              print_dashes(p->out, w);
-              fputs(i==nArg-1 ? rowSep : colSep, p->out);
-            }
-          }
+          int w = aExplainWidth[i];
+          utf8_width_print(p->out, w, azCol[i]);
+          fputs(i==nArg-1 ? "\n" : "  ", p->out);
         }
       }
       if( azArg==0 ) break;
-      fputs(rowStart, p->out);
       for(i=0; i<nArg; i++){
-        int w;
-        if( i<ArraySize(p->actualWidth) ){
-           w = p->actualWidth[i];
-        }else{
-           w = 10;
+        int w = aExplainWidth[i];
+        if( azArg[i] && strlenChar(azArg[i])>w ){
+          w = strlenChar(azArg[i]);
         }
-        if( p->cMode==MODE_Explain ){
-          if( azArg[i] && strlenChar(azArg[i])>w ){
-            w = strlenChar(azArg[i]);
-          }
-          if( i==1 && p->aiIndent && p->pStmt ){
-            if( p->iIndent<p->nIndent ){
-              utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
-            }
-            p->iIndent++;
+        if( i==1 && p->aiIndent && p->pStmt ){
+          if( p->iIndent<p->nIndent ){
+            utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
           }
+          p->iIndent++;
         }
         utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
-        utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : colSep);
+        fputs(i==nArg-1 ? "\n" : "  ", p->out);
       }
       break;
     }
@@ -3042,23 +2942,105 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
   sqlite3_finalize(pQ);
 }
 
-#if 0
 /*
 ** Run a prepared statement and output the result in one of the
-** table-oriented formats, either MODE_Markdown or MODE_Table.
+** table-oriented formats: MODE_Column, MODE_Markdown, or MODE_Table.
 **
 ** This is different from ordinary exec_prepared_stmt() in that
 ** it has to run the entire query and gather the results into memory
 ** first, in order to determine column widths, before providing
 ** any output.
 */
-static void exec_prepared_stmt_tablemode(
-  ShellState *pArg,                                /* Pointer to ShellState */
-  sqlite3_stmt *pStmt                              /* Statment to run */
+static void exec_prepared_stmt_columnar(
+  ShellState *p,                        /* Pointer to ShellState */
+  sqlite3_stmt *pStmt                   /* Statment to run */
 ){
+  int nRow = 0;
+  int nColumn = 0;
+  char **azData = 0;
+  char *zMsg = 0;
+  const char *z;
+  int rc;
+  int i, j, nTotal, w, n;
+  const char *colSep;
+  const char *rowSep;
 
+  rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt),
+                         &azData, &nRow, &nColumn, &zMsg);
+  if( rc ){
+    utf8_printf(p->out, "ERROR: %s\n", zMsg);
+    sqlite3_free(zMsg);
+    sqlite3_free_table(azData);
+    return;
+  }
+  if( nColumn>p->nWidth ){
+    p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
+    if( p->colWidth==0 ) shell_out_of_memory();
+    for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
+    p->nWidth = nColumn;
+    p->actualWidth = &p->colWidth[nColumn];
+  }
+  memset(p->actualWidth, 0, nColumn*sizeof(int));
+  for(i=0; i<nColumn; i++){
+    w = p->colWidth[i];
+    if( w<0 ) w = -w;
+    p->actualWidth[i] = w;
+  }
+  nTotal = nColumn*(nRow+1);
+  for(i=0; i<nTotal; i++){
+    z = azData[i];
+    if( z==0 ) z = p->nullValue;
+    n = strlenChar(z);
+    j = i%nColumn;
+    if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
+  }
+  if( p->cMode==MODE_Column ){
+    colSep = "  ";
+    rowSep = "\n";
+    if( p->showHeader ){
+      for(i=0; i<nColumn; i++){
+        w = p->actualWidth[i];
+        if( p->colWidth[i]<0 ) w = -w;
+        utf8_width_print(p->out, w, azData[i]);
+        fputs(i==nColumn-1?"\n":"  ", p->out);
+      }
+      for(i=0; i<nColumn; i++){
+        print_dashes(p->out, p->actualWidth[i]);
+        fputs(i==nColumn-1?"\n":"  ", p->out);
+      }
+    }
+  }else{
+    colSep = " | ";
+    rowSep = " |\n";
+    if( p->cMode==MODE_Table ) print_row_separator(p, nColumn, "+");
+    fputs("| ", p->out);
+    for(i=0; i<nColumn; i++){
+      w = p->actualWidth[i];
+      n = strlenChar(azData[i]);
+      utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+      fputs(i==nColumn-1?" |\n":" | ", p->out);
+    }
+    print_row_separator(p, nColumn, p->cMode==MODE_Table ? "+" : "|");
+  }
+  for(i=nColumn, j=0; i<nTotal; i++, j++){
+    if( j==0 && p->cMode!=MODE_Column ) fputs("| ", p->out);
+    z = azData[i];
+    if( z==0 ) z = p->nullValue;
+    w = p->actualWidth[j];
+    if( p->colWidth[j]<0 ) w = -w;
+    utf8_width_print(p->out, w, z);
+    if( j==nColumn-1 ){
+      fputs(rowSep, p->out);
+      j = -1;
+    }else{
+      fputs(colSep, p->out);
+    }
+  }
+  if( p->cMode==MODE_Table ){
+    print_row_separator(p, nColumn, "+");
+  }
+  sqlite3_free_table(azData);
 }
-#endif
 
 /*
 ** Run a prepared statement
@@ -3069,6 +3051,14 @@ static void exec_prepared_stmt(
 ){
   int rc;
 
+  if( pArg->cMode==MODE_Column
+   || pArg->cMode==MODE_Table
+   || pArg->cMode==MODE_Markdown
+  ){
+    exec_prepared_stmt_columnar(pArg, pStmt);
+    return;
+  }
+
   /* perform the first step.  this will tell us if we
   ** have a result set or not and how wide it is.
   */