[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.7 and 1.8

version 1.7, 2013/09/21 17:43:28 version 1.8, 2014/03/24 01:45:35
Line 45 
Line 45 
 # include <sys/types.h>  # include <sys/types.h>
 #endif  #endif
   
 #ifdef HAVE_EDITLINE  #if defined(HAVE_READLINE) && HAVE_READLINE!=0
 # include <editline/editline.h>  
 #endif  
 #if defined(HAVE_READLINE) && HAVE_READLINE==1  
 # 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) || HAVE_READLINE!=1)  #if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
   # define HAVE_READLINE 1
   # include <editline/readline.h>
   #endif
   #if !defined(HAVE_READLINE)
 # 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 62 
Line 65 
 #if defined(_WIN32) || defined(WIN32)  #if defined(_WIN32) || defined(WIN32)
 # include <io.h>  # include <io.h>
 #define isatty(h) _isatty(h)  #define isatty(h) _isatty(h)
 #define access(f,m) _access((f),(m))  #ifndef access
   # define access(f,m) _access((f),(m))
   #endif
 #undef popen  #undef popen
 #define popen _popen  #define popen _popen
 #undef pclose  #undef pclose
Line 71 
Line 76 
 /* Make sure isatty() has a prototype.  /* Make sure isatty() has a prototype.
 */  */
 extern int isatty(int);  extern int isatty(int);
 #endif  
   
 /* popen and pclose are not C89 functions and so are sometimes omitted from  /* popen and pclose are not C89 functions and so are sometimes omitted from
 ** the <stdio.h> header */  ** the <stdio.h> header */
 FILE *popen(const char*,const char*);  extern FILE *popen(const char*,const char*);
 int pclose(FILE*);  extern int pclose(FILE*);
   #endif
   
 #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()
Line 86 
Line 91 
 #define isatty(x) 1  #define isatty(x) 1
 #endif  #endif
   
 /* True if the timer is enabled */  
 static int enableTimer = 0;  
   
 /* ctype macros that work with signed characters */  /* ctype macros that work with signed characters */
 #define IsSpace(X)  isspace((unsigned char)X)  #define IsSpace(X)  isspace((unsigned char)X)
 #define IsDigit(X)  isdigit((unsigned char)X)  #define IsDigit(X)  isdigit((unsigned char)X)
 #define ToLower(X)  (char)tolower((unsigned char)X)  #define ToLower(X)  (char)tolower((unsigned char)X)
   
   
   /* True if the timer is enabled */
   static int enableTimer = 0;
   
   /* Return the current wall-clock time */
   static sqlite3_int64 timeOfDay(void){
     static sqlite3_vfs *clockVfs = 0;
     sqlite3_int64 t;
     if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
     if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
       clockVfs->xCurrentTimeInt64(clockVfs, &t);
     }else{
       double r;
       clockVfs->xCurrentTime(clockVfs, &r);
       t = (sqlite3_int64)(r*86400000.0);
     }
     return t;
   }
   
 #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \  #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
  && !defined(__minux)   && !defined(__minux)
 #include <sys/time.h>  #include <sys/time.h>
 #include <sys/resource.h>  #include <sys/resource.h>
   
 /* Saved resource information for the beginning of an operation */  /* Saved resource information for the beginning of an operation */
 static struct rusage sBegin;  static struct rusage sBegin;  /* CPU time at start */
   static sqlite3_int64 iBegin;  /* Wall-clock time at start */
   
 /*  /*
 ** Begin timing an operation  ** Begin timing an operation
Line 108 
Line 130 
 static void beginTimer(void){  static void beginTimer(void){
   if( enableTimer ){    if( enableTimer ){
     getrusage(RUSAGE_SELF, &sBegin);      getrusage(RUSAGE_SELF, &sBegin);
       iBegin = timeOfDay();
   }    }
 }  }
   
Line 123 
Line 146 
 static void endTimer(void){  static void endTimer(void){
   if( enableTimer ){    if( enableTimer ){
     struct rusage sEnd;      struct rusage sEnd;
       sqlite3_int64 iEnd = timeOfDay();
     getrusage(RUSAGE_SELF, &sEnd);      getrusage(RUSAGE_SELF, &sEnd);
     printf("CPU Time: user %f sys %f\n",      printf("Run Time: real %.3f user %f sys %f\n",
          (iEnd - iBegin)*0.001,
        timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),         timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
        timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));         timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
   }    }
Line 142 
Line 167 
 static HANDLE hProcess;  static HANDLE hProcess;
 static FILETIME ftKernelBegin;  static FILETIME ftKernelBegin;
 static FILETIME ftUserBegin;  static FILETIME ftUserBegin;
   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 179 
Line 205 
   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();
   }    }
 }  }
   
Line 195 
Line 222 
 static void endTimer(void){  static void endTimer(void){
   if( enableTimer && getProcessTimesAddr){    if( enableTimer && getProcessTimesAddr){
     FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;      FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
       sqlite3_int64 ftWallEnd = timeOfDay();
     getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);      getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
     printf("CPU Time: user %f sys %f\n",      printf("Run Time: real %.3f user %f sys %f\n",
          (ftWallEnd - ftWallBegin)*0.001,
        timeDiff(&ftUserBegin, &ftUserEnd),         timeDiff(&ftUserBegin, &ftUserEnd),
        timeDiff(&ftKernelBegin, &ftKernelEnd));         timeDiff(&ftKernelBegin, &ftKernelEnd));
   }    }
Line 389 
Line 418 
     zResult = local_getline(zPrior, in);      zResult = local_getline(zPrior, in);
   }else{    }else{
     zPrompt = isContinuation ? continuePrompt : mainPrompt;      zPrompt = isContinuation ? continuePrompt : mainPrompt;
 #if defined(HAVE_READLINE) && HAVE_READLINE==1  #if defined(HAVE_READLINE)
     free(zPrior);      free(zPrior);
     zResult = readline(zPrompt);      zResult = readline(zPrompt);
     if( zResult && *zResult ) add_history(zResult);      if( zResult && *zResult ) add_history(zResult);
Line 417 
Line 446 
 struct callback_data {  struct callback_data {
   sqlite3 *db;           /* The database */    sqlite3 *db;           /* The database */
   int echoOn;            /* True to echo input commands */    int echoOn;            /* True to echo input commands */
     int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL statement */
   int statsOn;           /* True to display memory stats before each finalize */    int statsOn;           /* True to display memory stats before each finalize */
   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 436 
