]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Separate conversion letters %J and %j. %J includes surrounding quotes and
authordrh <>
Thu, 7 May 2026 08:58:10 +0000 (08:58 +0000)
committerdrh <>
Thu, 7 May 2026 08:58:10 +0000 (08:58 +0000)
%j omits them.  Some test cases added.

FossilOrigin-Name: ea7c2c1a6bd32695fc3a1f2295b4c4719e3d9dd0a8f6480e7c95e17b564c3391

manifest
manifest.uuid
src/printf.c
test/printf.test

index 7e7cfa4a43748e5a0e73b4b31512925a4c902e59..0417ed7e391c0c5cfc97a1f44441f067bc976f66 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Get\sprecision\sworking\son\s%J,\sboth\swith\sand\swith\sthe\s!\sflag.\s\sWidth\sis\nstill\sa\sno-op,\sand\sthere\sare\sno\stest\scases.\s\sIncremental\scheck-in.
-D 2026-05-07T00:02:55.078
+C Separate\sconversion\sletters\s%J\sand\s%j.\s\s%J\sincludes\ssurrounding\squotes\sand\n%j\somits\sthem.\s\sSome\stest\scases\sadded.
+D 2026-05-07T08:58:10.524
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -731,7 +731,7 @@ F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
 F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
 F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d
 F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
-F src/printf.c 335f6f468ed6ff0d42e41fac952ab2e69e44e8134af6834589e922b14e080375
+F src/printf.c 1e6fc3f472d530f3a470ed608fdb65e491bcd47aa89f6398e396248d2b8c6eb8
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c fcc406bfb055bee9954ee77c023f4a2a66a24bcdf1573516a72280811a269c20
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
@@ -1519,7 +1519,7 @@ F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d
 F test/pragma6.test c5ec577ba087954b4dfa619a3cbe97b155b60a0af487527abe89b10fc17e6512
 F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
 F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
-F test/printf.test bcb093ef5cbd17e2d94d93d62045ee61ed0f465c1ca123f284774e474e73a9ea
+F test/printf.test 764be5acb9a05c1e95223be39f63700e08fef6fd2a00b0132367c24575399513
 F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
 F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
@@ -2203,8 +2203,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 7f6b1bae0849f0a840b95ae95aa6fdc6d51b72fdd50493649f584ad7829a3060
-R 64fe79042d670f076fa407257d28ae73
+P 18166bce208c64b7f3afaa88c27a10e0295a89f9c72942dcaa949cf7efb479e6
+R d336b3fe92a34a0f426cd88f8c5f00bf
 U drh
-Z 9ce0686262e45801ba6d31466b72b666
+Z 137464fef3bd5dbf80b7ef72f16e7f25
 # Remove this line to create a well-formed Fossil manifest.
index ae9540d7374b637e9def9f30efb33dc52a7b8210..e6d9304cae1b901574e74821625fc293f1c7623c 100644 (file)
@@ -1 +1 @@
-18166bce208c64b7f3afaa88c27a10e0295a89f9c72942dcaa949cf7efb479e6
+ea7c2c1a6bd32695fc3a1f2295b4c4719e3d9dd0a8f6480e7c95e17b564c3391
index ccb067dcee0103b96ab25078954678407b7baa1d..32105d6ecf589bebc7c5a01d3f0529264a5e8e29 100644 (file)
 #define etESCAPE_w    14 /* %w -> Strings with '\"' doubled */
 #define etORDINAL     15 /* %r -> 1st, 2nd, 3rd, 4th, etc.  English only */
 #define etDECIMAL     16 /* %d or %u, but not %x, %o */
-#define etJSONSTR     17 /* %J -> generate a JSON string literal */
+#define etESCAPE_j    17 /* %j -> JSON string literal w/o "..." */
+#define etESCAPE_J    18 /* %J -> JSON string literal with "..." */
 
-#define etINVALID     18 /* Any unrecognized conversion type */
+#define etINVALID     19 /* Any unrecognized conversion type */
 
 
 /*
@@ -66,20 +67,20 @@ typedef struct et_info {   /* Information about each format field */
 
 /*
 ** The table is searched by hash.  In the case of %C where C is the character
-** and that character has ASCII value j, then the hash is j%24.
+** and that character has ASCII value j, then the hash is j%25.
 **
 ** The order of the entries in fmtinfo[] and the hash chain was entered
 ** manually, but based on the output of the following TCL script:
 */
 #if 0  /*****  Beginning of script ******/
