From 3887ffe82a146aaee393d1d5560b9bce8058a75a Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 8 Sep 2022 17:42:33 +0000 Subject: [PATCH] Fix problems with recovering the sqlite_sequence table. FossilOrigin-Name: 356d2209ea5f6b69ce15b62027c63419c2d039e52f01c74a3810a6317abf4fb0 --- ext/recover/recover1.test | 26 ++++- ext/recover/sqlite3recover.c | 183 ++++++++++++++++++----------------- manifest | 14 +-- manifest.uuid | 2 +- 4 files changed, 128 insertions(+), 97 deletions(-) diff --git a/ext/recover/recover1.test b/ext/recover/recover1.test index 167b2796bd..26e7c60d26 100644 --- a/ext/recover/recover1.test +++ b/ext/recover/recover1.test @@ -45,6 +45,7 @@ proc do_recover_test {tn} { uplevel [list do_test $tn.1 { set R [sqlite3_recover_init db main test.db2] $R config testdb rstate.db + $R config rowids 1 $R step $R finish } {}] @@ -60,12 +61,14 @@ proc do_recover_test {tn} { set ::sqlhook [list] set R [sqlite3_recover_init_sql db main my_sql_hook] $R config testdb rstate.db + $R config rowids 1 $R step $R finish } {}] sqlite3 db2 test.db2 execsql [join $::sqlhook ";"] db2 + # puts [join $::sqlhook ";\n"] uplevel [list do_test $tn.4 [list compare_dbs db db2] {}] db2 close } @@ -82,6 +85,7 @@ do_execsql_test 1.0 { ) INSERT INTO t1 SELECT i*2, hex(randomblob(250)) FROM s; INSERT INTO t2 SELECT * FROM t1; + } do_recover_test 1 @@ -131,8 +135,28 @@ do_execsql_test 7.1 { SELECT * FROM t2 } {10 11 ten} -breakpoint do_recover_test 7.2 +#-------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.0 { + CREATE TABLE x1(a INTEGER PRIMARY KEY AUTOINCREMENT, b, c); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<2 + ) + INSERT INTO x1(b, c) SELECT hex(randomblob(100)), hex(randomblob(100)) FROM s; + + CREATE INDEX x1b ON x1(b); + CREATE INDEX x1cb ON x1(c, b); + DELETE FROM x1 WHERE a>50; + + ANALYZE; +} + +do_recover_test 8 + + + finish_test diff --git a/ext/recover/sqlite3recover.c b/ext/recover/sqlite3recover.c index de3dc6ea1a..1ab4f5d6d5 100644 --- a/ext/recover/sqlite3recover.c +++ b/ext/recover/sqlite3recover.c @@ -60,17 +60,6 @@ struct RecoverBitmap { u32 aElem[0]; /* Array of 32-bit bitmasks */ }; -/* -** -*/ -#define RECOVERY_SCHEMA \ -" CREATE TABLE recovery.map(" \ -" pgno INTEGER PRIMARY KEY, parent INT" \ -" );" \ -" CREATE TABLE recovery.schema(" \ -" type, name, tbl_name, rootpage, sql" \ -" );" - struct sqlite3_recover { sqlite3 *dbIn; @@ -1123,6 +1112,8 @@ static int recoverWriteData(sqlite3_recover *p){ RecoverTable *pTbl; int nMax = 0; sqlite3_value **apVal = 0; + + sqlite3_stmt *pTbls = 0; sqlite3_stmt *pSel = 0; /* Figure out the maximum number of columns for any table in the schema */ @@ -1133,114 +1124,130 @@ static int recoverWriteData(sqlite3_recover *p){ apVal = (sqlite3_value**)recoverMalloc(p, sizeof(sqlite3_value*) * (nMax+1)); if( apVal==0 ) return p->errCode; + pTbls = recoverPrepare(p, p->dbOut, + "SELECT rootpage FROM recovery.schema WHERE type='table'" + " ORDER BY (tbl_name='sqlite_sequence') ASC" + ); + pSel = recoverPrepare(p, p->dbOut, - "WITH RECURSIVE pages(root, page) AS (" - " SELECT rootpage, rootpage FROM recovery.schema" + "WITH RECURSIVE pages(page) AS (" + " SELECT ?1" " UNION" - " SELECT root, child FROM sqlite_dbptr('getpage()'), pages " + " SELECT child FROM sqlite_dbptr('getpage()'), pages " " WHERE pgno=page" ") " - "SELECT root, page, cell, field, value " + "SELECT page, cell, field, value " "FROM sqlite_dbdata('getpage()') d, pages p WHERE p.page=d.pgno " "UNION ALL " - "SELECT 0, 0, 0, 0, 0" + "SELECT 0, 0, 0, 0" ); if( pSel ){ - RecoverTable *pTab = 0; - sqlite3_stmt *pInsert = 0; - int nInsert = -1; - i64 iPrevRoot = -1; - i64 iPrevPage = -1; - int iPrevCell = -1; - int bHaveRowid = 0; /* True if iRowid is valid */ - i64 iRowid = 0; - int nVal = -1; - while( p->errCode==SQLITE_OK && sqlite3_step(pSel)==SQLITE_ROW ){ - i64 iRoot = sqlite3_column_int64(pSel, 0); - i64 iPage = sqlite3_column_int64(pSel, 1); - int iCell = sqlite3_column_int(pSel, 2); - int iField = sqlite3_column_int(pSel, 3); - sqlite3_value *pVal = sqlite3_column_value(pSel, 4); + /* The outer loop runs once for each table to recover. */ + while( sqlite3_step(pTbls)==SQLITE_ROW ){ + i64 iRoot = sqlite3_column_int64(pTbls, 0); + RecoverTable *pTab = recoverFindTable(p, iRoot); + if( pTab ){ + int ii; + sqlite3_stmt *pInsert = 0; + int nInsert = -1; + i64 iPrevPage = -1; + int iPrevCell = -1; + int bHaveRowid = 0; /* True if iRowid is valid */ + i64 iRowid = 0; + int nVal = -1; - int bNewCell = (iPrevRoot!=iRoot || iPrevPage!=iPage || iPrevCell!=iCell); - assert( bNewCell==0 || (iField==-1 || iField==0) ); - assert( bNewCell || iField==nVal ); + if( sqlite3_stricmp("sqlite_sequence", pTab->zTab)==0 ){ + recoverExec(p, p->dbOut, "DELETE FROM sqlite_sequence"); + recoverSqlCallback(p, "DELETE FROM sqlite_sequence"); + } - if( bNewCell ){ - if( nVal>=0 ){ - int ii; + sqlite3_bind_int64(pSel, 1, iRoot); + while( p->errCode==SQLITE_OK && sqlite3_step(pSel)==SQLITE_ROW ){ + i64 iPage = sqlite3_column_int64(pSel, 0); + int iCell = sqlite3_column_int(pSel, 1); + int iField = sqlite3_column_int(pSel, 2); + sqlite3_value *pVal = sqlite3_column_value(pSel, 3); - if( pTab ){ - int iVal = 0; - int iBind = 1; + int bNewCell = (iPrevPage!=iPage || iPrevCell!=iCell); + assert( bNewCell==0 || (iField==-1 || iField==0) ); + assert( bNewCell || iField==nVal ); - if( pInsert==0 || nVal!=nInsert ){ - recoverFinalize(p, pInsert); - pInsert = recoverInsertStmt(p, pTab, nVal); - nInsert = nVal; - } + if( bNewCell ){ + if( nVal>=0 ){ + int ii; + int iVal = 0; + int iBind = 1; - for(ii=0; iinCol; ii++){ - RecoverColumn *pCol = &pTab->aCol[ii]; + if( pInsert==0 || nVal!=nInsert ){ + recoverFinalize(p, pInsert); + pInsert = recoverInsertStmt(p, pTab, nVal); + nInsert = nVal; + } - if( pCol->iBind>0 ){ - if( pCol->bIPK ){ - sqlite3_bind_int64(pInsert, pCol->iBind, iRowid); - }else if( pCol->iFieldiBind, apVal[pCol->iField]); + for(ii=0; iinCol; ii++){ + RecoverColumn *pCol = &pTab->aCol[ii]; + + if( pCol->iBind>0 ){ + if( pCol->bIPK ){ + sqlite3_bind_int64(pInsert, pCol->iBind, iRowid); + }else if( pCol->iFieldiBind,apVal[pCol->iField]); + } } } - } - if( p->bRecoverRowid && pTab->iRowidBind>0 && bHaveRowid ){ - sqlite3_bind_int64(pInsert, pTab->iRowidBind, iRowid); + if( p->bRecoverRowid && pTab->iRowidBind>0 && bHaveRowid ){ + sqlite3_bind_int64(pInsert, pTab->iRowidBind, iRowid); + } + + if( SQLITE_ROW==sqlite3_step(pInsert) && p->xSql ){ + const char *zSql = (const char*)sqlite3_column_text(pInsert, 0); + recoverSqlCallback(p, zSql); + } + recoverReset(p, pInsert); + assert( p->errCode || pInsert ); + if( pInsert ) sqlite3_clear_bindings(pInsert); } - if( SQLITE_ROW==sqlite3_step(pInsert) && p->xSql ){ - const char *zSql = (const char*)sqlite3_column_text(pInsert, 0); - recoverSqlCallback(p, zSql); + for(ii=0; iierrCode || pInsert ); - if( pInsert ) sqlite3_clear_bindings(pInsert); + nVal = -1; + bHaveRowid = 0; } - for(ii=0; iierrCode; } diff --git a/manifest b/manifest index 421372fcab..f5344ad585 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\stest\sfile\srecoverclobber.test. -D 2022-09-08T11:04:23.161 +C Fix\sproblems\swith\srecovering\sthe\ssqlite_sequence\stable. +D 2022-09-08T17:42:33.679 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -387,12 +387,12 @@ F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2 F ext/rbu/sqlite3rbu.c 8737cabdfbee84bb25a7851ecef8b1312be332761238da9be6ddb10c62ad4291 F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812 F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a -F ext/recover/recover1.test ae8ce9828210aa6c466bf88e23b0933849d5bb43091abe48cf2e56d636e51e93 +F ext/recover/recover1.test ddc322148170eafe1dabbea91ac175a72f7e7d2777619a6434696a310beff9a3 F ext/recover/recover_common.tcl 6679af7dffc858e345053a91c9b0a897595b4a13007aceffafca75304ccb137c F ext/recover/recoverclobber.test e6537ebf99f57bfff6cca59550b5f4278319b57a89865abb98d755a8fd561d84 F ext/recover/recoverold.test f368a6ae2db12b6017257b332a19ab5df527f4061e43f12f5c85d8e2b236f074 F ext/recover/recoverrowid.test ec4436cd69e6cdacb48dd2963ff6dd9dbd5fe648376de5e7c0c2f4f6cbacb417 -F ext/recover/sqlite3recover.c 9724f913fd457f655e2873552bc6600a6aaff7104b9113ccb38fea18b6a71f03 +F ext/recover/sqlite3recover.c 2c45ab8cce41dcb578ef739652e65675d161751fe0d979b806d947a02de7fd32 F ext/recover/sqlite3recover.h 32f89b66f0235c0d94dfee0f1c3e9ed1ad726b3c4f3716ef0262b31cc33e8301 F ext/recover/test_recover.c 7aa268d3431d630eaa82ce14974ae04be50fe7feba660ffaea009cd581916d27 F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 @@ -2007,8 +2007,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6cca8913e703635ad89415a60fc84000ac188d9df43f45594b8ad87facb91d54 -R 102ea2ce4694a6be6ee34f8e72c4fbd9 +P cb4e950c472bd24a79a8505a7f8e4c3a0f7821648297d05cc760738b777d5149 +R e45081ba4805e1d831caf7a65d0c00b9 U dan -Z e86817dfd35f39cea8c450fbde6bc553 +Z 8c44bc5cd3a46bb8aa19fae7f571d64e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2f04809195..34b201c3c5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cb4e950c472bd24a79a8505a7f8e4c3a0f7821648297d05cc760738b777d5149 \ No newline at end of file +356d2209ea5f6b69ce15b62027c63419c2d039e52f01c74a3810a6317abf4fb0 \ No newline at end of file