[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.6 and 1.7

version 1.6, 2013/06/09 14:51:57 version 1.7, 2013/09/21 17:43:28
Line 53 
Line 53 
 # include <readline/history.h>  # include <readline/history.h>
 #endif  #endif
 #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)  #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
 # define readline(p) local_getline(p,stdin,0)  
 # define add_history(X)  # define add_history(X)
 # define read_history(X)  # define read_history(X)
 # define write_history(X)  # define write_history(X)
Line 65 
Line 64 
 #define isatty(h) _isatty(h)  #define isatty(h) _isatty(h)
 #define access(f,m) _access((f),(m))  #define access(f,m) _access((f),(m))
 #undef popen  #undef popen
 #define popen(a,b) _popen((a),(b))  #define popen _popen
 #undef pclose  #undef pclose
 #define pclose(x) _pclose(x)  #define pclose _pclose
 #else  #else
 /* Make sure isatty() has a prototype.  /* Make sure isatty() has a prototype.
 */  */
 extern int isatty(int);  extern int isatty(int);
 #endif  #endif
   
   /* popen and pclose are not C89 functions and so are sometimes omitted from
   ** the <stdio.h> header */
   FILE *popen(const char*,const char*);
   int pclose(FILE*);
   
 #if defined(_WIN32_WCE)  #if defined(_WIN32_WCE)
 /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()  /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
  * thus we always assume that we have a console. That can be   * thus we always assume that we have a console. That can be
Line 332 
Line 336 
 ** to the text.  NULL is returned at end of file, or if malloc()  ** to the text.  NULL is returned at end of file, or if malloc()
 ** fails.  ** fails.
 **  **
 ** The interface is like "readline" but no command-line editing  ** If zLine is not NULL then it is a malloced buffer returned from
 ** is done.  ** a previous call to this routine that may be reused.
 */  */
 static char *local_getline(char *zPrompt, FILE *in, int csvFlag){  static char *local_getline(char *zLine, FILE *in){
   char *zLine;    int nLine = zLine==0 ? 0 : 100;
   int nLine;    int n = 0;
   int n;  
   int inQuote = 0;  
   
   if( zPrompt && *zPrompt ){  
     printf("%s",zPrompt);  
     fflush(stdout);  
   }  
   nLine = 100;  
   zLine = malloc( nLine );  
   if( zLine==0 ) return 0;  
   n = 0;  
   while( 1 ){    while( 1 ){
     if( n+100>nLine ){      if( n+100>nLine ){
       nLine = nLine*2 + 100;        nLine = nLine*2 + 100;
Line 363 
Line 357 
       zLine[n] = 0;        zLine[n] = 0;
       break;        break;
     }      }
     while( zLine[n] ){      while( zLine[n] ) n++;
       if( zLine[n]=='"' ) inQuote = !inQuote;      if( n>0 && zLine[n-1]=='\n' ){
       n++;  
     }  
     if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){  
       n--;        n--;
       if( n>0 && zLine[n-1]=='\r' ) n--;        if( n>0 && zLine[n-1]=='\r' ) n--;
       zLine[n] = 0;        zLine[n] = 0;
       break;        break;
     }      }
   }    }
   zLine = realloc( zLine, n+1 );  
   return zLine;    return zLine;
 }  }
   
 /*  /*
 ** Retrieve a single line of input text.  ** Retrieve a single line of input text.
 **  **
 ** zPrior is a string of prior text retrieved.  If not the empty  ** If in==0 then read from standard input and prompt before each line.
 ** string, then issue a continuation prompt.  ** If isContinuation is true, then a continuation prompt is appropriate.
   ** If isContinuation is zero, then the main prompt should be used.
   **
   ** If zPrior is not NULL then it is a buffer from a prior call to this
   ** routine that can be reused.
   **
   ** The result is stored in space obtained from malloc() and must either
   ** be freed by the caller or else passed back into this routine via the
   ** zPrior argument for reuse.
 */  */
 static char *one_input_line(const char *zPrior, FILE *in){  static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
   char *zPrompt;    char *zPrompt;
   char *zResult;    char *zResult;
   if( in!=0 ){    if( in!=0 ){
     return local_getline(0, in, 0);      zResult = local_getline(zPrior, in);
   }  
   if( zPrior && zPrior[0] ){  
     zPrompt = continuePrompt;  
   }else{    }else{
     zPrompt = mainPrompt;      zPrompt = isContinuation ? continuePrompt : mainPrompt;
   }  
   zResult = readline(zPrompt);  
 #if defined(HAVE_READLINE) && HAVE_READLINE==1  #if defined(HAVE_READLINE) && HAVE_READLINE==1
   if( zResult && *zResult ) add_history(zResult);      free(zPrior);
       zResult = readline(zPrompt);
       if( zResult && *zResult ) add_history(zResult);
   #else
       printf("%s", zPrompt);
       fflush(stdout);
       zResult = local_getline(zPrior, stdin);
 #endif  #endif
     }
   return zResult;    return zResult;
 }  }
   
