]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
New text rendering style of QRF_TEXT_Relaxed.
authordrh <>
Sat, 6 Dec 2025 10:07:15 +0000 (10:07 +0000)
committerdrh <>
Sat, 6 Dec 2025 10:07:15 +0000 (10:07 +0000)
FossilOrigin-Name: d2049bffe6674b8840663b0e5f404a040b715640c87f022517cf11546548fda3

ext/qrf/README.md
ext/qrf/qrf.c
ext/qrf/qrf.h
manifest
manifest.uuid
src/shell.c.in
src/tclsqlite.c

index 397c0820768c97aaafd5a925a1f5020c858078a1..067eeeed5ae99297f8c5f1096b43171f60e20dac 100644 (file)
@@ -254,6 +254,7 @@ Both fields can have one of the following values:
 #define QRF_TEXT_Html    4 /* HTML-style quoting */
 #define QRF_TEXT_Tcl     5 /* C/Tcl quoting */
 #define QRF_TEXT_Json    6 /* JSON quoting */
+#define QRF_TEXT_Relaxed 7 /* Relaxed SQL quoting */
 ~~~
 
 A value of QRF_TEXT_Auto means that the query result formatter will choose
@@ -267,6 +268,14 @@ look like SQL literals.  That means the value will be surrounded by
 single-quotes (U+0027) and any single-quotes contained within the text
 will be doubled.
 
+QRF_TEXT_Relaxed is similar to QRF_TEXT_Sql, except that automatically
+reverts to QRF_TEXT_Plain if the value to be displayed does not contain
+special characters and is not easily confused with a NULL or a numeric
+value.  QRF_TEXT_Relaxed strives to minimize the amount of quoting syntax
+while keeping the result unambiguous and easy for humans to read.  The
+precise rules for when quoting is omitted in QRF_TEXT_Relaxed, and when
+it is applied, might be adjusted in future releases.
+
 A value of QRF_TEXT_Csv means that text values are escaped in accordance
 with RFC&nbsp;4180, which defines Comma-Separated-Value or CSV files.
 Text strings that contain no special values appears as-is.  Text strings
index ddcc2dbf49b0da7570d59b5d75bb2898a03837fa..8c92e6867645a1f976381c6ee1149c3a4c2e423b 100644 (file)
@@ -17,6 +17,7 @@
 #endif
 #include <string.h>
 #include <assert.h>
+#include <ctype.h>
 
 typedef sqlite3_int64 i64;
 
@@ -703,6 +704,45 @@ static void qrfEscape(
   }
 }
 
