]> git.lizzy.rs Git - sqlite3-cmake.git/blobdiff - src/shell.c
Update Sqlite-amalgamation to 3.8.5
[sqlite3-cmake.git] / src / shell.c
index 480ec5b4556b7c7a1f7b4524a81a992ebb0f8de8..1f8681f63950d2e0141c0f894293aadc0fd96f07 100644 (file)
 # include <sys/types.h>
 #endif
 
-#ifdef HAVE_EDITLINE
-# include <editline/editline.h>
-#endif
-#if defined(HAVE_READLINE) && HAVE_READLINE==1
+#if defined(HAVE_READLINE) && HAVE_READLINE!=0
 # include <readline/readline.h>
 # include <readline/history.h>
+#else
+# undef HAVE_READLINE
+#endif
+#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
+# define HAVE_READLINE 1
+# include <editline/readline.h>
 #endif
-#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
+#if !defined(HAVE_READLINE)
 # define add_history(X)
 # define read_history(X)
 # define write_history(X)
@@ -62,7 +65,9 @@
 #if defined(_WIN32) || defined(WIN32)
 # include <io.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
 #define popen _popen
 #undef pclose
@@ -413,7 +418,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
     zResult = local_getline(zPrior, in);
   }else{
     zPrompt = isContinuation ? continuePrompt : mainPrompt;
-#if defined(HAVE_READLINE) && HAVE_READLINE==1
+#if defined(HAVE_READLINE)
     free(zPrior);
     zResult = readline(zPrompt);
     if( zResult && *zResult ) add_history(zResult);
@@ -441,7 +446,9 @@ struct previous_mode_data {
 struct callback_data {
   sqlite3 *db;           /* The database */
   int echoOn;            /* True to echo input commands */
+  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
   int statsOn;           /* True to display memory stats before each finalize */
+  int outCount;          /* Revert to stdout when reaching zero */
   int cnt;               /* Number of records displayed so far */
   FILE *out;             /* Write results here */
   FILE *traceOut;        /* Output for sqlite3_trace() */
@@ -597,6 +604,7 @@ static void output_c_string(FILE *out, const char *z){
 */
 static void output_html_string(FILE *out, const char *z){
   int i;
+  if( z==0 ) z = "";
   while( *z ){
     for(i=0;   z[i] 
             && z[i]!='<' 
@@ -690,7 +698,8 @@ static void output_csv(struct callback_data *p, const char *z, int bSep){
 */
 static void interrupt_handler(int NotUsed){
   UNUSED_PARAMETER(NotUsed);
-  seenInterrupt = 1;
+  seenInterrupt++;
+  if( seenInterrupt>2 ) exit(1);
   if( db ) sqlite3_interrupt(db);
 }
 #endif
@@ -870,7 +879,8 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
         }else if( aiType && aiType[i]==SQLITE_TEXT ){
           if( zSep[0] ) fprintf(p->out,"%s",zSep);
           output_quoted_string(p->out, azArg[i]);
-        }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){
+        }else if( aiType && (aiType[i]==SQLITE_INTEGER
+                             || aiType[i]==SQLITE_FLOAT) ){
           fprintf(p->out,"%s%s",zSep, azArg[i]);
         }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
           const void *pBlob = sqlite3_column_blob(p->pStmt, i);
@@ -1004,7 +1014,7 @@ static int run_table_dump_query(
   int nResult;
   int i;
   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 ){
     fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
     if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
@@ -1176,7 +1186,8 @@ static int str_in_array(const char *zStr, const char **azArray){
 **
 **     * For each "Goto", if the jump destination is earlier in the program
 **       and ends on one of:
-**          Yield  SeekGt  SeekLt  RowSetRead
+**          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.
 */
@@ -1187,8 +1198,9 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
   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", 0 };
+  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
+                           "NextIfOpen", "PrevIfOpen", 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
@@ -1224,8 +1236,10 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
     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] ){
-      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;
     }
   }
 
@@ -1296,6 +1310,23 @@ static int shell_exec(
         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 */
       if( pArg && pArg->mode==MODE_Explain ){
         const char *zExplain = 0;
@@ -1452,7 +1483,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
     zTableInfo = appendText(zTableInfo, zTable, '"');
     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);
     if( rc!=SQLITE_OK || !pTableInfo ){
       return 1;
@@ -1541,16 +1572,17 @@ static int run_schema_dump_query(
 */
 static char zHelp[] =
   ".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"
   ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
   "                         If TABLE specified, only dump tables matching\n"
   "                         LIKE pattern TABLE.\n"
-  ".echo ON|OFF           Turn command echo on or off\n"
+  ".echo on|off           Turn command echo on or off\n"
   ".exit                  Exit this program\n"
-  ".explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.\n"
+  ".explain ?on|off?      Turn output mode suitable for EXPLAIN on or off.\n"
   "                         With no args, it turns EXPLAIN on.\n"
-  ".header(s) ON|OFF      Turn display of headers on or off\n"
+  ".headers on|off        Turn display of headers on or off\n"
   ".help                  Show this message\n"
   ".import FILE TABLE     Import data from FILE into TABLE\n"
   ".indices ?TABLE?       Show names of all indices\n"
@@ -1573,31 +1605,32 @@ static char zHelp[] =
   "                         tabs     Tab-separated values\n"
   "                         tcl      TCL list elements\n"
   ".nullvalue STRING      Use STRING in place of NULL values\n"
+  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
   ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
-  ".output FILENAME       Send output to FILENAME\n"
-  ".output stdout         Send output to the screen\n"
+  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
   ".print STRING...       Print literal STRING\n"
   ".prompt MAIN CONTINUE  Replace the standard prompts\n"
   ".quit                  Exit this program\n"
   ".read FILENAME         Execute SQL in FILENAME\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"
   "                         If TABLE specified, only show tables matching\n"
   "                         LIKE pattern TABLE.\n"
   ".separator STRING      Change separator used by output mode and .import\n"
+  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
   ".show                  Show the current values for various settings\n"
-  ".stats ON|OFF          Turn stats on or off\n"
+  ".stats on|off          Turn stats on or off\n"
+  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
   ".tables ?TABLE?        List names of tables\n"
   "                         If TABLE specified, only list tables matching\n"
   "                         LIKE pattern TABLE.\n"
   ".timeout MS            Try opening locked tables for MS milliseconds\n"
+  ".timer on|off          Turn SQL timer on or off\n"
   ".trace FILE|off        Output each SQL statement as it is run\n"
   ".vfsname ?AUX?         Print the name of the VFS stack\n"
   ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
-;
-
-static char zTimerHelp[] =
-  ".timer ON|OFF          Turn the CPU timer measurement on or off\n"
+  "                         Negative values right-justify\n"
 ;
 
 /* Forward reference */
@@ -1641,6 +1674,7 @@ static void open_db(struct callback_data *p, int keepAlive){
 static void resolve_backslashes(char *z){
   int i, j;
   char c;
+  while( *z && *z!='\\' ) z++;
   for(i=j=0; (c = z[i])!=0; i++, j++){
     if( c=='\\' ){
       c = z[++i];
@@ -1666,7 +1700,7 @@ static void resolve_backslashes(char *z){
     }
     z[j] = c;
   }
-  z[j] = 0;
+  if( j<i ) z[j] = 0;
 }
 
 /*
@@ -1836,7 +1870,7 @@ static void csv_append_char(CSVReader *p, int c){
 **   +  Report syntax errors on stderr
 */
 static char *csv_read_one_field(CSVReader *p){
-  int c, pc;
+  int c, pc, ppc;
   int cSep = p->cSeparator;
   p->n = 0;
   c = fgetc(p->in);
@@ -1847,7 +1881,7 @@ static char *csv_read_one_field(CSVReader *p){
   if( c=='"' ){
     int startLine = p->nLine;
     int cQuote = c;
-    pc = 0;
+    pc = ppc = 0;
     while( 1 ){
       c = fgetc(p->in);
       if( c=='\n' ) p->nLine++;
@@ -1859,7 +1893,7 @@ static char *csv_read_one_field(CSVReader *p){
       }
       if( (c==cSep && 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)
       ){
         do{ p->n--; }while( p->z[p->n]!=cQuote );
@@ -1877,6 +1911,7 @@ static char *csv_read_one_field(CSVReader *p){
         break;
       }
       csv_append_char(p, c);
+      ppc = pc;
       pc = c;
     }
   }else{
@@ -1886,7 +1921,7 @@ static char *csv_read_one_field(CSVReader *p){
     }
     if( c=='\n' ){
       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;
   }
@@ -1894,6 +1929,234 @@ static char *csv_read_one_field(CSVReader *p){
   return p->z;
 }
 
+/*
+** Try to transfer data for table zTable.  If an error is seen while
+** moving forward, try to go backwards.  The backwards movement won't
+** 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(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
+    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_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
+  }
+  sqlite3_close(newDb);
+}
+
+/*
+** Change the output file back to stdout
+*/
+static void output_reset(struct callback_data *p){
+  if( p->outfile[0]=='|' ){
+    pclose(p->out);
+  }else{
+    output_file_close(p->out);
+  }
+  p->outfile[0] = 0;
+  p->out = stdout;
+}
+
 /*
 ** If an input line begins with "." then invoke this routine to
 ** process that line.
@@ -1936,7 +2199,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
   if( nArg==0 ) return 0; /* no tokens, no error */
   n = strlen30(azArg[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 *zDb = 0;
     sqlite3 *pDest;
@@ -1990,8 +2255,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     sqlite3_close(pDest);
   }else
 
-  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){
-    bail_on_error = booleanValue(azArg[1]);
+  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
+    if( nArg==2 ){
+      bail_on_error = booleanValue(azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .bail on|off\n");
+      rc = 1;
+    }
   }else
 
   /* The undocumented ".breakpoint" command causes a call to the no-op
@@ -2001,7 +2271,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     test_breakpoint();
   }else
 
-  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
+  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
+    if( nArg==2 ){
+      tryToClone(p, azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .clone FILENAME\n");
+      rc = 1;
+    }
+  }else
+
+  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
     struct callback_data data;
     char *zErrMsg = 0;
     open_db(p, 0);
@@ -2020,11 +2299,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
-  if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
+  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
     open_db(p, 0);
     /* When playing back a "dump", the content might appear in an order
     ** which causes immediate foreign key constraints to be violated.
     ** So disable foreign-key constraint enforcement to prevent problems. */
+    if( nArg!=1 && nArg!=2 ){
+      fprintf(stderr, "Usage: .dump ?LIKE-PATTERN?\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
     fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
     fprintf(p->out, "BEGIN TRANSACTION;\n");
     p->writableSchema = 0;
@@ -2069,8 +2353,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
   }else
 
-  if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
-    p->echoOn = booleanValue(azArg[1]);
+  if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
+    if( nArg==2 ){
+      p->echoOn = booleanValue(azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .echo on|off\n");
+      rc = 1;
+    }
+  }else
+
+  if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
+    if( nArg==2 ){
+      p->autoEQP = booleanValue(azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .eqp on|off\n");
+      rc = 1;
+    }   
   }else
 
   if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
@@ -2078,7 +2376,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     rc = 2;
   }else
 
-  if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
+  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
     int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
     if(val == 1) {
       if(!p->explainPrev.valid) {
@@ -2113,21 +2411,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
-  if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
-                 strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
-    p->showHeader = booleanValue(azArg[1]);
+  if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
+    if( nArg==2 ){
+      p->showHeader = booleanValue(azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .headers on|off\n");
+      rc = 1;
+    }
   }else
 
   if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
-    fprintf(stderr,"%s",zHelp);
-    if( HAS_TIMER ){
-      fprintf(stderr,"%s",zTimerHelp);
-    }
+    fprintf(p->out, "%s", zHelp);
   }else
 
-  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
-    char *zTable = azArg[2];    /* Insert data into this table */
-    char *zFile = azArg[1];     /* Name of file to extra content from */
+  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
+    char *zTable;               /* Insert data into this table */
+    char *zFile;                /* Name of file to extra content from */
     sqlite3_stmt *pStmt = NULL; /* A statement */
     int nCol;                   /* Number of columns in the table */
     int nByte;                  /* Number of bytes in an SQL string */
@@ -2138,6 +2437,12 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     CSVReader sCsv;             /* Reader context */
     int (*xCloser)(FILE*);      /* Procedure to close th3 connection */
 
+    if( nArg!=3 ){
+      fprintf(stderr, "Usage: .import FILE TABLE\n");
+      goto meta_command_exit;
+    }
+    zFile = azArg[1];
+    zTable = azArg[2];
     seenInterrupt = 0;
     memset(&sCsv, 0, sizeof(sCsv));
     open_db(p, 0);
@@ -2173,7 +2478,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
       return 1;
     }
     nByte = strlen30(zSql);
-    rc = sqlite3_prepare(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 */
     if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
       char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
       char cSep = '(';
@@ -2199,7 +2505,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
         xCloser(sCsv.in);
         return 1;
       }
-      rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
     }
     sqlite3_free(zSql);
     if( rc ){
@@ -2226,7 +2532,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
     zSql[j++] = ')';
     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);
     if( rc ){
       fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
@@ -2275,7 +2581,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
   }else
 
-  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
+  if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
     struct callback_data data;
     char *zErrMsg = 0;
     open_db(p, 0);
@@ -2292,7 +2598,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
         "ORDER BY 1",
         callback, &data, &zErrMsg
       );
-    }else{
+    }else if( nArg==2 ){
       zShellStatic = azArg[1];
       rc = sqlite3_exec(p->db,
         "SELECT name FROM sqlite_master "
@@ -2304,6 +2610,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
         callback, &data, &zErrMsg
       );
       zShellStatic = 0;
+    }else{
+      fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
+      rc = 1;
+      goto meta_command_exit;
     }
     if( zErrMsg ){
       fprintf(stderr,"Error: %s\n", zErrMsg);
@@ -2339,9 +2649,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){
 #endif
 
 #ifndef SQLITE_OMIT_LOAD_EXTENSION
-  if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
+  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
     const char *zFile, *zProc;
     char *zErrMsg = 0;
+    if( nArg<2 ){
+      fprintf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
     zFile = azArg[1];
     zProc = nArg>=3 ? azArg[2] : 0;
     open_db(p, 0);
@@ -2354,38 +2669,41 @@ static int do_meta_command(char *zLine, struct callback_data *p){
   }else
 #endif
 
-  if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
-    const char *zFile = azArg[1];
-    output_file_close(p->pLog);
-    p->pLog = output_file_open(zFile);
+  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
+    if( nArg!=2 ){
+      fprintf(stderr, "Usage: .log FILENAME\n");
+      rc = 1;
+    }else{
+      const char *zFile = azArg[1];
+      output_file_close(p->pLog);
+      p->pLog = output_file_open(zFile);
+    }
   }else
 
-  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
-    int n2 = strlen30(azArg[1]);
-    if( (n2==4 && strncmp(azArg[1],"line",n2)==0)
-        ||
-        (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){
+  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
+    const char *zMode = nArg>=2 ? azArg[1] : "";
+    int n2 = (int)strlen(zMode);
+    int c2 = zMode[0];
+    if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
       p->mode = MODE_Line;
-    }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0)
-              ||
-              (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){
+    }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
       p->mode = MODE_Column;
-    }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){
+    }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
       p->mode = MODE_List;
-    }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){
+    }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
       p->mode = MODE_Html;
-    }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
+    }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
       p->mode = MODE_Tcl;
       sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
-    }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
+    }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
       p->mode = MODE_Csv;
       sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
-    }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){
+    }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
       p->mode = MODE_List;
       sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
-    }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
+    }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
       p->mode = MODE_Insert;
-      set_table_name(p, "table");
+      set_table_name(p, nArg>=3 ? azArg[2] : "table");
     }else {
       fprintf(stderr,"Error: mode should be one of: "
          "column csv html insert line list tabs tcl\n");
@@ -2393,23 +2711,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
-  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){
-    int n2 = strlen30(azArg[1]);
-    if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
-      p->mode = MODE_Insert;
-      set_table_name(p, azArg[2]);
-    }else {
-      fprintf(stderr, "Error: invalid arguments: "
-        " \"%s\". Enter \".help\" for help\n", azArg[2]);
+  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
+    if( nArg==2 ){
+      sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
+                       "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .nullvalue STRING\n");
       rc = 1;
     }
   }else
 
