[BACK]Return to shell.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sqlite3

Diff for /src/usr.bin/sqlite3/Attic/shell.c between version 1.10 and 1.11

version 1.10, 2015/03/16 00:09:33 version 1.11, 2015/04/04 23:26:54
Line 18 
Line 18 
 #endif  #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.  ** Enable large-file support for fopen() and friends on unix.
 */  */
 #ifndef SQLITE_DISABLE_LFS  #ifndef SQLITE_DISABLE_LFS
Line 48 
Line 55 
 # include <sys/types.h>  # include <sys/types.h>
 #endif  #endif
   
 #if defined(HAVE_READLINE) && HAVE_READLINE!=0  #if HAVE_READLINE
 # include <readline/readline.h>  # include <readline/readline.h>
 # include <readline/history.h>  # include <readline/history.h>
 #else  
 # undef HAVE_READLINE  
 #endif  #endif
 #if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)  
 # define HAVE_READLINE 1  #if HAVE_EDITLINE
 # include <editline/readline.h>  # include <editline/readline.h>
 #endif  #endif
 #if !defined(HAVE_READLINE)  
 # define add_history(X)  #if HAVE_EDITLINE || HAVE_READLINE
 # define read_history(X)  
 # define write_history(X)  # define shell_add_history(X) add_history(X)
 # define stifle_history(X)  # define shell_read_history(X) read_history(X)
   # define shell_write_history(X) write_history(X)
   # define shell_stifle_history(X) stifle_history(X)
   # define shell_readline(X) readline(X)
   
   #elif HAVE_LINENOISE
   
   # include "linenoise.h"
   # define shell_add_history(X) linenoiseHistoryAdd(X)
   # define shell_read_history(X) linenoiseHistoryLoad(X)
   # define shell_write_history(X) linenoiseHistorySave(X)
   # define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
   # define shell_readline(X) linenoise(X)
   
   #else
   
   # define shell_read_history(X)
   # define shell_write_history(X)
   # define shell_stifle_history(X)
   
   # define SHELL_USE_LOCAL_GETLINE 1
 #endif  #endif
   
   
 #if defined(_WIN32) || defined(WIN32)  #if defined(_WIN32) || defined(WIN32)
 # include <io.h>  # include <io.h>
 # include <fcntl.h>  # include <fcntl.h>