Line 466 
                          ** .explain ON */                           ** .explain ON */
   char outfile[FILENAME_MAX]; /* Filename for *out */    char outfile[FILENAME_MAX]; /* Filename for *out */
   const char *zDbFilename;    /* name of the database file */    const char *zDbFilename;    /* name of the database file */
     char *zFreeOnClose;         /* Filename to free when closing */
   const char *zVfs;           /* Name of VFS to use */    const char *zVfs;           /* Name of VFS to use */
   sqlite3_stmt *pStmt;   /* Current statement if any. */    sqlite3_stmt *pStmt;   /* Current statement if any. */
   FILE *pLog;            /* Write log output here */    FILE *pLog;            /* Write log output here */
     int *aiIndent;         /* Array of indents used in MODE_Explain */
     int nIndent;           /* Size of array aiIndent[] */
     int iIndent;           /* Index of current op in aiIndent[] */
 };  };
   
 /*  /*
Line 554 
Line 588 
     }else if( c=='\r' ){      }else if( c=='\r' ){
       fputc('\\', out);        fputc('\\', out);
       fputc('r', out);        fputc('r', out);
     }else if( !isprint(c) ){      }else if( !isprint(c&0xff) ){
       fprintf(out, "\\%03o", c&0xff);        fprintf(out, "\\%03o", c&0xff);
     }else{      }else{
       fputc(c, out);        fputc(c, out);
Line 569 
Line 603 
 */  */
 static void output_html_string(FILE *out, const char *z){  static void output_html_string(FILE *out, const char *z){
   int i;    int i;
     if( z==0 ) z = "";
   while( *z ){    while( *z ){
     for(i=0;   z[i]      for(i=0;   z[i]
             && z[i]!='<'              && z[i]!='<'
Line 740 
Line 775 
         }else{          }else{
            w = 10;             w = 10;
         }          }
         if( p->mode==MODE_Explain && azArg[i] &&          if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
            strlen30(azArg[i])>w ){  
           w = strlen30(azArg[i]);            w = strlen30(azArg[i]);
         }          }
           if( i==1 && p->aiIndent && p->pStmt ){
             if( p->iIndent<p->nIndent ){
               fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
             }
             p->iIndent++;
           }
         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 ? "\n": "  ");
Line 971 
Line 1011 
   int nResult;    int nResult;
   int i;    int i;
   const char *z;    const char *z;
   rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);    rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
   if( rc!=SQLITE_OK || !pSelect ){    if( rc!=SQLITE_OK || !pSelect ){
     fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));      fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
     p->nErr++;      if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
     return rc;      return rc;
   }    }
   rc = sqlite3_step(pSelect);    rc = sqlite3_step(pSelect);
Line 1001 
Line 1041 
   rc = sqlite3_finalize(pSelect);    rc = sqlite3_finalize(pSelect);
   if( rc!=SQLITE_OK ){    if( rc!=SQLITE_OK ){
     fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));      fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
     p->nErr++;      if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
   }    }
   return rc;    return rc;
 }  }
