]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make the (legacy, deprecated) ".header" command in the CLI responsive to title-always-default-on
authordrh <>
Wed, 8 Jul 2026 15:34:53 +0000 (15:34 +0000)
committerdrh <>
Wed, 8 Jul 2026 15:34:53 +0000 (15:34 +0000)
the "always" title mode.  Clean up title mode and define its operation with
improved comments in the TCL interface and in the CLI.  Add the
"-title auto" option to the CLI.

FossilOrigin-Name: f94259fc07cd7856e9c6f81a46689f4f96bbf464fda7f1d11b51a308c296aca0

manifest
manifest.uuid
src/shell.c.in
src/tclsqlite.c
test/modeA.sql
test/shell1.test

index c3e2299e5ec6aecc17ce383b58ea697c48a8eb56..b26efd4ffb889c90bbd8b191ac18f86aa3063fe2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Change\sthe\sCLI\sso\sthat\sthe\sdefault\s"--title"\sis\s"always"\sinstead\sof\s"on"\nfor\ssome\sdisplay\smodes.\s\sThis\scheck-in\salso\sinclude\sa\sfix\sto\s"--title\salways"\nfor\sthe\s"markdown"\sdisplay\smode.
-D 2026-07-07T14:53:53.364
+C Make\sthe\s(legacy,\sdeprecated)\s".header"\scommand\sin\sthe\sCLI\sresponsive\sto\nthe\s"always"\stitle\smode.\s\sClean\sup\stitle\smode\sand\sdefine\sits\soperation\swith\nimproved\scomments\sin\sthe\sTCL\sinterface\sand\sin\sthe\sCLI.\s\sAdd\sthe\n"-title\sauto"\soption\sto\sthe\sCLI.
+D 2026-07-08T15:34:53.977
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -743,7 +743,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 54395ee97eb710e695202d4112cf2b1c1c7767a57afcea745df71abb1c917768
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c f553420eaf5c72a49cef786621eea79dd8c4411671839fb05250bb49ca74a0a0
-F src/shell.c.in 8dd3e9145c5fb5e5ec1b343fa26cf007bdc9f995bd3574dab2518748cfe10724
+F src/shell.c.in 5b94be0ff5a385cd42beed62ca229a062e5a696c2afd6567ce699b0d6d8bd21b
 F src/sqlite.h.in d9ec41feb4cd804e68b174328b43beb3f1f71bba13e1c7a439efb826d301cccc
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
 F src/sqlite3ext.h 0efd4723bad9124ea1f581d9f1ea0254ac1c6f3e5fb29e4f3dcf36c72485a456
@@ -751,7 +751,7 @@ F src/sqliteInt.h 92563b8edc673513b82d87bf6a8d7aeb554b2c7b7d5e30992fbca04010db79
 F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c 9ac18aac16dd91fec546d1329c17a41b6b2fd095b2294ba063fa02aca0161f8e
+F src/tclsqlite.c fac4e166b90c1e8c4cac76c1339dfb9d94646debda2cdf8026120a7e19a822ff
 F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
 F src/test1.c df2df0a74c9aa81cbbad9d7d8277e49ac255334cba97da9ee22501beac274201
 F src/test2.c 2b9ab96bba63a1c369d5769390475259ad210f144a877805f2e32e563f9e93c1
@@ -1461,7 +1461,7 @@ F test/mmap4.test 2e2b4e32555b58da15176e6fe750f17c9dcf7f93
 F test/mmapcorrupt.test 470fb44fe92e99c1d23701d156f8c17865f5b027063c9119dcfdb842791f4465
 F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
 F test/mmapwarm.test 2272005969cd17a910077bd5082f70bc1fefad9a875afec7fc9af483898ecaf3
-F test/modeA.sql 70bd5172122f992c2a2caa8e247d3dae68dbac2d854915ea20d4e01b98940d78
+F test/modeA.sql 4c1e10ec06f0a061ae75f06c0dfc102674c519ee1574323faa1e11cb47db44c8
 F test/multiplex.test d74c034e52805f6de8cc5432cef8c9eb774bb64ec29b83a22effc8ca4dac1f08
 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
 F test/multiplex3.test fac575e0b1b852025575a6a8357701d80933e98b5d2fe6d35ddaa68f92f6a1f7
