]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the JsonLine output style.
authordrh <>
Fri, 7 Nov 2025 12:12:02 +0000 (12:12 +0000)
committerdrh <>
Fri, 7 Nov 2025 12:12:02 +0000 (12:12 +0000)
FossilOrigin-Name: 7dfba841cfc515ac28401c4eb90ec24e04fd52cddaeae41be3cfa6967dac0eac

ext/qrf/README.md
ext/qrf/qrf.c
ext/qrf/qrf.h
manifest
manifest.uuid
src/tclsqlite.c
test/qrf01.test

index 7d62b1939b71ab9a7caadfc2f50df8f991137e38..36ef6cf346e81433c2dd108c1fc8d26f72d21608 100644 (file)
@@ -386,15 +386,16 @@ The following output modes are currently defined:
 #define QRF_STYLE_Html      7 /* Generate an XHTML table */
 #define QRF_STYLE_Insert    8 /* Generate SQL "insert" statements */
 #define QRF_STYLE_Json      9 /* Output is a list of JSON objects */
-#define QRF_STYLE_Line     10 /* One column per line. */
-#define QRF_STYLE_List     11 /* One record per line with a separator */
-#define QRF_STYLE_Markdown 12 /* Markdown formatting */
-#define QRF_STYLE_Off      13 /* No query output shown */
-#define QRF_STYLE_Quote    14 /* SQL-quoted, comma-separated */
-#define QRF_STYLE_Stats    15 /* EQP-like output but with performance stats */
-#define QRF_STYLE_StatsEst 16 /* EQP-like output with planner estimates */
-#define QRF_STYLE_StatsVm  17 /* EXPLAIN-like output with performance stats */
-#define QRF_STYLE_Table    18 /* MySQL-style table formatting */
+#define QRF_STYLE_JsonLine 10 /* Independent JSON objects for each row */
+#define QRF_STYLE_Line     11 /* One column per line. */
+#define QRF_STYLE_List     12 /* One record per line with a separator */
+#define QRF_STYLE_Markdown 13 /* Markdown formatting */
+#define QRF_STYLE_Off      14 /* No query output shown */
+#define QRF_STYLE_Quote    15 /* SQL-quoted, comma-separated */
+#define QRF_STYLE_Stats    16 /* EQP-like output but with performance stats */
+#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
+#define QRF_STYLE_StatsVm  18 /* EXPLAIN-like output with performance stats */
+#define QRF_STYLE_Table    19 /* MySQL-style table formatting */
 ~~~
 
 In the following subsections, these styles will often be referred 
@@ -430,7 +431,7 @@ from the data below.  This is very similar to default output styling in
 psql.  The **Markdown** renders its result in the
 Markdown table format.
 
-### 4.3 Line-oriented Styles (Csv, Html, Insert, Json, Line, List, Quote)
+### 4.3 Line-oriented Styles
 
 The line-oriented styles output each row of result as it is received from
 the prepared statement.
@@ -460,8 +461,11 @@ that will inserts the data that is output into a table whose name is defined
 by the zTableName field of `sqlite3_qrf_spec`.  If zTableName is NULL,
 then a substitute name is used.
 
-The **Json** style generates JSON text for the query result.
-The JSON is an array of structures with on structure per row.
+The **Json** and **JsonLine** styles generates JSON text for the query result.
+The **Json** style produces a JSON array of structures with on 
+structure per row.  **JsonLine** outputs independent JSON objects, one per
+row, with each structure on a separate line all by itself, and not
+part of a larger array.
 
 Finally, the **Line** style paints each column of a row on a
 separate line with the column name on the left and a "`=`" separating the
index 9923aa9769c25904f7299631ca25bfc2522a65cf..e6790f0c4df83126bf60335db367b0da5b2f729c 100644 (file)
@@ -1679,8 +1679,8 @@ qrf_reinit:
       if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
       break;
     }