Line 172 
Line 198 
 static FILETIME ftKernelBegin;  static FILETIME ftKernelBegin;
 static FILETIME ftUserBegin;  static FILETIME ftUserBegin;
 static sqlite3_int64 ftWallBegin;  static sqlite3_int64 ftWallBegin;
 typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);  typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
                                       LPFILETIME, LPFILETIME);
 static GETPROCTIMES getProcessTimesAddr = NULL;  static GETPROCTIMES getProcessTimesAddr = NULL;
   
 /*  /*
Line 183 
Line 210 
   if( getProcessTimesAddr ){    if( getProcessTimesAddr ){
     return 1;      return 1;
   } else {    } else {
     /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.      /* GetProcessTimes() isn't supported in WIN95 and some other Windows
     ** See if the version we are running on has it, and if it does, save off      ** versions. See if the version we are running on has it, and if it
     ** a pointer to it and the current process handle.      ** does, save off a pointer to it and the current process handle.
     */      */
     hProcess = GetCurrentProcess();      hProcess = GetCurrentProcess();
     if( hProcess ){      if( hProcess ){
       HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));        HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
       if( NULL != hinstLib ){        if( NULL != hinstLib ){
         getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");          getProcessTimesAddr =
               (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
         if( NULL != getProcessTimesAddr ){          if( NULL != getProcessTimesAddr ){
           return 1;            return 1;
         }          }
Line 208 
Line 236 
 static void beginTimer(void){  static void beginTimer(void){
   if( enableTimer && getProcessTimesAddr ){    if( enableTimer && getProcessTimesAddr ){
     FILETIME ftCreation, ftExit;      FILETIME ftCreation, ftExit;
     getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);      getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
                           &ftKernelBegin,&ftUserBegin);
     ftWallBegin = timeOfDay();      ftWallBegin = timeOfDay();
   }    }
 }  }
Line 227 
Line 256 
   if( enableTimer && getProcessTimesAddr){    if( enableTimer && getProcessTimesAddr){
     FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;      FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
     sqlite3_int64 ftWallEnd = timeOfDay();      sqlite3_int64 ftWallEnd = timeOfDay();
     getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);      getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
     printf("Run Time: real %.3f user %f sys %f\n",      printf("Run Time: real %.3f user %f sys %f\n",
        (ftWallEnd - ftWallBegin)*0.001,         (ftWallEnd - ftWallBegin)*0.001,
        timeDiff(&ftUserBegin, &ftUserEnd),         timeDiff(&ftUserBegin, &ftUserEnd),
Line 422 
Line 451 
     zResult = local_getline(zPrior, in);      zResult = local_getline(zPrior, in);
   }else{    }else{
     zPrompt = isContinuation ? continuePrompt : mainPrompt;      zPrompt = isContinuation ? continuePrompt : mainPrompt;
 #if defined(HAVE_READLINE)  #if SHELL_USE_LOCAL_GETLINE
     free(zPrior);  
     zResult = readline(zPrompt);  
     if( zResult && *zResult ) add_history(zResult);  
 #else  
     printf("%s", zPrompt);      printf("%s", zPrompt);
     fflush(stdout);      fflush(stdout);
     zResult = local_getline(zPrior, stdin);      zResult = local_getline(zPrior, stdin);
   #else
       free(zPrior);
       zResult = shell_readline(zPrompt);
       if( zResult && *zResult ) shell_add_history(zResult);
 #endif  #endif
   }    }
   return zResult;    return zResult;
Line 457 
Line 486 
   int echoOn;            /* True to echo input commands */    int echoOn;            /* True to echo input commands */
   int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */    int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
   int statsOn;           /* True to display memory stats before each finalize */    int statsOn;           /* True to display memory stats before each finalize */
     int scanstatsOn;       /* True to display scan stats before each finalize */
   int outCount;          /* Revert to stdout when reaching zero */    int outCount;          /* Revert to stdout when reaching zero */
   int cnt;               /* Number of records displayed so far */    int cnt;               /* Number of records displayed so far */
   FILE *out;             /* Write results here */    FILE *out;             /* Write results here */
Line 467 
Line 497 
   int showHeader;        /* True to show column names in List or Column mode */    int showHeader;        /* True to show column names in List or Column mode */
   unsigned shellFlgs;    /* Various flags */    unsigned shellFlgs;    /* Various flags */
   char *zDestTable;      /* Name of destination table when MODE_Insert */    char *zDestTable;      /* Name of destination table when MODE_Insert */
   char separator[20];    /* Separator character for MODE_List */    char colSeparator[20]; /* Column separator character for several modes */
   char newline[20];      /* Record separator in MODE_Csv */    char rowSeparator[20]; /* Row separator character for MODE_Ascii */
   int colWidth[100];     /* Requested width of each column when in column mode*/    int colWidth[100];     /* Requested width of each column when in column mode*/
   int actualWidth[100];  /* Actual width of each column */    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 */                           ** the database */
   SavedModeInfo normalMode;/* Holds the mode just before .explain ON */    SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
   char outfile[FILENAME_MAX]; /* Filename for *out */    char outfile[FILENAME_MAX]; /* Filename for *out */
Line 504 
Line 534 
 #define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */  #define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
 #define MODE_Csv      7  /* Quote strings, numbers are plain */  #define MODE_Csv      7  /* Quote strings, numbers are plain */
 #define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */  #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[] = {  static const char *modeDescr[] = {
   "line",    "line",
Line 515 
Line 546 
   "tcl",    "tcl",
   "csv",    "csv",
   "explain",    "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  ** Number of elements in an array
 */  */
 #define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))  #define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
Line 673 
Line 718 
 };  };
   
 /*  /*
 ** Output a single term of CSV.  Actually, p->separator is used for  ** 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 separator, which may or may not be a comma.  p->nullValue is
 ** the null value.  Strings are quoted if necessary.  The separator  ** the null value.  Strings are quoted if necessary.  The separator
 ** is only issued if bSep is true.  ** is only issued if bSep is true.
 */  */
 static void output_csv(ShellState *p, const char *z, int bSep){  static void output_csv(ShellState *p, const char *z, int bSep){
   FILE *out = p->out;    FILE *out = p->out;
   if( z==0 ){    if( z==0 ){
     fprintf(out,"%s",p->nullvalue);      fprintf(out,"%s",p->nullValue);
   }else{    }else{
     int i;      int i;
     int nSep = strlen30(p->separator);      int nSep = strlen30(p->colSeparator);
     for(i=0; z[i]; i++){      for(i=0; z[i]; i++){
       if( needCsvQuote[((unsigned char*)z)[i]]        if( needCsvQuote[((unsigned char*)z)[i]]
          || (z[i]==p->separator[0] &&           || (z[i]==p->colSeparator[0] &&
              (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){               (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
         i = 0;          i = 0;
         break;          break;
       }        }
Line 705 
Line 750 
     }      }
   }    }
   if( bSep ){    if( bSep ){
     fprintf(p->out, "%s", p->separator);      fprintf(p->out, "%s", p->colSeparator);
   }    }
 }  }
   
Line 725 
Line 770 
 ** This is the callback routine that the shell  ** This is the callback routine that the shell
 ** invokes for each row of a query result.  ** invokes for each row of a query result.
 */  */
 static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){  static int shell_callback(
     void *pArg,
     int nArg,        /* Number of result columns */
     char **azArg,    /* Text of each result column */
     char **azCol,    /* Column names */
     int *aiType      /* Column types */
   ){
   int i;    int i;
   ShellState *p = (ShellState*)pArg;    ShellState *p = (ShellState*)pArg;
   
Line 737 
Line 788 
         int len = strlen30(azCol[i] ? azCol[i] : "");          int len = strlen30(azCol[i] ? azCol[i] : "");
         if( len>w ) w = len;          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++){        for(i=0; i<nArg; i++){
         fprintf(p->out,"%*s = %s\n", w, azCol[i],          fprintf(p->out,"%*s = %s%s", w, azCol[i],
                 azArg[i] ? azArg[i] : p->nullvalue);                  azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
       }        }
       break;        break;
     }      }
Line 757 
Line 808 
           if( w==0 ){            if( w==0 ){
             w = strlen30(azCol[i] ? azCol[i] : "");              w = strlen30(azCol[i] ? azCol[i] : "");
             if( w<10 ) w = 10;              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( w<n ) w = n;
           }            }
           if( i<ArraySize(p->actualWidth) ){            if( i<ArraySize(p->actualWidth) ){
Line 765 
Line 816 
           }            }
           if( p->showHeader ){            if( p->showHeader ){
             if( w<0 ){              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{              }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 : "  ");
             }              }
           }            }
         }          }
Line 782 
Line 835 
             }              }
             fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"              fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
                    "----------------------------------------------------------",                     "----------------------------------------------------------",
                     i==nArg-1 ? "\n": "  ");                      i==nArg-1 ? p->rowSeparator : "  ");
           }            }
         }          }
       }        }
