From: dan Date: Fri, 26 Apr 2019 15:14:53 +0000 (+0000) Subject: Fix a locking-page related problem with the ".recover" command. X-Git-Tag: version-3.29.0~176^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c0b42437ab69d01daa61bd77f74badb95c82bd40;p=thirdparty%2Fsqlite.git Fix a locking-page related problem with the ".recover" command. FossilOrigin-Name: afdae10424f0f3d0f10a4b73e9732aa55c5ee664814d8ca0edd372cfb17c2445 --- diff --git a/ext/misc/dbdata.c b/ext/misc/dbdata.c index 13bb51f08b..a27f19dc7a 100644 --- a/ext/misc/dbdata.c +++ b/ext/misc/dbdata.c @@ -89,6 +89,7 @@ struct DbdataCursor { int nCell; /* Number of cells on aPage[] */ int iCell; /* Current cell number */ int bOnePage; /* True to stop after one page */ + int szDb; sqlite3_int64 iRowid; /* Only for the sqlite_dbdata table */ @@ -303,18 +304,21 @@ static int dbdataLoadPage( sqlite3_bind_int64(pStmt, 2, pgno); if( SQLITE_ROW==sqlite3_step(pStmt) ){ int nCopy = sqlite3_column_bytes(pStmt, 0); - u8 *pPage = (u8*)sqlite3_malloc64(nCopy); - if( pPage==0 ){ - rc = SQLITE_NOMEM; - }else{ - const u8 *pCopy = sqlite3_column_blob(pStmt, 0); - memcpy(pPage, pCopy, nCopy); + if( nCopy>0 ){ + u8 *pPage; + pPage = (u8*)sqlite3_malloc64(nCopy); + if( pPage==0 ){ + rc = SQLITE_NOMEM; + }else{ + const u8 *pCopy = sqlite3_column_blob(pStmt, 0); + memcpy(pPage, pCopy, nCopy); + } *ppPage = pPage; *pnPage = nCopy; } } rc2 = sqlite3_reset(pStmt); - if( *ppPage==0 ) rc = rc2; + if( rc==SQLITE_OK ) rc = rc2; return rc; } @@ -419,8 +423,13 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){ int iOff = (pCsr->iPgno==1 ? 100 : 0); if( pCsr->aPage==0 ){ - rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); - if( rc!=SQLITE_OK || pCsr->aPage==0 ) return rc; + while( 1 ){ + if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; + rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); + if( rc!=SQLITE_OK ) return rc; + if( pCsr->aPage ) break; + pCsr->iPgno++; + } pCsr->iCell = pTab->bPtr ? -2 : 0; pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); } @@ -574,6 +583,24 @@ static int dbdataEof(sqlite3_vtab_cursor *pCursor){ return pCsr->aPage==0; } +static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){ + DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab; + char *zSql = 0; + int rc, rc2; + sqlite3_stmt *pStmt = 0; + + zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + pCsr->szDb = sqlite3_column_int(pStmt, 0); + } + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + return rc; +} + /* Position a cursor back to the beginning. */ static int dbdataFilter( @@ -594,16 +621,21 @@ static int dbdataFilter( if( idxNum & 0x02 ){ pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); pCsr->bOnePage = 1; + }else{ + pCsr->nPage = dbdataDbsize(pCsr, zSchema); + rc = dbdataDbsize(pCsr, zSchema); } - if( pTab->pStmt ){ - pCsr->pStmt = pTab->pStmt; - pTab->pStmt = 0; - }else{ - rc = sqlite3_prepare_v2(pTab->db, - "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, - &pCsr->pStmt, 0 - ); + if( rc==SQLITE_OK ){ + if( pTab->pStmt ){ + pCsr->pStmt = pTab->pStmt; + pTab->pStmt = 0; + }else{ + rc = sqlite3_prepare_v2(pTab->db, + "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, + &pCsr->pStmt, 0 + ); + } } if( rc==SQLITE_OK ){ rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); diff --git a/manifest b/manifest index c6b5a05076..d361dc7ebc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\strunk\schanges\sinto\sthis\sbranch. -D 2019-04-25T20:06:34.069 +C Fix\sa\slocking-page\srelated\sproblem\swith\sthe\s".recover"\scommand. +D 2019-04-26T15:14:53.514 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -284,7 +284,7 @@ F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c8 F ext/misc/completion.c cec672d40604075bb341a7f11ac48393efdcd90a979269b8fe7977ea62d0547f F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189 F ext/misc/csv.c 7f047aeb68f5802e7ce6639292095d622a488bb43526ed04810e0649faa71ceb -F ext/misc/dbdata.c 0c80f0757c3a1b5c57027328ab0ccfe30fcef1a4875b41dd9ddc0f53c7087e97 +F ext/misc/dbdata.c b7547f43906f9296e43be807ca78e2ef3f335ca26d6e91d178df30cd2fd46572 F ext/misc/dbdump.c baf6e37447c9d6968417b1cd34cbedb0b0ab3f91b5329501d8a8d5be3287c336 F ext/misc/eval.c 4b4757592d00fd32e44c7a067e6a0e4839c81a4d57abc4131ee7806d1be3104e F ext/misc/explain.c d5c12962d79913ef774b297006872af1fccda388f61a11d37758f9179a09551f @@ -520,7 +520,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 567888ee3faec14dae06519b4306201771058364a37560186a3e0e755ebc4cb8 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c b7304d2f491c11a03a7fbdf34bc218282ac54052377809d4dc3b4b1e7f4bfc93 -F src/shell.c.in 78004b100ed486695f4ff8bbc40b99c2e4d7b6d06278ce64b80ac1900bf356a3 +F src/shell.c.in 63b1075817997806d7f09c2a0433ffac854b6dee47836ef938d51531cdb8042f F src/sqlite.h.in 38390767acc1914d58930e03149595ee4710afa4e3c43ab6c3a8aea3f1a6b8cd F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5 @@ -1821,7 +1821,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8d2f52bb640d6d0f84b18d746043e56f45a73ace93239be1d036701f7f4018fd 7be6222c9ec44596e4eddd906c831eb1272b90fbdf68641d791f216264feb7cf -R af342ccd780cc18bf46aaaf7890063fa +P 1da302d85d7ad4ba54f877117a45d667439fd2ef31dc70ea1d54dc1fba196e68 +R 981714fd52a70e51cf4586f924a49fdc U dan -Z 147b326af09d7b23ccf3f83204577057 +Z 303a0ea3c8fcc86a61370f3e12d83ec5 diff --git a/manifest.uuid b/manifest.uuid index 0d49487589..b5f67ee780 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1da302d85d7ad4ba54f877117a45d667439fd2ef31dc70ea1d54dc1fba196e68 \ No newline at end of file +afdae10424f0f3d0f10a4b73e9732aa55c5ee664814d8ca0edd372cfb17c2445 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 55f7964319..1884e7bfe2 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -6165,6 +6165,22 @@ static void shellExec(sqlite3 *db, int *pRc, const char *zSql){ } } +static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ + char *z = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + va_start(ap, zFmt); + z = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( z==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + shellExec(db, pRc, z); + } + sqlite3_free(z); + } +} + static void *shellMalloc(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ @@ -6405,6 +6421,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ + const char *zRecoveryDb = ""; /* Name of "recovery" database */ int i; int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ @@ -6416,23 +6433,32 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){ bFreelist = 0; } + if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){ + i++; + zRecoveryDb = azArg[i]; + } else{ - raw_printf(stderr, - "unexpected option: %s - expected \"--freelist-corrupt\"\n", - azArg[i] - ); + raw_printf(stderr, "unexpected option: %s\n", azArg[i]); + raw_printf(stderr, "options are:\n"); + raw_printf(stderr, " --freelist-corrupt\n"); + raw_printf(stderr, " --recovery-db DATABASE\n"); return 1; } } - shellExec(pState->db, &rc, + shellExecPrintf(pState->db, &rc, /* Attach an in-memory database named 'recovery'. Create an indexed ** cache of the sqlite_dbptr virtual table. */ - "ATTACH '' AS recovery;" + "ATTACH %Q AS recovery;" + "DROP TABLE IF EXISTS recovery.dbptr;" + "DROP TABLE IF EXISTS recovery.freelist;" + "DROP TABLE IF EXISTS recovery.map;" + "DROP TABLE IF EXISTS recovery.schema;" "CREATE TABLE recovery.dbptr(" " pgno, child, PRIMARY KEY(child, pgno)" ") WITHOUT ROWID;" - "INSERT OR IGNORE INTO dbptr(pgno, child) SELECT * FROM sqlite_dbptr;" + "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) " + " SELECT * FROM sqlite_dbptr;" /* Delete any pointer to page 1. This ensures that page 1 is considered ** a root page, regardless of how corrupt the db is. */ @@ -6445,7 +6471,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1" ");" - "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);" + "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb ); if( bFreelist ){