Line 1117 
Line 1157 
 }  }
   
 /*  /*
   ** Parameter azArray points to a zero-terminated array of strings. 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.
   ** Otherwise, return zero.
   */
   static int str_in_array(const char *zStr, const char **azArray){
     int i;
     for(i=0; azArray[i]; i++){
       if( 0==strcmp(zStr, azArray[i]) ) return 1;
     }
     return 0;
   }
   
   /*
   ** If compiled statement pSql appears to be an EXPLAIN statement, allocate
   ** and populate the callback_data.aiIndent[] array with the number of
   ** spaces each opcode should be indented before it is output.
   **
   ** The indenting rules are:
   **
   **     * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
   **       all opcodes that occur between the p2 jump destination and the opcode
   **       itself by 2 spaces.
   **
   **     * For each "Goto", if the jump destination is earlier in the program
   **       and ends on one of:
   **          Yield  SeekGt  SeekLt  RowSetRead  Rewind
   **       or if the P1 parameter is one instead of zero,
   **       then indent all opcodes between the earlier instruction
   **       and "Goto" by 2 spaces.
   */
   static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
     const char *zSql;               /* The text of the SQL statement */
     const char *z;                  /* Used to check if this is an EXPLAIN */
     int *abYield = 0;               /* True if op is an OP_Yield */
     int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
     int iOp;                        /* Index of operation in p->aiIndent[] */
   
     const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
     const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
     const char *azGoto[] = { "Goto", 0 };
   
     /* Try to figure out if this is really an EXPLAIN statement. If this
     ** cannot be verified, return early.  */
     zSql = sqlite3_sql(pSql);
     if( zSql==0 ) return;
     for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
     if( sqlite3_strnicmp(z, "explain", 7) ) return;
   
     for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
       int i;
       int iAddr = sqlite3_column_int(pSql, 0);
       const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
   
       /* Set p2 to the P2 field of the current opcode. Then, assuming that
       ** p2 is an instruction address, set variable p2op to the index of that
       ** instruction in the aiIndent[] array. p2 and p2op may be different if
       ** the current instruction is part of a sub-program generated by an
       ** SQL trigger or foreign key.  */
       int p2 = sqlite3_column_int(pSql, 3);
       int p2op = (p2 + (iOp-iAddr));
   
       /* Grow the p->aiIndent array as required */
       if( iOp>=nAlloc ){
         nAlloc += 100;
         p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
         abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
       }
       abYield[iOp] = str_in_array(zOp, azYield);
       p->aiIndent[iOp] = 0;
       p->nIndent = iOp+1;
   
       if( str_in_array(zOp, azNext) ){
         for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
       }
       if( str_in_array(zOp, azGoto) && p2op<p->nIndent
        && (abYield[p2op] || sqlite3_column_int(pSql, 2))
       ){
         for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
       }
     }
   
     p->iIndent = 0;
     sqlite3_free(abYield);
     sqlite3_reset(pSql);
   }
   
   /*
   ** Free the array allocated by explain_data_prepare().
   */
   static void explain_data_delete(struct callback_data *p){
     sqlite3_free(p->aiIndent);
     p->aiIndent = 0;
     p->nIndent = 0;
     p->iIndent = 0;
   }
   
   /*
 ** Execute a statement or set of statements.  Print  ** Execute a statement or set of statements.  Print
 ** any result rows/columns depending on the current mode  ** any result rows/columns depending on the current mode
 ** set via the supplied callback.  ** set via the supplied callback.
Line 1168 
Line 1306 
         fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);          fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
       }        }
   
         /* Show the EXPLAIN QUERY PLAN if .eqp is on */
         if( pArg && pArg->autoEQP ){
           sqlite3_stmt *pExplain;
           char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt));
           rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
           if( rc==SQLITE_OK ){
             while( sqlite3_step(pExplain)==SQLITE_ROW ){
               fprintf(pArg->out,"--EQP-- %d,", sqlite3_column_int(pExplain, 0));
               fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
               fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
               fprintf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
             }
           }
           sqlite3_finalize(pExplain);
           sqlite3_free(zEQP);
         }
   
       /* Output TESTCTRL_EXPLAIN text of requested */        /* Output TESTCTRL_EXPLAIN text of requested */
       if( pArg && pArg->mode==MODE_Explain ){        if( pArg && pArg->mode==MODE_Explain ){
         const char *zExplain = 0;          const char *zExplain = 0;
Line 1177 
Line 1332 
         }          }
       }        }
   
         /* If the shell is currently in ".explain" mode, gather the extra
         ** data required to add indents to the output.*/
         if( pArg && pArg->mode==MODE_Explain ){
           explain_data_prepare(pArg, pStmt);
         }
   
       /* perform the first step.  this will tell us if we        /* perform the first step.  this will tell us if we
       ** have a result set or not and how wide it is.        ** have a result set or not and how wide it is.
       */        */
