]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Implementation of bWrapSnglCol in QRF.
authordrh <>
Sat, 22 Nov 2025 00:38:17 +0000 (00:38 +0000)
committerdrh <>
Sat, 22 Nov 2025 00:38:17 +0000 (00:38 +0000)
FossilOrigin-Name: 4bbd3f7ead50c0babd7843f58972e2e1762a84866cc4ed88a2a74375b13da11c

ext/qrf/qrf.c
manifest
manifest.uuid
src/tclsqlite.c
test/qrf01.test

index eb32424c3de4883d27261ec6cc55cd0a9dee4e4f..07a771242a895d6e4aed15a32c499839a5832e2f 100644 (file)
@@ -1463,12 +1463,126 @@ static void qrfLoadAlignment(qrfColData *pData, Qrf *p){
   }
 }
 
+/*
+** If the single column in pData->a[] with pData->n entries can be
+** laid out as nCol columns with a 2-space gap between each such
+** that all columns fit within nSW, then return a pointer to an array
+** of integers which is the width of each column from left to right.
+**
+** If the layout is not possible, return a NULL pointer.
+**
+** Space to hold the returned array is from sqlite_malloc64().
+*/
+static int *qrfValidLayout(
+  qrfColData *pData,   /* Collected query results */
+  Qrf *p,              /* On which to report an OOM */
+  int nCol,            /* Attempt this many columns */
+  int nSW              /* Screen width */
+){
+  int i;        /* Loop counter */
+  int nr;       /* Number of rows */
+  int w = 0;    /* Width of the current column */
+  int t;        /* Total width of all columns */
+  int *aw;      /* Array of individual column widths */
+
+  aw = sqlite3_malloc64( sizeof(int)*nCol );
+  if( aw==0 ){
+    qrfOom(p);
+    return 0;
+  }
+  nr = (pData->n + nCol - 1)/nCol;
+  for(i=0; i<pData->n; i++){
+    if( (i%nr)==0 ){
+      if( i>0 ) aw[i/nr-1] = w;
+      w = pData->aiWth[i];
+    }else if( pData->aiWth[i]>w ){
+      w = pData->aiWth[i];
+    }
+  }
+  aw[nCol-1] = w;
+  for(t=i=0; i<nCol; i++) t += aw[i];
+  t += 2*(nCol-1);
+  if( t>nSW ){
+    sqlite3_free(aw);
+    return 0;
+  }
+  return aw;
+}
+
 /*
 ** The output is single-column and the bWrapSnglCol flag is set.
 ** Check to see if the single-column output can be split into multiple
 ** columns that appear side-by-side.  Adjust pData appropriately.
 */
 static void qrfWrapSingleColumn(qrfColData *pData, Qrf *p){
+  int nCol = 1;
+  int *aw = 0;
+  char **az = 0;
+  int *aiWth = 0;
+  int nColNext = 2;
+  struct qrfPerCol *a = 0;
+  sqlite3_int64 nRow = 1;
+  sqlite3_int64 i;
+  while( 1/*exit-by-break*/ ){
+    int *awNew = qrfValidLayout(pData, p, nColNext, p->spec.nScreenWidth);
+    if( awNew==0 ) break;
+    sqlite3_free(aw);
+    aw = awNew;
+    nCol = nColNext;
+    nRow = (pData->n + nCol - 1)/nCol;
+    if( nRow==1 ) break;
+    nColNext++;
+    while( (pData->n + nColNext - 1)/nColNext == nRow ) nColNext++;
+  }
+  if( nCol==1 ){
+    sqlite3_free(aw);
+    return;  /* Cannot do better than 1 column */
+  }
+  az = sqlite3_malloc64( nRow*nCol*sizeof(char*) );
+  if( az==0 ){
+    qrfOom(p);
+    return;
+  }
+  aiWth = sqlite3_malloc64( nRow*nCol*sizeof(int) );
+  if( aiWth==0 ){
+    sqlite3_free(az);
+    qrfOom(p);
+    return;
+  }
+  a = sqlite3_malloc64( nCol*sizeof(struct qrfPerCol) );
+  if( a==0 ){
+    sqlite3_free(az);
+    sqlite3_free(aiWth);
+    qrfOom(p);
+    return;
+  }
+  for(i=0; i<pData->n; i++){
+    sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
+    az[j] = pData->az[i];
+    pData->az[i] = 0;
+    aiWth[j] = pData->aiWth[i];
+  }
+  while( i<nRow*nCol ){
+    sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
+    az[j] = sqlite3_mprintf("");
+    if( az[j]==0 ) qrfOom(p);
+    aiWth[j] = 0;
+    i++;
+  }
+  for(i=0; i<nCol; i++){
+    a[i].fx = a[i].mxW = a[i].w = aw[i];
+    a[i].e = pData->a[0].e;
+  }
+  sqlite3_free(pData->az);
+  sqlite3_free(pData->aiWth);
+  sqlite3_free(pData->a);
+  sqlite3_free(aw);
+  pData->az = az;
+  pData->aiWth = aiWth;
+  pData->a = a;
+  pData->nCol = nCol;
+  pData->n = pData->nAlloc = nRow*nCol;
+  pData->nMargin = 2;
 }
 
 /*
@@ -1671,7 +1785,7 @@ static void qrfColumnar(Qrf *p){
   }
 
   if( nColumn==1
-   && p->spec.bWrapSnglCol
+   && p->spec.bWrapSnglCol==QRF_Yes
    && p->spec.eStyle==QRF_STYLE_Column
    && p->spec.bTitles==QRF_No
    && p->spec.nScreenWidth>data.a[0].w+3
@@ -1680,6 +1794,7 @@ static void qrfColumnar(Qrf *p){
     ** verticle wrapping, if the screen is wide enough and if the
     ** bWrapSnglCol flag is set. */
     qrfWrapSingleColumn(&data, p);