Line 1109 
Line 1109 
     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);
       fprintf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
   }    }
   
   return 0;    return 0;
Line 1490 
Line 1492 
 **    \t    -> tab  **    \t    -> tab
 **    \n    -> newline  **    \n    -> newline
 **    \r    -> carriage return  **    \r    -> carriage return
   **    \"    -> "
 **    \NNN  -> ascii character NNN in octal  **    \NNN  -> ascii character NNN in octal
 **    \\    -> backslash  **    \\    -> backslash
 */  */
Line 1505 
Line 1508 
         c = '\t';          c = '\t';
       }else if( c=='r' ){        }else if( c=='r' ){
         c = '\r';          c = '\r';
         }else if( c=='\\' ){
           c = '\\';
       }else if( c>='0' && c<='7' ){        }else if( c>='0' && c<='7' ){
         c -= '0';          c -= '0';
         if( z[i+1]>='0' && z[i+1]<='7' ){          if( z[i+1]>='0' && z[i+1]<='7' ){
Line 1523 
Line 1528 
 }  }
   
 /*  /*
 ** Interpret zArg as a boolean value.  Return either 0 or 1.  ** Return the value of a hexadecimal digit.  Return -1 if the input
   ** is not a hex digit.
 */  */
 static int booleanValue(char *zArg){  static int hexDigitValue(char c){
   int i;    if( c>='0' && c<='9' ) return c - '0';
   for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}    if( c>='a' && c<='f' ) return c - 'a' + 10;
   if( i>0 && zArg[i]==0 ) return atoi(zArg);    if( c>='A' && c<='F' ) return c - 'A' + 10;
   if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){    return -1;
     return 1;  
   }  
   if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){  
     return 0;  
   }  
   fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",  
           zArg);  
   return 0;  
 }  }
   
 /*  /*
Line 1564 
Line 1562 
   }else if( zArg[0]=='+' ){    }else if( zArg[0]=='+' ){
     zArg++;      zArg++;
   }    }
   while( isdigit(zArg[0]) ){    if( zArg[0]=='0' && zArg[1]=='x' ){
     v = v*10 + zArg[0] - '0';      int x;
     zArg++;      zArg += 2;
       while( (x = hexDigitValue(zArg[0]))>=0 ){
         v = (v<<4) + x;
         zArg++;
       }
     }else{
       while( IsDigit(zArg[0]) ){
         v = v*10 + zArg[0] - '0';
         zArg++;
       }
   }    }
   for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){    for(i=0; i<ArraySize(aMult); i++){
     if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){      if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
       v *= aMult[i].iMult;        v *= aMult[i].iMult;
       break;        break;
Line 1578 
Line 1585 
 }  }
   
 /*  /*
   ** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
   ** for TRUE and FALSE.  Return the integer value if appropriate.
   */
   static int booleanValue(char *zArg){
     int i;
     if( zArg[0]=='0' && zArg[1]=='x' ){
       for(i=2; hexDigitValue(zArg[i])>=0; i++){}
     }else{
       for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
     }
     if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
     if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
       return 1;
     }
     if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
       return 0;
     }
     fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
             zArg);
     return 0;
   }
   
   /*
 ** Close an output file, assuming it is not stderr or stdout  ** Close an output file, assuming it is not stderr or stdout
 */  */
 static void output_file_close(FILE *f){  static void output_file_close(FILE *f){
Line 1624 
Line 1654 
 }  }
   
 /*  /*
   ** An object used to read a CSV file
   */
   typedef struct CSVReader CSVReader;
   struct CSVReader {
     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 */
     int n;              /* Number of bytes in z */
     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 ",") */
   };
   
   /* Append a single byte to z[] */
   static void csv_append_char(CSVReader *p, int c){
     if( p->n+1>=p->nAlloc ){
       p->nAlloc += p->nAlloc + 100;
       p->z = sqlite3_realloc(p->z, p->nAlloc);
       if( p->z==0 ){
         fprintf(stderr, "out of memory\n");
         exit(1);
       }
     }
     p->z[p->n++] = (char)c;
   }
   
   /* Read a single field of CSV text.  Compatible with rfc4180 and extended
   ** with the option of having a separator other than ",".
   **
   **   +  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 ",".
   **   +  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;
     int cSep = p->cSeparator;
     p->n = 0;
     c = fgetc(p->in);
     if( c==EOF || seenInterrupt ){
       p->cTerm = EOF;
       return 0;
     }
     if( c=='"' ){
       int startLine = p->nLine;
       int cQuote = c;
       pc = 0;
       while( 1 ){
         c = fgetc(p->in);
         if( c=='\n' ) p->nLine++;
         if( c==cQuote ){
           if( pc==cQuote ){
             pc = 0;
             continue;
           }
         }
         if( (c==cSep && pc==cQuote)
          || (c=='\n' && pc==cQuote)
          || (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote)
          || (c==EOF && pc==cQuote)
         ){
           do{ p->n--; }while( p->z[p->n]!=cQuote );
           p->cTerm = c;
           break;
         }
         if( pc==cQuote && c!='\r' ){
           fprintf(stderr, "%s:%d: unescaped %c character\n",
                   p->zFile, p->nLine, cQuote);
         }
         if( c==EOF ){
           fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
                   p->zFile, startLine, cQuote);
           p->cTerm = EOF;
           break;
         }
         csv_append_char(p, c);
         pc = c;
       }
     }else{
       while( c!=EOF && c!=cSep && c!='\n' ){
         csv_append_char(p, c);
         c = fgetc(p->in);
       }
       if( c=='\n' ){
         p->nLine++;
         if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
       }
       p->cTerm = c;
     }
     if( p->z ) p->z[p->n] = 0;
     return p->z;
   }
   
   /*
 ** If an input line begins with "." then invoke this routine to  ** If an input line begins with "." then invoke this routine to
 ** process that line.  ** process that line.
 **  **
Line 1644 
Line 1773 
     if( zLine[i]=='\'' || zLine[i]=='"' ){      if( zLine[i]=='\'' || zLine[i]=='"' ){
       int delim = zLine[i++];        int delim = zLine[i++];
       azArg[nArg++] = &zLine[i];        azArg[nArg++] = &zLine[i];
       while( zLine[i] && zLine[i]!=delim ){ i++; }        while( zLine[i] && zLine[i]!=delim ){
           if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++;
           i++;
         }
       if( zLine[i]==delim ){        if( zLine[i]==delim ){
         zLine[i++] = 0;          zLine[i++] = 0;
       }        }
Line 1665 
Line 1797 
   if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){    if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
     const char *zDestFile = 0;      const char *zDestFile = 0;
     const char *zDb = 0;      const char *zDb = 0;
     const char *zKey = 0;  
     sqlite3 *pDest;      sqlite3 *pDest;
     sqlite3_backup *pBackup;      sqlite3_backup *pBackup;
     int j;      int j;
Line 1673 
Line 1804 
       const char *z = azArg[j];        const char *z = azArg[j];
       if( z[0]=='-' ){        if( z[0]=='-' ){
         while( z[0]=='-' ) z++;          while( z[0]=='-' ) z++;
         if( strcmp(z,"key")==0 && j<nArg-1 ){          /* No options to process at this time */
           zKey = azArg[++j];  
         }else  
         {          {
           fprintf(stderr, "unknown option: %s\n", azArg[j]);            fprintf(stderr, "unknown option: %s\n", azArg[j]);
           return 1;            return 1;
Line 1701 
Line 1830 
       sqlite3_close(pDest);        sqlite3_close(pDest);
       return 1;        return 1;
     }      }
 #ifdef SQLITE_HAS_CODEC  
     sqlite3_key(pDest, zKey, (int)strlen(zKey));  
 #else  
     (void)zKey;  
 #endif  
     open_db(p);      open_db(p);
     pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);      pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
     if( pBackup==0 ){      if( pBackup==0 ){
Line 1808 
Line 1932 
   }else    }else
   
   if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){    if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
     if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc);      if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
     rc = 2;      rc = 2;
   }else    }else
   