Line 1194 
Line 1355 
             char **azCols = (char **)pData;      /* Names of result columns */              char **azCols = (char **)pData;      /* Names of result columns */
             char **azVals = &azCols[nCol];       /* Results */              char **azVals = &azCols[nCol];       /* Results */
             int *aiTypes = (int *)&azVals[nCol]; /* Result types */              int *aiTypes = (int *)&azVals[nCol]; /* Result types */
             int i;              int i, x;
             assert(sizeof(int) <= sizeof(char *));              assert(sizeof(int) <= sizeof(char *));
             /* save off ptrs to column names */              /* save off ptrs to column names */
             for(i=0; i<nCol; i++){              for(i=0; i<nCol; i++){
Line 1203 
Line 1364 
             do{              do{
               /* extract the data and data types */                /* extract the data and data types */
               for(i=0; i<nCol; i++){                for(i=0; i<nCol; i++){
                 azVals[i] = (char *)sqlite3_column_text(pStmt, i);                  aiTypes[i] = x = sqlite3_column_type(pStmt, i);
                 aiTypes[i] = sqlite3_column_type(pStmt, i);                  if( x==SQLITE_BLOB && pArg && pArg->mode==MODE_Insert ){
                     azVals[i] = "";
                   }else{
                     azVals[i] = (char*)sqlite3_column_text(pStmt, i);
                   }
                 if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){                  if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
                   rc = SQLITE_NOMEM;                    rc = SQLITE_NOMEM;
                   break; /* from for */                    break; /* from for */
Line 1230 
Line 1395 
         }          }
       }        }
   
         explain_data_delete(pArg);
   
       /* print usage stats if stats on */        /* print usage stats if stats on */
       if( pArg && pArg->statsOn ){        if( pArg && pArg->statsOn ){
         display_stats(db, pArg, 0);          display_stats(db, pArg, 0);
Line 1280 
Line 1447 
   
   if( strcmp(zTable, "sqlite_sequence")==0 ){    if( strcmp(zTable, "sqlite_sequence")==0 ){
     zPrepStmt = "DELETE FROM sqlite_sequence;\n";      zPrepStmt = "DELETE FROM sqlite_sequence;\n";
   }else if( strcmp(zTable, "sqlite_stat1")==0 ){    }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
     fprintf(p->out, "ANALYZE sqlite_master;\n");      fprintf(p->out, "ANALYZE sqlite_master;\n");
   }else if( strncmp(zTable, "sqlite_", 7)==0 ){    }else if( strncmp(zTable, "sqlite_", 7)==0 ){
     return 0;      return 0;
Line 1312 
Line 1479 
     zTableInfo = appendText(zTableInfo, zTable, '"');      zTableInfo = appendText(zTableInfo, zTable, '"');
     zTableInfo = appendText(zTableInfo, ");", 0);      zTableInfo = appendText(zTableInfo, ");", 0);
   
     rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);      rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
     free(zTableInfo);      free(zTableInfo);
     if( rc!=SQLITE_OK || !pTableInfo ){      if( rc!=SQLITE_OK || !pTableInfo ){
       return 1;        return 1;
Line 1402 
Line 1569 
 static char zHelp[] =  static char zHelp[] =
   ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"    ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
   ".bail ON|OFF           Stop after hitting an error.  Default OFF\n"    ".bail ON|OFF           Stop after hitting an error.  Default OFF\n"
     ".clone NEWDB           Clone data into NEWDB from the existing database\n"
   ".databases             List names and files of attached databases\n"    ".databases             List names and files of attached databases\n"
   ".dump ?TABLE? ...      Dump the database in an SQL text format\n"    ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
   "                         If TABLE specified, only dump tables matching\n"    "                         If TABLE specified, only dump tables matching\n"
Line 1433 
Line 1601 
   "                         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"
     ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
   ".output FILENAME       Send output to FILENAME\n"    ".output FILENAME       Send output to FILENAME\n"
   ".output stdout         Send output to the screen\n"    ".output stdout         Send output to the screen\n"
   ".print STRING...       Print literal STRING\n"    ".print STRING...       Print literal STRING\n"
Line 1440 
Line 1609 
   ".quit                  Exit this program\n"    ".quit                  Exit this program\n"
   ".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"
   ".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"
Line 1466 
Line 1636 
 ** Make sure the database is open.  If it is not, then open it.  If  ** Make sure the database is open.  If it is not, then open it.  If
 ** the database fails to open, print an error message and exit.  ** the database fails to open, print an error message and exit.
 */  */
 static void open_db(struct callback_data *p){  static void open_db(struct callback_data *p, int keepAlive){
   if( p->db==0 ){    if( p->db==0 ){
     sqlite3_initialize();      sqlite3_initialize();
     sqlite3_open(p->zDbFilename, &p->db);      sqlite3_open(p->zDbFilename, &p->db);
Line 1478 
Line 1648 
     if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){      if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
       fprintf(stderr,"Error: unable to open database \"%s\": %s\n",        fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
           p->zDbFilename, sqlite3_errmsg(db));            p->zDbFilename, sqlite3_errmsg(db));
         if( keepAlive ) return;
       exit(1);        exit(1);
     }      }
 #ifndef SQLITE_OMIT_LOAD_EXTENSION  #ifndef SQLITE_OMIT_LOAD_EXTENSION
Line 1694 
Line 1865 
 **   +  Report syntax errors on stderr  **   +  Report syntax errors on stderr
 */  */
 static char *csv_read_one_field(CSVReader *p){  static char *csv_read_one_field(CSVReader *p){
   int c, pc;    int c, pc, ppc;
   int cSep = p->cSeparator;    int cSep = p->cSeparator;
   p->n = 0;    p->n = 0;
   c = fgetc(p->in);    c = fgetc(p->in);
Line 1705 
Line 1876 
   if( c=='"' ){    if( c=='"' ){
     int startLine = p->nLine;      int startLine = p->nLine;
     int cQuote = c;      int cQuote = c;
     pc = 0;      pc = ppc = 0;
     while( 1 ){      while( 1 ){
       c = fgetc(p->in);        c = fgetc(p->in);
       if( c=='\n' ) p->nLine++;        if( c=='\n' ) p->nLine++;
Line 1717 
Line 1888 
       }        }
       if( (c==cSep && pc==cQuote)        if( (c==cSep && pc==cQuote)
        || (c=='\n' && pc==cQuote)         || (c=='\n' && pc==cQuote)
        || (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote)         || (c=='\n' && 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 1735 
Line 1906 
         break;          break;
       }        }
       csv_append_char(p, c);        csv_append_char(p, c);
         ppc = pc;
       pc = c;        pc = c;
     }      }
   }else{    }else{
Line 1744 
Line 1916 
     }      }
     if( c=='\n' ){      if( c=='\n' ){
       p->nLine++;        p->nLine++;
       if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;        if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
     }      }
     p->cTerm = c;      p->cTerm = c;
   }    }
Line 1753 
Line 1925 
 }  }
   
 /*  /*
   ** Try to transfer data for table zTable.  If an error is seen while
   ** moving forward, try to go backwards.  The backwards movement won't
   ** work for WITHOUT ROWID tables.
   */
   static void tryToCloneData(
     struct callback_data *p,
     sqlite3 *newDb,
     const char *zTable
   ){
     sqlite3_stmt *pQuery = 0;
     sqlite3_stmt *pInsert = 0;
     char *zQuery = 0;
     char *zInsert = 0;
     int rc;
     int i, j, n;
     int nTable = (int)strlen(zTable);
     int k = 0;
     int cnt = 0;
     const int spinRate = 10000;
   
     zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
     rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
     if( rc ){
       fprintf(stderr, "Error %d: %s on [%s]\n",
               sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
               zQuery);
       goto end_data_xfer;
     }
     n = sqlite3_column_count(pQuery);
     zInsert = sqlite3_malloc(200 + nTable + n*3);
     if( zInsert==0 ){
       fprintf(stderr, "out of memory\n");
       goto end_data_xfer;
     }
     sqlite3_snprintf(200+nTable,zInsert,
                      "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
     i = (int)strlen(zInsert);
     for(j=1; j<n; j++){
       memcpy(zInsert+i, ",?", 2);
       i += 2;
     }
     memcpy(zInsert+i, ");", 3);
     rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
     if( rc ){
       fprintf(stderr, "Error %d: %s on [%s]\n",
               sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
               zQuery);
       goto end_data_xfer;
     }
     for(k=0; k<2; k++){
       while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
         for(i=0; i<n; i++){
           switch( sqlite3_column_type(pQuery, i) ){
             case SQLITE_NULL: {
               sqlite3_bind_null(pInsert, i+1);
               break;
             }
             case SQLITE_INTEGER: {
               sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
               break;
             }
             case SQLITE_FLOAT: {
               sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
               break;
             }
             case SQLITE_TEXT: {
               sqlite3_bind_text(pInsert, i+1,
                                (const char*)sqlite3_column_text(pQuery,i),
                                -1, SQLITE_STATIC);
               break;
             }
             case SQLITE_BLOB: {
               sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
                                               sqlite3_column_bytes(pQuery,i),
                                               SQLITE_STATIC);
               break;
             }
           }
         } /* End for */
         rc = sqlite3_step(pInsert);
         if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
           fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
                           sqlite3_errmsg(newDb));
         }
         sqlite3_reset(pInsert);
         cnt++;
         if( (cnt%spinRate)==0 ){
           printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
           fflush(stdout);
         }
       } /* End while */
       if( rc==SQLITE_DONE ) break;
       sqlite3_finalize(pQuery);
       sqlite3_free(zQuery);
       zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
                                zTable);
       rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
       if( rc ){
         fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
         break;
       }
     } /* End for(k=0...) */
   
   end_data_xfer:
     sqlite3_finalize(pQuery);
     sqlite3_finalize(pInsert);
     sqlite3_free(zQuery);
     sqlite3_free(zInsert);
   }
   
   
   /*
   ** Try to transfer all rows of the schema that match zWhere.  For
   ** each row, invoke xForEach() on the object defined by that row.
   ** If an error is encountered while moving forward through the
   ** sqlite_master table, try again moving backwards.
   */
   static void tryToCloneSchema(
     struct callback_data *p,
     sqlite3 *newDb,
     const char *zWhere,
     void (*xForEach)(struct callback_data*,sqlite3*,const char*)
   ){
     sqlite3_stmt *pQuery = 0;
     char *zQuery = 0;
     int rc;
     const unsigned char *zName;
     const unsigned char *zSql;
     char *zErrMsg = 0;
   
     zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
                              " WHERE %s", zWhere);
     rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
     if( rc ){
       fprintf(stderr, "Error: (%d) %s on [%s]\n",
                       sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
                       zQuery);
       goto end_schema_xfer;
     }
     while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
       zName = sqlite3_column_text(pQuery, 0);
       zSql = sqlite3_column_text(pQuery, 1);
       printf("%s... ", zName); fflush(stdout);
       sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
       if( zErrMsg ){
         fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
         sqlite3_free(zErrMsg);
         zErrMsg = 0;
       }
       if( xForEach ){
         xForEach(p, newDb, (const char*)zName);
       }
       printf("done\n");
     }
     if( rc!=SQLITE_DONE ){
       sqlite3_finalize(pQuery);
       sqlite3_free(zQuery);
       zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
                                " WHERE %s ORDER BY rowid DESC", zWhere);
       rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
       if( rc ){
         fprintf(stderr, "Error: (%d) %s on [%s]\n",
                         sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
                         zQuery);
         goto end_schema_xfer;
       }
       while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
         zName = sqlite3_column_text(pQuery, 0);
         zSql = sqlite3_column_text(pQuery, 1);
         printf("%s... ", zName); fflush(stdout);
         sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
         if( zErrMsg ){
           fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
           sqlite3_free(zErrMsg);
           zErrMsg = 0;
         }
         if( xForEach ){
           xForEach(p, newDb, (const char*)zName);
         }
         printf("done\n");
       }
     }
   end_schema_xfer:
     sqlite3_finalize(pQuery);
     sqlite3_free(zQuery);
   }
   
   /*
   ** Open a new database file named "zNewDb".  Try to recover as much information
   ** as possible out of the main database (which might be corrupt) and write it
   ** into zNewDb.
   */
   static void tryToClone(struct callback_data *p, const char *zNewDb){
     int rc;
     sqlite3 *newDb = 0;
     if( access(zNewDb,0)==0 ){
       fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
       return;
     }
     rc = sqlite3_open(zNewDb, &newDb);
     if( rc ){
       fprintf(stderr, "Cannot create output database: %s\n",
               sqlite3_errmsg(newDb));
     }else{
       sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
       tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
       tryToCloneSchema(p, newDb, "type!='table'", 0);
       sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
     }
     sqlite3_close(newDb);
   }
   
   /*
 ** 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 1794 
Line 2179 
   if( nArg==0 ) return 0; /* no tokens, no error */    if( nArg==0 ) return 0; /* no tokens, no error */
   n = strlen30(azArg[0]);    n = strlen30(azArg[0]);
   c = azArg[0][0];    c = azArg[0][0];
   if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){    if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
      || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
     ){
     const char *zDestFile = 0;      const char *zDestFile = 0;
     const char *zDb = 0;      const char *zDb = 0;
     sqlite3 *pDest;      sqlite3 *pDest;
Line 1830 
Line 2217 
       sqlite3_close(pDest);        sqlite3_close(pDest);
       return 1;        return 1;
     }      }
     open_db(p);      open_db(p, 0);
     pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);      pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
     if( pBackup==0 ){      if( pBackup==0 ){
       fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
Line 1859 
Line 2246 
     test_breakpoint();      test_breakpoint();
   }else    }else
   
     if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
       tryToClone(p, azArg[1]);
     }else
   
   if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){    if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
     struct callback_data data;      struct callback_data data;
     char *zErrMsg = 0;      char *zErrMsg = 0;
     open_db(p);      open_db(p, 0);
     memcpy(&data, p, sizeof(data));      memcpy(&data, p, sizeof(data));
     data.showHeader = 1;      data.showHeader = 1;
     data.mode = MODE_Column;      data.mode = MODE_Column;
Line 1879 
Line 2270 
   }else    }else
   
   if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){    if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
     open_db(p);      open_db(p, 0);
     /* When playing back a "dump", the content might appear in an order      /* When playing back a "dump", the content might appear in an order
     ** which causes immediate foreign key constraints to be violated.      ** which causes immediate foreign key constraints to be violated.
     ** So disable foreign-key constraint enforcement to prevent problems. */      ** So disable foreign-key constraint enforcement to prevent problems. */
Line 1931 
Line 2322 
     p->echoOn = booleanValue(azArg[1]);      p->echoOn = booleanValue(azArg[1]);
   }else    }else
   
     if( c=='e' && strncmp(azArg[0], "eqp", n)==0 && nArg>1 && nArg<3 ){
       p->autoEQP = booleanValue(azArg[1]);
     }else
   
   if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){    if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
     if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);      if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
     rc = 2;      rc = 2;
