]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
CLI: For columnar modes ("box", "column", "table", "markdown") the ".width"
authordrh <>
Sun, 30 Jan 2022 21:09:03 +0000 (21:09 +0000)
committerdrh <>
Sun, 30 Jan 2022 21:09:03 +0000 (21:09 +0000)
is now both the minimum and maximum width of the column.  Text that spans
multiple lines or that contains tabs is properly formatted.  If any part of
the output contains multi-line text, then extra separators are provided between
each row.

FossilOrigin-Name: c10ed4a7fe33fd9330967ab714b1f09ad57c972997160dfc71477e43b905f69c

manifest
manifest.uuid
src/shell.c.in

index e41788870fa8e0bccec0a812602657c6702ea7b7..af137deae4813147f204901adbb4d9181bf8b533 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Always\senable\sall\sJSON\stests,\snow\sthat\sJSON\sis\sincluded\sby\sdefault.
-D 2022-01-30T11:44:17.962
+C CLI:\sFor\scolumnar\smodes\s("box",\s"column",\s"table",\s"markdown")\sthe\s".width"\nis\snow\sboth\sthe\sminimum\sand\smaximum\swidth\sof\sthe\scolumn.\s\sText\sthat\sspans\nmultiple\slines\sor\sthat\scontains\stabs\sis\sproperly\sformatted.\s\sIf\sany\spart\sof\nthe\soutput\scontains\smulti-line\stext,\sthen\sextra\sseparators\sare\sprovided\sbetween\neach\srow.
+D 2022-01-30T21:09:03.044
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -553,7 +553,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c a6d2d4bed279d7fe4fcedaf297eaf6441e8e17c6e3947a32d24d23be52ac02f2
-F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2
+F src/shell.c.in b33ead0e7e22264d229ed7a5aa61a65c4564fd4ef21ff0321ff7b6f02ccf6c9b
 F src/sqlite.h.in eaade58049152dac850d57415bcced885ca27ae9582f8aea2cfb7f1db78a521b
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
@@ -1942,8 +1942,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P d4e402458dd4cadb623a30158eb9ff5f24f011240b3b1bc5b1d6ae3c5b855892
-R c6388bc98f6a84d7097f143004850d0c
+P 8c9f350182140604a71e11d226acb3f80d1f2b4f75e5c3b55ec8f8a7c02941f3
+R 22a2c9cbde362213afbf92ae8fdaba40
 U drh
-Z 103c157b43e90dd4721cb0f6fef6c37e
+Z 0aba3faa9f23b01df6c28283e34cf7d3
 # Remove this line to create a well-formed Fossil manifest.
index 5316c2c8e7ecb98f27f8de852fc7398bd9321eb3..39dcc4d130e7ecdd3c0535f8a8543fb49dd674d4 100644 (file)
@@ -1 +1 @@
-8c9f350182140604a71e11d226acb3f80d1f2b4f75e5c3b55ec8f8a7c02941f3
\ No newline at end of file
+c10ed4a7fe33fd9330967ab714b1f09ad57c972997160dfc71477e43b905f69c
\ No newline at end of file
index 0a903672cc32f7ecbc54a63a2ec3cabadb1167ec..7e1f504a95f8cb1108f169df4caa4346768b1966 100644 (file)
@@ -3164,6 +3164,75 @@ static void print_box_row_separator(
   fputs("\n", p->out);
 }
 
