-C Enhance\sthe\s".quote"\smode\sin\sthe\sshell\sso\sthat\sit\shonors\s.separator.
-D 2020-05-28T20:37:17.793
+C Progress\stoward\sadding\snew\soutput\smodes\sto\sthe\sCLI:\s\sjson,\stable,\sand\nmarkdown.
+D 2020-05-28T23:49:50.023
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/resolve.c c2008519a0654f1e7490e9281ed0397d0f14bb840d81f0b96946248afcbdb25d
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 39a00a8bc89596dfb37c16afcbb1d33de5085b9963564b58aafe1566d08c0881
-F src/shell.c.in 2bca5f1474b43e7c0c1bcd0537b854c2e8a0fac0de2bde473b8c1e919554dcc6
+F src/shell.c.in d135e500f2c84808f86e8113fd22852af4c89f69305f122d3c529cd698ccb396
F src/sqlite.h.in 74342b41e9d68ff9e56b192009046f8dd0aa2bd76ce1a588f330de614ba61de7
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test 5bd10014ec494744f5e966a1521334e9d612119a0afcfa5251684a4e1f2ffc66
+F test/shell1.test 1c4713ccec468f9300100d5e1419b414b8dcccc742978ad8942e8bd31d2adc9c
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
F test/shell4.test 1c6aef11daaa2d6830acaba3ac9cbec93fbc1c3d5530743a637f39b3987d08ce
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 98d4262018a81a9a36dd8beb4b02ff0e75cdcbb8a121d143157ffb37b228d60d
-R 6e7a8027469df73da3225b0c75827874
+P b5e33ed537e7d7dcabc9f6dc91d6838e0d1657f323440e09e2e24ffa2ba6141a
+R 65dafea1aa0e6dfee5aa69ebe4f5d82f
U drh
-Z 824af62dceaa57c3d7f60896a599839b
+Z 8f810f781bfa2ede3701aac97fce45df
};
#endif
-/*
-** Shell output mode information from before ".explain on",
-** saved so that it can be restored by ".explain off"
-*/
-typedef struct SavedModeInfo SavedModeInfo;
-struct SavedModeInfo {
- int valid; /* Is there legit data in here? */
- int mode; /* Mode prior to ".explain on" */
- int showHeader; /* The ".header" setting prior to ".explain on" */
- int colWidth[100]; /* Column widths prior to ".explain on" */
-};
-
typedef struct ExpertInfo ExpertInfo;
struct ExpertInfo {
sqlite3expert *pExpert;
#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
#define MODE_Pretty 11 /* Pretty-print schemas */
#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define MODE_Json 13 /* Output JSON */
+#define MODE_Markdown 14 /* Markdown formatting */
+#define MODE_Table 15 /* MySQL-style table formatting */
static const char *modeDescr[] = {
"line",
"explain",
"ascii",
"prettyprint",
- "eqp"
+ "eqp",
+ "json",
+ "markdown",
+ "table"
};
/*
}
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
+/*
+** Print N dashes
+*/
+static void print_dashes(FILE *out, int N){
+ const char zDash[] = "--------------------------------------------------";
+ const int nDash = sizeof(zDash) - 1;
+ while( N>nDash ){
+ fputs(zDash, out);
+ N -= nDash;
+ }
+ raw_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Print a markdown or table-style row separator
+*/
+static void print_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep
+){
+ int i;
+ for(i=0; i<nArg; i++){
+ int w;
+ if( i<ArraySize(p->actualWidth) ){
+ w = p->actualWidth[i];
+ if( w<0 ) w = -w;
+ }else{
+ w = 10;
+ }
+ fputs(zSep, p->out);
+ print_dashes(p->out, w+2);
+ }
+ fputs(zSep, p->out);
+ fputs("\n", p->out);
+}
+
/*
** This is the callback routine that the shell
** invokes for each row of a query result.
}
break;
}
+ case MODE_Table:
+ case MODE_Markdown:
case MODE_Explain:
case MODE_Column: {
static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
const int *colWidth;
int showHdr;
char *rowSep;
+ char *colSep;
+ char *rowStart;
int nWidth;
if( p->cMode==MODE_Column ){
colWidth = p->colWidth;
nWidth = ArraySize(p->colWidth);
showHdr = p->showHeader;
rowSep = p->rowSeparator;
- }else{
+ colSep = " ";
+ rowStart = "";
+ }else if( p->cMode==MODE_Explain ){
colWidth = aExplainWidths;
nWidth = ArraySize(aExplainWidths);
showHdr = 1;
rowSep = SEP_Row;
+ colSep = " ";
+ rowStart = "";
+ }else{
+ colWidth = p->colWidth;
+ nWidth = ArraySize(p->colWidth);
+ showHdr = p->showHeader;
+ rowSep = " |\n";
+ colSep = " | ";
+ rowStart = "| ";
}
if( p->cnt++==0 ){
for(i=0; i<nArg; i++){
if( i<ArraySize(p->actualWidth) ){
p->actualWidth[i] = w;
}
- if( showHdr ){
- utf8_width_print(p->out, w, azCol[i]);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
- }
}
if( showHdr ){
+ if( p->cMode==MODE_Table ){
+ print_row_separator(p, nArg, "+");
+ }
+ fputs(rowStart, p->out);
for(i=0; i<nArg; i++){
int w;
if( i<ArraySize(p->actualWidth) ){
}else{
w = 10;
}
- utf8_printf(p->out,"%-*.*s%s",w,w,
- "----------------------------------------------------------"
- "----------------------------------------------------------",
- i==nArg-1 ? rowSep : " ");
+ utf8_width_print(p->out, w, azCol[i]);
+ fputs(i==nArg-1 ? rowSep : colSep, p->out);
+ }
+ for(i=0; i<nArg; i++){
+ int w;
+ if( i<ArraySize(p->actualWidth) ){
+ 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);
+ }
}
}
}
if( azArg==0 ) break;
+ fputs(rowStart, p->out);
for(i=0; i<nArg; i++){
int w;
if( i<ArraySize(p->actualWidth) ){
p->iIndent++;
}
utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
+ utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : colSep);
}
break;
}
raw_printf(p->out,");\n");
break;
}
+ case MODE_Json: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 ){
+ fputs("[{", p->out);
+ }else{
+ fputs(",\n{", p->out);
+ }
+ p->cnt++;
+ for(i=0; i<nArg; i++){
+ output_c_string(p->out, azCol[i]);
+ putc(':', p->out);
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ fputs("null",p->out);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_uint64 ur;
+ memcpy(&ur,&r,sizeof(r));
+ if( ur==0x7ff0000000000000LL ){
+ raw_printf(p->out, "1e999");
+ }else if( ur==0xfff0000000000000LL ){
+ raw_printf(p->out, "-1e999");
+ }else{
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ putc('"', p->out);
+ output_hex_blob(p->out, pBlob, nBlob);
+ putc('"', p->out);
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ output_c_string(p->out, azArg[i]);
+ }else{
+ utf8_printf(p->out,"%s", azArg[i]);
+ }
+ if( i<nArg-1 ){
+ putc(',', p->out);
+ }
+ }
+ putc('}', p->out);
+ break;
+ }
case MODE_Quote: {
if( azArg==0 ) break;
if( p->cnt==0 && p->showHeader ){
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.
+**
+** 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 */
+){
+
+}
+#endif
+
/*
** Run a prepared statement
*/
}
} while( SQLITE_ROW == rc );
sqlite3_free(pData);
+ if( pArg->cMode==MODE_Table ){
+ print_row_separator(pArg, nCol, "+");
+ }else if( pArg->cMode==MODE_Json ){
+ fputs("]\n", pArg->out);
+ }
}
}
}
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
+ }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){
+ p->mode = MODE_Markdown;
+ }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){
+ p->mode = MODE_Table;
+ }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){
+ p->mode = MODE_Json;
}else if( nArg==1 ){
raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
}else{
raw_printf(stderr, "Error: mode should be one of: "
- "ascii column csv html insert line list quote tabs tcl\n");
+ "ascii column csv html insert json line list markdown "
+ "quote table tabs tcl\n");
rc = 1;
}
p->cMode = p->mode;
" -help show this message\n"
" -html set output mode to HTML\n"
" -interactive force interactive I/O\n"
+ " -json set output mode to 'json'\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
+ " -markdown set output mode to 'markdown'\n"
#if defined(SQLITE_ENABLE_DESERIALIZE)
" -maxsize N maximum size for a --deserialize database\n"
#endif
" -sorterref SIZE sorter references threshold size\n"
#endif
" -stats print memory stats before each finalize\n"
+ " -table set output mode to 'table'\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
+ }else if( strcmp(z,"-json")==0 ){
+ data.mode = MODE_Json;
+ }else if( strcmp(z,"-markdown")==0 ){
+ data.mode = MODE_Markdown;
+ }else if( strcmp(z,"-table")==0 ){
+ data.mode = MODE_Table;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);