Line 1954 
Line 2349 
       */        */
       p->mode = MODE_Explain;        p->mode = MODE_Explain;
       p->showHeader = 1;        p->showHeader = 1;
       memset(p->colWidth,0,ArraySize(p->colWidth));        memset(p->colWidth,0,sizeof(p->colWidth));
       p->colWidth[0] = 4;                  /* addr */        p->colWidth[0] = 4;                  /* addr */
       p->colWidth[1] = 13;                 /* opcode */        p->colWidth[1] = 13;                 /* opcode */
       p->colWidth[2] = 4;                  /* P1 */        p->colWidth[2] = 4;                  /* P1 */
Line 1998 
Line 2393 
   
     seenInterrupt = 0;      seenInterrupt = 0;
     memset(&sCsv, 0, sizeof(sCsv));      memset(&sCsv, 0, sizeof(sCsv));
     open_db(p);      open_db(p, 0);
     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");
Line 2031 
Line 2426 
       return 1;        return 1;
     }      }
     nByte = strlen30(zSql);      nByte = strlen30(zSql);
     rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
     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 = '(';
Line 2057 
Line 2452 
         xCloser(sCsv.in);          xCloser(sCsv.in);
         return 1;          return 1;
       }        }
       rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);        rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
     }      }
     sqlite3_free(zSql);      sqlite3_free(zSql);
     if( rc ){      if( rc ){
Line 2084 
Line 2479 
     }      }
     zSql[j++] = ')';      zSql[j++] = ')';
     zSql[j] = 0;      zSql[j] = 0;
     rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
     sqlite3_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));
