mirror of
				https://github.com/sqlite/sqlite.git
				synced 2025-11-03 16:53:36 +03:00 
			
		
		
		
	Merge trunk 3.8.8 beta changes into the sessions branch
FossilOrigin-Name: 0ba124540b5b2a9ceda0f4f4a46e6be54edad813
This commit is contained in:
		
							
								
								
									
										388
									
								
								src/shell.c
									
									
									
									
									
								
							
							
						
						
									
										388
									
								
								src/shell.c
									
									
									
									
									
								
							@@ -17,6 +17,13 @@
 | 
			
		||||
#define _CRT_SECURE_NO_WARNINGS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** If requested, include the SQLite compiler options file for MSVC.
 | 
			
		||||
*/
 | 
			
		||||
#if defined(INCLUDE_MSVC_H)
 | 
			
		||||
#include "msvc.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** Enable large-file support for fopen() and friends on unix.
 | 
			
		||||
*/
 | 
			
		||||
@@ -48,17 +55,16 @@
 | 
			
		||||
# include <sys/types.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_READLINE) && HAVE_READLINE!=0
 | 
			
		||||
#if HAVE_READLINE
 | 
			
		||||
# include <readline/readline.h>
 | 
			
		||||
# include <readline/history.h>
 | 
			
		||||
#else
 | 
			
		||||
# undef HAVE_READLINE
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
 | 
			
		||||
#if HAVE_EDITLINE
 | 
			
		||||
# undef HAVE_READLINE
 | 
			
		||||
# define HAVE_READLINE 1
 | 
			
		||||
# include <editline/readline.h>
 | 
			
		||||
#endif
 | 
			
		||||
#if !defined(HAVE_READLINE)
 | 
			
		||||
#if !HAVE_READLINE
 | 
			
		||||
# define add_history(X)
 | 
			
		||||
# define read_history(X)
 | 
			
		||||
# define write_history(X)
 | 
			
		||||