Line 805 
Line 858 
         }          }
         if( w<0 ){          if( w<0 ){
           fprintf(p->out,"%*.*s%s",-w,-w,            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{          }else{
           fprintf(p->out,"%-*.*s%s",w,w,            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;        break;
Line 817 
Line 872 
     case MODE_List: {      case MODE_List: {
       if( p->cnt++==0 && p->showHeader ){        if( p->cnt++==0 && p->showHeader ){
         for(i=0; i<nArg; i++){          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;        if( azArg==0 ) break;
       for(i=0; i<nArg; i++){        for(i=0; i<nArg; i++){
         char *z = azArg[i];          char *z = azArg[i];
         if( z==0 ) z = p->nullvalue;          if( z==0 ) z = p->nullValue;
         fprintf(p->out, "%s", z);          fprintf(p->out, "%s", z);
         if( i<nArg-1 ){          if( i<nArg-1 ){
           fprintf(p->out, "%s", p->separator);            fprintf(p->out, "%s", p->colSeparator);
         }else if( p->mode==MODE_Semi ){          }else if( p->mode==MODE_Semi ){
           fprintf(p->out, ";\n");            fprintf(p->out, ";%s", p->rowSeparator);
         }else{          }else{
           fprintf(p->out, "\n");            fprintf(p->out, "%s", p->rowSeparator);
         }          }
       }        }
       break;        break;
Line 849 
Line 905 
       fprintf(p->out,"<TR>");        fprintf(p->out,"<TR>");
       for(i=0; i<nArg; i++){        for(i=0; i<nArg; i++){
         fprintf(p->out,"<TD>");          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,"</TD>\n");
       }        }
       fprintf(p->out,"</TR>\n");        fprintf(p->out,"</TR>\n");
Line 859 
Line 915 
       if( p->cnt++==0 && p->showHeader ){        if( p->cnt++==0 && p->showHeader ){
         for(i=0; i<nArg; i++){          for(i=0; i<nArg; i++){
           output_c_string(p->out,azCol[i] ? azCol[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;        if( azArg==0 ) break;
       for(i=0; i<nArg; i++){        for(i=0; i<nArg; i++){
         output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);          output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
         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);
       break;        break;
     }      }
     case MODE_Csv: {      case MODE_Csv: {
Line 880 
Line 936 
         for(i=0; i<nArg; i++){          for(i=0; i<nArg; i++){
           output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);            output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
         }          }
         fprintf(p->out,"%s",p->newline);          fprintf(p->out, "%s", p->rowSeparator);
       }        }
       if( azArg>0 ){        if( nArg>0 ){
         for(i=0; i<nArg; i++){          for(i=0; i<nArg; i++){
           output_csv(p, azArg[i], i<nArg-1);            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)  #if defined(WIN32) || defined(_WIN32)
       fflush(p->out);        fflush(p->out);
Line 923 
Line 979 
       fprintf(p->out,");\n");        fprintf(p->out,");\n");
       break;        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;    return 0;
 }  }
Line 1104 
Line 1176 
   
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Memory Used:                         %d (max %d) bytes\n", iCur, iHiwtr);      fprintf(pArg->out,
               "Memory Used:                         %d (max %d) bytes\n",
               iCur, iHiwtr);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n", iCur, iHiwtr);      fprintf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n",
               iCur, iHiwtr);
     if( pArg->shellFlgs & SHFLG_Pagecache ){      if( pArg->shellFlgs & SHFLG_Pagecache ){
       iHiwtr = iCur = -1;        iHiwtr = iCur = -1;
       sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);        sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
       fprintf(pArg->out, "Number of Pcache Pages Used:         %d (max %d) pages\n", iCur, iHiwtr);        fprintf(pArg->out,
                 "Number of Pcache Pages Used:         %d (max %d) pages\n",
                 iCur, iHiwtr);
     }      }
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n", iCur, iHiwtr);      fprintf(pArg->out,
               "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n",
               iCur, iHiwtr);
     if( pArg->shellFlgs & SHFLG_Scratch ){      if( pArg->shellFlgs & SHFLG_Scratch ){
       iHiwtr = iCur = -1;        iHiwtr = iCur = -1;
       sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);        sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
       fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n", iCur, iHiwtr);        fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n",
                 iCur, iHiwtr);
     }      }
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n", iCur, iHiwtr);      fprintf(pArg->out,
               "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n",
               iCur, iHiwtr);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Largest Allocation:                  %d bytes\n", iHiwtr);      fprintf(pArg->out, "Largest Allocation:                  %d bytes\n",
               iHiwtr);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n", iHiwtr);      fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n",
               iHiwtr);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n", iHiwtr);      fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n",
               iHiwtr);
 #ifdef YYTRACKMAXSTACKDEPTH  #ifdef YYTRACKMAXSTACKDEPTH
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);      sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n", iCur, iHiwtr);      fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n",
               iCur, iHiwtr);
 #endif  #endif
   }    }
   
   if( pArg && pArg->out && db ){    if( pArg && pArg->out && db ){
     if( pArg->shellFlgs & SHFLG_Lookaside ){      if( pArg->shellFlgs & SHFLG_Lookaside ){
       iHiwtr = iCur = -1;        iHiwtr = iCur = -1;
       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);        sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
       fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n", iCur, iHiwtr);                          &iCur, &iHiwtr, bReset);
       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset);        fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n",
                 iCur, iHiwtr);
         sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
                           &iCur, &iHiwtr, bReset);
       fprintf(pArg->out, "Successful lookaside attempts:       %d\n", iHiwtr);        fprintf(pArg->out, "Successful lookaside attempts:       %d\n", iHiwtr);
       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset);        sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
                           &iCur, &iHiwtr, bReset);
       fprintf(pArg->out, "Lookaside failures due to size:      %d\n", iHiwtr);        fprintf(pArg->out, "Lookaside failures due to size:      %d\n", iHiwtr);
       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset);        sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
                           &iCur, &iHiwtr, bReset);
       fprintf(pArg->out, "Lookaside failures due to OOM:       %d\n", iHiwtr);        fprintf(pArg->out, "Lookaside failures due to OOM:       %d\n", iHiwtr);
     }      }
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);      sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Pager Heap Usage:                    %d bytes\n", iCur);    iHiwtr = iCur = -1;      fprintf(pArg->out, "Pager Heap Usage:                    %d bytes\n",iCur);
       iHiwtr = iCur = -1;
     sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);      sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
     fprintf(pArg->out, "Page cache hits:                     %d\n", iCur);      fprintf(pArg->out, "Page cache hits:                     %d\n", iCur);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