+    nColumn = data.nCol;
   }else{
     /* Adjust the column widths due to screen width restrictions */
     qrfRestrictScreenWidth(&data, p);
@@ -1756,7 +1871,9 @@ static void qrfColumnar(Qrf *p){
         nWS = data.a[j].w - nWide;
         qrfPrintAligned(p->pOut, data.a[j].z, nThis, nWS, data.a[j].e);
         data.a[j].z += iNext;
-        if( data.a[j].z[0]!=0 ) bMore = 1;
+        if( data.a[j].z[0]!=0 ){
+          bMore = 1;
+        }
         if( j<nColumn-1 ){
           sqlite3_str_append(p->pOut, colSep, szColSep);
         }else{
index 0f09f6e0ed43027c855148211946fdf87bf35483..a0e22d8444995a1eac2b640ba5bcb181b7e32dcf 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sbWrapSnglCol\sflag\sto\sthe\sQRF\sspec,\sthough\sit\sis\snot\syet\sdocumented\nand\sdoes\snot\syet\swork.\s\sFix\scolumn\soutput\sso\sthat\sit\somits\strailing\sspace.
-D 2025-11-21T20:10:12.657
+C Implementation\sof\sbWrapSnglCol\sin\sQRF.
+D 2025-11-22T00:38:17.646
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -417,7 +417,7 @@ F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6
 F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c
 F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
 F ext/qrf/README.md dd565fd1ca0c46ea37dbf4d496e368b9ecade768c92669640bc106e039629016
-F ext/qrf/qrf.c 33379ad5044ba63729b204889fd6e59948ed5e80eb3037710d98f146907c4262
+F ext/qrf/qrf.c f388bd56d8f9804511fa0b3d704cca648084d05f716525f48fdaea8be761d7c7
 F ext/qrf/qrf.h 116f9d7847c04f6377d40cd22dd2b1c6a1336a26201dfe6d69b1d58ec41d02e7
 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
@@ -743,7 +743,7 @@ F src/sqliteInt.h a89c3a9296928dffcb4c287df176a739f9cf620c7c9d33aec59e8efb9b39cb
 F src/sqliteLimit.h 0a5516b4ec192a205c541e05f67009028a9451dc6678aae4cf8e68596903c246
 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c 381384fbe3cf342115f9ad01208fa81092e9a2156a4ea4d44de87852b8df3a8a
+F src/tclsqlite.c caceb8b872d414479a1df3715e565bc9a486cb5763dcf639ad4ff84550d19dc4
 F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
 F src/test1.c 0e71fbcb484a271564e98e0158192c28c24f5521594218c3ba48bcb4cf634f91
 F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
@@ -1509,7 +1509,7 @@ F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224c
 F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
 F test/pushdown.test 46a626ef1c0ca79b85296ff2e078b9da20a50e9b804b38f441590c3987580ddd
-F test/qrf01.test e76be7da90e9c40010fd08336461c4fdc9825875167ee17170442c1e23631342
+F test/qrf01.test 92334aaf93e0b96dbb117c9592f2ec7385e9077e65db16a175ec352f4d754ef3
 F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
 F test/qrf03.test 9de53aea459f5a127283db03cbb6011500757685646d21aa3c29c44c6ef23e86
 F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
@@ -2178,8 +2178,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 04394387e626cd99ff98df978c4b7f2d32f65760e0c26e53f1ef4f59e4e91a4f
-R c2811c2ce4ec10183543473b397451a5
+P a858027fc92727c680b7e984303df7f9e0a2d90c860c547176f290b113a69390
+R a51fa5dfb24a3bcee8421313d1d3bb87
 U drh
-Z 7925dda900ed8e83a9a5d4713fd7d290
+Z a16fb45a4bab603e7bb9dd853cb499d3
 # Remove this line to create a well-formed Fossil manifest.
index 706bb90ab349ad74df035b0f0635bcc2b678c986..e18dea149d06f68b055201e565f1e41cbed10431 100644 (file)
@@ -1 +1 @@
-a858027fc92727c680b7e984303df7f9e0a2d90c860c547176f290b113a69390
+4bbd3f7ead50c0babd7843f58972e2e1762a84866cc4ed88a2a74375b13da11c
index 4076e0dc09f930a3a2448b1f30270f102b4ff2b2..036de64f6e05946231b81383ba6927a05768c580 100644 (file)
@@ -2063,6 +2063,7 @@ static void DbHookCmd(
 **     -wordwrap ("auto"|"off"|"on")           Try to wrap at word boundry?
 **     -textjsonb ("auto"|"off"|"on")          Auto-convert JSONB to text?
 **     -textnull ("auto"|"off"|"on")           Use text encoding for -null.
+**     -wrapsnglcol ("auto"|"off"|"on")        Enable wrap-single-column
 **     -defaultalign ("auto"|"left"|...)       Default alignment
 **     -titalalign ("auto"|"left"|"right"|...) Default column name alignment
 **     -wrap NUMBER                            Max width of any single column
@@ -2089,6 +2090,7 @@ static void DbHookCmd(
 **     -wordwrap         bWordWrap
 **     -textjsonb        bTextJsonb
 **     -textnull         bTestNull
+**     -wrapsnglcol      bWrapSnglCol
 **     -defaultalign     eDfltAlign
 **     -titlealign       eTitleAlign
 **     -wrap             nWrap
@@ -2236,15 +2238,20 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
       if( rc ) goto format_failed;
       qrf.bWordWrap = aBoolMap[v];
       i++;
-    }else if( strcmp(zArg,"-textjsonb")==0 || strcmp(zArg,"-textnull")==0 ){
+    }else if( strcmp(zArg,"-textjsonb")==0
+           || strcmp(zArg,"-textnull")==0
+           || strcmp(zArg,"-wrapsnglcol")==0
+    ){
       int v = 0;
       rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool,
                               zArg, 0, &v);
       if( rc ) goto format_failed;
       if( zArg[5]=='j' ){
         qrf.bTextJsonb = aBoolMap[v];
-      }else{
+      }else if( zArg[5]=='n' ){
         qrf.bTextNull = aBoolMap[v];
+      }else{
+        qrf.bWrapSnglCol = aBoolMap[v];
       }
       i++;
     }else if( strcmp(zArg,"-defaultalign")==0 || strcmp(zArg,"-titlealign")==0){
index 4bba0fe9d44e87f3e6dbecfd2a74d511528a526b..81f1fc3a0503a741e0ac27f2d7b6d0621b603162 100644 (file)
@@ -895,6 +895,100 @@ do_test 9.4 {
   db format -style jobject  {SELECT * FROM t9 WHERE rowid<0}
 } {}
 
+do_test 10.1 {
+  db eval {
+    DROP TABLE IF EXISTS t1;
+    CREATE TABLE t1(x);
+    INSERT INTO t1(x) VALUES
+      ('alice'),
+      ('bob'),
+      ('cinderella-cinderella'),
+      ('daniel'),
+      ('emma'),
+      ('fred'),
+      ('gertrude'),
+      ('harold'),
+      ('ingrid'),
+      ('jake'),
+      ('lisa'),
+      ('mike'),
+      ('nina'),
+      ('octavian'),
+      ('paula'),
+      ('quintus'),
+      ('rita'),
+      ('sam'),
+      ('tammy'),
+      ('ulysses'),
+      ('violet'),
+      ('william'),
+      ('xanthippe'),
+      ('yates'),
+      ('zoe');
+  }
+  set result "\n[db format -style column -title off -screenwidth 41 -wrapsnglcol on \
+                    {SELECT x FROM t1}]"
+} {
+alice                  octavian
+bob                    paula
+cinderella-cinderella  quintus
+daniel                 rita
+emma                   sam
+fred                   tammy
+gertrude               ulysses
+harold                 violet
+ingrid                 william
+jake                   xanthippe
+lisa                   yates
+mike                   zoe
+nina
+}
+do_test 10.2 {
+  set result "\n[db format -style column -title off -screenwidth 42 -wrapsnglcol on \
+                    {SELECT x FROM t1}]"
+} {
+alice                  jake      tammy
+bob                    lisa      ulysses
+cinderella-cinderella  mike      violet
+daniel                 nina      william
+emma                   octavian  xanthippe
+fred                   paula     yates
+gertrude               quintus   zoe
+harold                 rita
+ingrid                 sam
+}
+do_test 10.3 {
+  set result "\n[db format -style column -title off -screenwidth 51 -wrapsnglcol on \
+                    {SELECT x FROM t1}]"
+} {
+alice                  harold    paula    william
+bob                    ingrid    quintus  xanthippe
+cinderella-cinderella  jake      rita     yates
+daniel                 lisa      sam      zoe
+emma                   mike      tammy
+fred                   nina      ulysses
+gertrude               octavian  violet
+}
+do_test 10.4 {
+  set result "\n[db format -style column -title off -screenwidth 61 -wrapsnglcol on \
+                    {SELECT x FROM t1}]"
+} {
+alice                  fred      lisa      quintus  violet
+bob                    gertrude  mike      rita     william
+cinderella-cinderella  harold    nina      sam      xanthippe
+daniel                 ingrid    octavian  tammy    yates
+emma                   jake      paula     ulysses  zoe
+}
+do_test 10.5 {
+  set result "\n[db format -style column -title off -screenwidth 74 -wrapsnglcol on \
+                    {SELECT x FROM t1}]"
+} {
+alice                  emma      ingrid  nina      rita     violet     zoe
+bob                    fred      jake    octavian  sam      william
+cinderella-cinderella  gertrude  lisa    paula     tammy    xanthippe
+daniel                 harold    mike    quintus   ulysses  yates
+}
+
 db close
 
 finish_test