+    case QRF_STYLE_JsonLine:
     case QRF_STYLE_Json: {
-      p->spec.zColumnSep = ",";
       p->spec.eText = QRF_TEXT_Json;
       p->spec.eBlob = QRF_BLOB_Json;
       p->spec.zNull = "null";
@@ -1792,6 +1792,26 @@ static int qrf_need_quote(const char *zName){
   return sqlite3_keyword_check(zName, i)!=0;
 }
 
+/*
+** Helper function for QRF_STYLE_Json and QRF_STYLE_JsonLine.
+** The initial "{" for a JSON object that will contain row content
+** has been output.  Now output all the content.
+*/
+static void qrfOneJsonRow(Qrf *p){
+  int i, nItem; 
+  for(nItem=i=0; i<p->nCol; i++){
+    const char *zCName;
+    if( sqlite3_column_type(p->pStmt,i)==SQLITE_NULL ) continue;
+    zCName = sqlite3_column_name(p->pStmt, i);
+    if( nItem>0 ) sqlite3_str_append(p->pOut, ",", 1);
+    nItem++;
+    qrfEncodeText(p, p->pOut, zCName);
+    sqlite3_str_append(p->pOut, ":", 1);
+    qrfRenderValue(p, p->pOut, i);
+  }
+  qrfWrite(p);
+}
+
 /*
 ** Render a single row of output.
 */
@@ -1809,14 +1829,16 @@ static void qrfOneSimpleRow(Qrf *p){
       }else{
         sqlite3_str_append(p->pOut, "},\n{", 4);
       }
-      for(i=0; i<p->nCol; i++){
-        const char *zCName = sqlite3_column_name(p->pStmt, i);
-        if( i>0 ) sqlite3_str_append(p->pOut, ",", 1);
-        qrfEncodeText(p, p->pOut, zCName);
-        sqlite3_str_append(p->pOut, ":", 1);
-        qrfRenderValue(p, p->pOut, i);
+      qrfOneJsonRow(p);
+      break;
+    }
+    case QRF_STYLE_JsonLine: {
+      if( p->nRow==0 ){
+        sqlite3_str_append(p->pOut, "{", 1);
+      }else{
+        sqlite3_str_append(p->pOut, "}\n{", 3);
       }
-      qrfWrite(p);
+      qrfOneJsonRow(p);
       break;
     }
     case QRF_STYLE_Html: {
@@ -1945,6 +1967,11 @@ static void qrfFinalize(Qrf *p){
       qrfWrite(p);
       break;
     }
+    case QRF_STYLE_JsonLine: {
+      sqlite3_str_append(p->pOut, "}\n", 2);
+      qrfWrite(p);
+      break;
+    }
     case QRF_STYLE_Line: {
       if( p->u.sLine.azCol ) sqlite3_free(p->u.sLine.azCol);
       break;
index 4638d1d5e76ac8b1fe7b8f52a23df4287a7982a7..fb567a77ffea1d745c8599f88b352eed1f70693f 100644 (file)
@@ -74,15 +74,16 @@ int sqlite3_format_query_result(
 #define QRF_STYLE_Html      7 /* Generate an XHTML table */
 #define QRF_STYLE_Insert    8 /* Generate SQL "insert" statements */
 #define QRF_STYLE_Json      9 /* Output is a list of JSON objects */
-#define QRF_STYLE_Line     10 /* One column per line. */
-#define QRF_STYLE_List     11 /* One record per line with a separator */
-#define QRF_STYLE_Markdown 12 /* Markdown formatting */
-#define QRF_STYLE_Off      13 /* No query output shown */
-#define QRF_STYLE_Quote    14 /* SQL-quoted, comma-separated */
-#define QRF_STYLE_Stats    15 /* EQP-like output but with performance stats */
-#define QRF_STYLE_StatsEst 16 /* EQP-like output with planner estimates */
-#define QRF_STYLE_StatsVm  17 /* EXPLAIN-like output with performance stats */
-#define QRF_STYLE_Table    18 /* MySQL-style table formatting */
+#define QRF_STYLE_JsonLine 10 /* Independent JSON objects for each row */
+#define QRF_STYLE_Line     11 /* One column per line. */
+#define QRF_STYLE_List     12 /* One record per line with a separator */
+#define QRF_STYLE_Markdown 13 /* Markdown formatting */
+#define QRF_STYLE_Off      14 /* No query output shown */
+#define QRF_STYLE_Quote    15 /* SQL-quoted, comma-separated */
+#define QRF_STYLE_Stats    16 /* EQP-like output but with performance stats */
+#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
+#define QRF_STYLE_StatsVm  18 /* EXPLAIN-like output with performance stats */
+#define QRF_STYLE_Table    19 /* MySQL-style table formatting */
 
 /*
 ** Quoting styles for text.
index 06ebad86591f07f65fb635ab361d9efa792525cb..96b492861f9f97150c798b9a01bc9f316cae088e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sthe\ssize\sof\san\sinteger\sin\sthe\sTCL\sinterface.
-D 2025-11-07T00:05:44.203
+C Add\sthe\sJsonLine\soutput\sstyle.
+D 2025-11-07T12:12:02.995
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -416,9 +416,9 @@ F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f6
 F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
 F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c
 F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
-F ext/qrf/README.md 6f5a674919ef7fafdd48253ce20f3a4ca0ebd60d343ef95d731399a745ed66b2
-F ext/qrf/qrf.c 82392dc3fb199d019dea4aa0bb381b7f4fa3b9cefb8e24f4806306f6fae17c02
-F ext/qrf/qrf.h 82723bce4cc458a9afc8e935c93a61bd210f0b67016d5b5c4b778da68e73edf3
+F ext/qrf/README.md 251568600920db5f82524ec63fc07e2dfebf98697cbaa708271b4ac6055ffb58
+F ext/qrf/qrf.c 772c87f50d591d7fa6e82730856ce04ac4321c31169d5025eae8608df3adc9b9
+F ext/qrf/qrf.h 39ba5d895f123bcce155b40446ec6d2728055f1f8bf29fdf8221f1eb8835d56d
 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
 F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
@@ -743,7 +743,7 @@ F src/sqliteInt.h 88f7fc9ce1630d9a5f7e0a8e1f3287cdc63882fba985c18e7eee1b9f457f59
 F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c 7232269f64f386ad3718f6a4e13f8fec4a81ce987a2cda60f7b6f2ebff7a7a03
+F src/tclsqlite.c c180acb528411fcb468a2d5f925befdc53afe4c4f821bd7ca35d86826a6d4787
 F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
 F src/test1.c f880ab766eeedf2c063662bd9538b923fd42c4341b7bfc2150a6d93ab8b9341c
 F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
@@ -1506,7 +1506,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 1560df867282d37c4d43a4b2e66606ab129ade70fa1a1a3b9a720769ec8e36d0
+F test/qrf01.test 3f4d7169b7965545eb511258ed2ca4ef204a58f52cfe802d555b24239ef62ec8
 F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
 F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
 F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
@@ -2173,8 +2173,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 d5e891426f8b2a0c3326bf868f2d811c44a1f7e619f42b273c7445ab443d618c
-R d99d23dcb374c7d11bbf931dfdaab5ca
+P 04156c34e4efeebe9b8c2ee2944f9576b685c6aa7e6180c8a5caff4958cde2e8
+R f3ddaa46784828527c17e04e8e958c82
 U drh
-Z 92bea9d231151b2c0d2bdb00c6a35f42
+Z 61b1f0db4819b7d638d03ceafac00a34
 # Remove this line to create a well-formed Fossil manifest.
index 7422aa83d53bac1208e40290409172a791490f04..d4055d2c7867f16dfc8325b3844d29782c599405 100644 (file)
@@ -1 +1 @@
-04156c34e4efeebe9b8c2ee2944f9576b685c6aa7e6180c8a5caff4958cde2e8
+7dfba841cfc515ac28401c4eb90ec24e04fd52cddaeae41be3cfa6967dac0eac
index 5e897e13bbcfbb3a78c7d54df8ce3734d70173f8..31c03acdb194a56b3a893934b5bfd74dc9470afa 100644 (file)
@@ -2121,17 +2121,19 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
         "auto",             "box",              "column",
         "count",            "csv",              "eqp",
         "explain",          "html",             "insert",
-        "json",             "line",             "list",
-        "markdown",         "quote",            "stats",
-        "stats-est",        "stats-vm",         "table",            0
+        "json",             "json-line",        "line",
+        "list",             "markdown",         "quote",
+        "stats",            "stats-est",        "stats-vm",
+        "table",            0
       };
       static unsigned char aStyleMap[] = {
         QRF_STYLE_Auto,     QRF_STYLE_Box,      QRF_STYLE_Column,
         QRF_STYLE_Count,    QRF_STYLE_Csv,      QRF_STYLE_Eqp,
         QRF_STYLE_Explain,  QRF_STYLE_Html,     QRF_STYLE_Insert,
-        QRF_STYLE_Json,     QRF_STYLE_Line,     QRF_STYLE_List,
-        QRF_STYLE_Markdown, QRF_STYLE_Quote,    QRF_STYLE_Stats,
-        QRF_STYLE_StatsEst, QRF_STYLE_StatsVm,  QRF_STYLE_Table
+        QRF_STYLE_Json,     QRF_STYLE_JsonLine, QRF_STYLE_Line,
+        QRF_STYLE_List,     QRF_STYLE_Markdown, QRF_STYLE_Quote,
+        QRF_STYLE_Stats,    QRF_STYLE_StatsEst, QRF_STYLE_StatsVm,
+        QRF_STYLE_Table
       };
       int style;
       rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azStyles,
index 77d8b9329d02d3da3b54bf139188d51e4c8e527e..e4b87948ad71f296ad8df3f7fb387f63c2644182 100644 (file)
@@ -207,7 +207,19 @@ do_test 1.90 {
   set result "\n[db format -style json {SELECT * FROM t1}]"
 } {
 [{"a":1,"b":2.5,"c":"three"},
-{"a":"\u0042\u004c\u004f\u0042","b":null,"c":"Ἀμήν"}]
+{"a":"\u0042\u004c\u004f\u0042","c":"Ἀμήν"}]
+}
+do_test 1.91 {
+  set result "\n[db format -style json-line {SELECT * FROM t1}]"
+} {
+{"a":1,"b":2.5,"c":"three"}
+{"a":"\u0042\u004c\u004f\u0042","c":"Ἀμήν"}
+}
+do_test 1.92 {
+  set result "\n[db format -style json-line {SELECT *, unistr('abc\u000a123\u000d\u000axyz') AS xyz FROM t1}]"
+} {
+{"a":1,"b":2.5,"c":"three","xyz":"abc\n123\r\nxyz"}
+{"a":"\u0042\u004c\u004f\u0042","c":"Ἀμήν","xyz":"abc\n123\r\nxyz"}
 }
 
 do_test 1.100 {