Line 2136 
Line 2531 
   if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){    if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
     struct callback_data data;      struct callback_data data;
     char *zErrMsg = 0;      char *zErrMsg = 0;
     open_db(p);      open_db(p, 0);
     memcpy(&data, p, sizeof(data));      memcpy(&data, p, sizeof(data));
     data.showHeader = 0;      data.showHeader = 0;
     data.mode = MODE_List;      data.mode = MODE_List;
Line 2202 
Line 2597 
     char *zErrMsg = 0;      char *zErrMsg = 0;
     zFile = azArg[1];      zFile = azArg[1];
     zProc = nArg>=3 ? azArg[2] : 0;      zProc = nArg>=3 ? azArg[2] : 0;
     open_db(p);      open_db(p, 0);
     rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);      rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
     if( rc!=SQLITE_OK ){      if( rc!=SQLITE_OK ){
       fprintf(stderr, "Error: %s\n", zErrMsg);        fprintf(stderr, "Error: %s\n", zErrMsg);
Line 2268 
Line 2663 
                      "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);                       "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
   }else    }else
   
     if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
       sqlite3 *savedDb = p->db;
       const char *zSavedFilename = p->zDbFilename;
       char *zNewFilename = 0;
       p->db = 0;
       if( nArg>=2 ){
         p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]);
       }
       open_db(p, 1);
       if( p->db!=0 ){
         sqlite3_close(savedDb);
         sqlite3_free(p->zFreeOnClose);
         p->zFreeOnClose = zNewFilename;
       }else{
         sqlite3_free(zNewFilename);
         p->db = savedDb;
         p->zDbFilename = zSavedFilename;
       }
     }else
   
   if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){    if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
     if( p->outfile[0]=='|' ){      if( p->outfile[0]=='|' ){
       pclose(p->out);        pclose(p->out);
Line 2351 
Line 2766 
       sqlite3_close(pSrc);        sqlite3_close(pSrc);
       return 1;        return 1;
     }      }
     open_db(p);      open_db(p, 0);
     pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");      pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
     if( pBackup==0 ){      if( pBackup==0 ){
       fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
Line 2381 
Line 2796 
   if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){    if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
     struct callback_data data;      struct callback_data data;
     char *zErrMsg = 0;      char *zErrMsg = 0;
     open_db(p);      open_db(p, 0);
     memcpy(&data, p, sizeof(data));      memcpy(&data, p, sizeof(data));
     data.showHeader = 0;      data.showHeader = 0;
     data.mode = MODE_Semi;      data.mode = MODE_Semi;
Line 2483 
Line 2898 
   if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){    if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
     int i;      int i;
     fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");      fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
       fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
     fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");      fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
     fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");      fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
     fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);      fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
Line 2512 
Line 2928 
     int nRow, nAlloc;      int nRow, nAlloc;
     char *zSql = 0;      char *zSql = 0;
     int ii;      int ii;
     open_db(p);      open_db(p, 0);
     rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);      rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
     if( rc ) return rc;      if( rc ) return rc;
     zSql = sqlite3_mprintf(      zSql = sqlite3_mprintf(
Line 2612 
Line 3028 
     int testctrl = -1;      int testctrl = -1;
     int rc = 0;      int rc = 0;
     int i, n;      int i, n;
     open_db(p);      open_db(p, 0);
   
     /* convert testctrl text option to value. allow any unique prefix      /* convert testctrl text option to value. allow any unique prefix
     ** of the option name, or a numerical value. */      ** of the option name, or a numerical value. */
Line 2711 
Line 3127 
   }else    }else
   
   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, 0);
     sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));      sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));
   }else    }else
   