Line 1165 
Line 1257 
     fprintf(pArg->out, "Page cache writes:                   %d\n", iCur);      fprintf(pArg->out, "Page cache writes:                   %d\n", iCur);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);      sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n", iCur);      fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n",iCur);
     iHiwtr = iCur = -1;      iHiwtr = iCur = -1;
     sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);      sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
     fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n", iCur);      fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n",iCur);
   }    }
   
   if( pArg && pArg->out && db && pArg->pStmt ){    if( pArg && pArg->out && db && pArg->pStmt ){
     iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);      iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
                                  bReset);
     fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);      fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
     iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);      iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
     fprintf(pArg->out, "Sort Operations:                     %d\n", iCur);      fprintf(pArg->out, "Sort Operations:                     %d\n", iCur);
     iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);      iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
     fprintf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);      fprintf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
     iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);      iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
     fprintf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);      fprintf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
Line 1186 
Line 1279 
 }  }
   
 /*  /*
   ** Display scan stats.
   */
   static void display_scanstats(
     sqlite3 *db,                    /* Database to query */
     ShellState *pArg                /* Pointer to ShellState */
   ){
   #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
     int i, k, n, mx;
     fprintf(pArg->out, "-------- scanstats --------\n");
     mx = 0;
     for(k=0; k<=mx; k++){
       double rEstLoop = 1.0;
       for(i=n=0; 1; i++){
         sqlite3_stmt *p = pArg->pStmt;
         sqlite3_int64 nLoop, nVisit;
         double rEst;
         int iSid;
         const char *zExplain;
         if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
           break;
         }
         sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
         if( iSid>mx ) mx = iSid;
         if( iSid!=k ) continue;
         if( n==0 ){
           rEstLoop = (double)nLoop;
           if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k);
         }
         n++;
         sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
         sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
         sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
         fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain);
         rEstLoop *= rEst;
         fprintf(pArg->out,
             "         nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
             nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
         );
       }
     }
     fprintf(pArg->out, "---------------------------\n");
   #endif
   }
   
   /*
 ** Parameter azArray points to a zero-terminated array of strings. zStr  ** Parameter azArray points to a zero-terminated array of strings. zStr
 ** points to a single nul-terminated string. Return non-zero if zStr  ** points to a single nul-terminated string. Return non-zero if zStr
 ** is equal, according to strcmp(), to any of the strings in the array.  ** is equal, according to strcmp(), to any of the strings in the array.
Line 1226 
Line 1364 
   
   const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",    const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
                            "NextIfOpen", "PrevIfOpen", 0 };                             "NextIfOpen", "PrevIfOpen", 0 };
   const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 };    const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
                               "Rewind", 0 };
   const char *azGoto[] = { "Goto", 0 };    const char *azGoto[] = { "Goto", 0 };
   
   /* Try to figure out if this is really an EXPLAIN statement. If this    /* Try to figure out if this is really an EXPLAIN statement. If this
Line 1339 
Line 1478 
       /* Show the EXPLAIN QUERY PLAN if .eqp is on */        /* Show the EXPLAIN QUERY PLAN if .eqp is on */
       if( pArg && pArg->autoEQP ){        if( pArg && pArg->autoEQP ){
         sqlite3_stmt *pExplain;          sqlite3_stmt *pExplain;
         char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt));          char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
                                        sqlite3_sql(pStmt));
         rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);          rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
         if( rc==SQLITE_OK ){          if( rc==SQLITE_OK ){
           while( sqlite3_step(pExplain)==SQLITE_ROW ){            while( sqlite3_step(pExplain)==SQLITE_ROW ){
Line 1423 
Line 1563 
         display_stats(db, pArg, 0);          display_stats(db, pArg, 0);
       }        }
   
         /* print loop-counters if required */
         if( pArg && pArg->scanstatsOn ){
           display_scanstats(db, pArg);
         }
   
       /* Finalize the statement just executed. If this fails, save a        /* Finalize the statement just executed. If this fails, save a
       ** copy of the error message. Otherwise, set zSql to point to the        ** copy of the error message. Otherwise, set zSql to point to the
       ** next statement to execute. */        ** next statement to execute. */
Line 1615 
Line 1760 
 #endif  #endif
   ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"    ".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"    ".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"    "                         csv      Comma-separated values\n"
   "                         column   Left-aligned columns.  (See .width)\n"    "                         column   Left-aligned columns.  (See .width)\n"
   "                         html     HTML <table> code\n"    "                         html     HTML <table> code\n"
   "                         insert   SQL insert statements for TABLE\n"    "                         insert   SQL insert statements for TABLE\n"
   "                         line     One value per line\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"    "                         tabs     Tab-separated values\n"
   "                         tcl      TCL list elements\n"    "                         tcl      TCL list elements\n"
   ".nullvalue STRING      Use STRING in place of NULL values\n"    ".nullvalue STRING      Use STRING in place of NULL values\n"
Line 1633 
Line 1779 
   ".read FILENAME         Execute SQL in FILENAME\n"    ".read FILENAME         Execute SQL in FILENAME\n"
   ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"    ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
   ".save FILE             Write in-memory database into FILE\n"    ".save FILE             Write in-memory database into FILE\n"
     ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
   ".schema ?TABLE?        Show the CREATE statements\n"    ".schema ?TABLE?        Show the CREATE statements\n"
   "                         If TABLE specified, only show tables matching\n"    "                         If TABLE specified, only show tables matching\n"
   "                         LIKE pattern TABLE.\n"    "                         LIKE pattern TABLE.\n"
   ".separator STRING ?NL? Change separator used by output mode and .import\n"    ".separator COL ?ROW?   Change the column separator and optionally the row\n"
   "                         NL is the end-of-line mark for CSV\n"    "                         separator for both the output mode and .import\n"
   ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"    ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
   ".show                  Show the current values for various settings\n"    ".show                  Show the current values for various settings\n"
   ".stats on|off          Turn stats on or off\n"    ".stats on|off          Turn stats on or off\n"
Line 1918 
Line 2065 
 }  }
   
 /*  /*
 ** An object used to read a CSV file  ** An object used to read a CSV and other files for import.
 */  */
 typedef struct CSVReader CSVReader;  typedef struct ImportCtx ImportCtx;
 struct CSVReader {  struct ImportCtx {
   const char *zFile;  /* Name of the input file */    const char *zFile;  /* Name of the input file */
   FILE *in;           /* Read the CSV text from this input stream */    FILE *in;           /* Read the CSV text from this input stream */
   char *z;            /* Accumulated text for a field */    char *z;            /* Accumulated text for a field */
Line 1929 
Line 2076 
   int nAlloc;         /* Space allocated for z[] */    int nAlloc;         /* Space allocated for z[] */
   int nLine;          /* Current line number */    int nLine;          /* Current line number */
   int cTerm;          /* Character that terminated the most recent field */    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[] */  /* 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 ){    if( p->n+1>=p->nAlloc ){
     p->nAlloc += p->nAlloc + 100;      p->nAlloc += p->nAlloc + 100;
     p->z = sqlite3_realloc(p->z, p->nAlloc);      p->z = sqlite3_realloc(p->z, p->nAlloc);
Line 1951 
Line 2099 
 **   +  Input comes from p->in.  **   +  Input comes from p->in.
 **   +  Store results in p->z of length p->n.  Space to hold p->z comes  **   +  Store results in p->z of length p->n.  Space to hold p->z comes
 **      from sqlite3_malloc().  **      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.  **   +  Keep track of the line number in p->nLine.
 **   +  Store the character that terminates the field in p->cTerm.  Store  **   +  Store the character that terminates the field in p->cTerm.  Store
 **      EOF on end-of-file.  **      EOF on end-of-file.
 **   +  Report syntax errors on stderr  **   +  Report syntax errors on stderr
 */  */
 static char *csv_read_one_field(CSVReader *p){  static char *csv_read_one_field(ImportCtx *p){
   int c, pc, ppc;    int c;
   int cSep = p->cSeparator;    int cSep = p->cColSep;
     int rSep = p->cRowSep;
   p->n = 0;    p->n = 0;
   c = fgetc(p->in);    c = fgetc(p->in);
   if( c==EOF || seenInterrupt ){    if( c==EOF || seenInterrupt ){
Line 1967 
Line 2117 
     return 0;      return 0;
   }    }
   if( c=='"' ){    if( c=='"' ){
       int pc, ppc;
     int startLine = p->nLine;      int startLine = p->nLine;
     int cQuote = c;      int cQuote = c;
     pc = ppc = 0;      pc = ppc = 0;
     while( 1 ){      while( 1 ){
       c = fgetc(p->in);        c = fgetc(p->in);
       if( c=='\n' ) p->nLine++;        if( c==rSep ) p->nLine++;
       if( c==cQuote ){        if( c==cQuote ){
         if( pc==cQuote ){          if( pc==cQuote ){
           pc = 0;            pc = 0;
Line 1980 
Line 2131 
         }          }
       }        }
       if( (c==cSep && pc==cQuote)        if( (c==cSep && pc==cQuote)
        || (c=='\n' && pc==cQuote)         || (c==rSep && pc==cQuote)
        || (c=='\n' && pc=='\r' && ppc==cQuote)         || (c==rSep && pc=='\r' && ppc==cQuote)
        || (c==EOF && pc==cQuote)         || (c==EOF && pc==cQuote)
       ){        ){
         do{ p->n--; }while( p->z[p->n]!=cQuote );          do{ p->n--; }while( p->z[p->n]!=cQuote );
Line 1995 
Line 2146 
       if( c==EOF ){        if( c==EOF ){
         fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",          fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
                 p->zFile, startLine, cQuote);                  p->zFile, startLine, cQuote);
         p->cTerm = EOF;          p->cTerm = c;
         break;          break;
       }        }
       csv_append_char(p, c);        import_append_char(p, c);
       ppc = pc;        ppc = pc;
       pc = c;        pc = c;
     }      }
   }else{    }else{
     while( c!=EOF && c!=cSep && c!='\n' ){      while( c!=EOF && c!=cSep && c!=rSep ){
       csv_append_char(p, c);        import_append_char(p, c);
       c = fgetc(p->in);        c = fgetc(p->in);
     }      }
     if( c=='\n' ){      if( c==rSep ){
       p->nLine++;        p->nLine++;
       if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;        if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
     }      }
Line 2017 
Line 2168 
   return p->z;    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  ** Try to transfer data for table zTable.  If an error is seen while
 ** moving forward, try to go backwards.  The backwards movement won't  ** moving forward, try to go backwards.  The backwards movement won't
Line 2571 
Line 2756 
     int nByte;                  /* Number of bytes in an SQL string */      int nByte;                  /* Number of bytes in an SQL string */
     int i, j;                   /* Loop counters */      int i, j;                   /* Loop counters */
     int needCommit;             /* True to COMMIT or ROLLBACK at end */      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 */      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 */      int (*xCloser)(FILE*);      /* Procedure to close th3 connection */
   
     if( nArg!=3 ){      if( nArg!=3 ){
Line 2583 
Line 2769 
     zFile = azArg[1];      zFile = azArg[1];
     zTable = azArg[2];      zTable = azArg[2];
     seenInterrupt = 0;      seenInterrupt = 0;
     memset(&sCsv, 0, sizeof(sCsv));      memset(&sCtx, 0, sizeof(sCtx));
     open_db(p, 0);      open_db(p, 0);
     nSep = strlen30(p->separator);      nSep = strlen30(p->colSeparator);
     if( nSep==0 ){      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;        return 1;
     }      }
     if( nSep>1 ){      if( nSep>1 ){
       fprintf(stderr, "Error: multi-character separators not allowed"        fprintf(stderr, "Error: multi-character column separators not allowed"
                       " for import\n");                        " for import\n");
       return 1;        return 1;
     }      }
     sCsv.zFile = zFile;      nSep = strlen30(p->rowSeparator);
     sCsv.nLine = 1;      if( nSep==0 ){
     if( sCsv.zFile[0]=='|' ){        fprintf(stderr, "Error: non-null row separator required for import\n");
       sCsv.in = popen(sCsv.zFile+1, "r");        return 1;
       sCsv.zFile = "<pipe>";      }
       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;        xCloser = pclose;
     }else{      }else{
       sCsv.in = fopen(sCsv.zFile, "rb");        sCtx.in = fopen(sCtx.zFile, "rb");
       xCloser = fclose;        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);        fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
       return 1;        return 1;
     }      }
     sCsv.cSeparator = p->separator[0];      sCtx.cColSep = p->colSeparator[0];
       sCtx.cRowSep = p->rowSeparator[0];
     zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);      zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
     if( zSql==0 ){      if( zSql==0 ){
       fprintf(stderr, "Error: out of memory\n");        fprintf(stderr, "Error: out of memory\n");
       xCloser(sCsv.in);        xCloser(sCtx.in);
       return 1;        return 1;
     }      }
     nByte = strlen30(zSql);      nByte = strlen30(zSql);
     rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);      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 ){      if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
       char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);        char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
       char cSep = '(';        char cSep = '(';
       while( csv_read_one_field(&sCsv) ){        while( xRead(&sCtx) ){
         zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCsv.z);          zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCtx.z);
         cSep = ',';          cSep = ',';
         if( sCsv.cTerm!=sCsv.cSeparator ) break;          if( sCtx.cTerm!=sCtx.cColSep ) break;
       }        }
       if( cSep=='(' ){        if( cSep=='(' ){
         sqlite3_free(zCreate);          sqlite3_free(zCreate);
         sqlite3_free(sCsv.z);          sqlite3_free(sCtx.z);
         xCloser(sCsv.in);          xCloser(sCtx.in);
         fprintf(stderr,"%s: empty file\n", sCsv.zFile);          fprintf(stderr,"%s: empty file\n", sCtx.zFile);
         return 1;          return 1;
       }        }
       zCreate = sqlite3_mprintf("%z\n)", zCreate);        zCreate = sqlite3_mprintf("%z\n)", zCreate);