+/*
+** Determine if the string z[] can be shown as plain text.  Return true
+** if z[] is unambiguously text.  Return false if z[] needs to be
+** quoted.
+**
+** All of the following must be true in order for z[] to be relaxable:
+**
+**    (1) z[] does not begin or end with ' or whitespace
+**    (2) z[] is not the same as the NULL rendering
+**    (3) z[] does not looks like a numeric literal
+*/
+static int qrfRelaxable(Qrf *p, const char *z){
+  size_t i, n;
+  if( z[0]=='\'' || isspace(z[0]) ) return 0;
+  if( z[0]==0 && (p->spec.zNull==0 || p->spec.zNull[0]==0) ) return 0;
+  n = strlen(z);
+  if( z[n-1]=='\'' || isspace(z[n-1]) ) return 0;
+  if( p->spec.zNull && strcmp(p->spec.zNull,z)==0 ) return 0;
+  i = (z[0]=='-' || z[0]=='+');
+  if( strcmp(z+i,"Inf")==0 ) return 0;
+  if( !isdigit(z[i]) ) return 1;
+  i++;
+  while( isdigit(z[i]) ){ i++; }
+  if( z[i]==0 ) return 0;
+  if( z[i]=='.' ){
+    i++;
+    while( isdigit(z[i]) ){ i++; }
+    if( z[i]==0 ) return 0;
+  }
+  if( z[i]=='e' || z[i]=='E' ){
+    i++;
+    if( z[i]=='+' || z[i]=='-' ){ i++; }
+    if( !isdigit(z[i]) ) return 1;
+    i++;
+    while( isdigit(z[i]) ){ i++; }
+  }
+  return z[i]!=0;
+}
+
 /*
 ** If a field contains any character identified by a 1 in the following
 ** array, then the string must be quoted for CSV.
@@ -732,6 +772,13 @@ static const char qrfCsvQuote[] = {
 static void qrfEncodeText(Qrf *p, sqlite3_str *pOut, const char *zTxt){
   int iStart = sqlite3_str_length(pOut);
   switch( p->spec.eText ){
+    case QRF_TEXT_Relaxed: {
+      if( qrfRelaxable(p, zTxt) ){
+        sqlite3_str_appendall(pOut, zTxt);
+        break;
+      }
+      /* Fall through into the SQL case */
+    }
     case QRF_TEXT_Sql: {
       if( p->spec.eEsc==QRF_ESC_Off ){
         sqlite3_str_appendf(pOut, "%Q", zTxt);
@@ -2517,8 +2564,8 @@ static void qrfInitialize(
   if( p->mxHeight<=0 ) p->mxHeight = 2147483647;
   if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto;
   if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto;
-  if( p->spec.eText>QRF_TEXT_Json ) p->spec.eText = QRF_Auto;
-  if( p->spec.eTitle>QRF_TEXT_Json ) p->spec.eTitle = QRF_Auto;
+  if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto;
+  if( p->spec.eTitle>QRF_TEXT_Relaxed ) p->spec.eTitle = QRF_Auto;
   if( p->spec.eBlob>QRF_BLOB_Size ) p->spec.eBlob = QRF_Auto;
 qrf_reinit:
   switch( p->spec.eStyle ){
index 5e28d1e9cd203ff68b230a837da10e3586761044..06ada9abee11902f8dc38655afc70b2c5419e9ab 100644 (file)
@@ -109,6 +109,7 @@ int sqlite3_format_query_result(
 #define QRF_TEXT_Html    4 /* HTML-style quoting */
 #define QRF_TEXT_Tcl     5 /* C/Tcl quoting */
 #define QRF_TEXT_Json    6 /* JSON quoting */
+#define QRF_TEXT_Relaxed 7 /* Relaxed SQL quoting */
 
 /*
 ** Quoting styles for BLOBs
index 1e2ead5d266a448fca8d075ca1810c32d7ecebad..db580e61d912bea4c0b6a9878dc63c8c283d9ebe 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C When\sdrawing\sboxes\susing\sQRF,\suse\srounded\scorners\sand\suse\sa\sdouble-line\sto\nseparate\scolumn\sheaders\sfrom\sthe\scontent.
-D 2025-12-05T22:04:49.269
+C New\stext\srendering\sstyle\sof\sQRF_TEXT_Relaxed.
+D 2025-12-06T10:07:15.670
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -416,10 +416,10 @@ F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f6
 F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
 F ext/misc/zipfile.c 9981cda2f5d08ff01f33c2e4cea82df75f83a4c0fdcbc5dce67e0f775b770fb1
 F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
-F ext/qrf/README.md 86fc5c3c5e3eddbe54fc1235cbdc52b8c2c0732791d224345c3014cd45c4c0e7
+F ext/qrf/README.md fc76ed07e60060ae2832d732193dfe4e5218c685604a905a2dee950eb5269ca3
 F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
-F ext/qrf/qrf.c 639179fcbf6768fa61e5d931121c3f8bdc7cb62e92b9b239b3c6583c4d6ff49e
-F ext/qrf/qrf.h 2cd7bd43579c522d3ae5c16034c7fdf41085684189811ae8e18ebc932a1cc79f
+F ext/qrf/qrf.c 3bf0286cb6ac9afb022a93b7ab2266c2692fa35070573273e796975be5878425
+F ext/qrf/qrf.h 0f0387eb4c56eaa46405cd640132624933377e46df3d2baa940392f9a7d35768
 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
 F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
@@ -737,7 +737,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 8d53771eb51a4ab5f970150c3a70969d8db79cd04a8774c2d296bbcf471a0dd0
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c 344518c1bba9c4636bf651b7642304abd2e7075ba35feb4bae42a51e5efe991f
-F src/shell.c.in a4a05fcc14c5e84867b3a2bb04cc1d53cb924b810ad72976157861a5d5f1a76b
+F src/shell.c.in 09585992a8752390fab97ade0a6136468180ad991fe152b1c140e2aa7283e82f
 F src/sqlite.h.in 706cacea5308b0244fb6cec92e08310fb427a125375c64137cc1f878ae4cf5c0
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
@@ -745,7 +745,7 @@ F src/sqliteInt.h af67bc95fa6b66cd3c7f3d18d2d040ad386e4cbb02965ee318cc721ee9d5fa
 F src/sqliteLimit.h 7e705474d59912388832cc5465edbc0dbb552872e23452812846e90d280987f3
 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c 4b6f6b142b951a8a127e0cbd2e37284fc71f8e6a391ec8c6188fb831b51ec0b8
+F src/tclsqlite.c cf5d43c1549e32804bf8ac1eb2478a695caaee688a7b29e8db1be33206b600b4
 F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
 F src/test1.c 0e71fbcb484a271564e98e0158192c28c24f5521594218c3ba48bcb4cf634f91
 F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
@@ -2184,11 +2184,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 f82376f080ca5cb316b8eb2e48a128b1838eb376b9e903c7af611b398cfe9b1f
-R 875f89180e49565d507ad67ac515a40e
-T *branch * qrf-box-enhancements
-T *sym-qrf-box-enhancements *
-T -sym-trunk *
+P 8c1ca30707c36f074dad29556df4176a74aa573491bb4aad973789aee5ad80da
+R 81b5ef778830cc60943eae42e77827ea
 U drh
-Z ede9962b23f4bc5bbbb7a1e52559a3c0
+Z 8f661d440d11fe3a4df6fb112e8f304a
 # Remove this line to create a well-formed Fossil manifest.
index a184b467505b82b66a686d104bf01fc12b89269a..f9028c0eed0fdd0643b5df75aa2f15a02b333f89 100644 (file)
@@ -1 +1 @@
-8c1ca30707c36f074dad29556df4176a74aa573491bb4aad973789aee5ad80da
+d2049bffe6674b8840663b0e5f404a040b715640c87f022517cf11546548fda3
index 27ed68bd9b10d9c3bd01f1f9f750c93beee4aaf4..824e7bcb2739c123e175b715daf9d735ffb75e3e 100644 (file)
@@ -1386,7 +1386,7 @@ static ShellState shellState;
 */
 static const char *qrfEscNames[] = { "auto", "off", "ascii", "symbol" };
 static const char *qrfQuoteNames[] = 
-      { "off","off","sql","hex","csv","tcl","json"};
+      { "off","off","sql","hex","csv","tcl","json","relaxed"};
 
 /*
 ** These are the allowed shellFlgs values
@@ -7916,9 +7916,10 @@ static int dotCmdMode(ShellState *p){
         if( (k = pickStr(azArg[i],0,"no","yes","0","1",""))>=0 ){
           k &= 1;   /* 0 for "off".  1 for "on". */
         }else{
-          char *zErr = 0;         /*  0     1    2     3     4      5     6 */
-          k = pickStr(azArg[i],&zErr,"off","on","sql","csv","html","tcl","json",
-                                     "");
+          char *zErr = 0;
+          k = pickStr(azArg[i],&zErr,
+                 "off","on","sql","csv","html","tcl","json","relaxed","");
+              /*  0     1    2     3     4      5     6      7   */
           if( k<0 ){
             dotCmdError(p, i, "unknown", "%z", zErr);
             return 1;
@@ -7947,6 +7948,9 @@ static int dotCmdMode(ShellState *p){
         case 6:  /* json */
           p->mode.spec.eText = QRF_TEXT_Json;
           break;
+        case 7:  /* relaxed */
+          p->mode.spec.eText = QRF_TEXT_Relaxed;
+          break;
         default: /* off */
           p->mode.spec.eText = QRF_TEXT_Plain;
           break;
index 147a64745b7f5cb0f1e5213ef65a70d5e9d6295b..3d20c3153a487bb898479e4604c7fc0a44711571 100644 (file)
@@ -2194,12 +2194,12 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
       static const char *azText[] = {           "off",   "on",
         "auto",             "csv",              "html",
         "json",             "plain",            "sql",
-        "tcl",              0
+        "tcl",              "relaxed",          0
       };
       static unsigned char aTextMap[] = {
         QRF_TEXT_Auto,      QRF_TEXT_Csv,       QRF_TEXT_Html,
         QRF_TEXT_Json,      QRF_TEXT_Plain,     QRF_TEXT_Sql,
-        QRF_TEXT_Tcl
+        QRF_TEXT_Tcl,       QRF_TEXT_Relaxed
       };
       int txt;
       int k = zArg[2]=='e';