### 2.4 Show Column Names (bTitles)
-The sqlite3_qrf_spec.bTitles field can be either QRF_SW_Auto,
-QRF_SW_On, or QRF_SW_Off. Those three constants also have shorter
-alternative spellings: QRF_Auto, QRF_No, and
-QRF_Yes.
+The sqlite3_qrf_spec.bTitles field can be one of QRF_SW_Auto,
+QRF_SW_On, QRF_SW_Off, or QRF_Always. The first three constants also
+have shorter alternative spellings: QRF_Auto, QRF_No, and QRF_Yes.
> ~~~
#define QRF_SW_Auto 0 /* Let QRF choose the best value */
#define QRF_Auto 0 /* Alternate spelling for QRF_SW_Auto and others */
#define QRF_No 1 /* Alternate spelling for QRF_SW_Off */
#define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */
+#define QRF_Always 3 /* Always try to show column names */
~~~
-If the value is QRF_Yes, then column names appear in the output.
+If the value is QRF_Yes, then column names appear in the output when
+there are one or more rows of output.
If the value is QRF_No, column names are omitted. If the
value is QRF_Auto, then an appropriate default is chosen.
+The value QRF_Always is like QRF_Yes except that the output might
+still show column headers even if the number of result rows is zero,
+depending on eStyle.
### 2.5 Control Character Escapes (eEsc)
sqlite3_column_name() interface not from sqlite3_column_value(),
and so that names of columns are never processed by xRender.
+### 2.18 Show Row Counts On Query Output (bRowCount)
+
+If the value of bRowCount is QRF_Yes, then an extra line of text
+of the form "(N rows)" might be appended to the end of query output,
+depending on eStyle.
+
## 3.0 The `sqlite3_format_query_result()` Interface
Invoke the `sqlite3_format_query_result(P,S,E)` interface to run
if( nColumn==0 ){
return; /* Not a query. No results every shown. */
}
- if( rc!=SQLITE_ROW && (rc!=SQLITE_DONE || p->spec.bTitles!=QRF_Always) ){
+ if( rc==SQLITE_DONE && nColumn>0 ){
+ /* Empty query */
+ if( p->spec.bTitles==QRF_Always ){
+ /* fall through into the columnar logic below */
+ }else{
+ if( p->spec.bRowCount==QRF_Yes ){
+ sqlite3_str_appendf(p->pOut, "(0 rows)\n");
+ qrfWrite(p);
+ }
+ return; /* No output, other than the row count */
+ }
+ }else if( rc!=SQLITE_ROW ){
return; /* No output */
}
qrfWrite(p);
}
+/*
+** Render a title row (a row containing column names) if the spec
+** calls for one and if it makes sense for the eStyle. Title rows
+** do not make sense for some eStyles, such as QRF_STYLE_Off,
+** QRF_STYLE_Count, QRF_STYLE_Json, and similar.
+*/
+static void qrfSimpleTitle(Qrf *p){
+ assert( p->nRow==0 );
+ assert( p->spec.bTitles>=QRF_Yes );
+ switch( p->spec.eStyle ){
+ case QRF_STYLE_Html: {
+ int i;
+ sqlite3_str_append(p->pOut, "<TR>", 4);
+ for(i=0; i<p->nCol; i++){
+ const char *zCName = sqlite3_column_name(p->pStmt, i);
+ sqlite3_str_append(p->pOut, "\n<TH>", 5);
+ qrfEncodeText(p, p->pOut, zCName);
+ }
+ sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
+ break;
+ }
+ case QRF_STYLE_Quote:
+ case QRF_STYLE_List: {
+ int i;
+ int saved_eText = p->spec.eText;
+ p->spec.eText = p->spec.eTitle;
+ for(i=0; i<p->nCol; i++){
+ const char *zCName = sqlite3_column_name(p->pStmt, i);
+ if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
+ qrfEncodeText(p, p->pOut, zCName);
+ }
+ sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
+ qrfWrite(p);
+ p->spec.eText = saved_eText;
+ break;
+ }
+ }
+}
+
/*
** Render a single row of output for non-columnar styles - any
** style that lets us render row by row as the content is received
}
case QRF_STYLE_Html: {
if( p->nRow==0 && p->spec.bTitles>=QRF_Yes ){
- sqlite3_str_append(p->pOut, "<TR>", 4);
- for(i=0; i<p->nCol; i++){
- const char *zCName = sqlite3_column_name(p->pStmt, i);
- sqlite3_str_append(p->pOut, "\n<TH>", 5);
- qrfEncodeText(p, p->pOut, zCName);
- }
- sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
+ qrfSimpleTitle(p);
}
sqlite3_str_append(p->pOut, "<TR>", 4);
for(i=0; i<p->nCol; i++){
}
default: { /* QRF_STYLE_List */
if( p->nRow==0 && p->spec.bTitles>=QRF_Yes ){
- int saved_eText = p->spec.eText;
- p->spec.eText = p->spec.eTitle;
- for(i=0; i<p->nCol; i++){
- const char *zCName = sqlite3_column_name(p->pStmt, i);
- if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
- qrfEncodeText(p, p->pOut, zCName);
- }
- sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
- qrfWrite(p);
- p->spec.eText = saved_eText;
+ qrfSimpleTitle(p);
}
for(i=0; i<p->nCol; i++){
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
while( qrf.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
qrfOneSimpleRow(&qrf);
}
+ if( qrf.nCol>0 && qrf.nRow==0 && qrf.spec.bTitles==QRF_Always ){
+ qrfSimpleTitle(&qrf);
+ }
+ if( qrf.nCol>0 && qrf.spec.bRowCount==QRF_Yes ){
+ switch( qrf.spec.eStyle ){
+ case QRF_STYLE_Line:
+ if( qrf.nRow>0 ) sqlite3_str_append(qrf.pOut, "\n", 1);
+ /* Fall through */
+ case QRF_STYLE_Csv:
+ case QRF_STYLE_List:
+ case QRF_STYLE_Quote:
+ sqlite3_str_appendf(qrf.pOut,"(%d row%s)\n",
+ qrf.nRow, qrf.nRow==1 ? "" : "s");
+ break;
+ case QRF_STYLE_Html:
+ sqlite3_str_appendf(qrf.pOut,"<!-- %d row%s -->\n",
+ qrf.nRow, qrf.nRow==1 ? "" : "s");
+ break;
+ }
+ }
break;
}
}
-C Add\snew\soption\s"bRowCount"\sto\sQRF.\s\sAdd\sQRF_Always\sas\sa\spossibility\sfor\nbTitles.\s\sUse\sthese\sfeature\sto\senhance\s".mode\spsql"\sto\sbe\sa\sbetter\napproximation\sof\swhat\spsql\sactually\sdoes.
-D 2026-07-06T19:24:15.260
+C Continuing\swork\son\s--rowcount\sand\s--title\salways.
+D 2026-07-07T00:23:38.996
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 5cf901996c840b32a5c03d947c4ee86bda166f6e595a41871840df8520458054
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
-F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
+F ext/qrf/README.md 3dfd5de860cdc0c572d8926ba0c1b3cc8925487dfbda10e63af66a8811907687
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
-F ext/qrf/qrf.c 99c3ab46eedbc68211296e58797d601a80667f75a8db746a75cb92ec20ca923a
+F ext/qrf/qrf.c 151396f96eb0262443b2dda0313976ffb072b17341374d80cd9681d38345000d
F ext/qrf/qrf.h fcbc33578176b2fd9dda8310d8f6ba4eaf4f75052f466dfe682802e6664df8bd
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
F src/resolve.c 54395ee97eb710e695202d4112cf2b1c1c7767a57afcea745df71abb1c917768
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c f553420eaf5c72a49cef786621eea79dd8c4411671839fb05250bb49ca74a0a0
-F src/shell.c.in c26f8aca2312ed8a8be1f63f887c23f45e37911d4ede17f9c6b9d7897d574b80
+F src/shell.c.in ad7b45289ca6867ca2d87230aefc5acc63b86511f9605f23765b0129105e5576
F src/sqlite.h.in d9ec41feb4cd804e68b174328b43beb3f1f71bba13e1c7a439efb826d301cccc
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 0efd4723bad9124ea1f581d9f1ea0254ac1c6f3e5fb29e4f3dcf36c72485a456
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd
+F src/tclsqlite.c 9ac18aac16dd91fec546d1329c17a41b6b2fd095b2294ba063fa02aca0161f8e
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
F src/test1.c df2df0a74c9aa81cbbad9d7d8277e49ac255334cba97da9ee22501beac274201
F src/test2.c 2b9ab96bba63a1c369d5769390475259ad210f144a877805f2e32e563f9e93c1
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/pushdown.test 46a626ef1c0ca79b85296ff2e078b9da20a50e9b804b38f441590c3987580ddd
-F test/qrf01.test 0b5095dfc841eaa12806fe20fc0ede72573885390b3152edc0edb66378fb55f7
+F test/qrf01.test cc17b3efe5d4de8b1f2c9ddd0bb8a6b6934d4f32252803d9d145fac3cecb369e
F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
F test/qrf03.test e7efe46d204671726b4707585126cd78d107368de4a7d0c7b8d5157cdd8624ed
F test/qrf04.test 0894692c998d2401dcc33449c02051b503ecce0c94217be54fb007c82d2d1379
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 7f49a7a90eda01753c0dff65197bd7bc48a751e24a46919d30af6e2baf0788fc
-R d458787ae041129a9286190077b172aa
-T *branch * psql-mode
-T *sym-psql-mode *
-T -sym-trunk *
+P 600c6b464050078b38cc688668148f684243e7c5f08d0aae4d5f72aa6f985482
+R 6b8e1ec56e5918c44216302c94fac591
U drh
-Z e2f6af93169d3a630e55ed3303140615
+Z 7a466c86906d29efc86be3f3db820048
# Remove this line to create a well-formed Fossil manifest.
-600c6b464050078b38cc688668148f684243e7c5f08d0aae4d5f72aa6f985482
+adeb4fbb86a8a781d7efb0eecb9c84ce605d0bd45f63992bf2ecd60765a60d2c
pM->spec.bRowCount = QRF_Yes;
}else{
pM->spec.bBorder = QRF_Auto;
+ pM->spec.bRowCount = QRF_No;
}
if( pI->mFlg & 0x02 ){
pM->spec.bSplitColumn = QRF_Yes;
** "tcl", or "json". "off" means show the text as-is.
** "on" is an alias for "sql".
** --reset Changes all mode settings back to their default.
-** --rowcount BOOLEAN Show "(N rows)" at the end of output.
+** --rowcount BOOLEAN Show "(N rows)" at the end of query results.
** --rowsep STRING Use STRING as the row separator
** --sw|--screenwidth N Declare the screen width of the output device
** to be N characters. An attempt may be made to
** --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", or "json".
+** "sql", "csv", "html", "tcl", "json", or "always".
** --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
** -defaultalign ("auto"|"left"|...) Default alignment
** -titalalign ("auto"|"left"|"right"|...) Default column name alignment
** -border ("auto"|"off"|"on") Border for box and table styles
+** -rowcount ("auto"|"off"|"on") Show row counts
** -wrap NUMBER Max width of any single column
** -screenwidth NUMBER Width of the display TTY
** -linelimit NUMBER Max lines for any cell
};
memset(&qrf, 0, sizeof(qrf));
- qrf.iVersion = 1;
+ qrf.iVersion = 2;
qrf.pzOutput = &zResult;
for(i=2; i<objc; i++){
const char *zArg = Tcl_GetString(objv[i]);
}
zSql = zArg;
}else if( i==objc-1 ){
- Tcl_AppendResult(pDb->interp, "option has no argument: ", zArg, (char*)0);
+ Tcl_AppendResult(pDb->interp, "option has no argument: ", zArg,(char*)0);
rc = TCL_ERROR;
goto format_failed;
}else if( strcmp(zArg,"-style")==0 ){
/* NB: --title can be "off" or "on but --text may not be. Thus we put
** the "off" and "on" choices first and start the search on the
** thrid element of the array when processing --text */
- static const char *azText[] = { "off", "on",
+ static const char *azText[] = { "off", "on", "always",
"auto", "csv", "html",
"json", "plain", "relaxed",
"sql", "tcl", 0
};
int txt;
int k = zArg[2]=='e';
- rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], &azText[k*2], zArg,
+ rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], &azText[k*3], zArg,
0, &txt);
if( rc ) goto format_failed;
if( k ){
qrf.eText = aTextMap[txt];
- }else if( txt<=1 ){
- qrf.bTitles = txt ? QRF_Yes : QRF_No;
+ }else if( txt<=2 ){
+ assert( QRF_No==1 );
+ assert( QRF_Yes==2 );
+ assert( QRF_Always==3 );
+ qrf.bTitles = txt+QRF_No;
qrf.eTitle = QRF_TEXT_Auto;
}else{
qrf.bTitles = QRF_Yes;
- qrf.eTitle = aTextMap[txt-2];
+ qrf.eTitle = aTextMap[txt-3];
}
i++;
}else if( strcmp(zArg,"-blob")==0 ){
}else if( strcmp(zArg,"-textjsonb")==0
|| strcmp(zArg,"-splitcolumn")==0
|| strcmp(zArg,"-border")==0
+ || strcmp(zArg,"-rowcount")==0
){
int v = 0;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool,
qrf.bTextJsonb = aBoolMap[v];
}else if( zArg[1]=='b' ){
qrf.bBorder = aBoolMap[v];
+ }else if( zArg[1]=='r' ){
+ qrf.bRowCount = aBoolMap[v];
}else{
qrf.bSplitColumn = aBoolMap[v];
}
i++;
- }else if( strcmp(zArg,"-defaultalign")==0 || strcmp(zArg,"-titlealign")==0){
+ }else if( strcmp(zArg,"-defaultalign")==0
+ || strcmp(zArg,"-titlealign")==0){
int ax = 0;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azAlign,
zArg[1]=='d' ? "default alignment (-defaultalign)" :
1 │ 2.5 │ three
x'424c4f42' │ │ Ἀμήν
}
+do_test 1.11e {
+ set result "\n[db format -rowcount on {SELECT * FROM t1}]"
+} {
+╭──────┬─────┬───────╮
+│ a │ b │ c │
+╞══════╪═════╪═══════╡
+│ 1 │ 2.5 │ three │
+│ BLOB │ │ Ἀμήν │
+╰──────┴─────┴───────╯
+(2 rows)
+}
+do_test 1.11f {
+ set result "\n[db format -rowcount on {SELECT * FROM t1 WHERE a=1}]"
+} {
+╭───┬─────┬───────╮
+│ a │ b │ c │
+╞═══╪═════╪═══════╡
+│ 1 │ 2.5 │ three │
+╰───┴─────┴───────╯
+(1 row)
+}
+do_test 1.11g {
+ set result "\n[db format {SELECT * FROM t1 WHERE a=2}]"
+} {}
+do_test 1.11h {
+ set result "\n[db format -rowcount on {SELECT * FROM t1 WHERE a=2}]"
+} {
+(0 rows)
+}
+do_test 1.11i {
+ set result "\n[db format -title always -rowcount off {SELECT * FROM t1 WHERE a=2}]"
+} {
+╭───┬───┬───╮
+│ a │ b │ c │
+╰───┴───┴───╯
+}
+do_test 1.11j {
+ set result "\n[db format -title always -rowcount on {SELECT * FROM t1 WHERE a=2}]"
+} {
+╭───┬───┬───╮
+│ a │ b │ c │
+╰───┴───┴───╯
+(0 rows)
+}
+
do_test 1.12 {
set result "\n[db format -text csv {SELECT * FROM t1}]"
} {
do_test 1.118 {
set rc [catch {db format -style list -title unk {SELECT * FROM t1}} res]
lappend rc $res
-} {1 {bad -title "unk": must be off, on, auto, csv, html, json, plain, relaxed, sql, or tcl}}
+} {1 {bad -title "unk": must be off, on, always, auto, csv, html, json, plain, relaxed, sql, or tcl}}
do_test 1.120 {
x'424c4f42',NULL,'Ἀμήν'
}
-
do_execsql_test 2.0 {
DELETE FROM t1;
INSERT INTO t1 VALUES(1,2,'The quick fox jumps over the lazy brown dog.');