Line 2640 
Line 2850 
       if( rc ){        if( rc ){
         fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,          fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
                 sqlite3_errmsg(db));                  sqlite3_errmsg(db));
         sqlite3_free(sCsv.z);          sqlite3_free(sCtx.z);
         xCloser(sCsv.in);          xCloser(sCtx.in);
         return 1;          return 1;
       }        }
       rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);        rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
Line 2650 
Line 2860 
     if( rc ){      if( rc ){
       if (pStmt) sqlite3_finalize(pStmt);        if (pStmt) sqlite3_finalize(pStmt);
       fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
       xCloser(sCsv.in);        xCloser(sCtx.in);
       return 1;        return 1;
     }      }
     nCol = sqlite3_column_count(pStmt);      nCol = sqlite3_column_count(pStmt);
Line 2660 
Line 2870 
     zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );      zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
     if( zSql==0 ){      if( zSql==0 ){
       fprintf(stderr, "Error: out of memory\n");        fprintf(stderr, "Error: out of memory\n");
       xCloser(sCsv.in);        xCloser(sCtx.in);
       return 1;        return 1;
     }      }
     sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);      sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
Line 2676 
Line 2886 
     if( rc ){      if( rc ){
       fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
       if (pStmt) sqlite3_finalize(pStmt);        if (pStmt) sqlite3_finalize(pStmt);
       xCloser(sCsv.in);        xCloser(sCtx.in);
       return 1;        return 1;
     }      }
     needCommit = sqlite3_get_autocommit(db);      needCommit = sqlite3_get_autocommit(db);
     if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);      if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
     do{      do{
       int startLine = sCsv.nLine;        int startLine = sCtx.nLine;
       for(i=0; i<nCol; i++){        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;          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);          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 - "            fprintf(stderr, "%s:%d: expected %d columns but found %d - "
                           "filling the rest with NULL\n",                            "filling the rest with NULL\n",
                           sCsv.zFile, startLine, nCol, i+1);                            sCtx.zFile, startLine, nCol, i+1);
           i++;            i++;
           while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }            while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
         }          }
       }        }
       if( sCsv.cTerm==sCsv.cSeparator ){        if( sCtx.cTerm==sCtx.cColSep ){
         do{          do{
           csv_read_one_field(&sCsv);            xRead(&sCtx);
           i++;            i++;
         }while( sCsv.cTerm==sCsv.cSeparator );          }while( sCtx.cTerm==sCtx.cColSep );
         fprintf(stderr, "%s:%d: expected %d columns but found %d - "          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
                         "extras ignored\n",                          "extras ignored\n",
                         sCsv.zFile, startLine, nCol, i);                          sCtx.zFile, startLine, nCol, i);
       }        }
       if( i>=nCol ){        if( i>=nCol ){
         sqlite3_step(pStmt);          sqlite3_step(pStmt);
         rc = sqlite3_reset(pStmt);          rc = sqlite3_reset(pStmt);
         if( rc!=SQLITE_OK ){          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));                    sqlite3_errmsg(db));
         }          }
       }        }
     }while( sCsv.cTerm!=EOF );      }while( sCtx.cTerm!=EOF );
   
     xCloser(sCsv.in);      xCloser(sCtx.in);
     sqlite3_free(sCsv.z);      sqlite3_free(sCtx.z);
     sqlite3_finalize(pStmt);      sqlite3_finalize(pStmt);
     if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);      if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
   }else    }else