-  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
-    sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
-                     "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
-  }else
-
   if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
     sqlite3 *savedDb = p->db;
     const char *zSavedFilename = p->zDbFilename;
@@ -2430,32 +2741,45 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
-  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
-    if( p->outfile[0]=='|' ){
-      pclose(p->out);
+  if( c=='o'
+   && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
+  ){
+    const char *zFile = nArg>=2 ? azArg[1] : "stdout";
+    if( nArg>2 ){
+      fprintf(stderr, "Usage: .%s FILE\n", azArg[0]);
+      rc = 1;
+      goto meta_command_exit;
+    }
+    if( n>1 && strncmp(azArg[0], "once", n)==0 ){
+      if( nArg<2 ){
+        fprintf(stderr, "Usage: .once FILE\n");
+        rc = 1;
+        goto meta_command_exit;
+      }
+      p->outCount = 2;
     }else{
-      output_file_close(p->out);
+      p->outCount = 0;
     }
-    p->outfile[0] = 0;
-    if( azArg[1][0]=='|' ){
-      p->out = popen(&azArg[1][1], "w");
+    output_reset(p);
+    if( zFile[0]=='|' ){
+      p->out = popen(zFile + 1, "w");
       if( p->out==0 ){
-        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]);
+        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
         p->out = stdout;
         rc = 1;
       }else{
-        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
+        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
       }
     }else{
-      p->out = output_file_open(azArg[1]);
+      p->out = output_file_open(zFile);
       if( p->out==0 ){
-        if( strcmp(azArg[1],"off")!=0 ){
-          fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
+        if( strcmp(zFile,"off")!=0 ){
+          fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
         }
         p->out = stdout;
         rc = 1;
       } else {
-        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
+        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
       }
     }
   }else
@@ -2469,7 +2793,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     fprintf(p->out, "\n");
   }else
 