Line 1861 
Line 1985 
   
   if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){    if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
     char *zTable = azArg[2];    /* Insert data into this table */      char *zTable = azArg[2];    /* Insert data into this table */
     char *zFile = azArg[1];     /* The file from which to extract data */      char *zFile = azArg[1];     /* Name of file to extra content from */
     sqlite3_stmt *pStmt = NULL; /* A statement */      sqlite3_stmt *pStmt = NULL; /* A statement */
     int nCol;                   /* Number of columns in the table */      int nCol;                   /* Number of columns in the table */
     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 nSep;                   /* Number of bytes in p->separator[] */      int nSep;                   /* Number of bytes in p->separator[] */
     char *zSql;                 /* An SQL statement */      char *zSql;                 /* An SQL statement */
     char *zLine;                /* A single line of input from the file */      CSVReader sCsv;             /* Reader context */
     char **azCol;               /* zLine[] broken up into columns */      int (*xCloser)(FILE*);      /* Procedure to close th3 connection */
     char *zCommit;              /* How to commit changes */  
     FILE *in;                   /* The input file */  
     int lineno = 0;             /* Line number of input file */  
   
       seenInterrupt = 0;
       memset(&sCsv, 0, sizeof(sCsv));
     open_db(p);      open_db(p);
     nSep = strlen30(p->separator);      nSep = strlen30(p->separator);
     if( nSep==0 ){      if( nSep==0 ){
       fprintf(stderr, "Error: non-null separator required for import\n");        fprintf(stderr, "Error: non-null separator required for import\n");
       return 1;        return 1;
     }      }
       if( nSep>1 ){
         fprintf(stderr, "Error: multi-character 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>";
         xCloser = pclose;
       }else{
         sCsv.in = fopen(sCsv.zFile, "rb");
         xCloser = fclose;
       }
       if( sCsv.in==0 ){
         fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
         return 1;
       }
       sCsv.cSeparator = p->separator[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);
       return 1;        return 1;
     }      }
     nByte = strlen30(zSql);      nByte = strlen30(zSql);
     rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);      rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
       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);
           cSep = ',';
           if( sCsv.cTerm!=sCsv.cSeparator ) break;
         }
         if( cSep=='(' ){
           sqlite3_free(zCreate);
           sqlite3_free(sCsv.z);
           xCloser(sCsv.in);
           fprintf(stderr,"%s: empty file\n", sCsv.zFile);
           return 1;
         }
         zCreate = sqlite3_mprintf("%z\n)", zCreate);
         rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
         sqlite3_free(zCreate);
         if( rc ){
           fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
                   sqlite3_errmsg(db));
           sqlite3_free(sCsv.z);
           xCloser(sCsv.in);
           return 1;
         }
         rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
       }
     sqlite3_free(zSql);      sqlite3_free(zSql);
     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);
       return 1;        return 1;
     }      }
     nCol = sqlite3_column_count(pStmt);      nCol = sqlite3_column_count(pStmt);
     sqlite3_finalize(pStmt);      sqlite3_finalize(pStmt);
     pStmt = 0;      pStmt = 0;
     if( nCol==0 ) return 0; /* no columns, no error */      if( nCol==0 ) return 0; /* no columns, no error */
     zSql = malloc( nByte + 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);
       return 1;        return 1;
     }      }
     sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable);      sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
     j = strlen30(zSql);      j = strlen30(zSql);
     for(i=1; i<nCol; i++){      for(i=1; i<nCol; i++){
       zSql[j++] = ',';        zSql[j++] = ',';
Line 1911 
Line 2085 
     zSql[j++] = ')';      zSql[j++] = ')';
     zSql[j] = 0;      zSql[j] = 0;
     rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);      rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
     free(zSql);      sqlite3_free(zSql);
     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);
       return 1;        return 1;
     }      }
     in = fopen(zFile, "rb");      needCommit = sqlite3_get_autocommit(db);
     if( in==0 ){      if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
       fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);      do{
       sqlite3_finalize(pStmt);        int startLine = sCsv.nLine;
       return 1;        for(i=0; i<nCol; i++){
     }          char *z = csv_read_one_field(&sCsv);
     azCol = malloc( sizeof(azCol[0])*(nCol+1) );          if( z==0 && i==0 ) break;
     if( azCol==0 ){          sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
       fprintf(stderr, "Error: out of memory\n");          if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
       fclose(in);            fprintf(stderr, "%s:%d: expected %d columns but found %d - "
       sqlite3_finalize(pStmt);                            "filling the rest with NULL\n",
       return 1;                            sCsv.zFile, startLine, nCol, i+1);
     }  
     sqlite3_exec(p->db, "BEGIN", 0, 0, 0);  
     zCommit = "COMMIT";  
     while( (zLine = local_getline(0, in, 1))!=0 ){  
       char *z, c;  
       int inQuote = 0;  
       lineno++;  
       azCol[0] = zLine;  
       for(i=0, z=zLine; (c = *z)!=0; z++){  
         if( c=='"' ) inQuote = !inQuote;  
         if( c=='\n' ) lineno++;  
         if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){  
           *z = 0;  
           i++;            i++;
           if( i<nCol ){            while( i<nCol ){ sqlite3_bind_null(pStmt, i); i++; }
             azCol[i] = &z[nSep];  
             z += nSep-1;  
           }  
         }          }
       } /* end for */  
       *z = 0;  
       if( i+1!=nCol ){  
         fprintf(stderr,  
                 "Error: %s line %d: expected %d columns of data but found %d\n",  
                 zFile, lineno, nCol, i+1);  
         zCommit = "ROLLBACK";  
         free(zLine);  
         rc = 1;  
         break; /* from while */  
       }        }
       for(i=0; i<nCol; i++){        if( sCsv.cTerm==sCsv.cSeparator ){
         if( azCol[i][0]=='"' ){          do{
           int k;            csv_read_one_field(&sCsv);
           for(z=azCol[i], j=1, k=0; z[j]; j++){            i++;
             if( z[j]=='"' ){ j++; if( z[j]==0 ) break; }          }while( sCsv.cTerm==sCsv.cSeparator );
             z[k++] = z[j];          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
           }                          "extras ignored\n",
           z[k] = 0;                          sCsv.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,
                     sqlite3_errmsg(db));
         }          }
         sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);  
       }        }
       sqlite3_step(pStmt);      }while( sCsv.cTerm!=EOF );
       rc = sqlite3_reset(pStmt);  
       free(zLine);      xCloser(sCsv.in);
       if( rc!=SQLITE_OK ){      sqlite3_free(sCsv.z);
         fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));  
         zCommit = "ROLLBACK";  
         rc = 1;  
         break; /* from while */  
       }  
     } /* end while */  
     free(azCol);  
     fclose(in);  
     sqlite3_finalize(pStmt);      sqlite3_finalize(pStmt);
     sqlite3_exec(p->db, zCommit, 0, 0, 0);      if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
   }else    }else
   
   if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){    if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
Line 2305 
Line 2452 
     }      }
   }else    }else
   
   #ifdef SQLITE_DEBUG
     /* Undocumented commands for internal testing.  Subject to change
     ** without notice. */
     if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){
       if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){
         int i, v;
         for(i=1; i<nArg; i++){
           v = booleanValue(azArg[i]);
           fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
         }
       }
       if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
         int i; sqlite3_int64 v;
         for(i=1; i<nArg; i++){
           char zBuf[200];
           v = integerValue(azArg[i]);
           sqlite3_snprintf(sizeof(zBuf), zBuf, "%s: %lld 0x%llx\n", azArg[i], v, v);
           fprintf(p->out, "%s", zBuf);
         }
       }
     }else
   #endif
   
   if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){    if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
     sqlite3_snprintf(sizeof(p->separator), p->separator,      sqlite3_snprintf(sizeof(p->separator), p->separator,
                      "%.*s", (int)sizeof(p->separator)-1, azArg[1]);                       "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
Line 2458 
Line 2628 
         }          }
       }        }
     }      }
     if( testctrl<0 ) testctrl = atoi(azArg[1]);      if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
     if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){      if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
       fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);        fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
     }else{      }else{
Line 2492 
Line 2662 
         /* sqlite3_test_control(int, uint) */          /* sqlite3_test_control(int, uint) */
         case SQLITE_TESTCTRL_PENDING_BYTE:          case SQLITE_TESTCTRL_PENDING_BYTE:
           if( nArg==3 ){            if( nArg==3 ){
             unsigned int opt = (unsigned int)integerValue(azArg[2]);              unsigned int opt = (unsigned int)integerValue(azArg[2]);
             rc = sqlite3_test_control(testctrl, opt);              rc = sqlite3_test_control(testctrl, opt);
             fprintf(p->out, "%d (0x%08x)\n", rc, rc);              fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {            } else {
Line 2505 
Line 2675 
         case SQLITE_TESTCTRL_ASSERT:          case SQLITE_TESTCTRL_ASSERT:
         case SQLITE_TESTCTRL_ALWAYS:          case SQLITE_TESTCTRL_ALWAYS:
           if( nArg==3 ){            if( nArg==3 ){
             int opt = atoi(azArg[2]);              int opt = booleanValue(azArg[2]);
             rc = sqlite3_test_control(testctrl, opt);              rc = sqlite3_test_control(testctrl, opt);
             fprintf(p->out, "%d (0x%08x)\n", rc, rc);              fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {            } else {
Line 2542 
Line 2712 
   
   if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){    if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
     open_db(p);      open_db(p);
     sqlite3_busy_timeout(p->db, atoi(azArg[1]));      sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));
   }else    }else
   
   if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0    if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
Line 2592 
Line 2762 
     int j;      int j;
     assert( nArg<=ArraySize(azArg) );      assert( nArg<=ArraySize(azArg) );
     for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){      for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
       p->colWidth[j-1] = atoi(azArg[j]);        p->colWidth[j-1] = (int)integerValue(azArg[j]);
     }      }
   }else    }else
   