-foreach c {d s g z q Q w c o u x X f e E G i n % p T S r J} {
+foreach c {d s g z q Q w c o u x X f e E G i n % p T S r J j} {
   scan $c %c x
   set n($c) $x
 }
 set mx [llength [array names n]]
 puts "count: $mx"
 
-set mx 27
+set mx 25
 puts "*********** mx=$mx ************"
 for {set r 0} {$r<$mx} {incr r} {
   puts -nonewline [format %2d: $r]
@@ -93,31 +94,32 @@ for {set r 0} {$r<$mx} {incr r} {
 static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
 static const char aHex[]    = "0123456789abcdef";
 static const char aPrefix[] = "-x0\000X0";
-static const et_info fmtinfo[24] = {
-  /*  0 */  {  'x', 16, 0, etRADIX,      16, 1,  0 },
-  /*  1 */  {  'J',  0, 0, etJSONSTR,    0,  0,  0 },  /* Hash: 2 */
-  /*  2 */  {  'z',  0, 4, etDYNSTRING,  0,  0,  1 },
-  /*  3 */  {  'c',  0, 0, etCHARX,      0,  0,  0 },
-  /*  4 */  {  'd', 10, 1, etDECIMAL,    0,  0,  0 },
-  /*  5 */  {  'e',  0, 1, etEXP,        30, 0,  0 },
-  /*  6 */  {  'f',  0, 1, etFLOAT,      0,  0,  0 },
-  /*  7 */  {  'g',  0, 1, etGENERIC,    30, 0,  0 },
-  /*  8 */  {  'i', 10, 1, etDECIMAL,    0,  0,  0 },  /* Hash: 9 */
-  /*  9 */  {  'Q',  0, 4, etESCAPE_Q,   0,  0,  8 },
-  /* 10 */  {  'X', 16, 0, etRADIX,      0,  4,  0 },  /* Hash: 16 */
-  /* 11 */  {  'S',  0, 0, etSRCITEM,    0,  0,  0 },
-  /* 12 */  {  'T',  0, 0, etTOKEN,      0,  0,  0 },
-  /* 13 */  {  '%',  0, 0, etPERCENT,    0,  0,  0 },
-  /* 14 */  {  'n',  0, 0, etSIZE,       0,  0,  0 },
-  /* 15 */  {  'o',  8, 0, etRADIX,      0,  2,  0 },
-  /* 16 */  {  'p', 16, 0, etPOINTER,    0,  1, 10 },
-  /* 17 */  {  'q',  0, 4, etESCAPE_q,   0,  0,  0 },
-  /* 18 */  {  'r', 10, 1, etORDINAL,    0,  0,  0 },
-  /* 19 */  {  's',  0, 4, etSTRING,     0,  0,  0 },
-  /* 20 */  {  'E',  0, 1, etEXP,        14, 0,  0 },  /* Hash: 21 */
-  /* 21 */  {  'u', 10, 0, etDECIMAL,    0,  0, 20 },
-  /* 22 */  {  'G',  0, 1, etGENERIC,    14, 0,  0 },  /* Hash: 23 */
-  /* 23 */  {  'w',  0, 4, etESCAPE_w,   0,  0, 22 }
+static const et_info fmtinfo[25] = {
+  /*  0 */  {  'd', 10, 1, etDECIMAL,    0,  0,  0 },
+  /*  1 */  {  'e',  0, 1, etEXP,        30, 0,  0 },
+  /*  2 */  {  'f',  0, 1, etFLOAT,      0,  0,  0 },
+  /*  3 */  {  'g',  0, 1, etGENERIC,    30, 0,  0 },
+  /*  4 */  {  'j',  0, 0, etESCAPE_j,   0,  0,  0 },  /* Hash: 6 */
+  /*  5 */  {  'i', 10, 1, etDECIMAL,    0,  0,  0 },
+  /*  6 */  {  'Q',  0, 4, etESCAPE_Q,   0,  0,  4 },
+  /*  7 */  {  'p', 16, 0, etPOINTER,    0,  1,  0 },  /* Hash: 12 */
+  /*  8 */  {  'S',  0, 0, etSRCITEM,    0,  0,  0 },
+  /*  9 */  {  'T',  0, 0, etTOKEN,      0,  0,  0 },
+  /* 10 */  {  'n',  0, 0, etSIZE,       0,  0,  0 },
+  /* 11 */  {  'o',  8, 0, etRADIX,      0,  2,  0 },
+  /* 12 */  {  '%',  0, 0, etPERCENT,    0,  0,  7 },
+  /* 13 */  {  'q',  0, 4, etESCAPE_q,   0,  0, 16 },
+  /* 14 */  {  'r', 10, 1, etORDINAL,    0,  0,  0 },
+  /* 15 */  {  's',  0, 4, etSTRING,     0,  0,  0 },
+  /* 16 */  {  'X', 16, 0, etRADIX,      0,  4,  0 },  /* Hash: 13 */
+  /* 17 */  {  'u', 10, 0, etDECIMAL,    0,  0,  0 },
+  /* 18 */  {  'w',  0, 4, etESCAPE_w,   0,  0,  0 },  /* Hash: 19 */
+  /* 19 */  {  'E',  0, 1, etEXP,        14, 0, 18 },
+  /* 20 */  {  'x', 16, 0, etRADIX,      16, 1,  0 },
+  /* 21 */  {  'G',  0, 1, etGENERIC,    14, 0,  0 },
+  /* 22 */  {  'z',  0, 4, etDYNSTRING,  0,  0,  0 },
+  /* 23 */  {  'J',  0, 0, etESCAPE_J,   0,  0,  0 },  /* Hash: 24 */
+  /* 24 */  {  'c',  0, 0, etCHARX,      0,  0, 23 }
 };
 
 /* Additional Notes:
@@ -378,8 +380,8 @@ void sqlite3_str_vappendf(
     }
 #else
     /* Fast hash-table lookup */
-    assert( ArraySize(fmtinfo)==24 );
-    idx = ((unsigned)c) % 24;
+    assert( ArraySize(fmtinfo)==25 );
+    idx = ((unsigned)c) % 25;
     if( fmtinfo[idx].fmttype==c
      || fmtinfo[idx = fmtinfo[idx].iNxt].fmttype==c
     ){
@@ -870,7 +872,8 @@ void sqlite3_str_vappendf(
           while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
         }
         break;
-      case etJSONSTR: {         /* %J: Generate a JSON string literal */
+      case etESCAPE_j:           /* %j: JSON string literal w/o "..." */
+      case etESCAPE_J: {         /* %J: Generate a JSON string literal */
         char *escarg;
         i64 i, j, px;
         unsigned char ch;
@@ -881,9 +884,9 @@ void sqlite3_str_vappendf(
           escarg = va_arg(ap,char*);
         }
         if( escarg==0 ){
-          sqlite3_str_append(pAccum, "null", 4);
+          if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "null", 4);
         }else{
-          sqlite3_str_append(pAccum, "\"", 1);
+          if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "\"", 1);
           px = precision;
           if( px<=0 ){
             px = 0x7fffffff;
@@ -913,7 +916,7 @@ void sqlite3_str_vappendf(
             }
           }
           if( j<i-1 ) sqlite3_str_append(pAccum, &escarg[j], i-j);
-          sqlite3_str_append(pAccum, "\"", 1);
+          if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "\"", 1);
         }
         length = 0;
         width = 0;
index 1f8ab25a59a585084a5763a4483235f2be0c60dc..e17eb5543429414da87149e116bb41bc40f9cbe8 100644 (file)
@@ -3854,5 +3854,43 @@ do_execsql_test printf-19.3 {
   SELECT format('%,.0f %,.0f',12345e+10, 12345e+11);
 } {{123,450,000,000,000 1,234,500,000,000,000}}
 
+# %J and %j
+#
+do_execsql_test printf-20.1 {
+  SELECT format('{%!.3J:5}','abcdefg')->>'abc';
+} 5
+do_execsql_test printf-20.2 {
+  SELECT format('{%!.3J:5}','αβγδεζη')->>'αβγ';
+} 5
+do_execsql_test printf-20.3 {
+  SELECT format('{%.6J:5}','abcdefg')->>'abcdef';
+} 5
+do_execsql_test printf-20.4 {
+  SELECT format('{%.6J:5}','αβγδεζη')->>'αβγ';
+} 5
+do_execsql_test printf-20.5 {
+  SELECT format('{"%!.3j":5}','abcdefg')->>'abc';
+} 5
+do_execsql_test printf-20.6 {
+  SELECT format('{"%!.3j":5}','αβγδεζη')->>'αβγ';
+} 5
+do_execsql_test printf-20.7 {
+  SELECT format('{"%.6j":5}','abcdefg')->>'abcdef';
+} 5
+do_execsql_test printf-20.8 {
+  SELECT format('{"%.6j":5}','αβγδεζη')->>'αβγ';
+} 5
+do_execsql_test printf-20.9 {
+  WITH RECURSIVE c(n,t) AS (
+    VALUES(1,char(1))
+    UNION ALL
+    SELECT n+1, t||char(n+1) FROM c WHERE n<0x7e
+  )
+  SELECT hex(format('{"a":%J}',t)->>'a') FROM c WHERE n=0x7e;
+} {0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E}
+do_execsql_test printf-20.10 {
+  SELECT format('1-%j-2-%J-3',null,null);
+} {1--2-null-3}
+
 
 finish_test