@@ -1634,7 +1634,7 @@ F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8e
 F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
 F test/shell-prompt.sql 8a320a78812d75349bd5e1a95178f7ff1f2194bb4cceee572865d127c51684b3
-F test/shell1.test df7a33a7056220ae12966228731658b36c98c22ba27e114bbf2785ff5b84fea2
+F test/shell1.test 72cd5c5e7d172d28aefba8fe72d174945d06cba2818440648b57d27382203fb6
 F test/shell2.test 1d7b9133b612d53f3c355dcba55845f84fcf2fe0d09459f82adbfaccae3c60b1
 F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
 F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
@@ -2213,11 +2213,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 4edba31af4ef18350cb415079fb92cae0c53767fc0e74d63d404296974e75e5c
-R 91f96872ad01984a543b449ea7837a3b
-T *branch * title-always-default-on
-T *sym-title-always-default-on *
-T -sym-trunk *
+P c3b0fff1b76b8c354b34fef17ff639968698e97234d6ab7af15e0e1a835486e9
+R 688db872c29fb684e76bc6c6acf8cc9b
 U drh
-Z 8732b504c20e338d03135e902dabf4df
+Z abf35e5e3a6771887b73b278adcf21be
 # Remove this line to create a well-formed Fossil manifest.
index 679fac24d6530b49e55b5dd3e66f23b029520dc5..e2979933ad8067d1a557a72f543adafb8bfbf2d8 100644 (file)
@@ -1 +1 @@
-c3b0fff1b76b8c354b34fef17ff639968698e97234d6ab7af15e0e1a835486e9
+f94259fc07cd7856e9c6f81a46689f4f96bbf464fda7f1d11b51a308c296aca0
index d000d88ed342a20379eb774253254a5254d624e0..a30c82b810bccf3d9620b34823930ce1b450badf 100644 (file)
@@ -8558,12 +8558,12 @@ static int dotCmdImport(ShellState *p){
 ** titles (or column-names).  Output is an integer between 0 and 3:
 **
 **    0:     The titles do not matter.  Never show anything.
-**    1:     Show  "--titles off"
-**    2:     Show  "--titles on"
-**    3:     Show  "--titles always"
+**    1:     Show  "--title off"
+**    2:     Show  "--title on"
+**    3:     Show  "--title always"
 **    4:     Show  "--title VALUE"  where VALUE is an encoding method
 **             to use, one of: plain sql csv html tcl json
-**    5:     Show  "--title VALUE" as in 3, followed by "--titles always"
+**    5:     Show  "--title VALUE" as in 3, followed by "--title always"
 **
 ** Inputs are:
 **
@@ -8603,8 +8603,8 @@ static int modeTitleDsply(ShellState *p, int bAll){
   v &= 3;
   /* At this point v means:
   **    0:     The titles do not matter.  Never show anything.
-  **    1:     Show  "--titles off"
-  **    2:     Show  "--titles on"
+  **    1:     Show  "--title off"
+  **    2:     Show  "--title on"
   **    3:     Show  "--title VALUE"  where VALUE is an encoding method
   **             to use, one of: plain sql csv html tcl json
   ** If bTitles is QRF_Always, convert 2->3, 3->5.  If bTitles is not
@@ -8676,7 +8676,7 @@ static int modeTitleDsply(ShellState *p, int bAll){
 **   --textjsonb BOOLEAN      If enabled, JSONB text is displayed as text JSON.
 **   --title ARG              Whether or not to show column headers, and if so
 **                            how to encode them.  ARG can be "off", "on",
-**                            "sql", "csv", "html", "tcl", "json", or "always".
+**                            "always", "sql", "csv", "html", "tcl", or "json".
 **   --titlelimit N           Limit the length of column titles to N characters.
 **   -v|--verbose             Verbose output
 **   --widths LIST            Set the columns widths for columnar modes. The
@@ -8964,24 +8964,58 @@ static int dotCmdMode(ShellState *p){
       p->mode.spec.bTextJsonb = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No;
       chng = 1;
     }else if( optionMatch(z,"titles") || optionMatch(z,"title") ){
+      /* The --titles option controls two fields of the
+      ** sqlite3_qrf_spec object: eTitle and bTitles.
+      **
+      **    --titles      eTitle             bTitles
+      **    --------      ---------------    ---------------------
+      **    "off"         (unchanged)        QRF_Off
+      **    "on"          (unchanged)        QRF_On
+      **    "always"      (unchanged)        QRF_Always
+      **    "auto",       (default)          (default)
+      **    "plain"       QRF_TEXT_Plain     QRF_Always or QRF_On
+      **    "sql"         QRF_TEXT_Sql       QRF_Always or QRF_On
+      **    "csv"         QRF_TEXT_Csv       QRF_Always or QRF_On
+      **    "html"        QRF_TEXT_Html      QRF_Always or QRF_On
+      **    "tcl"         QRF_TEXT_Tcl       QRF_Always or QRF_On
+      **    "json"        QRF_TEXT_Json      QRF_Always or QRF_On
+      **
+      ** This mapping is different from the -title option to the "format"
+      ** method of the TCL interface.  In this mapping:
+      **
+      **    *   "off", "on", and "always" affect only bTitles and leave
+      **        eTitle unchanged
+      **
+      **    *   "auto" sets both bTitles and eTitle to the default value
+      **        in aModeInfo[] according to the current --style.
+      **
+      **    *   "plain" through "json" set eTitle but leave bTitles
+      **        unchanged if it is not QRF_Off.  If bTitles is QRF_Off,
+      **        then it is changed QRF_Always.
+      */
       char *zErr = 0;
       if( i+1>=nArg ){
         dotCmdError(p, i, "missing argument", 0);
         return 1;
       }
       k = pickStr(azArg[++i],&zErr,
-              "off","on","plain","sql","csv","html","tcl","json","always","");
-          /*   0     1    2       3     4     5     6      7      8  */
+          "off","on","always","auto","plain","sql","csv","html","tcl","json","");
+        /* 0     1    2        3      4       5     6     7      8     9 */
       if( k<0 ){
         dotCmdError(p, i, "bad --titles value","%z", zErr);
         return 1;
       }
-      if( k==8 ){
-        p->mode.spec.bTitles = QRF_Always;
+      p->mode.mFlags &= ~MFLG_HDR;
+      if( k<=2 ){
+        p->mode.spec.bTitles = QRF_No+k;
+      }else if( k==3 ){
+        p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr;
+        p->mode.spec.bTitles = aModeInfo[p->mode.eMode].bHdr;
       }else{
-        p->mode.spec.bTitles = k>=1 ? QRF_Yes : QRF_No;
-        p->mode.mFlags &= ~MFLG_HDR;
-        p->mode.spec.eTitle = k>1 ? k-1 : aModeInfo[p->mode.eMode].eHdr;
+        p->mode.spec.eTitle = (k-4)+QRF_TEXT_Plain;
+        if( p->mode.spec.bTitles==QRF_No ){
+          p->mode.spec.bTitles = QRF_Always;
+        }
       }
       chng = 1;
     }else if( optionMatch(z,"widths") || optionMatch(z,"width") ){
@@ -10502,11 +10536,15 @@ static int do_meta_command(const char *zLine, ShellState *p){
 
   if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
     if( nArg==2 ){
-      p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No;
+      if( cli_strcmp(azArg[1],"always")==0 ){
+        p->mode.spec.bTitles = QRF_Always;
+      }else{
+        p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No;
+      }
       p->mode.mFlags |= MFLG_HDR;
       p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr;
     }else{
-      eputz("Usage: .headers on|off\n");
+      eputz("Usage: .headers off|on|always\n");
       rc = 1;
     }
   }else
@@ -12102,7 +12140,8 @@ static int do_meta_command(const char *zLine, ShellState *p){
     cli_printf(p->out, "%12.12s: %s\n","explain",
                              p->mode.autoExplain ? "auto" : "off");
     cli_printf(p->out, "%12.12s: %s\n","headers",
-          azBool[p->mode.spec.bTitles==QRF_Yes]);
+          p->mode.spec.bTitles==QRF_Always ? "always" :
+            azBool[p->mode.spec.bTitles==QRF_Yes]);
     if( p->mode.spec.eStyle==QRF_STYLE_Column
      || p->mode.spec.eStyle==QRF_STYLE_Box
      || p->mode.spec.eStyle==QRF_STYLE_Table
@@ -14176,7 +14215,7 @@ int SQLITE_CDECL main(int argc, char **argv){
      modeSetStr(&data.mode.spec.zNull, 
                        cmdline_option_value(argc,argv,++i));
     }else if( cli_strcmp(z,"-header")==0 ){
-      data.mode.spec.bTitles = QRF_Yes;
+      data.mode.spec.bTitles = QRF_Always;
       data.mode.mFlags |= MFLG_HDR;
      }else if( cli_strcmp(z,"-noheader")==0 ){
       data.mode.spec.bTitles = QRF_No;
index bee03fe3d9af74c2ec7d6dc816da57e0a67302f6..cd133580127466ab1632b48f396f1df94c125946 100644 (file)
@@ -2088,7 +2088,7 @@ static void DbHookCmd(
 **     -style            eStyle
 **     -esc              eEsc
 **     -text             eText
-**     -title            eTitle, bTitle
+**     -title            eTitle, bTitles
 **     -blob             eBlob
 **     -wordwrap         bWordWrap
 **     -textjsonb        bTextJsonb
@@ -2108,6 +2108,26 @@ static void DbHookCmd(
 **     -rowsep           zRowSep
 **     -tablename        zTableName
 **     -null             zNull
+**
+** The TCL -title option maps to eTitle and bTitles as follows:
+**
+**     -title       eTitle              bTitles 
+**     -------      -----------------   ------------
+**     off          QRF_TEXT_Auto       QRF_Off
+**     on           QRF_TEXT_Auto       QRF_On
+**     always       QRF_TEXT_Auto       QRF_Always
+**     auto         QRF_TEXT_Auto       QRF_On
+**     csv          QRF_TEXT_Csv        QRF_On
+**     html         QRF_TEXT_Html       QRF_On
+**     json         QRF_TEXT_Json       QRF_On
+**     plain        QRF_TEXT_Plain      QRF_On
+**     relaxed      QRF_TEXT_Relaxed    QRF_On
+**     sql          QRF_TEXT_Sql        QRF_On
+**     tcl          QRF_TEXT_Tcl        QRF_On
+**
+** Note in particular that for the last seven entries ("csv" through "tcl"),
+** the CLI .mode --title option sets bTitles to QRF_Always, whereas this TCL
+** interface set it to QRF_On.
 */
 static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
 #ifndef SQLITE_QRF_H
index 62de2ecdb61d90633eaff2ab15750dcff6e2a48f..675b6c39aa74b6e385b0b2f639de21537be82917 100644 (file)
@@ -406,3 +406,88 @@ SELECT * FROM t1;
         2 |             |       2
 (2 rows)
 END
+
+# Variations on ".mode -title"
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1("a b", "c'""<""'d", "xyz", "123");
+.testcase 1000
+.mode box -reset -title off -title plain
+SELECT * FROM t1;
+.check <<END
+╭─────┬─────────┬─────┬─────╮
+│ a b │ c'"<"'d │ xyz │ 123 │
+╘═════╧═════════╧═════╧═════╛
+END
+.testcase 1001
+.mode -title off -title sql
+SELECT * FROM t1;
+.check <<END
+╭───────┬─────────────┬───────┬───────╮
+│ 'a b' │ 'c''"<"''d' │ 'xyz' │ '123' │
+╘═══════╧═════════════╧═══════╧═══════╛
+END
+.testcase 1002
+.mode -title off -title csv
+SELECT * FROM t1;
+.check <<END
+╭───────┬─────────────┬─────┬─────╮
+│ "a b" │ "c'""<""'d" │ xyz │ 123 │
+╘═══════╧═════════════╧═════╧═════╛
+END
+.testcase 1003
+.mode -title off -title html
+SELECT * FROM t1;
+.check <<END
+╭─────┬──────────────────────────────┬─────┬─────╮
+│ a b │ c&#39;&quot;&lt;&quot;&#39;d │ xyz │ 123 │
+╘═════╧══════════════════════════════╧═════╧═════╛
+END
+.testcase 1003b
+.mode -title off -title html -title off --title always
+SELECT * FROM t1;
+.check <<END
+╭─────┬──────────────────────────────┬─────┬─────╮
+│ a b │ c&#39;&quot;&lt;&quot;&#39;d │ xyz │ 123 │
+╘═════╧══════════════════════════════╧═════╧═════╛
+END
+.testcase 1003c
+.show
+.check --glob "*headers: always*"
+.testcase 1004
+.mode -title off -title tcl
+SELECT * FROM t1;
+.check <<END
+╭───────┬─────────────┬───────┬───────╮
+│ "a b" │ "c'\"<\"'d" │ "xyz" │ "123" │
+╘═══════╧═════════════╧═══════╧═══════╛
+END
+.testcase 1005
+.mode -title off -title json
+SELECT * FROM t1;
+.check <<END
+╭───────┬─────────────┬───────┬───────╮
+│ "a b" │ "c'\"<\"'d" │ "xyz" │ "123" │
+╘═══════╧═════════════╧═══════╧═══════╛
+END
+.testcase 1006
+.mode -title on -title json
+SELECT * FROM t1;
+.check ""
+.testcase 1007
+.mode -title on -title json -title auto
+SELECT * FROM t1;
+.check <<END
+╭─────┬─────────┬─────┬─────╮
+│ a b │ c'"<"'d │ xyz │ 123 │
+╘═════╧═════════╧═════╧═════╛
+END
+.testcase 1008
+.mode -title off -title json
+.headers always
+SELECT * FROM t1;
+.check <<END
+╭─────┬─────────┬─────┬─────╮
+│ a b │ c'"<"'d │ xyz │ 123 │
+╘═════╧═════════╧═════╧═════╛
+END
index aa0281758dae0e68e9c189c950299b6e4940ae6a..767ac2dcba622260227896283eb4d0cfa691aaa8 100644 (file)
@@ -386,7 +386,7 @@ do_test shell1-3.7.4 {
 # .header(s) ON|OFF      Turn display of headers on or off
 do_test shell1-3.9.1 {
   catchcmd "test.db" ".header"
-} {1 {Usage: .headers on|off}}
+} {1 {Usage: .headers off|on|always}}
 do_test shell1-3.9.2 {
   catchcmd "test.db" ".header ON"
 } {0 {}}
@@ -396,11 +396,11 @@ do_test shell1-3.9.3 {
 do_test shell1-3.9.4 {
   # too many arguments
   catchcmd "test.db" ".header OFF BAD"
-} {1 {Usage: .headers on|off}}
+} {1 {Usage: .headers off|on|always}}
 
 do_test shell1-3.9.5 {
   catchcmd "test.db" ".headers"
-} {1 {Usage: .headers on|off}}
+} {1 {Usage: .headers off|on|always}}
 do_test shell1-3.9.6 {
   catchcmd "test.db" ".headers ON"
 } {0 {}}
@@ -410,7 +410,7 @@ do_test shell1-3.9.7 {
 do_test shell1-3.9.8 {
   # too many arguments
   catchcmd "test.db" ".headers OFF BAD"
-} {1 {Usage: .headers on|off}}
+} {1 {Usage: .headers off|on|always}}
 
 # .help                  Show this message
 do_test shell1-3.10.1 {