Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -1043,16 +1043,19 @@ if( db->auth.authLevel==UAUTH_User ){ /* Do not allow non-admin users to modify the schema arbitrarily */ mask &= ~(SQLITE_WriteSchema); } #endif - - if( sqlite3GetBoolean(zRight, 0) ){ + if( sqlite3StrICmp(zRight, "toggle")==0 ){ + db->flags ^= mask; + }else if( sqlite3GetBoolean(zRight, 0) ){ db->flags |= mask; }else{ db->flags &= ~mask; - if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + } + if( mask==SQLITE_DeferFKs && (db->flags & mask)==0 ){ + db->nDeferredImmCons = 0; } /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -1408,10 +1408,11 @@ #define SHFLG_Lookaside 0x00000004 /* Lookaside memory is used */ #define SHFLG_Backslash 0x00000008 /* The --backslash option is used */ #define SHFLG_PreserveRowid 0x00000010 /* .dump preserves rowid values */ #define SHFLG_CountChanges 0x00000020 /* .changes setting */ #define SHFLG_Echo 0x00000040 /* .echo or --echo setting */ +#define SHFLG_RecoveryMode 0x00000080 /* The --recovery-mode flag for .dump */ /* ** Macros for testing and setting shellFlgs */ #define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0) @@ -2217,11 +2218,11 @@ iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); - if( pArg->shellFlgs & SHFLG_Pagecache ){ + if( ShellHasFlag(pArg, SHFLG_Pagecache) ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); @@ -2229,11 +2230,11 @@ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); - if( pArg->shellFlgs & SHFLG_Scratch ){ + if( ShellHasFlag(pArg, SHFLG_Scratch) ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); @@ -2262,11 +2263,11 @@ iCur, iHiwtr); #endif } if( pArg && pArg->out && db ){ - if( pArg->shellFlgs & SHFLG_Lookaside ){ + if( ShellHasFlag(pArg, SHFLG_Lookaside) ){ iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", @@ -2944,10 +2945,18 @@ savedDestTable = p->zDestTable; savedMode = p->mode; p->zDestTable = sTable.z; p->mode = p->cMode = MODE_Insert; rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0); + if( (rc&0xff)==SQLITE_CORRUPT ){ + raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); + if( ShellHasFlag(p, SHFLG_RecoveryMode) ){ + sqlite3_exec(p->db, "PRAGMA reverse_unordered_selects=TOGGLE",0,0,0); + shell_exec(p->db, sSelect.z, shell_callback, p, 0); + sqlite3_exec(p->db, "PRAGMA reverse_unordered_selects=TOGGLE",0,0,0); + } + } p->zDestTable = savedDestTable; p->mode = savedMode; freeText(&sTable); freeText(&sSelect); if( rc ) p->nErr++; @@ -2957,21 +2966,22 @@ /* ** Run zQuery. Use dump_callback() as the callback routine so that ** the contents of the query are output as SQL statements. ** -** If we get a SQLITE_CORRUPT error, rerun the query after appending -** "ORDER BY rowid DESC" to the end. +** If we get a SQLITE_CORRUPT error and the --recovery-mode flag is +** set, then rerun the query in reverse order to try to get more +** data. */ static int run_schema_dump_query( ShellState *p, const char *zQuery ){ int rc; char *zErr = 0; rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); - if( rc==SQLITE_CORRUPT ){ + if( rc==SQLITE_CORRUPT && ShellHasFlag(p, SHFLG_RecoveryMode) ){ char *zQ2; int len = strlen30(zQuery); raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); if( zErr ){ utf8_printf(p->out, "/****** %s ******/\n", zErr); @@ -4568,20 +4578,25 @@ }else if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ const char *zLike = 0; int i; - ShellClearFlag(p, SHFLG_PreserveRowid); + ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_RecoveryMode); for(i=1; iout, "PRAGMA foreign_keys=OFF;\n"); raw_printf(p->out, "BEGIN TRANSACTION;\n"); p->writableSchema = 0; - /* Set writable_schema=ON since doing so forces SQLite to initialize - ** as much of the schema as it can even if the sqlite_master table is - ** corrupt. */ - sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); + if( ShellHasFlag(p, SHFLG_RecoveryMode) ){ + /* Set writable_schema=ON since doing so forces SQLite to initialize + ** as much of the schema as it can even if the sqlite_master table is + ** corrupt. */ + sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); + } p->nErr = 0; if( zLike==0 ){ run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" @@ -4634,12 +4651,14 @@ } if( p->writableSchema ){ raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); p->writableSchema = 0; } - sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); - sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); + if( ShellHasFlag(p, SHFLG_RecoveryMode) ){ + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); + sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); + } raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ if( nArg==2 ){