mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-05 04:30:38 +03:00
In the command-line shell, in CSV output mode, terminate rows with CRNL but
do not expand NL characters in data into CRNL. Provide the extra -newline command-line option and the extra argument to .separator to designate an alternative newline character sequence for CSV output. FossilOrigin-Name: 16c8ce10e1530731441e6c4538691b71564684ed
This commit is contained in:
49
src/shell.c
49
src/shell.c
@@ -64,6 +64,7 @@
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
#define isatty(h) _isatty(h)
|
||||
#ifndef access
|
||||
# define access(f,m) _access((f),(m))
|
||||
@@ -458,6 +459,7 @@ struct callback_data {
|
||||
int showHeader; /* True to show column names in List or Column mode */
|
||||
char *zDestTable; /* Name of destination table when MODE_Insert */
|
||||
char separator[20]; /* Separator character for MODE_List */
|
||||
char newline[20]; /* Record separator in MODE_Csv */
|
||||
int colWidth[100]; /* Requested width of each column when in column mode*/
|
||||
int actualWidth[100]; /* Actual width of each column */
|
||||
char nullvalue[20]; /* The text to print when a NULL comes back from
|
||||
@@ -659,7 +661,8 @@ static const char needCsvQuote[] = {
|
||||
/*
|
||||
** Output a single term of CSV. Actually, p->separator is used for
|
||||
** the separator, which may or may not be a comma. p->nullvalue is
|
||||
** the null value. Strings are quoted if necessary.
|
||||
** the null value. Strings are quoted if necessary. The separator
|
||||
** is only issued if bSep is true.
|
||||
*/
|
||||
static void output_csv(struct callback_data *p, const char *z, int bSep){
|
||||
FILE *out = p->out;
|
||||
@@ -855,17 +858,26 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
|
||||
break;
|
||||
}
|
||||
case MODE_Csv: {
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
fflush(p->out);
|
||||
_setmode(_fileno(p->out), _O_BINARY);
|
||||
#endif
|
||||
if( p->cnt++==0 && p->showHeader ){
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
|
||||
}
|
||||
fprintf(p->out,"\n");
|
||||
fprintf(p->out,"%s",p->newline);
|
||||
}
|
||||
if( azArg==0 ) break;
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azArg[i], i<nArg-1);
|
||||
if( azArg>0 ){
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azArg[i], i<nArg-1);
|
||||
}
|
||||
fprintf(p->out,"%s",p->newline);
|
||||
}
|
||||
fprintf(p->out,"\n");
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
fflush(p->out);
|
||||
_setmode(_fileno(p->out), _O_TEXT);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case MODE_Insert: {
|
||||
@@ -1619,7 +1631,8 @@ static char zHelp[] =
|
||||
".schema ?TABLE? Show the CREATE statements\n"
|
||||
" If TABLE specified, only show tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
".separator STRING Change separator used by output mode and .import\n"
|
||||
".separator STRING ?NL? Change separator used by output mode and .import\n"
|
||||
" NL is the end-of-line mark for CSV\n"
|
||||
".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
|
||||
".show Show the current values for various settings\n"
|
||||
".stats on|off Turn stats on or off\n"
|
||||
@@ -2751,6 +2764,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
|
||||
p->mode = MODE_Csv;
|
||||
sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
|
||||
sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");
|
||||
}else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
|
||||
p->mode = MODE_List;
|
||||
sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
|
||||
@@ -3029,13 +3043,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
#endif
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
sqlite3_snprintf(sizeof(p->separator), p->separator,
|
||||
"%.*s", (int)sizeof(p->separator)-1, azArg[1]);
|
||||
}else{
|
||||
fprintf(stderr, "Usage: .separator STRING\n");
|
||||
if( nArg<2 || nArg>3 ){
|
||||
fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
|
||||
rc = 1;
|
||||
}
|
||||
if( nArg>=2 ){
|
||||
sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);
|
||||
}
|
||||
if( nArg>=3 ){
|
||||
sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='s'
|
||||
@@ -3076,6 +3093,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
strlen30(p->outfile) ? p->outfile : "stdout");
|
||||
fprintf(p->out,"%9.9s: ", "separator");
|
||||
output_c_string(p->out, p->separator);
|
||||
fprintf(p->out," ");
|
||||
output_c_string(p->out, p->newline);
|
||||
fprintf(p->out, "\n");
|
||||
fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: ","width");
|
||||
@@ -3692,6 +3711,7 @@ static const char zOptions[] =
|
||||
#ifdef SQLITE_ENABLE_MULTIPLEX
|
||||
" -multiplex enable the multiplexor VFS\n"
|
||||
#endif
|
||||
" -newline SEP set newline character(s) for CSV\n"
|
||||
" -nullvalue TEXT set text string for NULL values. Default ''\n"
|
||||
" -separator SEP set output field separator. Default: '|'\n"
|
||||
" -stats print memory stats before each finalize\n"
|
||||
@@ -3721,6 +3741,7 @@ static void main_init(struct callback_data *data) {
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->mode = MODE_List;
|
||||
memcpy(data->separator,"|", 2);
|
||||
memcpy(data->newline,"\r\n", 3);
|
||||
data->showHeader = 0;
|
||||
sqlite3_config(SQLITE_CONFIG_URI, 1);
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
|
||||
@@ -3813,6 +3834,7 @@ int main(int argc, char **argv){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-separator")==0
|
||||
|| strcmp(z,"-nullvalue")==0
|
||||
|| strcmp(z,"-newline")==0
|
||||
|| strcmp(z,"-cmd")==0
|
||||
){
|
||||
(void)cmdline_option_value(argc, argv, ++i);
|
||||
@@ -3922,6 +3944,9 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-separator")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.separator), data.separator,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
}else if( strcmp(z,"-newline")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.newline), data.newline,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
}else if( strcmp(z,"-nullvalue")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
|
||||
Reference in New Issue
Block a user