-  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
+  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
     if( nArg >= 2) {
       strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
     }
@@ -2478,12 +2802,18 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
-  if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){
+  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
     rc = 2;
   }else
 
-  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
-    FILE *alt = fopen(azArg[1], "rb");
+  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
+    FILE *alt;
+    if( nArg!=2 ){
+      fprintf(stderr, "Usage: .read FILE\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
+    alt = fopen(azArg[1], "rb");
     if( alt==0 ){
       fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
       rc = 1;
@@ -2493,7 +2823,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
-  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
+  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
     const char *zSrcFile;
     const char *zDb;
     sqlite3 *pSrc;
@@ -2503,9 +2833,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     if( nArg==2 ){
       zSrcFile = azArg[1];
       zDb = "main";
-    }else{
+    }else if( nArg==3 ){
       zSrcFile = azArg[2];
       zDb = azArg[1];
+    }else{
+      fprintf(stderr, "Usage: .restore ?DB? FILE\n");
+      rc = 1;
+      goto meta_command_exit;
     }
     rc = sqlite3_open(zSrcFile, &pSrc);
     if( rc!=SQLITE_OK ){
@@ -2540,14 +2874,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     sqlite3_close(pSrc);
   }else
 
-  if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
+  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
     struct callback_data data;
     char *zErrMsg = 0;
     open_db(p, 0);
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
     data.mode = MODE_Semi;
-    if( nArg>1 ){
+    if( nArg==2 ){
       int i;
       for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
       if( strcmp(azArg[1],"sqlite_master")==0 ){
@@ -2591,7 +2925,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
           callback, &data, &zErrMsg);
         zShellStatic = 0;
       }
-    }else{
+    }else if( nArg==1 ){
       rc = sqlite3_exec(p->db,
          "SELECT sql FROM "
          "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
@@ -2601,6 +2935,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
          "ORDER BY rowid",
          callback, &data, &zErrMsg
       );
+    }else{
+      fprintf(stderr, "Usage: .schema ?LIKE-PATTERN?\n");
+      rc = 1;
+      goto meta_command_exit;
     }
     if( zErrMsg ){
       fprintf(stderr,"Error: %s\n", zErrMsg);
@@ -2630,21 +2968,51 @@ static int do_meta_command(char *zLine, struct callback_data *p){
       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);
+        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 ){
-    sqlite3_snprintf(sizeof(p->separator), p->separator,
-                     "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
+  if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
+    if( nArg==2 ){
+      sqlite3_snprintf(sizeof(p->separator), p->separator,
+                       "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .separator STRING\n");
+      rc = 1;
+    }
+  }else
+
+  if( c=='s'
+   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
+  ){
+    char *zCmd;
+    int i;
+    if( nArg<2 ){
+      fprintf(stderr, "Usage: .system COMMAND\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
+    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
+    for(i=2; i<nArg; i++){
+      zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
+                             zCmd, azArg[i]);
+    }
+    (void)system(zCmd);
+    sqlite3_free(zCmd);
   }else
 
-  if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
+  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
     int i;
+    if( nArg!=1 ){
+      fprintf(stderr, "Usage: .show\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
     fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
+    fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
     fprintf(p->out,"%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","mode", modeDescr[p->mode]);
@@ -2664,11 +3032,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     fprintf(p->out,"\n");
   }else
 
-  if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){
-    p->statsOn = booleanValue(azArg[1]);
+  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
+    if( nArg==2 ){
+      p->statsOn = booleanValue(azArg[1]);
+    }else{
+      fprintf(stderr, "Usage: .stats on|off\n");
+      rc = 1;
+    }
   }else
 
-  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
+  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
     sqlite3_stmt *pStmt;
     char **azResult;
     int nRow, nAlloc;
@@ -2770,6 +3143,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
       { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
       { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
       { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
+      { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },
     };
     int testctrl = -1;
     int rc = 0;
@@ -2810,9 +3184,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
           break;
 
         /* sqlite3_test_control(int) */
-        case SQLITE_TESTCTRL_PRNG_SAVE:           
-        case SQLITE_TESTCTRL_PRNG_RESTORE:        
+        case SQLITE_TESTCTRL_PRNG_SAVE:
+        case SQLITE_TESTCTRL_PRNG_RESTORE:
         case SQLITE_TESTCTRL_PRNG_RESET:
+        case SQLITE_TESTCTRL_BYTEORDER:
           if( nArg==2 ){
             rc = sqlite3_test_control(testctrl);
             fprintf(p->out, "%d (0x%08x)\n", rc, rc);
@@ -2872,20 +3247,32 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }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 ){
     open_db(p, 0);
-    sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));
+    sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
   }else
     
-  if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
-   && nArg==2
-  ){
-    enableTimer = booleanValue(azArg[1]);
+  if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
+    if( nArg==2 ){
+      enableTimer = booleanValue(azArg[1]);
+      if( enableTimer && !HAS_TIMER ){
+        fprintf(stderr, "Error: timer not available on this system.\n");
+        enableTimer = 0;
+      }
+    }else{
+      fprintf(stderr, "Usage: .timer on|off\n");
+      rc = 1;
+    }
   }else
   
-  if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
+  if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
     open_db(p, 0);
     output_file_close(p->traceOut);
+    if( nArg!=2 ){
+      fprintf(stderr, "Usage: .trace FILE|off\n");
+      rc = 1;
+      goto meta_command_exit;
+    }
     p->traceOut = output_file_open(azArg[1]);
 #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
     if( p->traceOut==0 ){
@@ -2916,11 +3303,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){
 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
   if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
     extern int sqlite3WhereTrace;
-    sqlite3WhereTrace = booleanValue(azArg[1]);
+    sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
   }else
 #endif
 
-  if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
+  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
     int j;
     assert( nArg<=ArraySize(azArg) );
     for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
@@ -2934,6 +3321,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     rc = 1;
   }
 
+meta_command_exit:
+  if( p->outCount ){
+    p->outCount--;
+    if( p->outCount==0 ) output_reset(p);
+  }
   return rc;
 }
 
@@ -3037,7 +3429,10 @@ static int process_input(struct callback_data *p, FILE *in){
       seenInterrupt = 0;
     }
     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( p->echoOn ) printf("%s\n", zLine);
       rc = do_meta_command(zLine, p);
@@ -3098,7 +3493,12 @@ static int process_input(struct callback_data *p, FILE *in){
         errCnt++;
       }
       nSql = 0;
+      if( p->outCount ){
+        output_reset(p);
+        p->outCount = 0;
+      }
     }else if( nSql && _all_whitespace(zSql) ){
+      if( p->echoOn ) printf("%s\n", zSql);
       nSql = 0;
     }
   }