Line 2722 
Line 3138 
   }else    }else
   
   if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){    if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
     open_db(p);      open_db(p, 0);
     output_file_close(p->traceOut);      output_file_close(p->traceOut);
     p->traceOut = output_file_open(azArg[1]);      p->traceOut = output_file_open(azArg[1]);
 #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)  #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
Line 2875 
Line 3291 
       seenInterrupt = 0;        seenInterrupt = 0;
     }      }
     lineno++;      lineno++;
     if( nSql==0 && _all_whitespace(zLine) ) continue;      if( nSql==0 && _all_whitespace(zLine) ){
         if( p->echoOn ) printf("%s\n", 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 2914 
Line 3333 
     if( nSql && line_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, 0);
       BEGIN_TIMER;        BEGIN_TIMER;
       rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);        rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
       END_TIMER;        END_TIMER;
Line 2937 
Line 3356 
       }        }
       nSql = 0;        nSql = 0;
     }else if( nSql && _all_whitespace(zSql) ){      }else if( nSql && _all_whitespace(zSql) ){
         if( p->echoOn ) printf("%s\n", zSql);
       nSql = 0;        nSql = 0;
     }      }
   }    }
Line 3115 
Line 3535 
 }  }
   
 /*  /*
   ** Output text to the console in a font that attracts extra attention.
   */
   #ifdef _WIN32
   static void printBold(const char *zText){
     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
     CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
     GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
     SetConsoleTextAttribute(out,
            FOREGROUND_RED|FOREGROUND_INTENSITY
     );
     printf("%s", zText);
     SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
   }
   #else
   static void printBold(const char *zText){
     printf("\033[1m%s\033[0m", zText);
   }
   #endif
   
   /*
 ** Get the argument to an --option.  Throw an error and die if no argument  ** Get the argument to an --option.  Throw an error and die if no argument
 ** is available.  ** is available.
 */  */