Line 2609 
Line 2779 
 ** Return TRUE if a semicolon occurs anywhere in the first N characters  ** Return TRUE if a semicolon occurs anywhere in the first N characters
 ** of string z[].  ** of string z[].
 */  */
 static int _contains_semicolon(const char *z, int N){  static int line_contains_semicolon(const char *z, int N){
   int i;    int i;
   for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }    for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }
   return 0;    return 0;
Line 2644 
Line 2814 
 ** than a semi-colon.  The SQL Server style "go" command is understood  ** than a semi-colon.  The SQL Server style "go" command is understood
 ** as is the Oracle "/".  ** as is the Oracle "/".
 */  */
 static int _is_command_terminator(const char *zLine){  static int line_is_command_terminator(const char *zLine){
   while( IsSpace(zLine[0]) ){ zLine++; };    while( IsSpace(zLine[0]) ){ zLine++; };
   if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){    if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
     return 1;  /* Oracle */      return 1;  /* Oracle */
Line 2660 
Line 2830 
 ** Return true if zSql is a complete SQL statement.  Return false if it  ** Return true if zSql is a complete SQL statement.  Return false if it
 ** ends in the middle of a string literal or C-style comment.  ** ends in the middle of a string literal or C-style comment.
 */  */
 static int _is_complete(char *zSql, int nSql){  static int line_is_complete(char *zSql, int nSql){
   int rc;    int rc;
   if( zSql==0 ) return 1;    if( zSql==0 ) return 1;
   zSql[nSql] = ';';    zSql[nSql] = ';';
Line 2680 
Line 2850 
 ** Return the number of errors.  ** Return the number of errors.
 */  */
 static int process_input(struct callback_data *p, FILE *in){  static int process_input(struct callback_data *p, FILE *in){
   char *zLine = 0;    char *zLine = 0;          /* A single input line */
   char *zSql = 0;    char *zSql = 0;           /* Accumulated SQL text */
   int nSql = 0;    int nLine;                /* Length of current line */
   int nSqlPrior = 0;    int nSql = 0;             /* Bytes of zSql[] used */
   char *zErrMsg;    int nAlloc = 0;           /* Allocated zSql[] space */
   int rc;    int nSqlPrior = 0;        /* Bytes of zSql[] used by prior line */
   int errCnt = 0;    char *zErrMsg;            /* Error message returned */
   int lineno = 0;    int rc;                   /* Error code */
   int startline = 0;    int errCnt = 0;           /* Number of errors seen */
     int lineno = 0;           /* Current line number */
     int startline = 0;        /* Line number for start of current input */
   
   while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){    while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
     fflush(p->out);      fflush(p->out);
     free(zLine);      zLine = one_input_line(in, zLine, nSql>0);
     zLine = one_input_line(zSql, in);  
     if( zLine==0 ){      if( zLine==0 ){
       /* End of input */        /* End of input */
       if( stdin_is_interactive ) printf("\n");        if( stdin_is_interactive ) printf("\n");
Line 2704 
Line 2875 
       seenInterrupt = 0;        seenInterrupt = 0;
     }      }
     lineno++;      lineno++;
     if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;      if( nSql==0 && _all_whitespace(zLine) ) continue;
     if( zLine && zLine[0]=='.' && nSql==0 ){      if( zLine && zLine[0]=='.' && nSql==0 ){
       if( p->echoOn ) printf("%s\n", zLine);        if( p->echoOn ) printf("%s\n", zLine);
       rc = do_meta_command(zLine, p);        rc = do_meta_command(zLine, p);
Line 2715 
Line 2886 
       }        }
       continue;        continue;
     }      }
     if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){      if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
       memcpy(zLine,";",2);        memcpy(zLine,";",2);
     }      }
       nLine = strlen30(zLine);
       if( nSql+nLine+2>=nAlloc ){
         nAlloc = nSql+nLine+100;
         zSql = realloc(zSql, nAlloc);
         if( zSql==0 ){
           fprintf(stderr, "Error: out of memory\n");
           exit(1);
         }
       }
     nSqlPrior = nSql;      nSqlPrior = nSql;
     if( zSql==0 ){      if( nSql==0 ){
       int i;        int i;
       for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}        for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
       if( zLine[i]!=0 ){        assert( nAlloc>0 && zSql!=0 );
         nSql = strlen30(zLine);        memcpy(zSql, zLine+i, nLine+1-i);
         zSql = malloc( nSql+3 );        startline = lineno;
         if( zSql==0 ){        nSql = nLine-i;
           fprintf(stderr, "Error: out of memory\n");  
           exit(1);  
         }  
         memcpy(zSql, zLine, nSql+1);  
         startline = lineno;  
       }  
     }else{      }else{
       int len = strlen30(zLine);  
       zSql = realloc( zSql, nSql + len + 4 );  
       if( zSql==0 ){  
         fprintf(stderr,"Error: out of memory\n");  
         exit(1);  
       }  
       zSql[nSql++] = '\n';        zSql[nSql++] = '\n';
       memcpy(&zSql[nSql], zLine, len+1);        memcpy(zSql+nSql, zLine, nLine+1);
       nSql += len;        nSql += nLine;
     }      }
     if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)      if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
                 && sqlite3_complete(zSql) ){                  && sqlite3_complete(zSql) ){
       p->cnt = 0;        p->cnt = 0;
       open_db(p);        open_db(p);
Line 2767 
Line 2935 
         }          }
         errCnt++;          errCnt++;
       }        }
       free(zSql);  
       zSql = 0;  
       nSql = 0;        nSql = 0;
     }else if( zSql && _all_whitespace(zSql) ){      }else if( nSql && _all_whitespace(zSql) ){
       free(zSql);  
       zSql = 0;  
       nSql = 0;        nSql = 0;
     }      }
   }    }
   if( zSql ){    if( nSql ){
     if( !_all_whitespace(zSql) ){      if( !_all_whitespace(zSql) ){
       fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);        fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
     }      }
Line 3024 
Line 3188 
       stdin_is_interactive = 0;        stdin_is_interactive = 0;
     }else if( strcmp(z,"-heap")==0 ){      }else if( strcmp(z,"-heap")==0 ){
 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)  #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
       int j, c;  
       const char *zSize;        const char *zSize;
       sqlite3_int64 szHeap;        sqlite3_int64 szHeap;
   

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7