u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
u8 bSafeMode; /* True to prohibit unsafe operations */
u8 bSafeModePersist; /* The long-term value of bSafeMode */
+ u8 bQuote; /* Quote results for .mode box and table */
+ int iWrap; /* Wrap lines this long or longer in some output modes */
unsigned statsOn; /* True to display memory stats before each finalize */
unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
int inputNesting; /* Track nesting level of .read and other redirects */
return (char*)zOut;
}
-
+/* Extract the value of the i-th current column for pStmt as an SQL literal
+** value. Memory is obtained from sqlite3_malloc64() and must be freed by
+** the caller.
+*/
+static char *quoted_column(sqlite3_stmt *pStmt, int i){
+ switch( sqlite3_column_type(pStmt, i) ){
+ case SQLITE_NULL: {
+ return sqlite3_mprintf("NULL");
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
+ }
+ case SQLITE_TEXT: {
+ return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
+ }
+ case SQLITE_BLOB: {
+ int j;
+ sqlite3_str *pStr = sqlite3_str_new(0);
+ const unsigned char *a = sqlite3_column_blob(pStmt,i);
+ int n = sqlite3_column_bytes(pStmt,i);
+ sqlite3_str_append(pStr, "x'", 2);
+ for(j=0; j<n; j++){
+ sqlite3_str_appendf(pStr, "%02x", a[j]);
+ }
+ sqlite3_str_append(pStr, "'", 1);
+ return sqlite3_str_finish(pStr);
+ }
+ }
+ return 0; /* Not reached */
+}
/*
** Run a prepared statement and output the result in one of the
char *abRowDiv = 0;
const unsigned char *uz;
const char *z;
+ char **azQuoted = 0;
int rc;
sqlite3_int64 i, nData;
int j, nTotal, w, n;
azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
shell_check_oom(azNextLine);
memset(azNextLine, 0, nColumn*sizeof(char*) );
+ if( p->bQuote ){
+ azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
+ shell_check_oom(azQuoted);
+ memset(azQuoted, 0, nColumn*sizeof(char*) );
+ }
abRowDiv = sqlite3_malloc64( nAlloc/nColumn );
shell_check_oom(abRowDiv);
if( nColumn>p->nWidth ){
abRowDiv[nRow] = 1;
nRow++;
for(i=0; i<nColumn; i++){
+ int w = p->colWidth[i];
+ if( w==0 ) w = p->iWrap;
if( useNextLine ){
uz = azNextLine[i];
+ }else if( p->bQuote ){
+ sqlite3_free(azQuoted[i]);
+ azQuoted[i] = quoted_column(pStmt,i);
+ uz = (const unsigned char*)azQuoted[i];
}else{
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
}
- azData[nRow*nColumn + i] =
- translateForDisplayAndDup(uz, &azNextLine[i], p->colWidth[i]);
+ azData[nRow*nColumn + i] = translateForDisplayAndDup(uz, &azNextLine[i], w);
if( azNextLine[i] ){
bNextLine = 1;
abRowDiv[nRow-1] = 0;
sqlite3_free(azData);
sqlite3_free(azNextLine);
sqlite3_free(abRowDiv);
+ if( azQuoted ){
+ for(i=0; i<nColumn; i++) sqlite3_free(azQuoted[i]);
+ sqlite3_free(azQuoted);
+ }
}
/*
".load FILE ?ENTRY? Load an extension library",
#endif
".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
- ".mode MODE ?TABLE? Set output mode",
+ ".mode MODE ?TABLE? ?OPTIONS? Set output mode",
" MODE is one of:",
- " ascii Columns/rows delimited by 0x1F and 0x1E",
- " box Tables using unicode box-drawing characters",
- " csv Comma-separated values",
- " column Output in columns. (See .width)",
- " html HTML <table> code",
- " insert SQL insert statements for TABLE",
- " json Results in a JSON array",
- " line One value per line",
- " list Values delimited by \"|\"",
- " markdown Markdown table format",
- " quote Escape answers as for SQL",
- " table ASCII-art table",
- " tabs Tab-separated values",
- " tcl TCL list elements",
+ " ascii Columns/rows delimited by 0x1F and 0x1E",
+ " box Tables using unicode box-drawing characters",
+ " csv Comma-separated values",
+ " column Output in columns. (See .width)",
+ " html HTML <table> code",
+ " insert SQL insert statements for TABLE",
+ " json Results in a JSON array",
+ " line One value per line",
+ " list Values delimited by \"|\"",
+ " markdown Markdown table format",
+ " qbox Shorthand for \"box --width 60 --quote\"",
+ " quote Escape answers as for SQL",
+ " table ASCII-art table",
+ " tabs Tab-separated values",
+ " tcl TCL list elements",
+ " OPTIONS: (value for columnar modes only):",
+ " --wrap N Wrap output lines longer than N character",
+ " --quote Quote output text as SQL literals",
+ " --noquote Do not quote output text",
".nonce STRING Disable safe mode for one command if the nonce matches",
".nullvalue STRING Use STRING in place of NULL values",
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
}else
if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
- const char *zMode = nArg>=2 ? azArg[1] : "";
- int n2 = strlen30(zMode);
- int c2 = zMode[0];
- if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
+ const char *zMode = 0;
+ const char *zTabname = 0;
+ int i, n2;
+ int bQuoteChng = 0;
+ int bWrapChng = 0;
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( optionMatch(z,"wrap") && i+1<nArg ){
+ p->iWrap = integerValue(azArg[++i]);
+ bWrapChng = 1;
+ }else if( optionMatch(z,"quote") ){
+ p->bQuote = 1;
+ bQuoteChng = 1;
+ }else if( optionMatch(z,"noquote") ){
+ p->bQuote = 0;
+ bQuoteChng = 1;
+ }else if( zMode==0 ){
+ zMode = z;
+ }else if( zTabname==0 ){
+ zTabname = z;
+ }else if( z[0]=='-' ){
+ utf8_printf(stderr, "unknown option: %s\n", z);
+ utf8_printf(stderr, "options:\n"
+ " --noquote\n"
+ " --quote\n"
+ " --wrap N\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ utf8_printf(stderr, "extra argument: \"%s\"\n", z);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ if( zMode==0 ){
+ if( p->mode==MODE_Column
+ || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
+ ){
+ raw_printf(p->out, "current output mode: %s --wrap %d --%squote\n",
+ modeDescr[p->mode], p->iWrap, p->bQuote ? "" : "no");
+ }else{
+ raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
+ }
+ bWrapChng = bQuoteChng = 1;
+ zMode = modeDescr[p->mode];
+ }
+ n2 = strlen30(zMode);
+ if( strncmp(zMode,"lines",n2)==0 ){
p->mode = MODE_Line;
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
+ }else if( strncmp(zMode,"columns",n2)==0 ){
p->mode = MODE_Column;
if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
p->showHeader = 1;
}
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
+ if( !bWrapChng ) p->iWrap = 0;
+ if( !bQuoteChng ) p->bQuote = 0;
+ }else if( strncmp(zMode,"list",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
+ }else if( strncmp(zMode,"html",n2)==0 ){
p->mode = MODE_Html;
- }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
+ }else if( strncmp(zMode,"tcl",n2)==0 ){
p->mode = MODE_Tcl;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
+ }else if( strncmp(zMode,"csv",n2)==0 ){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
- }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
+ }else if( strncmp(zMode,"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
- }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
+ }else if( strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
- set_table_name(p, nArg>=3 ? azArg[2] : "table");
- }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
+ set_table_name(p, zTabname ? zTabname : "table");
+ }else if( strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
+ }else if( strncmp(zMode,"ascii",n2)==0 ){
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 ){
+ }else if( strncmp(zMode,"markdown",n2)==0 ){
p->mode = MODE_Markdown;
- }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){
+ if( !bWrapChng ) p->iWrap = 0;
+ if( !bQuoteChng ) p->bQuote = 0;
+ }else if( strncmp(zMode,"table",n2)==0 ){
p->mode = MODE_Table;
- }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){
+ if( !bWrapChng ) p->iWrap = 0;
+ if( !bQuoteChng ) p->bQuote = 0;
+ }else if( strncmp(zMode,"box",n2)==0 ){
+ p->mode = MODE_Box;
+ if( !bWrapChng ) p->iWrap = 0;
+ if( !bQuoteChng ) p->bQuote = 0;
+ }else if( strcmp(zMode,"qbox")==0 ){
p->mode = MODE_Box;
- }else if( c2=='c' && strncmp(azArg[1],"count",n2)==0 ){
+ if( !bWrapChng ) p->iWrap = 60;
+ if( !bQuoteChng ) p->bQuote = 1;
+ }else if( strncmp(zMode,"count",n2)==0 ){
p->mode = MODE_Count;
- }else if( c2=='o' && strncmp(azArg[1],"off",n2)==0 ){
+ }else if( strncmp(zMode,"off",n2)==0 ){
p->mode = MODE_Off;
- }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){
+ }else if( strncmp(zMode,"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 box column csv html insert json line list markdown "
- "quote table tabs tcl\n");
+ "qbox quote table tabs tcl\n");
rc = 1;
}
p->cMode = p->mode;
utf8_printf(p->out, "%12.12s: %s\n","explain",
p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
- utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
+ if( p->mode==MODE_Column
+ || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
+ ){
+ utf8_printf(p->out, "%12.12s: %s --wrap %d --%squote\n", "mode",
+ modeDescr[p->mode], p->iWrap, p->bQuote ? "" : "no");
+ }else{
+ utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
+ }
utf8_printf(p->out, "%12.12s: ", "nullvalue");
output_c_string(p->out, p->nullValue);
raw_printf(p->out, "\n");