From: drh Date: Fri, 29 May 2020 16:15:58 +0000 (+0000) Subject: Improvements to columnar output in the CLI. Columns automatically expand X-Git-Tag: version-3.33.0~160 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8c748633a9ac764766dca9c2e9872a2996414945;p=thirdparty%2Fsqlite.git Improvements to columnar output in the CLI. Columns automatically expand to contain the largest row. FossilOrigin-Name: 4e1db8e9a9ee370a398f13fd8546a520111b8cfb84460389535b5bc5bd9f4f82 --- diff --git a/manifest b/manifest index edf9e43a80..d4109e2ff9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Space\sto\shold\sthe\s".width"\sof\scolumns\sin\sthe\sCLI\sis\snow\sobtained\sfrom\nmalloc()\sand\shence\sis\snot\slimited\sin\sthe\snumber\sof\scolumns\ssupported. -D 2020-05-29T14:38:43.840 +C Improvements\sto\scolumnar\soutput\sin\sthe\sCLI.\s\sColumns\sautomatically\sexpand\nto\scontain\sthe\slargest\srow. +D 2020-05-29T16:15:58.318 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -534,7 +534,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c c2008519a0654f1e7490e9281ed0397d0f14bb840d81f0b96946248afcbdb25d F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 39a00a8bc89596dfb37c16afcbb1d33de5085b9963564b58aafe1566d08c0881 -F src/shell.c.in 77530a909ab0e8e44c7797993b0f3143e95226380bc5f311158ad3e3209abf28 +F src/shell.c.in 9675df5f6be969309421509eef9c49a20179e5c4df8770f2d62edd41a9dee339 F src/sqlite.h.in 74342b41e9d68ff9e56b192009046f8dd0aa2bd76ce1a588f330de614ba61de7 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197 @@ -1866,7 +1866,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P af28bff91ad7e2d69db0052323c9c05c75a41d4134974bd1305f1c4f579d3558 -R 7199cbe7bb1c2e7279bcd8d792b04d19 +P 445ed5dab2c26e9f4a7fb5277abdba3359d23cf5318cfd0d8322162d9616ee7a +R 5cd70920783d10744759d8e97b9aed09 U drh -Z e4dd532cb0e0bd045df8215b6bacef2f +Z 0a5f6eacc5288734a9f57cf18ebe2785 diff --git a/manifest.uuid b/manifest.uuid index 589b69c5fc..cbe0de7cd3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -445ed5dab2c26e9f4a7fb5277abdba3359d23cf5318cfd0d8322162d9616ee7a \ No newline at end of file +4e1db8e9a9ee370a398f13fd8546a520111b8cfb84460389535b5bc5bd9f4f82 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 299670755d..e4883c1474 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1945,15 +1945,8 @@ static void print_row_separator( ){ int i; for(i=0; iactualWidth) ){ - w = p->actualWidth[i]; - if( w<0 ) w = -w; - }else{ - w = 10; - } fputs(zSep, p->out); - print_dashes(p->out, w+2); + print_dashes(p->out, p->actualWidth[i]+2); } fputs(zSep, p->out); fputs("\n", p->out); @@ -1989,125 +1982,32 @@ static int shell_callback( } break; } - case MODE_Table: - case MODE_Markdown: - case MODE_Explain: - case MODE_Column: { - int showHdr; - char *rowSep; - char *colSep; - char *rowStart; - if( p->cMode==MODE_Column ){ - showHdr = p->showHeader; - rowSep = p->rowSeparator; - colSep = " "; - rowStart = ""; - }else if( p->cMode==MODE_Explain ){ - showHdr = 1; - rowSep = SEP_Row; - colSep = " "; - rowStart = ""; - }else{ - showHdr = 1; - rowSep = " |\n"; - colSep = " | "; - rowStart = "| "; + case MODE_Explain: { + static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13}; + if( nArg>ArraySize(aExplainWidth) ){ + nArg = ArraySize(aExplainWidth); } - if( p->cnt++==0 ){ - /* Compute column widths in p->actualWidth[] when the first row - ** is seen. The width of each column is either the defined - ** width in p->colWidth[], or if p->colWidth[i]==0, then the - ** width is the larger of the width of the first row and the - ** column name. */ - static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13}; - const int *colWidth; - int nWidth; - if( p->cMode==MODE_Explain ){ - colWidth = aExplainWidths; - nWidth = ArraySize(aExplainWidths); - }else{ - colWidth = p->colWidth; - nWidth = p->nWidth; - } for(i=0; inullValue); - if( wactualWidth) ){ - p->actualWidth[i] = w; - } - } - if( p->cMode==MODE_Table ){ - print_row_separator(p, nArg, "+"); - } - if( showHdr ){ - fputs(rowStart, p->out); - for(i=0; iactualWidth) ){ - w = p->actualWidth[i]; - if( w<0 ) w = -w; - }else{ - w = 10; - } - utf8_width_print(p->out, w, azCol[i]); - fputs(i==nArg-1 ? rowSep : colSep, p->out); - } - for(i=0; iactualWidth) ){ - w = p->actualWidth[i]; - if( w<0 ) w = -w; - }else{ - w = 10; - } - if( p->cMode==MODE_Table || p->cMode==MODE_Markdown ){ - char *zX = p->cMode==MODE_Markdown ? "|" : "+"; - fputs(zX, p->out); - print_dashes(p->out, w+2); - if( i==nArg-1 ){ - fputs(zX, p->out); - fputs("\n", p->out); - } - }else{ - print_dashes(p->out, w); - fputs(i==nArg-1 ? rowSep : colSep, p->out); - } - } + int w = aExplainWidth[i]; + utf8_width_print(p->out, w, azCol[i]); + fputs(i==nArg-1 ? "\n" : " ", p->out); } } if( azArg==0 ) break; - fputs(rowStart, p->out); for(i=0; iactualWidth) ){ - w = p->actualWidth[i]; - }else{ - w = 10; + int w = aExplainWidth[i]; + if( azArg[i] && strlenChar(azArg[i])>w ){ + w = strlenChar(azArg[i]); } - if( p->cMode==MODE_Explain ){ - if( azArg[i] && strlenChar(azArg[i])>w ){ - w = strlenChar(azArg[i]); - } - if( i==1 && p->aiIndent && p->pStmt ){ - if( p->iIndentnIndent ){ - utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); - } - p->iIndent++; + if( i==1 && p->aiIndent && p->pStmt ){ + if( p->iIndentnIndent ){ + utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); } + p->iIndent++; } utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue); - utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : colSep); + fputs(i==nArg-1 ? "\n" : " ", p->out); } break; } @@ -3042,23 +2942,105 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){ sqlite3_finalize(pQ); } -#if 0 /* ** Run a prepared statement and output the result in one of the -** table-oriented formats, either MODE_Markdown or MODE_Table. +** table-oriented formats: MODE_Column, MODE_Markdown, or MODE_Table. ** ** This is different from ordinary exec_prepared_stmt() in that ** it has to run the entire query and gather the results into memory ** first, in order to determine column widths, before providing ** any output. */ -static void exec_prepared_stmt_tablemode( - ShellState *pArg, /* Pointer to ShellState */ - sqlite3_stmt *pStmt /* Statment to run */ +static void exec_prepared_stmt_columnar( + ShellState *p, /* Pointer to ShellState */ + sqlite3_stmt *pStmt /* Statment to run */ ){ + int nRow = 0; + int nColumn = 0; + char **azData = 0; + char *zMsg = 0; + const char *z; + int rc; + int i, j, nTotal, w, n; + const char *colSep; + const char *rowSep; + rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt), + &azData, &nRow, &nColumn, &zMsg); + if( rc ){ + utf8_printf(p->out, "ERROR: %s\n", zMsg); + sqlite3_free(zMsg); + sqlite3_free_table(azData); + return; + } + if( nColumn>p->nWidth ){ + p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int)); + if( p->colWidth==0 ) shell_out_of_memory(); + for(i=p->nWidth; icolWidth[i] = 0; + p->nWidth = nColumn; + p->actualWidth = &p->colWidth[nColumn]; + } + memset(p->actualWidth, 0, nColumn*sizeof(int)); + for(i=0; icolWidth[i]; + if( w<0 ) w = -w; + p->actualWidth[i] = w; + } + nTotal = nColumn*(nRow+1); + for(i=0; inullValue; + n = strlenChar(z); + j = i%nColumn; + if( n>p->actualWidth[j] ) p->actualWidth[j] = n; + } + if( p->cMode==MODE_Column ){ + colSep = " "; + rowSep = "\n"; + if( p->showHeader ){ + for(i=0; iactualWidth[i]; + if( p->colWidth[i]<0 ) w = -w; + utf8_width_print(p->out, w, azData[i]); + fputs(i==nColumn-1?"\n":" ", p->out); + } + for(i=0; iout, p->actualWidth[i]); + fputs(i==nColumn-1?"\n":" ", p->out); + } + } + }else{ + colSep = " | "; + rowSep = " |\n"; + if( p->cMode==MODE_Table ) print_row_separator(p, nColumn, "+"); + fputs("| ", p->out); + for(i=0; iactualWidth[i]; + n = strlenChar(azData[i]); + utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); + fputs(i==nColumn-1?" |\n":" | ", p->out); + } + print_row_separator(p, nColumn, p->cMode==MODE_Table ? "+" : "|"); + } + for(i=nColumn, j=0; icMode!=MODE_Column ) fputs("| ", p->out); + z = azData[i]; + if( z==0 ) z = p->nullValue; + w = p->actualWidth[j]; + if( p->colWidth[j]<0 ) w = -w; + utf8_width_print(p->out, w, z); + if( j==nColumn-1 ){ + fputs(rowSep, p->out); + j = -1; + }else{ + fputs(colSep, p->out); + } + } + if( p->cMode==MODE_Table ){ + print_row_separator(p, nColumn, "+"); + } + sqlite3_free_table(azData); } -#endif /* ** Run a prepared statement @@ -3069,6 +3051,14 @@ static void exec_prepared_stmt( ){ int rc; + if( pArg->cMode==MODE_Column + || pArg->cMode==MODE_Table + || pArg->cMode==MODE_Markdown + ){ + exec_prepared_stmt_columnar(pArg, pStmt); + return; + } + /* perform the first step. this will tell us if we ** have a result set or not and how wide it is. */