Line 2833 
Line 3053 
       p->mode = MODE_Html;        p->mode = MODE_Html;
     }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){      }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
       p->mode = MODE_Tcl;        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 ){      }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
       p->mode = MODE_Csv;        p->mode = MODE_Csv;
       sqlite3_snprintf(sizeof(p->separator), p->separator, ",");        sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
       sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
     }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){      }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
       p->mode = MODE_List;        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 ){      }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
       p->mode = MODE_Insert;        p->mode = MODE_Insert;
       set_table_name(p, nArg>=3 ? azArg[2] : "table");        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 {      }else {
       fprintf(stderr,"Error: mode should be one of: "        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;        rc = 1;
     }      }
   }else    }else
   
   if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){    if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
     if( nArg==2 ){      if( nArg==2 ){
       sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,        sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
                        "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);                         "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
     }else{      }else{
       fprintf(stderr, "Usage: .nullvalue STRING\n");        fprintf(stderr, "Usage: .nullvalue STRING\n");
       rc = 1;        rc = 1;
Line 3014 
Line 3238 
     sqlite3_close(pSrc);      sqlite3_close(pSrc);
   }else    }else
   
   
     if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
       if( nArg==2 ){
         p->scanstatsOn = booleanValue(azArg[1]);
   #ifndef SQLITE_ENABLE_STMT_SCANSTATUS
         fprintf(stderr, "Warning: .scanstats not available in this build.\n");
   #endif
       }else{
         fprintf(stderr, "Usage: .scanstats on|off\n");
         rc = 1;
       }
     }else
   
   if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){    if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
     ShellState data;      ShellState data;
     char *zErrMsg = 0;      char *zErrMsg = 0;
Line 3126 
Line 3363 
   
   if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){    if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
     if( nArg<2 || nArg>3 ){      if( nArg<2 || nArg>3 ){
       fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");        fprintf(stderr, "Usage: .separator COL ?ROW?\n");
       rc = 1;        rc = 1;
     }      }
     if( nArg>=2 ){      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 ){      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    }else
   
Line 3164 
Line 3403 
       rc = 1;        rc = 1;
       goto meta_command_exit;        goto meta_command_exit;
     }      }
     fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");      fprintf(p->out,"%12.12s: %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","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","explain", p->normalMode.valid ? "on" :"off");
     fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");      fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
     fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);      fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
     fprintf(p->out,"%9.9s: ", "nullvalue");      fprintf(p->out,"%12.12s: ", "nullvalue");
       output_c_string(p->out, p->nullvalue);        output_c_string(p->out, p->nullValue);
       fprintf(p->out, "\n");        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");              strlen30(p->outfile) ? p->outfile : "stdout");
     fprintf(p->out,"%9.9s: ", "separator");      fprintf(p->out,"%12.12s: ", "colseparator");
       output_c_string(p->out, p->separator);        output_c_string(p->out, p->colSeparator);
       fprintf(p->out," ");  
       output_c_string(p->out, p->newline);  
       fprintf(p->out, "\n");        fprintf(p->out, "\n");
     fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");      fprintf(p->out,"%12.12s: ", "rowseparator");
     fprintf(p->out,"%9.9s: ","width");        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++) {      for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
       fprintf(p->out,"%d ",p->colWidth[i]);        fprintf(p->out,"%d ",p->colWidth[i]);
     }      }