@@ -3276,6 +3676,26 @@ static void main_init(struct callback_data *data) {
   sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
 }
 
+/*
+** 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
 ** is available.
@@ -3296,12 +3716,15 @@ int main(int argc, char **argv){
   char *zFirstCmd = 0;
   int i;
   int rc = 0;
+  int warnInmemoryDb = 0;
 
+#if USE_SYSTEM_SQLITE+0!=1
   if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
     fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
             sqlite3_sourceid(), SQLITE_SOURCE_ID);
     exit(1);
   }
+#endif
   Argv0 = argv[0];
   main_init(&data);
   stdin_is_interactive = isatty(0);
@@ -3390,9 +3813,15 @@ int main(int argc, char **argv){
   if( data.zDbFilename==0 ){
 #ifndef SQLITE_OMIT_MEMORYDB
     data.zDbFilename = ":memory:";
+    warnInmemoryDb = argc==1;
 #else
     fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
     return 1;
+#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;
@@ -3449,6 +3878,8 @@ int main(int argc, char **argv){
       data.showHeader = 0;
     }else if( strcmp(z,"-echo")==0 ){
       data.echoOn = 1;
+    }else if( strcmp(z,"-eqp")==0 ){
+      data.autoEQP = 1;
     }else if( strcmp(z,"-stats")==0 ){
       data.statsOn = 1;
     }else if( strcmp(z,"-bail")==0 ){
@@ -3526,10 +3957,15 @@ int main(int argc, char **argv){
       int nHistory;
       printf(
         "SQLite version %s %.19s\n" /*extra-version-info*/
-        "Enter \".help\" for instructions\n"
-        "Enter SQL statements terminated with a \";\"\n",
+        "Enter \".help\" for usage hints.\n",
         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();
       if( zHome ){
         nHistory = strlen30(zHome) + 20;
@@ -3537,7 +3973,7 @@ int main(int argc, char **argv){
           sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
         }
       }
-#if defined(HAVE_READLINE) && HAVE_READLINE==1
+#if defined(HAVE_READLINE)
       if( zHistory ) read_history(zHistory);
 #endif
       rc = process_input(&data, 0);