]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The -textjsonb option is on by default in the standard non-batch mode of
authordrh <>
Mon, 17 Nov 2025 18:51:55 +0000 (18:51 +0000)
committerdrh <>
Mon, 17 Nov 2025 18:51:55 +0000 (18:51 +0000)
the CLI.  New fast screening test for JSONB.

FossilOrigin-Name: fd09f934d64ec07fd56f1b80ab05dafb28b605d5802ff5758eea17d8ad24e3cc

ext/qrf/qrf.c
manifest
manifest.uuid
src/shell.c.in
test/qrf01.test
test/shell1.test

index fdee93a86f0d08920ec40d49855a28908e185b3d..317a760e36e9f6b0b99b6905c65312befde872b8 100644 (file)
@@ -813,10 +813,33 @@ static void qrfEncodeText(Qrf *p, sqlite3_str *pOut, const char *zTxt){
   }
 }
 
+/*
+** Do a quick sanity check to see aBlob[0..nBlob-1] is valid JSONB
+** return true if it is and false if it is not.
+**
+** False positives are possible, but not false negatives.
+*/
+static int qrfJsonbQuickCheck(unsigned char *aBlob, int nBlob){
+  unsigned char x;   /* Payload size half-byte */
+  int i;             /* Loop counter */   
+  int n;             /* Bytes in the payload size integer */
+  sqlite3_uint64 sz; /* value of the payload size integer */
+
+  if( nBlob==0 ) return 0;
+  x = aBlob[0]>>4;
+  if( x<=11 ) return nBlob==(1+x);
+  n = x<14 ? x-11 : 4*(x-13);
+  if( nBlob<1+n ) return 0;
+  sz = aBlob[1];
+  for(i=1; i<n; i++) sz = (sz<<8) + aBlob[i+1];
+  return sz+n+1==(sqlite3_uint64)nBlob;
+}
+
 /*
 ** The current iCol-th column of p->pStmt is known to be a BLOB.  Check
 ** to see if that BLOB is really a JSONB blob.  If it is, then translate
 ** it into a text JSON representation and return a pointer to that text JSON.
+** If the BLOB is not JSONB, then return a NULL pointer.
 **
 ** The memory used to hold the JSON text is managed internally by the
 ** "p" object and is overwritten and/or deallocated upon the next call
@@ -827,6 +850,11 @@ static const char *qrfJsonbToJson(Qrf *p, int iCol){
   int nByte;
   const void *pBlob;
   int rc;
+  nByte = sqlite3_column_bytes(p->pStmt, iCol);
+  pBlob = sqlite3_column_blob(p->pStmt, iCol);
+  if( qrfJsonbQuickCheck((unsigned char*)pBlob, nByte)==0 ){
+    return 0;
+  }
   if( p->pJTrans==0 ){
     sqlite3 *db;
     rc = sqlite3_open(":memory:",&db);
@@ -844,8 +872,6 @@ static const char *qrfJsonbToJson(Qrf *p, int iCol){
   }else{
     sqlite3_reset(p->pJTrans);
   }
-  nByte = sqlite3_column_bytes(p->pStmt, iCol);
-  pBlob = sqlite3_column_blob(p->pStmt, iCol);
   sqlite3_bind_blob(p->pJTrans, 1, (void*)pBlob, nByte, SQLITE_STATIC);
   rc = sqlite3_step(p->pJTrans);
   if( rc==SQLITE_ROW ){
@@ -888,7 +914,13 @@ static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){
       if( p->spec.bTextJsonb==QRF_Yes ){
         const char *zJson = qrfJsonbToJson(p, iCol);
         if( zJson ){
-          qrfEncodeText(p, pOut, zJson);
+          if( p->spec.eText==QRF_TEXT_Sql ){
+            sqlite3_str_append(pOut,"jsonb(",6);
+            qrfEncodeText(p, pOut, zJson);
+            sqlite3_str_append(pOut,")",1);
+          }else{
+            qrfEncodeText(p, pOut, zJson);
+          }
           break;
         }
       }
index 6dc92154c262cc8a89a53f27280a3b96fef636be..52da629ca532e7bcd02adea44c74b287410f5d0f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C CLI\scomes\sup\sin\slegacy\s"list"\smode\sif\sneither\sstdin\sor\sstdout\sare\sa\stty,\sor\nif\s"--compat\s20251114"\sor\searlier\sis\sspecified,\sor\sif\s"--batch"\sis\sused.\nNew\smodes\s"batch"\sand\s"tty"\sselect\seither\slegacy\s"list"\smode\sor\sthe\snewer\n"qbox"\smode\swith\slimits.\nMake\sCVS\soutput\scompatible\swith\slegacy.\s\sBreak\sout\s".import"\sinto\sa\sseparate\nsubroutine\sin\santicipation\sof\sforthcoming\simprovements.\s\sGeneral\scode\ncleanup.
-D 2025-11-17T16:44:13.271
+C The\s-textjsonb\soption\sis\son\sby\sdefault\sin\sthe\sstandard\snon-batch\smode\sof\nthe\sCLI.\s\sNew\sfast\sscreening\stest\sfor\sJSONB.
+D 2025-11-17T18:51:55.138
 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 b62a16a4d380223c6fe90ae28c33aa27b44af128a2e1e39c496d3452ac6ae14f
+F ext/qrf/qrf.c ee3964addf075c87fc60e312a472eec35112ba34581edf655fcd5c34e2492602
 F ext/qrf/qrf.h b4b3489b3b3683523fd248d15cf5945830643b036943efacdb772a3e00367aa2
 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
@@ -735,7 +735,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c ba9cd07ffa3277883c1986085f6ddc4320f4d35d5f212ab58df79a7ecc1a576a
-F src/shell.c.in 4cae6e0560037d4916f2819e3ca576e71e4a40adee9fc273f320cd28644e99c6
+F src/shell.c.in b5e82438ea3c5d30a425335180e1660dcccaf6cc64f8beec97b8fe6a5fb47da5
 F src/sqlite.h.in 795ce84cc136b4e74d882cf4fab56d2927c20b9af9fd2fcea27760a6fe50851b
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
@@ -1507,7 +1507,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 1caa611b69e07c6c134c3749f633ef014a97640b8f57f03c8fc0ca4d064b6dd2
+F test/qrf01.test dfdbbd2b5f2808f5ff6598c8632ee002389b690eb5016450c2f847d8e51b9b92
 F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
 F test/qrf03.test 9d88aeb5cdd53f050b7ab9bd203281f7c9d063c33f22f8808e441b7ac0874ccf
 F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
@@ -1603,7 +1603,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
 F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
 F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test b88af002858e1923f90fccf07f841d853e8fba568cecf38efd29f5172c661735
+F test/shell1.test 8fbb73650b685766cdf4b5e8b5d12dee72664f44195eeb788d0f52fce08e04eb
 F test/shell2.test 103140814bdc7508aa41dd3462413cbc4aa84b4261112cb8d501d74275cb7d48
 F test/shell3.test 840192774cc4edf7653520c0434a311c7477b9bc324abbc7bd2887915792fa8c
 F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
@@ -2176,8 +2176,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 8fc05faef91186429c6c710991fd736b1df9a9af946c29d207db2518d6436b38
-R bb02fe9715521dfd12626a15ebffae99
+P f6bfcea9a01493af182e9aa0d35df6f81bf9e36220df79139afa287fa43d9aa3
+R b7a01a16064bbc5b3a06e1b50d74bad2
 U drh
-Z 405f1a2cbb60052057d2e27df0bf6378
+Z a61739906e608ff5d320a84e1182df9a
 # Remove this line to create a well-formed Fossil manifest.
index 437b001ca5906d62193aaac822b921a9584a88a2..71bb9cafa42ec2cde5db53b1cf875165369a48e9 100644 (file)
@@ -1 +1 @@
-f6bfcea9a01493af182e9aa0d35df6f81bf9e36220df79139afa287fa43d9aa3
+fd09f934d64ec07fd56f1b80ab05dafb28b605d5802ff5758eea17d8ad24e3cc
index 0453c1bd00a64ad162148a1b12ba69e9c5dddd47..c823b6dc094c32e179fca3ac131dba50debf807e 100644 (file)
@@ -1625,6 +1625,7 @@ static void modeChange(ShellState *p, unsigned char eMode){
     p->mode.bAutoScreenWidth = 1;
     p->mode.spec.nCharLimit = 300;
     p->mode.spec.nLineLimit = 5;
+    p->mode.spec.bTextJsonb = QRF_Yes;
     p->mode.mFlags = mFlags;
   }
 }
index c79a32defec9f5511520956432852cbdc2053bb1..431f51f51ae5e783095cd30a4fdc8f84fd1bf241 100644 (file)
@@ -536,11 +536,11 @@ do_test 4.1 {
 do_test 4.2 {
   set result "\n[db format -text sql -textjsonb on {SELECT * FROM t1}]"
 } {
-┌─────────────────┬─────────────────┬────┐
-│        a        │        b        │ c  │
-├─────────────────┼─────────────────┼────┤
-│ '{"a":5,"b":6}' │ '{"c":1,"d":2}' │ 99 │
-└─────────────────┴─────────────────┴────┘
\94\8câ\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94¬â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94¬â\94\80â\94\80â\94\80â\94\80â\94\90
+│        a        │           b            │ c  │
\94\9câ\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94¼â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94¼â\94\80â\94\80â\94\80â\94\80â\94¤
+│ '{"a":5,"b":6}' │ jsonb('{"c":1,"d":2}') │ 99 │
\94\94â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94´â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94\80â\94´â\94\80â\94\80â\94\80â\94\80â\94\98
 }
 do_test 4.3 {
   set result "\n[db format -text plain -textjsonb on -wrap 11 \
@@ -871,4 +871,23 @@ do_test 8.4 {
 +-----+----+--------------------+
 }
 
+do_test 9.1 {
+  db eval {
+    CREATE TABLE t9(x);
+    INSERT INTO t9 VALUES
+      (x'4331323334'),
+      (x'c30431323334'),
+      (x'd3000431323334'),
+      (x'e30000000431323334'),
+      (x'f3000000000000000431323334');
+  }
+  db format -style list -text plain -rowsep , -textjsonb on \
+               {SELECT * FROM t9}
+} {1234,1234,1234,1234,1234,}
+do_test 9.2 {
+  db format -style list -text sql -rowsep , -textjsonb on \
+               {SELECT * FROM t9}
+} {jsonb('1234'),jsonb('1234'),jsonb('1234'),jsonb('1234'),jsonb('1234'),}
+db close
+
 finish_test
index 1a502336c3dbde961660392f9237a6f80b1cd088..2ff218f4d59ef96cca02dafd181b4fb744089e5a 100644 (file)
@@ -1378,4 +1378,30 @@ select base85(zeroblob(2000000000));
 }
 } {/1.*too big.*/}
 
+#----------------------------------------------------------------------------
+# As of 2025-11-17, the default mode is:
+#
+#     qbox --screenwidth auto --linelimit 5 --charlimit 300 --textjsonb on
+#
+do_test shell1-12.1 {
+  catchcmd :memory: {.mode tty
+.print
+SELECT jsonb(1234) AS x;}
+} {0 {
+┌───────────────┐
+│       x       │
+├───────────────┤
+│ jsonb('1234') │
+└───────────────┘}}
+do_test shell1-12.2 {
+  catchcmd :memory: {.mode box --textjsonb on
+.print
+SELECT jsonb(1234) AS x;}
+} {0 {
+┌──────┐
+│  x   │
+├──────┤
+│ 1234 │
+└──────┘}}
+
 finish_test