Line 3134 
Line 3574 
   char *zFirstCmd = 0;    char *zFirstCmd = 0;
   int i;    int i;
   int rc = 0;    int rc = 0;
     int warnInmemoryDb = 0;
   
   #if USE_SYSTEM_SQLITE+0!=1
   if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){    if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
     fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",      fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
             sqlite3_sourceid(), SQLITE_SOURCE_ID);              sqlite3_sourceid(), SQLITE_SOURCE_ID);
     exit(1);      exit(1);
   }    }
   #endif
   Argv0 = argv[0];    Argv0 = argv[0];
   main_init(&data);    main_init(&data);
   stdin_is_interactive = isatty(0);    stdin_is_interactive = isatty(0);
Line 3228 
Line 3671 
   if( data.zDbFilename==0 ){    if( data.zDbFilename==0 ){
 #ifndef SQLITE_OMIT_MEMORYDB  #ifndef SQLITE_OMIT_MEMORYDB
     data.zDbFilename = ":memory:";      data.zDbFilename = ":memory:";
       warnInmemoryDb = argc==1;
 #else  #else
     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 3241 
Line 3690 
   ** to the sqlite command-line tool.    ** to the sqlite command-line tool.
   */    */
   if( access(data.zDbFilename, 0)==0 ){    if( access(data.zDbFilename, 0)==0 ){
     open_db(&data);      open_db(&data, 0);
   }    }
   
   /* Process the initialization file if there is one.  If no -init option    /* Process the initialization file if there is one.  If no -init option
Line 3287 
Line 3736 
       data.showHeader = 0;        data.showHeader = 0;
     }else if( strcmp(z,"-echo")==0 ){      }else if( strcmp(z,"-echo")==0 ){
       data.echoOn = 1;        data.echoOn = 1;
       }else if( strcmp(z,"-eqp")==0 ){
         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,"-bail")==0 ){      }else if( strcmp(z,"-bail")==0 ){
Line 3321 
Line 3772 
         rc = do_meta_command(z, &data);          rc = do_meta_command(z, &data);
         if( rc && bail_on_error ) return rc==2 ? 0 : rc;          if( rc && bail_on_error ) return rc==2 ? 0 : rc;
       }else{        }else{
         open_db(&data);          open_db(&data, 0);
         rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);          rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
         if( zErrMsg!=0 ){          if( zErrMsg!=0 ){
           fprintf(stderr,"Error: %s\n", zErrMsg);            fprintf(stderr,"Error: %s\n", zErrMsg);
Line 3345 
Line 3796 
       rc = do_meta_command(zFirstCmd, &data);        rc = do_meta_command(zFirstCmd, &data);
       if( rc==2 ) rc = 0;        if( rc==2 ) rc = 0;
     }else{      }else{
       open_db(&data);        open_db(&data, 0);
       rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);        rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
       if( zErrMsg!=0 ){        if( zErrMsg!=0 ){
         fprintf(stderr,"Error: %s\n", zErrMsg);          fprintf(stderr,"Error: %s\n", zErrMsg);
Line 3364 
Line 3815 
       int nHistory;        int nHistory;
       printf(        printf(
         "SQLite version %s %.19s\n" /*extra-version-info*/          "SQLite version %s %.19s\n" /*extra-version-info*/
         "Enter \".help\" for instructions\n"          "Enter \".help\" for usage hints.\n",
         "Enter SQL statements terminated with a \";\"\n",  
         sqlite3_libversion(), sqlite3_sourceid()          sqlite3_libversion(), sqlite3_sourceid()
       );        );
         if( warnInmemoryDb ){
           printf("Connected to a ");
           printBold("transient in-memory database");
           printf(".\nUse \".open FILENAME\" to reopen on a "
                  "persistent database.\n");
         }
       zHome = find_home_dir();        zHome = find_home_dir();
       if( zHome ){        if( zHome ){
         nHistory = strlen30(zHome) + 20;          nHistory = strlen30(zHome) + 20;
Line 3375 
Line 3831 
           sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);            sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
         }          }
       }        }
 #if defined(HAVE_READLINE) && HAVE_READLINE==1  #if defined(HAVE_READLINE)
       if( zHistory ) read_history(zHistory);        if( zHistory ) read_history(zHistory);
 #endif  #endif
       rc = process_input(&data, 0);        rc = process_input(&data, 0);
Line 3392 
Line 3848 
   if( data.db ){    if( data.db ){
     sqlite3_close(data.db);      sqlite3_close(data.db);
   }    }
     sqlite3_free(data.zFreeOnClose);
   return rc;    return rc;
 }  }

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