#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
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 4180, which defines Comma-Separated-Value or CSV files.
Text strings that contain no special values appears as-is. Text strings
#endif
#include <string.h>
#include <assert.h>
+#include <ctype.h>
typedef sqlite3_int64 i64;
}
}
+/*
+** 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.
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);
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 ){
#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
-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
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
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
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
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.
-8c1ca30707c36f074dad29556df4176a74aa573491bb4aad973789aee5ad80da
+d2049bffe6674b8840663b0e5f404a040b715640c87f022517cf11546548fda3
*/
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
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;
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;
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';