=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/sqlite3/Attic/shell.c,v retrieving revision 1.7 retrieving revision 1.8 diff -c -r1.7 -r1.8 *** src/usr.bin/sqlite3/Attic/shell.c 2013/09/21 17:43:28 1.7 --- src/usr.bin/sqlite3/Attic/shell.c 2014/03/24 01:45:35 1.8 *************** *** 45,58 **** # include #endif ! #ifdef HAVE_EDITLINE ! # include ! #endif ! #if defined(HAVE_READLINE) && HAVE_READLINE==1 # include # include #endif ! #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1) # define add_history(X) # define read_history(X) # define write_history(X) --- 45,61 ---- # include #endif ! #if defined(HAVE_READLINE) && HAVE_READLINE!=0 # include # include + #else + # undef HAVE_READLINE #endif ! #if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE) ! # define HAVE_READLINE 1 ! # include ! #endif ! #if !defined(HAVE_READLINE) # define add_history(X) # define read_history(X) # define write_history(X) *************** *** 62,68 **** #if defined(_WIN32) || defined(WIN32) # include #define isatty(h) _isatty(h) ! #define access(f,m) _access((f),(m)) #undef popen #define popen _popen #undef pclose --- 65,73 ---- #if defined(_WIN32) || defined(WIN32) # include #define isatty(h) _isatty(h) ! #ifndef access ! # define access(f,m) _access((f),(m)) ! #endif #undef popen #define popen _popen #undef pclose *************** *** 71,82 **** /* Make sure isatty() has a prototype. */ extern int isatty(int); - #endif /* popen and pclose are not C89 functions and so are sometimes omitted from ** the header */ ! FILE *popen(const char*,const char*); ! int pclose(FILE*); #if defined(_WIN32_WCE) /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() --- 76,87 ---- /* Make sure isatty() has a prototype. */ extern int isatty(int); /* popen and pclose are not C89 functions and so are sometimes omitted from ** the header */ ! extern FILE *popen(const char*,const char*); ! extern int pclose(FILE*); ! #endif #if defined(_WIN32_WCE) /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() *************** *** 86,106 **** #define isatty(x) 1 #endif - /* True if the timer is enabled */ - static int enableTimer = 0; - /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ && !defined(__minux) #include #include /* Saved resource information for the beginning of an operation */ ! static struct rusage sBegin; /* ** Begin timing an operation --- 91,128 ---- #define isatty(x) 1 #endif /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((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) \ && !defined(__minux) #include #include /* Saved resource information for the beginning of an operation */ ! static struct rusage sBegin; /* CPU time at start */ ! static sqlite3_int64 iBegin; /* Wall-clock time at start */ /* ** Begin timing an operation *************** *** 108,113 **** --- 130,136 ---- static void beginTimer(void){ if( enableTimer ){ getrusage(RUSAGE_SELF, &sBegin); + iBegin = timeOfDay(); } } *************** *** 123,130 **** static void endTimer(void){ if( enableTimer ){ struct rusage sEnd; getrusage(RUSAGE_SELF, &sEnd); ! printf("CPU Time: user %f sys %f\n", timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); } --- 146,155 ---- static void endTimer(void){ if( enableTimer ){ struct rusage sEnd; + sqlite3_int64 iEnd = timeOfDay(); getrusage(RUSAGE_SELF, &sEnd); ! printf("Run Time: real %.3f user %f sys %f\n", ! (iEnd - iBegin)*0.001, timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); } *************** *** 142,147 **** --- 167,173 ---- static HANDLE hProcess; static FILETIME ftKernelBegin; static FILETIME ftUserBegin; + static sqlite3_int64 ftWallBegin; typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); static GETPROCTIMES getProcessTimesAddr = NULL; *************** *** 179,184 **** --- 205,211 ---- if( enableTimer && getProcessTimesAddr ){ FILETIME ftCreation, ftExit; getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); + ftWallBegin = timeOfDay(); } } *************** *** 195,202 **** static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); ! printf("CPU Time: user %f sys %f\n", timeDiff(&ftUserBegin, &ftUserEnd), timeDiff(&ftKernelBegin, &ftKernelEnd)); } --- 222,231 ---- static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; + sqlite3_int64 ftWallEnd = timeOfDay(); getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); ! printf("Run Time: real %.3f user %f sys %f\n", ! (ftWallEnd - ftWallBegin)*0.001, timeDiff(&ftUserBegin, &ftUserEnd), timeDiff(&ftKernelBegin, &ftKernelEnd)); } *************** *** 389,395 **** zResult = local_getline(zPrior, in); }else{ zPrompt = isContinuation ? continuePrompt : mainPrompt; ! #if defined(HAVE_READLINE) && HAVE_READLINE==1 free(zPrior); zResult = readline(zPrompt); if( zResult && *zResult ) add_history(zResult); --- 418,424 ---- zResult = local_getline(zPrior, in); }else{ zPrompt = isContinuation ? continuePrompt : mainPrompt; ! #if defined(HAVE_READLINE) free(zPrior); zResult = readline(zPrompt); if( zResult && *zResult ) add_history(zResult); *************** *** 417,422 **** --- 446,452 ---- struct callback_data { sqlite3 *db; /* The database */ 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 cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ *************** *** 436,444 **** --- 466,478 ---- ** .explain ON */ char outfile[FILENAME_MAX]; /* Filename for *out */ const char *zDbFilename; /* name of the database file */ + char *zFreeOnClose; /* Filename to free when closing */ const char *zVfs; /* Name of VFS to use */ sqlite3_stmt *pStmt; /* Current statement if any. */ 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[] */ }; /* *************** *** 554,560 **** }else if( c=='\r' ){ fputc('\\', out); fputc('r', out); ! }else if( !isprint(c) ){ fprintf(out, "\\%03o", c&0xff); }else{ fputc(c, out); --- 588,594 ---- }else if( c=='\r' ){ fputc('\\', out); fputc('r', out); ! }else if( !isprint(c&0xff) ){ fprintf(out, "\\%03o", c&0xff); }else{ fputc(c, out); *************** *** 569,574 **** --- 603,609 ---- */ 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]!='<' *************** *** 740,749 **** }else{ w = 10; } ! if( p->mode==MODE_Explain && azArg[i] && ! strlen30(azArg[i])>w ){ w = strlen30(azArg[i]); } if( w<0 ){ fprintf(p->out,"%*.*s%s",-w,-w, azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); --- 775,789 ---- }else{ w = 10; } ! if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){ w = strlen30(azArg[i]); } + if( i==1 && p->aiIndent && p->pStmt ){ + if( p->iIndentnIndent ){ + fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); + } + p->iIndent++; + } if( w<0 ){ fprintf(p->out,"%*.*s%s",-w,-w, azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); *************** *** 971,980 **** int nResult; int i; const char *z; ! rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0); if( rc!=SQLITE_OK || !pSelect ){ fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); ! p->nErr++; return rc; } rc = sqlite3_step(pSelect); --- 1011,1020 ---- int nResult; int i; const char *z; ! 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++; return rc; } rc = sqlite3_step(pSelect); *************** *** 1001,1007 **** rc = sqlite3_finalize(pSelect); if( rc!=SQLITE_OK ){ fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); ! p->nErr++; } return rc; } --- 1041,1047 ---- rc = sqlite3_finalize(pSelect); if( rc!=SQLITE_OK ){ fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); ! if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } *************** *** 1117,1122 **** --- 1157,1260 ---- } /* + ** 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; iaiIndent[i] += 2; + } + if( str_in_array(zOp, azGoto) && p2opnIndent + && (abYield[p2op] || sqlite3_column_int(pSql, 2)) + ){ + for(i=p2op+1; iaiIndent[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 ** any result rows/columns depending on the current mode ** set via the supplied callback. *************** *** 1168,1173 **** --- 1306,1328 ---- 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; *************** *** 1177,1182 **** --- 1332,1343 ---- } } + /* 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 ** have a result set or not and how wide it is. */ *************** *** 1194,1200 **** char **azCols = (char **)pData; /* Names of result columns */ char **azVals = &azCols[nCol]; /* Results */ int *aiTypes = (int *)&azVals[nCol]; /* Result types */ ! int i; assert(sizeof(int) <= sizeof(char *)); /* save off ptrs to column names */ for(i=0; imode==MODE_Insert ){ ! azVals[i] = ""; ! }else{ ! azVals[i] = (char*)sqlite3_column_text(pStmt, i); ! } if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ rc = SQLITE_NOMEM; break; /* from for */ *************** *** 1230,1235 **** --- 1395,1402 ---- } } + explain_data_delete(pArg); + /* print usage stats if stats on */ if( pArg && pArg->statsOn ){ display_stats(db, pArg, 0); *************** *** 1280,1286 **** if( strcmp(zTable, "sqlite_sequence")==0 ){ zPrepStmt = "DELETE FROM sqlite_sequence;\n"; ! }else if( strcmp(zTable, "sqlite_stat1")==0 ){ fprintf(p->out, "ANALYZE sqlite_master;\n"); }else if( strncmp(zTable, "sqlite_", 7)==0 ){ return 0; --- 1447,1453 ---- if( strcmp(zTable, "sqlite_sequence")==0 ){ zPrepStmt = "DELETE FROM sqlite_sequence;\n"; ! }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ fprintf(p->out, "ANALYZE sqlite_master;\n"); }else if( strncmp(zTable, "sqlite_", 7)==0 ){ return 0; *************** *** 1312,1318 **** zTableInfo = appendText(zTableInfo, zTable, '"'); zTableInfo = appendText(zTableInfo, ");", 0); ! rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0); free(zTableInfo); if( rc!=SQLITE_OK || !pTableInfo ){ return 1; --- 1479,1485 ---- zTableInfo = appendText(zTableInfo, zTable, '"'); zTableInfo = appendText(zTableInfo, ");", 0); ! rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0); free(zTableInfo); if( rc!=SQLITE_OK || !pTableInfo ){ return 1; *************** *** 1402,1407 **** --- 1569,1575 ---- static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\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" *************** *** 1433,1438 **** --- 1601,1607 ---- " tabs Tab-separated values\n" " tcl TCL list elements\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 stdout Send output to the screen\n" ".print STRING... Print literal STRING\n" *************** *** 1440,1445 **** --- 1609,1615 ---- ".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" *************** *** 1466,1472 **** ** 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. */ ! static void open_db(struct callback_data *p){ if( p->db==0 ){ sqlite3_initialize(); sqlite3_open(p->zDbFilename, &p->db); --- 1636,1642 ---- ** 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. */ ! static void open_db(struct callback_data *p, int keepAlive){ if( p->db==0 ){ sqlite3_initialize(); sqlite3_open(p->zDbFilename, &p->db); *************** *** 1478,1483 **** --- 1648,1654 ---- if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ fprintf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(db)); + if( keepAlive ) return; exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION *************** *** 1694,1700 **** ** + Report syntax errors on stderr */ static char *csv_read_one_field(CSVReader *p){ ! int c, pc; int cSep = p->cSeparator; p->n = 0; c = fgetc(p->in); --- 1865,1871 ---- ** + Report syntax errors on stderr */ static char *csv_read_one_field(CSVReader *p){ ! int c, pc, ppc; int cSep = p->cSeparator; p->n = 0; c = fgetc(p->in); *************** *** 1705,1711 **** if( c=='"' ){ int startLine = p->nLine; int cQuote = c; ! pc = 0; while( 1 ){ c = fgetc(p->in); if( c=='\n' ) p->nLine++; --- 1876,1882 ---- if( c=='"' ){ int startLine = p->nLine; int cQuote = c; ! pc = ppc = 0; while( 1 ){ c = fgetc(p->in); if( c=='\n' ) p->nLine++; *************** *** 1717,1723 **** } if( (c==cSep && pc==cQuote) || (c=='\n' && pc==cQuote) ! || (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote) || (c==EOF && pc==cQuote) ){ do{ p->n--; }while( p->z[p->n]!=cQuote ); --- 1888,1894 ---- } if( (c==cSep && pc==cQuote) || (c=='\n' && pc==cQuote) ! || (c=='\n' && pc=='\r' && ppc==cQuote) || (c==EOF && pc==cQuote) ){ do{ p->n--; }while( p->z[p->n]!=cQuote ); *************** *** 1735,1740 **** --- 1906,1912 ---- break; } csv_append_char(p, c); + ppc = pc; pc = c; } }else{ *************** *** 1744,1750 **** } if( c=='\n' ){ p->nLine++; ! if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--; } p->cTerm = c; } --- 1916,1922 ---- } if( c=='\n' ){ p->nLine++; ! if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } p->cTerm = c; } *************** *** 1753,1758 **** --- 1925,2143 ---- } /* + ** 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; jdb, 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 ** process that line. ** *************** *** 1794,1800 **** 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 ){ const char *zDestFile = 0; const char *zDb = 0; sqlite3 *pDest; --- 2179,2187 ---- 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) ! || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) ! ){ const char *zDestFile = 0; const char *zDb = 0; sqlite3 *pDest; *************** *** 1830,1836 **** sqlite3_close(pDest); return 1; } ! open_db(p); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); --- 2217,2223 ---- sqlite3_close(pDest); return 1; } ! open_db(p, 0); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); *************** *** 1859,1868 **** test_breakpoint(); }else if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ struct callback_data data; char *zErrMsg = 0; ! open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 1; data.mode = MODE_Column; --- 2246,2259 ---- test_breakpoint(); }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 ){ struct callback_data data; char *zErrMsg = 0; ! open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 1; data.mode = MODE_Column; *************** *** 1879,1885 **** }else if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ ! open_db(p); /* 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. */ --- 2270,2276 ---- }else if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ ! 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. */ *************** *** 1931,1936 **** --- 2322,2331 ---- p->echoOn = booleanValue(azArg[1]); }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( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); rc = 2; *************** *** 1954,1960 **** */ p->mode = MODE_Explain; p->showHeader = 1; ! memset(p->colWidth,0,ArraySize(p->colWidth)); p->colWidth[0] = 4; /* addr */ p->colWidth[1] = 13; /* opcode */ p->colWidth[2] = 4; /* P1 */ --- 2349,2355 ---- */ p->mode = MODE_Explain; p->showHeader = 1; ! memset(p->colWidth,0,sizeof(p->colWidth)); p->colWidth[0] = 4; /* addr */ p->colWidth[1] = 13; /* opcode */ p->colWidth[2] = 4; /* P1 */ *************** *** 1998,2004 **** seenInterrupt = 0; memset(&sCsv, 0, sizeof(sCsv)); ! open_db(p); nSep = strlen30(p->separator); if( nSep==0 ){ fprintf(stderr, "Error: non-null separator required for import\n"); --- 2393,2399 ---- seenInterrupt = 0; memset(&sCsv, 0, sizeof(sCsv)); ! open_db(p, 0); nSep = strlen30(p->separator); if( nSep==0 ){ fprintf(stderr, "Error: non-null separator required for import\n"); *************** *** 2031,2037 **** return 1; } nByte = strlen30(zSql); ! rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); char cSep = '('; --- 2426,2432 ---- return 1; } nByte = strlen30(zSql); ! rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); char cSep = '('; *************** *** 2057,2063 **** xCloser(sCsv.in); return 1; } ! rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); if( rc ){ --- 2452,2458 ---- xCloser(sCsv.in); return 1; } ! rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); if( rc ){ *************** *** 2084,2090 **** } zSql[j++] = ')'; zSql[j] = 0; ! rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); --- 2479,2485 ---- } zSql[j++] = ')'; zSql[j] = 0; ! rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); *************** *** 2136,2142 **** if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ struct callback_data data; char *zErrMsg = 0; ! open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_List; --- 2531,2537 ---- if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ struct callback_data data; char *zErrMsg = 0; ! open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_List; *************** *** 2202,2208 **** char *zErrMsg = 0; zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; ! open_db(p); rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); if( rc!=SQLITE_OK ){ fprintf(stderr, "Error: %s\n", zErrMsg); --- 2597,2603 ---- char *zErrMsg = 0; zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; ! open_db(p, 0); rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); if( rc!=SQLITE_OK ){ fprintf(stderr, "Error: %s\n", zErrMsg); *************** *** 2268,2273 **** --- 2663,2688 ---- "%.*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; + 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( p->outfile[0]=='|' ){ pclose(p->out); *************** *** 2351,2357 **** sqlite3_close(pSrc); return 1; } ! open_db(p); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); --- 2766,2772 ---- sqlite3_close(pSrc); return 1; } ! open_db(p, 0); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); *************** *** 2381,2387 **** if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){ struct callback_data data; char *zErrMsg = 0; ! open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_Semi; --- 2796,2802 ---- if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){ struct callback_data data; char *zErrMsg = 0; ! open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_Semi; *************** *** 2483,2488 **** --- 2898,2904 ---- if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){ int i; 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]); *************** *** 2512,2518 **** int nRow, nAlloc; char *zSql = 0; int ii; ! open_db(p); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ) return rc; zSql = sqlite3_mprintf( --- 2928,2934 ---- int nRow, nAlloc; char *zSql = 0; int ii; ! open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ) return rc; zSql = sqlite3_mprintf( *************** *** 2612,2618 **** int testctrl = -1; int rc = 0; int i, n; ! open_db(p); /* convert testctrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ --- 3028,3034 ---- int testctrl = -1; int rc = 0; int i, n; ! open_db(p, 0); /* convert testctrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ *************** *** 2711,2717 **** }else if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ ! open_db(p); sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1])); }else --- 3127,3133 ---- }else if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ ! open_db(p, 0); sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1])); }else *************** *** 2722,2728 **** }else if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ ! open_db(p); output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) --- 3138,3144 ---- }else if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ ! open_db(p, 0); output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) *************** *** 2875,2881 **** seenInterrupt = 0; } lineno++; ! if( nSql==0 && _all_whitespace(zLine) ) continue; if( zLine && zLine[0]=='.' && nSql==0 ){ if( p->echoOn ) printf("%s\n", zLine); rc = do_meta_command(zLine, p); --- 3291,3300 ---- seenInterrupt = 0; } lineno++; ! 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); *************** *** 2914,2920 **** if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) && sqlite3_complete(zSql) ){ p->cnt = 0; ! open_db(p); BEGIN_TIMER; rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); END_TIMER; --- 3333,3339 ---- if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) && sqlite3_complete(zSql) ){ p->cnt = 0; ! open_db(p, 0); BEGIN_TIMER; rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); END_TIMER; *************** *** 2937,2942 **** --- 3356,3362 ---- } nSql = 0; }else if( nSql && _all_whitespace(zSql) ){ + if( p->echoOn ) printf("%s\n", zSql); nSql = 0; } } *************** *** 3115,3120 **** --- 3535,3560 ---- } /* + ** 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. */ *************** *** 3134,3145 **** --- 3574,3588 ---- 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); *************** *** 3228,3237 **** --- 3671,3686 ---- 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; *************** *** 3241,3247 **** ** to the sqlite command-line tool. */ if( access(data.zDbFilename, 0)==0 ){ ! open_db(&data); } /* Process the initialization file if there is one. If no -init option --- 3690,3696 ---- ** to the sqlite command-line tool. */ if( access(data.zDbFilename, 0)==0 ){ ! open_db(&data, 0); } /* Process the initialization file if there is one. If no -init option *************** *** 3287,3292 **** --- 3736,3743 ---- 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 ){ *************** *** 3321,3327 **** rc = do_meta_command(z, &data); if( rc && bail_on_error ) return rc==2 ? 0 : rc; }else{ ! open_db(&data); rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); --- 3772,3778 ---- rc = do_meta_command(z, &data); if( rc && bail_on_error ) return rc==2 ? 0 : rc; }else{ ! open_db(&data, 0); rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); *************** *** 3345,3351 **** rc = do_meta_command(zFirstCmd, &data); if( rc==2 ) rc = 0; }else{ ! open_db(&data); rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); --- 3796,3802 ---- rc = do_meta_command(zFirstCmd, &data); if( rc==2 ) rc = 0; }else{ ! open_db(&data, 0); rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); *************** *** 3364,3373 **** int nHistory; printf( "SQLite version %s %.19s\n" /*extra-version-info*/ ! "Enter \".help\" for instructions\n" ! "Enter SQL statements terminated with a \";\"\n", sqlite3_libversion(), sqlite3_sourceid() ); zHome = find_home_dir(); if( zHome ){ nHistory = strlen30(zHome) + 20; --- 3815,3829 ---- int nHistory; printf( "SQLite version %s %.19s\n" /*extra-version-info*/ ! "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; *************** *** 3375,3381 **** sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); } } ! #if defined(HAVE_READLINE) && HAVE_READLINE==1 if( zHistory ) read_history(zHistory); #endif rc = process_input(&data, 0); --- 3831,3837 ---- sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); } } ! #if defined(HAVE_READLINE) if( zHistory ) read_history(zHistory); #endif rc = process_input(&data, 0); *************** *** 3392,3396 **** --- 3848,3853 ---- if( data.db ){ sqlite3_close(data.db); } + sqlite3_free(data.zFreeOnClose); return rc; }