Add the ".repair" command to the command-line shell.
FossilOrigin-Name: d1dfadea87ecf18eeb6d2f21769deaa97473ca0e
This commit is contained in:
parent
5dfd3d9080
commit
3350ce95f7
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C In\sthe\sWin32\sVFS,\sthe\swinSysInfo\svariable\sshould\sbe\sstatic.
|
||||
D 2014-02-05T11:05:47.687
|
||||
C Add\sthe\s".repair"\scommand\sto\sthe\scommand-line\sshell.
|
||||
D 2014-02-06T00:49:12.328
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -220,7 +220,7 @@ F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c b78f5e62c283aca2e38657938bc1fec1051df728
|
||||
F src/shell.c 24722d24d4ea8ca93db35e44db7308de786767ca
|
||||
F src/shell.c c128bf92b3ed268d8ec6f0df275a5d737edf2968
|
||||
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
@ -1152,7 +1152,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P f2504089df0bf4011864e67825b37f6aa3d03458
|
||||
R f919fd88b0fe2a17b41d9c03ff44720f
|
||||
U mistachkin
|
||||
Z fecb65c3944a970d4d7662e030506246
|
||||
P 4a4dd371a72b7d475185923bebb4cd9bd83e1bd9
|
||||
R 235c07c6649435d22d14c7aa202be2ed
|
||||
U drh
|
||||
Z b9d162ba79528a4d7df551b82e7b6e75
|
||||
|
@ -1 +1 @@
|
||||
4a4dd371a72b7d475185923bebb4cd9bd83e1bd9
|
||||
d1dfadea87ecf18eeb6d2f21769deaa97473ca0e
|
194
src/shell.c
194
src/shell.c
@ -1581,6 +1581,7 @@ static char zHelp[] =
|
||||
".prompt MAIN CONTINUE Replace the standard prompts\n"
|
||||
".quit Exit this program\n"
|
||||
".read FILENAME Execute SQL in FILENAME\n"
|
||||
".repair NEWDB Recover data into NEWDB from a corrupt database\n"
|
||||
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
|
||||
".schema ?TABLE? Show the CREATE statements\n"
|
||||
" If TABLE specified, only show tables matching\n"
|
||||
@ -1896,6 +1897,195 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
return p->z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to transfer data for table zTable
|
||||
*/
|
||||
static void tryToRepairData(
|
||||
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;
|
||||
|
||||
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 */
|
||||
sqlite3_step(pInsert);
|
||||
sqlite3_reset(pInsert);
|
||||
} /* 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, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
} /* 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.
|
||||
*/
|
||||
static void tryToRepairSchema(
|
||||
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;
|
||||
|
||||
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, 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, 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 tryToRepair(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);
|
||||
tryToRepairSchema(p, newDb, "type='table'", tryToRepairData);
|
||||
tryToRepairSchema(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.
|
||||
@ -2495,6 +2685,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='r' && strncmp(azArg[0], "repair", n)==0 && nArg>1 && nArg<3 ){
|
||||
tryToRepair(p, azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
|
||||
const char *zSrcFile;
|
||||
const char *zDb;
|
||||
|
Loading…
Reference in New Issue
Block a user