Line 3271 
Line 3511 
       for(i=0; i<nPrintRow; i++){        for(i=0; i<nPrintRow; i++){
         for(j=i; j<nRow; j+=nPrintRow){          for(j=i; j<nRow; j+=nPrintRow){
           char *zSp = j<nPrintRow ? "" : "  ";            char *zSp = j<nPrintRow ? "" : "  ";
           fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");            fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
         }          }
         fprintf(p->out, "\n");          fprintf(p->out, "\n");
       }        }
Line 3741 
Line 3981 
   static char *home_dir = NULL;    static char *home_dir = NULL;
   if( home_dir ) return home_dir;    if( home_dir ) return home_dir;
   
 #if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)  #if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
        && !defined(__RTP__) && !defined(_WRS_KERNEL)
   {    {
     struct passwd *pwent;      struct passwd *pwent;
     uid_t uid = getuid();      uid_t uid = getuid();
Line 3840 
Line 4081 
 ** Show available command line options  ** Show available command line options
 */  */
 static const char zOptions[] =  static const char zOptions[] =
     "   -ascii               set output mode to 'ascii'\n"
   "   -bail                stop after hitting an error\n"    "   -bail                stop after hitting an error\n"
   "   -batch               force batch I/O\n"    "   -batch               force batch I/O\n"
   "   -column              set output mode to 'column'\n"    "   -column              set output mode to 'column'\n"
Line 3861 
Line 4103 
 #ifdef SQLITE_ENABLE_MULTIPLEX  #ifdef SQLITE_ENABLE_MULTIPLEX
   "   -multiplex           enable the multiplexor VFS\n"    "   -multiplex           enable the multiplexor VFS\n"
 #endif  #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"    "   -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"    "   -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"    "   -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"    "   -stats               print memory stats before each finalize\n"
   "   -version             show SQLite version\n"    "   -version             show SQLite version\n"
   "   -vfs NAME            use NAME as the default VFS\n"    "   -vfs NAME            use NAME as the default VFS\n"
Line 3892 
Line 4134 
 static void main_init(ShellState *data) {  static void main_init(ShellState *data) {
   memset(data, 0, sizeof(*data));    memset(data, 0, sizeof(*data));
   data->mode = MODE_List;    data->mode = MODE_List;
   memcpy(data->separator,"|", 2);    memcpy(data->colSeparator,SEP_Column, 2);
   memcpy(data->newline,"\r\n", 3);    memcpy(data->rowSeparator,SEP_Row, 2);
   data->showHeader = 0;    data->showHeader = 0;
   data->shellFlgs = SHFLG_Lookaside;    data->shellFlgs = SHFLG_Lookaside;
   sqlite3_config(SQLITE_CONFIG_URI, 1);    sqlite3_config(SQLITE_CONFIG_URI, 1);
Line 3940 
Line 4182 
   char *zErrMsg = 0;    char *zErrMsg = 0;
   ShellState data;    ShellState data;
   const char *zInitFile = 0;    const char *zInitFile = 0;
   char *zFirstCmd = 0;  
   int i;    int i;
   int rc = 0;    int rc = 0;
   int warnInmemoryDb = 0;    int warnInmemoryDb = 0;
     int readStdin = 1;
     int nCmd = 0;
     char **azCmd = 0;
   
 #if USE_SYSTEM_SQLITE+0!=1  #if USE_SYSTEM_SQLITE+0!=1
   if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){    if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
Line 3963 
Line 4207 
   signal(SIGINT, interrupt_handler);    signal(SIGINT, interrupt_handler);
 #endif  #endif
   
   #ifdef SQLITE_SHELL_DBNAME_PROC
     {
       /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
       ** of a C-function that will provide the name of the database file.  Use
       ** this compile-time option to embed this shell program in larger
       ** applications. */
       extern void SQLITE_SHELL_DBNAME_PROC(const char**);
       SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
       warnInmemoryDb = 0;
     }
   #endif
   
   /* Do an initial pass through the command-line argument to locate    /* Do an initial pass through the command-line argument to locate
   ** the name of the database file, the name of the initialization file,    ** the name of the database file, the name of the initialization file,
   ** the size of the alternative malloc heap,    ** the size of the alternative malloc heap,
Line 3974 
Line 4230 
     if( z[0]!='-' ){      if( z[0]!='-' ){
       if( data.zDbFilename==0 ){        if( data.zDbFilename==0 ){
         data.zDbFilename = z;          data.zDbFilename = z;
         continue;        }else{
           /* Excesss arguments are interpreted as SQL (or dot-commands) and
           ** mean that nothing is read from stdin */
           readStdin = 0;
           nCmd++;
           azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
           if( azCmd==0 ){
             fprintf(stderr, "out of memory\n");
             exit(1);
           }
           azCmd[nCmd-1] = z;
       }        }
       if( zFirstCmd==0 ){  
         zFirstCmd = z;  
         continue;  
       }  
       fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);  
       fprintf(stderr,"Use -help for a list of options.\n");  
       return 1;  
     }      }
     if( z[1]=='-' ) z++;      if( z[1]=='-' ) z++;
     if( strcmp(z,"-separator")==0      if( strcmp(z,"-separator")==0
Line 4073 
Line 4332 
     fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);      fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
     return 1;      return 1;
 #endif  #endif
 #ifdef SQLITE_SHELL_DBNAME_PROC  
     { extern void SQLITE_SHELL_DBNAME_PROC(const char**);  
       SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);  
       warnInmemoryDb = 0; }  
 #endif  
   }    }
   data.out = stdout;    data.out = stdout;
   