@@ -425,7 +431,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
 | 
			
		||||
    zResult = local_getline(zPrior, in);
 | 
			
		||||
  }else{
 | 
			
		||||
    zPrompt = isContinuation ? continuePrompt : mainPrompt;
 | 
			
		||||
#if defined(HAVE_READLINE)
 | 
			
		||||
#if HAVE_READLINE
 | 
			
		||||
    free(zPrior);
 | 
			
		||||
    zResult = readline(zPrompt);
 | 
			
		||||
    if( zResult && *zResult ) add_history(zResult);
 | 
			
		||||
@@ -484,11 +490,11 @@ struct ShellState {
 | 
			
		||||
  int showHeader;        /* True to show column names in List or Column mode */
 | 
			
		||||
  unsigned shellFlgs;    /* Various flags */
 | 
			
		||||
  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 */
 | 
			
		||||
  char colSeparator[20]; /* Column separator character for several modes */
 | 
			
		||||
  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
 | 
			
		||||
  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
 | 
			
		||||
  char nullValue[20];    /* The text to print when a NULL comes back from
 | 
			
		||||
                         ** the database */
 | 
			
		||||
  SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
 | 
			
		||||
  char outfile[FILENAME_MAX]; /* Filename for *out */
 | 
			
		||||
@@ -525,6 +531,7 @@ struct ShellState {
 | 
			
		||||
#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
 | 
			
		||||
#define MODE_Csv      7  /* Quote strings, numbers are plain */
 | 
			
		||||
#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
 | 
			
		||||
#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */
 | 
			
		||||
 | 
			
		||||
static const char *modeDescr[] = {
 | 
			
		||||
  "line",
 | 
			
		||||
@@ -536,8 +543,22 @@ static const char *modeDescr[] = {
 | 
			
		||||
  "tcl",
 | 
			
		||||
  "csv",
 | 
			
		||||
  "explain",
 | 
			
		||||
  "ascii",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** These are the column/row/line separators used by the various
 | 
			
		||||
** import/export modes.
 | 
			
		||||
*/
 | 
			
		||||
#define SEP_Column    "|"
 | 
			
		||||
#define SEP_Row       "\n"
 | 
			
		||||
#define SEP_Tab       "\t"
 | 
			
		||||
#define SEP_Space     " "
 | 
			
		||||
#define SEP_Comma     ","
 | 
			
		||||
#define SEP_CrLf      "\r\n"
 | 
			
		||||
#define SEP_Unit      "\x1F"
 | 
			
		||||
#define SEP_Record    "\x1E"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** Number of elements in an array
 | 
			
		||||
*/
 | 
			
		||||
@@ -694,22 +715,22 @@ 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
 | 
			
		||||
** Output a single term of CSV.  Actually, p->colSeparator 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 separator
 | 
			
		||||
** is only issued if bSep is true.
 | 
			
		||||
*/
 | 
			
		||||
static void output_csv(ShellState *p, const char *z, int bSep){
 | 
			
		||||
  FILE *out = p->out;
 | 
			
		||||
  if( z==0 ){
 | 
			
		||||
    fprintf(out,"%s",p->nullvalue);
 | 
			
		||||
    fprintf(out,"%s",p->nullValue);
 | 
			
		||||
  }else{
 | 
			
		||||
    int i;
 | 
			
		||||
    int nSep = strlen30(p->separator);
 | 
			
		||||
    int nSep = strlen30(p->colSeparator);
 | 
			
		||||
    for(i=0; z[i]; i++){
 | 
			
		||||
      if( needCsvQuote[((unsigned char*)z)[i]] 
 | 
			
		||||
         || (z[i]==p->separator[0] && 
 | 
			
		||||
             (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
 | 
			
		||||
         || (z[i]==p->colSeparator[0] && 
 | 
			
		||||
             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
 | 
			
		||||
        i = 0;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
@@ -726,7 +747,7 @@ static void output_csv(ShellState *p, const char *z, int bSep){
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if( bSep ){
 | 
			
		||||
    fprintf(p->out, "%s", p->separator);
 | 
			
		||||
    fprintf(p->out, "%s", p->colSeparator);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -764,10 +785,10 @@ static int shell_callback(
 | 
			
		||||
        int len = strlen30(azCol[i] ? azCol[i] : "");
 | 
			
		||||
        if( len>w ) w = len;
 | 
			
		||||
      }
 | 
			
		||||
      if( p->cnt++>0 ) fprintf(p->out,"\n");
 | 
			
		||||
      if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        fprintf(p->out,"%*s = %s\n", w, azCol[i],
 | 
			
		||||
                azArg[i] ? azArg[i] : p->nullvalue);
 | 
			
		||||
        fprintf(p->out,"%*s = %s%s", w, azCol[i],
 | 
			
		||||
                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
@@ -784,7 +805,7 @@ static int shell_callback(
 | 
			
		||||
          if( w==0 ){
 | 
			
		||||
            w = strlen30(azCol[i] ? azCol[i] : "");
 | 
			
		||||
            if( w<10 ) w = 10;
 | 
			
		||||
            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
 | 
			
		||||
            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
 | 
			
		||||
            if( w<n ) w = n;
 | 
			
		||||
          }
 | 
			
		||||
          if( i<ArraySize(p->actualWidth) ){
 | 
			
		||||
@@ -792,9 +813,11 @@ static int shell_callback(
 | 
			
		||||
          }
 | 
			
		||||
          if( p->showHeader ){
 | 
			
		||||
            if( w<0 ){
 | 
			
		||||
              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": "  ");
 | 
			
		||||
              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
 | 
			
		||||
                      i==nArg-1 ? p->rowSeparator : "  ");
 | 
			
		||||
            }else{
 | 
			
		||||
              fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
 | 
			
		||||
              fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
 | 
			
		||||
                      i==nArg-1 ? p->rowSeparator : "  ");
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
@@ -809,7 +832,7 @@ static int shell_callback(
 | 
			
		||||
            }
 | 
			
		||||
            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
 | 
			
		||||
                   "----------------------------------------------------------",
 | 
			
		||||
                    i==nArg-1 ? "\n": "  ");
 | 
			
		||||
                    i==nArg-1 ? p->rowSeparator : "  ");
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
@@ -832,10 +855,12 @@ static int shell_callback(
 | 
			
		||||
        }
 | 
			
		||||
        if( w<0 ){
 | 
			
		||||
          fprintf(p->out,"%*.*s%s",-w,-w,
 | 
			
		||||
              azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
 | 
			
		||||
              azArg[i] ? azArg[i] : p->nullValue,
 | 
			
		||||
              i==nArg-1 ? p->rowSeparator : "  ");
 | 
			
		||||
        }else{
 | 
			
		||||
          fprintf(p->out,"%-*.*s%s",w,w,
 | 
			
		||||
              azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
 | 
			
		||||
              azArg[i] ? azArg[i] : p->nullValue,
 | 
			
		||||
              i==nArg-1 ? p->rowSeparator : "  ");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
@@ -844,20 +869,21 @@ static int shell_callback(
 | 
			
		||||
    case MODE_List: {
 | 
			
		||||
      if( p->cnt++==0 && p->showHeader ){
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
 | 
			
		||||
          fprintf(p->out,"%s%s",azCol[i],
 | 
			
		||||
                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if( azArg==0 ) break;
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        char *z = azArg[i];
 | 
			
		||||
        if( z==0 ) z = p->nullvalue;
 | 
			
		||||
        if( z==0 ) z = p->nullValue;
 | 
			
		||||
        fprintf(p->out, "%s", z);
 | 
			
		||||
        if( i<nArg-1 ){
 | 
			
		||||
          fprintf(p->out, "%s", p->separator);
 | 
			
		||||
          fprintf(p->out, "%s", p->colSeparator);
 | 
			
		||||
        }else if( p->mode==MODE_Semi ){
 | 
			
		||||
          fprintf(p->out, ";\n");
 | 
			
		||||
          fprintf(p->out, ";%s", p->rowSeparator);
 | 
			
		||||
        }else{
 | 
			
		||||
          fprintf(p->out, "\n");
 | 
			
		||||
          fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
@@ -876,7 +902,7 @@ static int shell_callback(
 | 
			
		||||
      fprintf(p->out,"<TR>");
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        fprintf(p->out,"<TD>");
 | 
			
		||||
        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
 | 
			
		||||
        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
 | 
			
		||||
        fprintf(p->out,"</TD>\n");
 | 
			
		||||
      }
 | 
			
		||||
      fprintf(p->out,"</TR>\n");
 | 
			
		||||
@@ -886,16 +912,16 @@ static int shell_callback(
 | 
			
		||||
      if( p->cnt++==0 && p->showHeader ){
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          output_c_string(p->out,azCol[i] ? azCol[i] : "");
 | 
			
		||||
          if(i<nArg-1) fprintf(p->out, "%s", p->separator);
 | 
			
		||||
          if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(p->out,"\n");
 | 
			
		||||
        fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      }
 | 
			
		||||
      if( azArg==0 ) break;
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
 | 
			
		||||
        if(i<nArg-1) fprintf(p->out, "%s", p->separator);
 | 
			
		||||
        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
 | 
			
		||||
        if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
 | 
			
		||||
      }
 | 
			
		||||
      fprintf(p->out,"\n");
 | 
			
		||||
      fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MODE_Csv: {
 | 
			
		||||
@@ -907,13 +933,13 @@ static int shell_callback(
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(p->out,"%s",p->newline);
 | 
			
		||||
        fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      }
 | 
			
		||||
      if( nArg>0 ){
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          output_csv(p, azArg[i], i<nArg-1);
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(p->out,"%s",p->newline);
 | 
			
		||||
        fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      }
 | 
			
		||||
#if defined(WIN32) || defined(_WIN32)
 | 
			
		||||
      fflush(p->out);
 | 
			
		||||
@@ -950,6 +976,22 @@ static int shell_callback(
 | 
			
		||||
      fprintf(p->out,");\n");
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MODE_Ascii: {
 | 
			
		||||
      if( p->cnt++==0 && p->showHeader ){
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
 | 
			
		||||
          fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      }
 | 
			
		||||
      if( azArg==0 ) break;
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
 | 
			
		||||
        fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
 | 
			
		||||
      }
 | 
			
		||||
      fprintf(p->out, "%s", p->rowSeparator);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -1715,12 +1757,13 @@ static char zHelp[] =
 | 
			
		||||
#endif
 | 
			
		||||
  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
 | 
			
		||||
  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
 | 
			
		||||
  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
 | 
			
		||||
  "                         csv      Comma-separated values\n"
 | 
			
		||||
  "                         column   Left-aligned columns.  (See .width)\n"
 | 
			
		||||
  "                         html     HTML <table> code\n"
 | 
			
		||||
  "                         insert   SQL insert statements for TABLE\n"
 | 
			
		||||
  "                         line     One value per line\n"
 | 
			
		||||
  "                         list     Values delimited by .separator string\n"
 | 
			
		||||
  "                         list     Values delimited by .separator strings\n"
 | 
			
		||||
  "                         tabs     Tab-separated values\n"
 | 
			
		||||
  "                         tcl      TCL list elements\n"
 | 
			
		||||
  ".nullvalue STRING      Use STRING in place of NULL values\n"
 | 
			
		||||
@@ -1737,8 +1780,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 ?NL? Change separator used by output mode and .import\n"
 | 
			
		||||
  "                         NL is the end-of-line mark for CSV\n"
 | 
			
		||||
  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
 | 
			
		||||
  "                         separator for both the output mode and .import\n"
 | 
			
		||||
#if defined(SQLITE_ENABLE_SESSION)
 | 
			
		||||
  ".session CMD ...       Create or control sessions\n"
 | 
			
		||||
#endif
 | 
			
		||||
@@ -2091,10 +2134,10 @@ static void test_breakpoint(void){
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** An object used to read a CSV file
 | 
			
		||||
** An object used to read a CSV and other files for import.
 | 
			
		||||
*/
 | 
			
		||||
typedef struct CSVReader CSVReader;
 | 
			
		||||
struct CSVReader {
 | 
			
		||||
typedef struct ImportCtx ImportCtx;
 | 
			
		||||
struct ImportCtx {
 | 
			
		||||
  const char *zFile;  /* Name of the input file */
 | 
			
		||||
  FILE *in;           /* Read the CSV text from this input stream */
 | 
			
		||||
  char *z;            /* Accumulated text for a field */
 | 
			
		||||
@@ -2102,11 +2145,12 @@ struct CSVReader {
 | 
			
		||||
  int nAlloc;         /* Space allocated for z[] */
 | 
			
		||||
  int nLine;          /* Current line number */
 | 
			
		||||
  int cTerm;          /* Character that terminated the most recent field */
 | 
			
		||||
  int cSeparator;     /* The separator character.  (Usually ",") */
 | 
			
		||||
  int cColSep;        /* The column separator character.  (Usually ",") */
 | 
			
		||||
  int cRowSep;        /* The row separator character.  (Usually "\n") */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Append a single byte to z[] */
 | 
			
		||||
static void csv_append_char(CSVReader *p, int c){
 | 
			
		||||
static void import_append_char(ImportCtx *p, int c){
 | 
			
		||||
  if( p->n+1>=p->nAlloc ){
 | 
			
		||||
    p->nAlloc += p->nAlloc + 100;
 | 
			
		||||
    p->z = sqlite3_realloc(p->z, p->nAlloc);
 | 
			
		||||
@@ -2124,15 +2168,17 @@ static void csv_append_char(CSVReader *p, int c){
 | 
			
		||||
**   +  Input comes from p->in.
 | 
			
		||||
**   +  Store results in p->z of length p->n.  Space to hold p->z comes
 | 
			
		||||
**      from sqlite3_malloc().
 | 
			
		||||
**   +  Use p->cSep as the separator.  The default is ",".
 | 
			
		||||
**   +  Use p->cSep as the column separator.  The default is ",".
 | 
			
		||||
**   +  Use p->rSep as the row separator.  The default is "\n".
 | 
			
		||||
**   +  Keep track of the line number in p->nLine.
 | 
			
		||||
**   +  Store the character that terminates the field in p->cTerm.  Store
 | 
			
		||||
**      EOF on end-of-file.
 | 
			
		||||
**   +  Report syntax errors on stderr
 | 
			
		||||
*/
 | 
			
		||||
static char *csv_read_one_field(CSVReader *p){
 | 
			
		||||
  int c, pc, ppc;
 | 
			
		||||
  int cSep = p->cSeparator;
 | 
			
		||||
static char *csv_read_one_field(ImportCtx *p){
 | 
			
		||||
  int c;
 | 
			
		||||
  int cSep = p->cColSep;
 | 
			
		||||
  int rSep = p->cRowSep;
 | 
			
		||||
  p->n = 0;
 | 
			
		||||
  c = fgetc(p->in);
 | 
			
		||||
  if( c==EOF || seenInterrupt ){
 | 
			
		||||
@@ -2140,12 +2186,13 @@ static char *csv_read_one_field(CSVReader *p){
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  if( c=='"' ){
 | 
			
		||||
    int pc, ppc;
 | 
			
		||||
    int startLine = p->nLine;
 | 
			
		||||
    int cQuote = c;
 | 
			
		||||
    pc = ppc = 0;
 | 
			
		||||
    while( 1 ){
 | 
			
		||||
      c = fgetc(p->in);
 | 
			
		||||
      if( c=='\n' ) p->nLine++;
 | 
			
		||||
      if( c==rSep ) p->nLine++;
 | 
			
		||||
      if( c==cQuote ){
 | 
			
		||||
        if( pc==cQuote ){
 | 
			
		||||
          pc = 0;
 | 
			
		||||
@@ -2153,8 +2200,8 @@ static char *csv_read_one_field(CSVReader *p){
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if( (c==cSep && pc==cQuote)
 | 
			
		||||
       || (c=='\n' && pc==cQuote)
 | 
			
		||||
       || (c=='\n' && pc=='\r' && ppc==cQuote)
 | 
			
		||||
       || (c==rSep && pc==cQuote)
 | 
			
		||||
       || (c==rSep && pc=='\r' && ppc==cQuote)
 | 
			
		||||
       || (c==EOF && pc==cQuote)
 | 
			
		||||
      ){
 | 
			
		||||
        do{ p->n--; }while( p->z[p->n]!=cQuote );
 | 
			
		||||
@@ -2168,19 +2215,19 @@ static char *csv_read_one_field(CSVReader *p){
 | 
			
		||||
      if( c==EOF ){
 | 
			
		||||
        fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
 | 
			
		||||
                p->zFile, startLine, cQuote);
 | 
			
		||||
        p->cTerm = EOF;
 | 
			
		||||
        p->cTerm = c;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      csv_append_char(p, c);
 | 
			
		||||
      import_append_char(p, c);
 | 
			
		||||
      ppc = pc;
 | 
			
		||||
      pc = c;
 | 
			
		||||
    }
 | 
			
		||||
  }else{
 | 
			
		||||
    while( c!=EOF && c!=cSep && c!='\n' ){
 | 
			
		||||
      csv_append_char(p, c);
 | 
			
		||||
    while( c!=EOF && c!=cSep && c!=rSep ){
 | 
			
		||||
      import_append_char(p, c);
 | 
			
		||||
      c = fgetc(p->in);
 | 
			
		||||
    }
 | 
			
		||||
    if( c=='\n' ){
 | 
			
		||||
    if( c==rSep ){
 | 
			
		||||
      p->nLine++;
 | 
			
		||||
      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
 | 
			
		||||
    }
 | 
			
		||||
@@ -2190,6 +2237,40 @@ static char *csv_read_one_field(CSVReader *p){
 | 
			
		||||
  return p->z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read a single field of ASCII delimited text.
 | 
			
		||||
**
 | 
			
		||||
**   +  Input comes from p->in.
 | 
			
		||||
**   +  Store results in p->z of length p->n.  Space to hold p->z comes
 | 
			
		||||
**      from sqlite3_malloc().
 | 
			
		||||
**   +  Use p->cSep as the column separator.  The default is "\x1F".
 | 
			
		||||
**   +  Use p->rSep as the row separator.  The default is "\x1E".
 | 
			
		||||
**   +  Keep track of the row number in p->nLine.
 | 
			
		||||
**   +  Store the character that terminates the field in p->cTerm.  Store
 | 
			
		||||
**      EOF on end-of-file.
 | 
			
		||||
**   +  Report syntax errors on stderr
 | 
			
		||||
*/
 | 
			
		||||
static char *ascii_read_one_field(ImportCtx *p){
 | 
			
		||||
  int c;
 | 
			
		||||
  int cSep = p->cColSep;
 | 
			
		||||
  int rSep = p->cRowSep;
 | 
			
		||||
  p->n = 0;
 | 
			
		||||
  c = fgetc(p->in);
 | 
			
		||||
  if( c==EOF || seenInterrupt ){
 | 
			
		||||
    p->cTerm = EOF;
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  while( c!=EOF && c!=cSep && c!=rSep ){
 | 
			
		||||
    import_append_char(p, c);
 | 
			
		||||
    c = fgetc(p->in);
 | 
			
		||||
  }
 | 
			
		||||
  if( c==rSep ){
 | 
			
		||||
    p->nLine++;
 | 
			
		||||
  }
 | 
			
		||||
  p->cTerm = c;
 | 
			
		||||
  if( p->z ) p->z[p->n] = 0;
 | 
			
		||||
  return p->z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** Try to transfer data for table zTable.  If an error is seen while
 | 
			
		||||
** moving forward, try to go backwards.  The backwards movement won't
 | 
			
		||||
@@ -2744,9 +2825,10 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
    int nByte;                  /* Number of bytes in an SQL string */
 | 
			
		||||
    int i, j;                   /* Loop counters */
 | 
			
		||||
    int needCommit;             /* True to COMMIT or ROLLBACK at end */
 | 
			
		||||
    int nSep;                   /* Number of bytes in p->separator[] */
 | 
			
		||||
    int nSep;                   /* Number of bytes in p->colSeparator[] */
 | 
			
		||||
    char *zSql;                 /* An SQL statement */
 | 
			
		||||
    CSVReader sCsv;             /* Reader context */
 | 
			
		||||
    ImportCtx sCtx;             /* Reader context */
 | 
			
		||||
    char *(*xRead)(ImportCtx*); /* Procedure to read one value */
 | 
			
		||||
    int (*xCloser)(FILE*);      /* Procedure to close th3 connection */
 | 
			
		||||
 | 
			
		||||
    if( nArg!=3 ){
 | 
			
		||||
@@ -2756,55 +2838,79 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
    zFile = azArg[1];
 | 
			
		||||
    zTable = azArg[2];
 | 
			
		||||
    seenInterrupt = 0;
 | 
			
		||||
    memset(&sCsv, 0, sizeof(sCsv));
 | 
			
		||||
    memset(&sCtx, 0, sizeof(sCtx));
 | 
			
		||||
    open_db(p, 0);
 | 
			
		||||
    nSep = strlen30(p->separator);
 | 
			
		||||
    nSep = strlen30(p->colSeparator);
 | 
			
		||||
    if( nSep==0 ){
 | 
			
		||||
      fprintf(stderr, "Error: non-null separator required for import\n");
 | 
			
		||||
      fprintf(stderr, "Error: non-null column separator required for import\n");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if( nSep>1 ){
 | 
			
		||||
      fprintf(stderr, "Error: multi-character separators not allowed"
 | 
			
		||||
      fprintf(stderr, "Error: multi-character column separators not allowed"
 | 
			
		||||
                      " for import\n");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    sCsv.zFile = zFile;
 | 
			
		||||
    sCsv.nLine = 1;
 | 
			
		||||
    if( sCsv.zFile[0]=='|' ){
 | 
			
		||||
      sCsv.in = popen(sCsv.zFile+1, "r");
 | 
			
		||||
      sCsv.zFile = "<pipe>";
 | 
			
		||||
    nSep = strlen30(p->rowSeparator);
 | 
			
		||||
    if( nSep==0 ){
 | 
			
		||||
      fprintf(stderr, "Error: non-null row separator required for import\n");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
 | 
			
		||||
      /* When importing CSV (only), if the row separator is set to the
 | 
			
		||||
      ** default output row separator, change it to the default input
 | 
			
		||||
      ** row separator.  This avoids having to maintain different input
 | 
			
		||||
      ** and output row separators. */
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
 | 
			
		||||
      nSep = strlen30(p->rowSeparator);
 | 
			
		||||
    }
 | 
			
		||||
    if( nSep>1 ){
 | 
			
		||||
      fprintf(stderr, "Error: multi-character row separators not allowed"
 | 
			
		||||
                      " for import\n");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    sCtx.zFile = zFile;
 | 
			
		||||
    sCtx.nLine = 1;
 | 
			
		||||
    if( sCtx.zFile[0]=='|' ){
 | 
			
		||||
      sCtx.in = popen(sCtx.zFile+1, "r");
 | 
			
		||||
      sCtx.zFile = "<pipe>";
 | 
			
		||||
      xCloser = pclose;
 | 
			
		||||
    }else{
 | 
			
		||||
      sCsv.in = fopen(sCsv.zFile, "rb");
 | 
			
		||||
      sCtx.in = fopen(sCtx.zFile, "rb");
 | 
			
		||||
      xCloser = fclose;
 | 
			
		||||
    }
 | 
			
		||||
    if( sCsv.in==0 ){
 | 
			
		||||
    if( p->mode==MODE_Ascii ){
 | 
			
		||||
      xRead = ascii_read_one_field;
 | 
			
		||||
    }else{
 | 
			
		||||
      xRead = csv_read_one_field;
 | 
			
		||||
    }
 | 
			
		||||
    if( sCtx.in==0 ){
 | 
			
		||||
      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    sCsv.cSeparator = p->separator[0];
 | 
			
		||||
    sCtx.cColSep = p->colSeparator[0];
 | 
			
		||||
    sCtx.cRowSep = p->rowSeparator[0];
 | 
			
		||||
    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
 | 
			
		||||
    if( zSql==0 ){
 | 
			
		||||
      fprintf(stderr, "Error: out of memory\n");
 | 
			
		||||
      xCloser(sCsv.in);
 | 
			
		||||
      xCloser(sCtx.in);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    nByte = strlen30(zSql);
 | 
			
		||||
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
 | 
			
		||||
    csv_append_char(&sCsv, 0);    /* To ensure sCsv.z is allocated */
 | 
			
		||||
    import_append_char(&sCtx, 0);    /* To ensure sCtx.z is allocated */
 | 
			
		||||
    if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
 | 
			
		||||
      char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
 | 
			
		||||
      char cSep = '(';
 | 
			
		||||
      while( csv_read_one_field(&sCsv) ){
 | 
			
		||||
        zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCsv.z);
 | 
			
		||||
      while( xRead(&sCtx) ){
 | 
			
		||||
        zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCtx.z);
 | 
			
		||||
        cSep = ',';
 | 
			
		||||
        if( sCsv.cTerm!=sCsv.cSeparator ) break;
 | 
			
		||||
        if( sCtx.cTerm!=sCtx.cColSep ) break;
 | 
			
		||||
      }
 | 
			
		||||
      if( cSep=='(' ){
 | 
			
		||||
        sqlite3_free(zCreate);
 | 
			
		||||
        sqlite3_free(sCsv.z);
 | 
			
		||||
        xCloser(sCsv.in);
 | 
			
		||||
        fprintf(stderr,"%s: empty file\n", sCsv.zFile);
 | 
			
		||||
        sqlite3_free(sCtx.z);
 | 
			
		||||
        xCloser(sCtx.in);
 | 
			
		||||
        fprintf(stderr,"%s: empty file\n", sCtx.zFile);
 | 
			
		||||
        return 1;
 | 
			
		||||
      }
 | 
			
		||||
      zCreate = sqlite3_mprintf("%z\n)", zCreate);
 | 
			
		||||
@@ -2813,8 +2919,8 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
      if( rc ){
 | 
			
		||||
        fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
 | 
			
		||||
                sqlite3_errmsg(db));
 | 
			
		||||
        sqlite3_free(sCsv.z);
 | 
			
		||||
        xCloser(sCsv.in);
 | 
			
		||||
        sqlite3_free(sCtx.z);
 | 
			
		||||
        xCloser(sCtx.in);
 | 
			
		||||
        return 1;
 | 
			
		||||
      }
 | 
			
		||||
      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
 | 
			
		||||
@@ -2823,7 +2929,7 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
    if( rc ){
 | 
			
		||||
      if (pStmt) sqlite3_finalize(pStmt);
 | 
			
		||||
      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
 | 
			
		||||
      xCloser(sCsv.in);
 | 
			
		||||
      xCloser(sCtx.in);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    nCol = sqlite3_column_count(pStmt);
 | 
			
		||||
@@ -2833,7 +2939,7 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
    zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
 | 
			
		||||
    if( zSql==0 ){
 | 
			
		||||
      fprintf(stderr, "Error: out of memory\n");
 | 
			
		||||
      xCloser(sCsv.in);
 | 
			
		||||
      xCloser(sCtx.in);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
 | 
			
		||||
@@ -2849,46 +2955,56 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
    if( rc ){
 | 
			
		||||
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
 | 
			
		||||
      if (pStmt) sqlite3_finalize(pStmt);
 | 
			
		||||
      xCloser(sCsv.in);
 | 
			
		||||
      xCloser(sCtx.in);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    needCommit = sqlite3_get_autocommit(db);
 | 
			
		||||
    if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
 | 
			
		||||
    do{
 | 
			
		||||
      int startLine = sCsv.nLine;
 | 
			
		||||
      int startLine = sCtx.nLine;
 | 
			
		||||
      for(i=0; i<nCol; i++){
 | 
			
		||||
        char *z = csv_read_one_field(&sCsv);
 | 
			
		||||
        char *z = xRead(&sCtx);
 | 
			
		||||
        /*
 | 
			
		||||
        ** Did we reach end-of-file before finding any columns?
 | 
			
		||||
        ** If so, stop instead of NULL filling the remaining columns.
 | 
			
		||||
        */
 | 
			
		||||
        if( z==0 && i==0 ) break;
 | 
			
		||||
        /*
 | 
			
		||||
        ** Did we reach end-of-file OR end-of-line before finding any
 | 
			
		||||
        ** columns in ASCII mode?  If so, stop instead of NULL filling
 | 
			
		||||
        ** the remaining columns.
 | 
			
		||||
        */
 | 
			
		||||
        if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
 | 
			
		||||
        sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
 | 
			
		||||
        if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
 | 
			
		||||
        if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
 | 
			
		||||
          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
 | 
			
		||||
                          "filling the rest with NULL\n",
 | 
			
		||||
                          sCsv.zFile, startLine, nCol, i+1);
 | 
			
		||||
                          sCtx.zFile, startLine, nCol, i+1);
 | 
			
		||||
          i++;
 | 
			
		||||
          while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if( sCsv.cTerm==sCsv.cSeparator ){
 | 
			
		||||
      if( sCtx.cTerm==sCtx.cColSep ){
 | 
			
		||||
        do{
 | 
			
		||||
          csv_read_one_field(&sCsv);
 | 
			
		||||
          xRead(&sCtx);
 | 
			
		||||
          i++;
 | 
			
		||||
        }while( sCsv.cTerm==sCsv.cSeparator );
 | 
			
		||||
        }while( sCtx.cTerm==sCtx.cColSep );
 | 
			
		||||
        fprintf(stderr, "%s:%d: expected %d columns but found %d - "
 | 
			
		||||
                        "extras ignored\n",
 | 
			
		||||
                        sCsv.zFile, startLine, nCol, i);
 | 
			
		||||
                        sCtx.zFile, startLine, nCol, i);
 | 
			
		||||
      }
 | 
			
		||||
      if( i>=nCol ){
 | 
			
		||||
        sqlite3_step(pStmt);
 | 
			
		||||
        rc = sqlite3_reset(pStmt);
 | 
			
		||||
        if( rc!=SQLITE_OK ){
 | 
			
		||||
          fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine,
 | 
			
		||||
          fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
 | 
			
		||||
                  sqlite3_errmsg(db));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }while( sCsv.cTerm!=EOF );
 | 
			
		||||
    }while( sCtx.cTerm!=EOF );
 | 
			
		||||
 | 
			
		||||
    xCloser(sCsv.in);
 | 
			
		||||
    sqlite3_free(sCsv.z);
 | 
			
		||||
    xCloser(sCtx.in);
 | 
			
		||||
    sqlite3_free(sCtx.z);
 | 
			
		||||
    sqlite3_finalize(pStmt);
 | 
			
		||||
    if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
 | 
			
		||||
  }else
 | 
			
		||||
@@ -3006,28 +3122,32 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
      p->mode = MODE_Html;
 | 
			
		||||
    }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
 | 
			
		||||
      p->mode = MODE_Tcl;
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
 | 
			
		||||
    }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");
 | 
			
		||||
      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 ){
 | 
			
		||||
      p->mode = MODE_List;
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
 | 
			
		||||
    }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
 | 
			
		||||
      p->mode = MODE_Insert;
 | 
			
		||||
      set_table_name(p, nArg>=3 ? azArg[2] : "table");
 | 
			
		||||
    }else if( c2=='a' && strncmp(azArg[1],"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 {
 | 
			
		||||
      fprintf(stderr,"Error: mode should be one of: "
 | 
			
		||||
         "column csv html insert line list tabs tcl\n");
 | 
			
		||||
         "ascii column csv html insert line list tabs tcl\n");
 | 
			
		||||
      rc = 1;
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
 | 
			
		||||
    if( nArg==2 ){
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
 | 
			
		||||
                       "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
 | 
			
		||||
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
 | 
			
		||||
    }else{
 | 
			
		||||
      fprintf(stderr, "Usage: .nullvalue STRING\n");
 | 
			
		||||
      rc = 1;
 | 
			
		||||
@@ -3504,14 +3624,16 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
 | 
			
		||||
  if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
 | 
			
		||||
    if( nArg<2 || nArg>3 ){
 | 
			
		||||
      fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
 | 
			
		||||
      fprintf(stderr, "Usage: .separator COL ?ROW?\n");
 | 
			
		||||
      rc = 1;
 | 
			
		||||
    }
 | 
			
		||||
    if( nArg>=2 ){
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
 | 
			
		||||
                       "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
 | 
			
		||||
    }
 | 
			
		||||
    if( nArg>=3 ){
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);
 | 
			
		||||
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
 | 
			
		||||
                       "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
@@ -3542,23 +3664,24 @@ static int do_meta_command(char *zLine, ShellState *p){
 | 
			
		||||
      rc = 1;
 | 
			
		||||
      goto meta_command_exit;
 | 
			
		||||
    }
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
 | 
			
		||||
    fprintf(p->out,"%9.9s: ", "nullvalue");
 | 
			
		||||
      output_c_string(p->out, p->nullvalue);
 | 
			
		||||
    fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
 | 
			
		||||
    fprintf(p->out,"%12.12s: ", "nullvalue");
 | 
			
		||||
      output_c_string(p->out, p->nullValue);
 | 
			
		||||
      fprintf(p->out, "\n");
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","output",
 | 
			
		||||
    fprintf(p->out,"%12.12s: %s\n","output",
 | 
			
		||||
            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,"%12.12s: ", "colseparator");
 | 
			
		||||
      output_c_string(p->out, p->colSeparator);
 | 
			
		||||
      fprintf(p->out, "\n");
 | 
			
		||||
    fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%9.9s: ","width");
 | 
			
		||||
    fprintf(p->out,"%12.12s: ", "rowseparator");
 | 
			
		||||
      output_c_string(p->out, p->rowSeparator);
 | 
			
		||||
      fprintf(p->out, "\n");
 | 
			
		||||
    fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
 | 
			
		||||
    fprintf(p->out,"%12.12s: ","width");
 | 
			
		||||
    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
 | 
			
		||||
      fprintf(p->out,"%d ",p->colWidth[i]);
 | 
			
		||||
    }
 | 
			
		||||
@@ -4219,6 +4342,7 @@ static int process_sqliterc(
 | 
			
		||||
** Show available command line options
 | 
			
		||||
*/
 | 
			
		||||
static const char zOptions[] = 
 | 
			
		||||
  "   -ascii               set output mode to 'ascii'\n"
 | 
			
		||||
  "   -bail                stop after hitting an error\n"
 | 
			
		||||
  "   -batch               force batch I/O\n"
 | 
			
		||||
  "   -column              set output mode to 'column'\n"
 | 
			
		||||
@@ -4240,11 +4364,11 @@ static const char zOptions[] =
 | 
			
		||||
#ifdef SQLITE_ENABLE_MULTIPLEX
 | 
			
		||||
  "   -multiplex           enable the multiplexor VFS\n"
 | 
			
		||||
#endif
 | 
			
		||||
  "   -newline SEP         set newline character(s) for CSV\n"
 | 
			
		||||
  "   -newline SEP         set output row separator. Default: '\\n'\n"
 | 
			
		||||
  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
 | 
			
		||||
  "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
 | 
			
		||||
  "   -scratch SIZE N      use N slots of SZ bytes each for scratch memory\n"
 | 
			
		||||
  "   -separator SEP       set output field separator. Default: '|'\n"
 | 
			
		||||
  "   -separator SEP       set output column separator. Default: '|'\n"
 | 
			
		||||
  "   -stats               print memory stats before each finalize\n"
 | 
			
		||||
  "   -version             show SQLite version\n"
 | 
			
		||||
  "   -vfs NAME            use NAME as the default VFS\n"
 | 
			
		||||
@@ -4271,8 +4395,8 @@ static void usage(int showDetail){
 | 
			
		||||
static void main_init(ShellState *data) {
 | 
			
		||||
  memset(data, 0, sizeof(*data));
 | 
			
		||||
  data->mode = MODE_List;
 | 
			
		||||
  memcpy(data->separator,"|", 2);
 | 
			
		||||
  memcpy(data->newline,"\r\n", 3);
 | 
			
		||||
  memcpy(data->colSeparator,SEP_Column, 2);
 | 
			
		||||
  memcpy(data->rowSeparator,SEP_Row, 2);
 | 
			
		||||
  data->showHeader = 0;
 | 
			
		||||
  data->shellFlgs = SHFLG_Lookaside;
 | 
			
		||||
  sqlite3_config(SQLITE_CONFIG_URI, 1);
 | 
			
		||||
@@ -4511,15 +4635,21 @@ int main(int argc, char **argv){
 | 
			
		||||
      data.mode = MODE_Column;
 | 
			
		||||
    }else if( strcmp(z,"-csv")==0 ){
 | 
			
		||||
      data.mode = MODE_Csv;
 | 
			
		||||
      memcpy(data.separator,",",2);
 | 
			
		||||
      memcpy(data.colSeparator,",",2);
 | 
			
		||||
    }else if( strcmp(z,"-ascii")==0 ){
 | 
			
		||||
      data.mode = MODE_Ascii;
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
 | 
			
		||||
                       SEP_Unit);
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
 | 
			
		||||
                       SEP_Record);
 | 
			
		||||
    }else if( strcmp(z,"-separator")==0 ){
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.separator), data.separator,
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
 | 
			
		||||
                       "%s",cmdline_option_value(argc,argv,++i));
 | 
			
		||||
    }else if( strcmp(z,"-newline")==0 ){
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.newline), data.newline,
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
 | 
			
		||||
                       "%s",cmdline_option_value(argc,argv,++i));
 | 
			
		||||
    }else if( strcmp(z,"-nullvalue")==0 ){
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
 | 
			
		||||
      sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
 | 
			
		||||
                       "%s",cmdline_option_value(argc,argv,++i));
 | 
			
		||||
    }else if( strcmp(z,"-header")==0 ){
 | 
			
		||||
      data.showHeader = 1;
 | 
			
		||||
@@ -4639,7 +4769,7 @@ int main(int argc, char **argv){
 | 
			
		||||
          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
#if defined(HAVE_READLINE)
 | 
			
		||||
#if HAVE_READLINE
 | 
			
		||||
      if( zHistory ) read_history(zHistory);
 | 
			
		||||
#endif
 | 
			
		||||
      rc = process_input(&data, 0);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user