+/*
+** z[] is a line of text that is to be displayed the .mode box or table or
+** similar tabular formats.  z[] might contain control characters such
+** as \n, \t, \f, or \r.
+**
+** Compute characters to display on the first line of z[].  Stop at the
+** first \r, \n, or \f.  Expand \t into spaces.  Return a copy (obtained
+** from malloc()) of that first line.  Write anything to display
+** on the next line into *pzTail.  If this is the last line, write a NULL
+** into *pzTail.
+*/
+static char *translateForDisplayAndDup(
+  const unsigned char *z,
+  const unsigned char **pzTail,
+  int mxWidth
+){
+  int i, n;
+  unsigned char *zOut;
+  if( z==0 ){
+    *pzTail = 0;
+    return 0;
+  }
+  if( mxWidth<0 ) mxWidth = -mxWidth;
+  if( mxWidth==0 ) mxWidth = 1000000;
+  i = n = 0;
+  while( n<mxWidth ){
+    if( z[i]>=' ' ){
+      n++;
+      i++;
+      continue;
+    }
+    if( z[i]=='\t' ){
+      n += 8;
+      n &= ~7;
+      i++;
+      continue;
+    }
+    break;
+  }
+  if( n>=mxWidth && z[i]>=' ' ){
+   *pzTail = &z[i];
+  }else if( z[i]=='\r' && z[i+1]=='\n' ){
+    *pzTail = z[i+2] ? &z[i+2] : 0;
+  }else if( z[i]==0 ){
+    *pzTail = 0;
+  }else{
+    *pzTail = &z[i+1];
+  }
+  zOut = malloc( n+1 );
+  shell_check_oom(zOut);
+  i = n = 0;
+  while( n<mxWidth ){
+    if( z[i]>=' ' ){
+      zOut[n++] = z[i++];
+      continue;
+    }
+    if( z[i]=='\t' ){
+      do{
+        zOut[n++] = ' ';
+      }while( (n&7)!=0 && n<mxWidth );
+      i++;
+      continue;
+    }
+    break;
+  }
+  zOut[n] = 0;
+  return (char*)zOut;  
+}
+
 
 
 /*
@@ -3184,12 +3253,17 @@ static void exec_prepared_stmt_columnar(
   int nColumn = 0;
   char **azData = 0;
   sqlite3_int64 nAlloc = 0;
+  char *abRowDiv = 0;
+  const unsigned char *uz;
   const char *z;
   int rc;
   sqlite3_int64 i, nData;
   int j, nTotal, w, n;
   const char *colSep = 0;
   const char *rowSep = 0;
+  const unsigned char **azNextLine = 0;
+  int bNextLine = 0;
+  int bMultiLineRowExists = 0;
 
   rc = sqlite3_step(pStmt);
   if( rc!=SQLITE_ROW ) return;
@@ -3198,21 +3272,11 @@ static void exec_prepared_stmt_columnar(
   if( nAlloc<=0 ) nAlloc = 1;
   azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
   shell_check_oom(azData);
-  for(i=0; i<nColumn; i++){
-    azData[i] = strdup(sqlite3_column_name(pStmt,i));
-  }
-  do{
-    if( (nRow+2)*nColumn >= nAlloc ){
-      nAlloc *= 2;
-      azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
-      shell_check_oom(azData);
-    }
-    nRow++;
-    for(i=0; i<nColumn; i++){
-      z = (const char*)sqlite3_column_text(pStmt,i);
-      azData[nRow*nColumn + i] = z ? strdup(z) : 0;
-    }
-  }while( sqlite3_step(pStmt)==SQLITE_ROW );
+  azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
+  shell_check_oom(azNextLine);
+  memset(azNextLine, 0, nColumn*sizeof(char*) );
+  abRowDiv = sqlite3_malloc64( nAlloc/nColumn );
+  shell_check_oom(abRowDiv);
   if( nColumn>p->nWidth ){
     p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int));
     shell_check_oom(p->colWidth);
@@ -3226,6 +3290,36 @@ static void exec_prepared_stmt_columnar(
     if( w<0 ) w = -w;
     p->actualWidth[i] = w;
   }
+  for(i=0; i<nColumn; i++){
+    azData[i] = strdup(sqlite3_column_name(pStmt,i));
+  }
+  do{
+    int useNextLine = bNextLine;
+    bNextLine = 0;
+    if( (nRow+2)*nColumn >= nAlloc ){
+      nAlloc *= 2;
+      azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
+      shell_check_oom(azData);
+      abRowDiv = sqlite3_realloc64(abRowDiv, nAlloc/nColumn);
+      shell_check_oom(abRowDiv);
+    }
+    abRowDiv[nRow] = 1;
+    nRow++;
+    for(i=0; i<nColumn; i++){
+      if( useNextLine ){
+        uz = azNextLine[i];
+      }else{
+        uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
+      }
+      azData[nRow*nColumn + i] =
+         translateForDisplayAndDup(uz, &azNextLine[i], p->colWidth[i]);
+      if( azNextLine[i] ){
+        bNextLine = 1;
+        abRowDiv[nRow-1] = 0;
+        bMultiLineRowExists = 1;
+      }
+    }
+  }while( bNextLine || sqlite3_step(pStmt)==SQLITE_ROW );
   nTotal = nColumn*(nRow+1);
   for(i=0; i<nTotal; i++){
     z = azData[i];
@@ -3308,6 +3402,13 @@ static void exec_prepared_stmt_columnar(
     utf8_width_print(p->out, w, z);
     if( j==nColumn-1 ){
       utf8_printf(p->out, "%s", rowSep);
+      if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
+        if( p->cMode==MODE_Table ){
+          print_row_separator(p, nColumn, "+");
+        }else if( p->cMode==MODE_Box ){
+          print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
+        }
+      }
       j = -1;
       if( seenInterrupt ) goto columnar_end;
     }else{
@@ -3326,6 +3427,8 @@ columnar_end:
   nData = (nRow+1)*nColumn;
   for(i=0; i<nData; i++) free(azData[i]);
   sqlite3_free(azData);
+  sqlite3_free(azNextLine);
+  sqlite3_free(abRowDiv);
 }
 
 /*