Line 4120 
Line 4374 
       data.mode = MODE_Column;        data.mode = MODE_Column;
     }else if( strcmp(z,"-csv")==0 ){      }else if( strcmp(z,"-csv")==0 ){
       data.mode = MODE_Csv;        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 ){      }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));                         "%s",cmdline_option_value(argc,argv,++i));
     }else if( strcmp(z,"-newline")==0 ){      }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));                         "%s",cmdline_option_value(argc,argv,++i));
     }else if( strcmp(z,"-nullvalue")==0 ){      }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));                         "%s",cmdline_option_value(argc,argv,++i));
     }else if( strcmp(z,"-header")==0 ){      }else if( strcmp(z,"-header")==0 ){
       data.showHeader = 1;        data.showHeader = 1;
Line 4140 
Line 4400 
       data.autoEQP = 1;        data.autoEQP = 1;
     }else if( strcmp(z,"-stats")==0 ){      }else if( strcmp(z,"-stats")==0 ){
       data.statsOn = 1;        data.statsOn = 1;
       }else if( strcmp(z,"-scanstats")==0 ){
         data.scanstatsOn = 1;
     }else if( strcmp(z,"-bail")==0 ){      }else if( strcmp(z,"-bail")==0 ){
       bail_on_error = 1;        bail_on_error = 1;
     }else if( strcmp(z,"-version")==0 ){      }else if( strcmp(z,"-version")==0 ){
Line 4172 
Line 4434 
     }else if( strcmp(z,"-help")==0 ){      }else if( strcmp(z,"-help")==0 ){
       usage(1);        usage(1);
     }else if( strcmp(z,"-cmd")==0 ){      }else if( strcmp(z,"-cmd")==0 ){
         /* Run commands that follow -cmd first and separately from commands
         ** that simply appear on the command-line.  This seems goofy.  It would
         ** be better if all commands ran in the order that they appear.  But
         ** we retain the goofy behavior for historical compatibility. */
       if( i==argc-1 ) break;        if( i==argc-1 ) break;
       z = cmdline_option_value(argc,argv,++i);        z = cmdline_option_value(argc,argv,++i);
       if( z[0]=='.' ){        if( z[0]=='.' ){
Line 4195 
Line 4461 
     }      }
   }    }
   
   if( zFirstCmd ){    if( !readStdin ){
     /* Run just the command that follows the database name      /* Run all arguments that do not begin with '-' as if they were separate
       ** command-line inputs, except for the argToSkip argument which contains
       ** the database filename.
     */      */
     if( zFirstCmd[0]=='.' ){      for(i=0; i<nCmd; i++){
       rc = do_meta_command(zFirstCmd, &data);        if( azCmd[i][0]=='.' ){
       if( rc==2 ) rc = 0;          rc = do_meta_command(azCmd[i], &data);
     }else{          if( rc ) return rc==2 ? 0 : rc;
       open_db(&data, 0);        }else{
       rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);          open_db(&data, 0);
       if( zErrMsg!=0 ){          rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
         fprintf(stderr,"Error: %s\n", zErrMsg);          if( zErrMsg!=0 ){
         return rc!=0 ? rc : 1;            fprintf(stderr,"Error: %s\n", zErrMsg);
       }else if( rc!=0 ){            return rc!=0 ? rc : 1;
         fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);          }else if( rc!=0 ){
         return rc;            fprintf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
             return rc;
           }
       }        }
     }      }
       free(azCmd);
   }else{    }else{
     /* Run commands received from standard input      /* Run commands received from standard input
     */      */
Line 4237 
Line 4508 
           sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);            sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
         }          }
       }        }
 #if defined(HAVE_READLINE)        if( zHistory ) shell_read_history(zHistory);
       if( zHistory ) read_history(zHistory);  
 #endif  
       rc = process_input(&data, 0);        rc = process_input(&data, 0);
       if( zHistory ){        if( zHistory ){
         stifle_history(100);          shell_stifle_history(100);
         write_history(zHistory);          shell_write_history(zHistory);
         free(zHistory);          free(zHistory);
       }        }
     }else{      }else{

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11