mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Add the SQLITE_RECOVER_ROWIDS option. To specify that rowid values that are not also explicit INTEGER PRIMARY KEY values should be preserved.
FossilOrigin-Name: 69cc9aba56a196bbd159bd24868aa5ccc60bed0dc612d09ed8a3ae898f156809
This commit is contained in:
@ -49,6 +49,7 @@ struct RecoverTable {
|
|||||||
int nCol; /* Number of columns in table */
|
int nCol; /* Number of columns in table */
|
||||||
RecoverColumn *aCol; /* Array of columns */
|
RecoverColumn *aCol; /* Array of columns */
|
||||||
int bIntkey; /* True for intkey, false for without rowid */
|
int bIntkey; /* True for intkey, false for without rowid */
|
||||||
|
int iRowidBind; /* If >0, bind rowid to INSERT here */
|
||||||
|
|
||||||
RecoverTable *pNext;
|
RecoverTable *pNext;
|
||||||
};
|
};
|
||||||
@ -94,6 +95,7 @@ struct sqlite3_recover {
|
|||||||
char *zStateDb;
|
char *zStateDb;
|
||||||
char *zLostAndFound; /* Name of lost-and-found table (or NULL) */
|
char *zLostAndFound; /* Name of lost-and-found table (or NULL) */
|
||||||
int bFreelistCorrupt;
|
int bFreelistCorrupt;
|
||||||
|
int bRecoverRowid;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -476,6 +478,7 @@ static void recoverAddTable(sqlite3_recover *p, const char *zName, i64 iRoot){
|
|||||||
|
|
||||||
if( pStmt ){
|
if( pStmt ){
|
||||||
int iPk = -1;
|
int iPk = -1;
|
||||||
|
int iBind = 1;
|
||||||
RecoverTable *pNew = 0;
|
RecoverTable *pNew = 0;
|
||||||
int nCol = 0;
|
int nCol = 0;
|
||||||
int nName = recoverStrlen(zName);
|
int nName = recoverStrlen(zName);
|
||||||
@ -491,7 +494,6 @@ static void recoverAddTable(sqlite3_recover *p, const char *zName, i64 iRoot){
|
|||||||
if( pNew ){
|
if( pNew ){
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int iField = 0;
|
int iField = 0;
|
||||||
int iBind = 1;
|
|
||||||
char *csr = 0;
|
char *csr = 0;
|
||||||
pNew->aCol = (RecoverColumn*)&pNew[1];
|
pNew->aCol = (RecoverColumn*)&pNew[1];
|
||||||
pNew->zTab = csr = (char*)&pNew->aCol[nCol];
|
pNew->zTab = csr = (char*)&pNew->aCol[nCol];
|
||||||
@ -545,7 +547,11 @@ static void recoverAddTable(sqlite3_recover *p, const char *zName, i64 iRoot){
|
|||||||
}
|
}
|
||||||
recoverFinalize(p, pStmt);
|
recoverFinalize(p, pStmt);
|
||||||
|
|
||||||
if( iPk>=0 ) pNew->aCol[iPk].bIPK = 1;
|
if( iPk>=0 ){
|
||||||
|
pNew->aCol[iPk].bIPK = 1;
|
||||||
|
}else if( pNew->bIntkey ){
|
||||||
|
pNew->iRowidBind = iBind++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,6 +652,13 @@ static sqlite3_stmt *recoverInsertStmt(
|
|||||||
assert( nField<=pTab->nCol );
|
assert( nField<=pTab->nCol );
|
||||||
|
|
||||||
zSql = recoverMPrintf(p, "INSERT OR IGNORE INTO %Q(", pTab->zTab);
|
zSql = recoverMPrintf(p, "INSERT OR IGNORE INTO %Q(", pTab->zTab);
|
||||||
|
|
||||||
|
if( pTab->iRowidBind ){
|
||||||
|
assert( pTab->bIntkey );
|
||||||
|
zSql = recoverMPrintf(p, "%z_rowid_", zSql);
|
||||||
|
zBind = recoverMPrintf(p, "%z?%d", zBind, pTab->iRowidBind);
|
||||||
|
zSep = ", ";
|
||||||
|
}
|
||||||
for(ii=0; ii<nField; ii++){
|
for(ii=0; ii<nField; ii++){
|
||||||
int eHidden = pTab->aCol[ii].eHidden;
|
int eHidden = pTab->aCol[ii].eHidden;
|
||||||
if( eHidden!=RECOVER_EHIDDEN_VIRTUAL
|
if( eHidden!=RECOVER_EHIDDEN_VIRTUAL
|
||||||
@ -995,6 +1008,7 @@ static int recoverWriteData(sqlite3_recover *p){
|
|||||||
i64 iPrevRoot = -1;
|
i64 iPrevRoot = -1;
|
||||||
i64 iPrevPage = -1;
|
i64 iPrevPage = -1;
|
||||||
int iPrevCell = -1;
|
int iPrevCell = -1;
|
||||||
|
int bHaveRowid = 0; /* True if iRowid is valid */
|
||||||
i64 iRowid = 0;
|
i64 iRowid = 0;
|
||||||
int nVal = -1;
|
int nVal = -1;
|
||||||
|
|
||||||
@ -1034,6 +1048,9 @@ static int recoverWriteData(sqlite3_recover *p){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( p->bRecoverRowid && pTab->iRowidBind>0 && bHaveRowid ){
|
||||||
|
sqlite3_bind_int64(pInsert, pTab->iRowidBind, iRowid);
|
||||||
|
}
|
||||||
|
|
||||||
sqlite3_step(pInsert);
|
sqlite3_step(pInsert);
|
||||||
recoverReset(p, pInsert);
|
recoverReset(p, pInsert);
|
||||||
@ -1046,6 +1063,7 @@ static int recoverWriteData(sqlite3_recover *p){
|
|||||||
apVal[ii] = 0;
|
apVal[ii] = 0;
|
||||||
}
|
}
|
||||||
nVal = -1;
|
nVal = -1;
|
||||||
|
bHaveRowid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( iRoot==0 ) continue;
|
if( iRoot==0 ) continue;
|
||||||
@ -1061,6 +1079,7 @@ static int recoverWriteData(sqlite3_recover *p){
|
|||||||
iRowid = sqlite3_column_int64(pSel, 4);
|
iRowid = sqlite3_column_int64(pSel, 4);
|
||||||
assert( nVal==-1 );
|
assert( nVal==-1 );
|
||||||
nVal = 0;
|
nVal = 0;
|
||||||
|
bHaveRowid = 1;
|
||||||
}else if( iField<nMax ){
|
}else if( iField<nMax ){
|
||||||
assert( apVal[iField]==0 );
|
assert( apVal[iField]==0 );
|
||||||
apVal[iField] = sqlite3_value_dup( pVal );
|
apVal[iField] = sqlite3_value_dup( pVal );
|
||||||
@ -1139,6 +1158,10 @@ int sqlite3_recover_config(sqlite3_recover *p, int op, void *pArg){
|
|||||||
p->bFreelistCorrupt = (pArg ? 1 : 0);
|
p->bFreelistCorrupt = (pArg ? 1 : 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SQLITE_RECOVER_ROWIDS:
|
||||||
|
p->bRecoverRowid = (pArg ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rc = SQLITE_NOTFOUND;
|
rc = SQLITE_NOTFOUND;
|
||||||
break;
|
break;
|
||||||
|
@ -58,10 +58,13 @@ int sqlite3_recover_config(sqlite3_recover*, int op, void *pArg);
|
|||||||
** appear to be linked into the freelist. Otherwise, pages on the freelist
|
** appear to be linked into the freelist. Otherwise, pages on the freelist
|
||||||
** are ignored. Setting this option can recover more data from the
|
** are ignored. Setting this option can recover more data from the
|
||||||
** database, but often ends up "recovering" deleted records.
|
** database, but often ends up "recovering" deleted records.
|
||||||
|
**
|
||||||
|
** SQLITE_RECOVER_ROWIDS:
|
||||||
*/
|
*/
|
||||||
#define SQLITE_RECOVER_TESTDB 789
|
#define SQLITE_RECOVER_TESTDB 789
|
||||||
#define SQLITE_RECOVER_LOST_AND_FOUND 790
|
#define SQLITE_RECOVER_LOST_AND_FOUND 790
|
||||||
#define SQLITE_RECOVER_FREELIST_CORRUPT 791
|
#define SQLITE_RECOVER_FREELIST_CORRUPT 791
|
||||||
|
#define SQLITE_RECOVER_ROWIDS 792
|
||||||
|
|
||||||
/* Step the recovery object. Return SQLITE_DONE if recovery is complete,
|
/* Step the recovery object. Return SQLITE_DONE if recovery is complete,
|
||||||
** SQLITE_OK if recovery is not complete but no error has occurred, or
|
** SQLITE_OK if recovery is not complete but no error has occurred, or
|
||||||
|
@ -82,6 +82,7 @@ static int testRecoverCmd(
|
|||||||
"testdb", /* 0 */
|
"testdb", /* 0 */
|
||||||
"lostandfound", /* 1 */
|
"lostandfound", /* 1 */
|
||||||
"freelistcorrupt", /* 2 */
|
"freelistcorrupt", /* 2 */
|
||||||
|
"rowids", /* 3 */
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
int iOp = 0;
|
int iOp = 0;
|
||||||
@ -102,12 +103,20 @@ static int testRecoverCmd(
|
|||||||
break;
|
break;
|
||||||
case 2: {
|
case 2: {
|
||||||
int iVal = 0;
|
int iVal = 0;
|
||||||
if( Tcl_GetIntFromObj(interp, objv[3], &iVal) ) return TCL_ERROR;
|
if( Tcl_GetBooleanFromObj(interp, objv[3], &iVal) ) return TCL_ERROR;
|
||||||
res = sqlite3_recover_config(pTest->p,
|
res = sqlite3_recover_config(pTest->p,
|
||||||
SQLITE_RECOVER_FREELIST_CORRUPT, (void*)iVal
|
SQLITE_RECOVER_FREELIST_CORRUPT, (void*)iVal
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 3: {
|
||||||
|
int iVal = 0;
|
||||||
|
if( Tcl_GetBooleanFromObj(interp, objv[3], &iVal) ) return TCL_ERROR;
|
||||||
|
res = sqlite3_recover_config(pTest->p,
|
||||||
|
SQLITE_RECOVER_ROWIDS, (void*)iVal
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
|
Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
|
||||||
break;
|
break;
|
||||||
|
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
|||||||
C Add\san\soption\sto\sassume\sthe\sfreelist\sis\scorrupt\swhen\srecovering\sdata.
|
C Add\sthe\sSQLITE_RECOVER_ROWIDS\soption.\sTo\sspecify\sthat\srowid\svalues\sthat\sare\snot\salso\sexplicit\sINTEGER\sPRIMARY\sKEY\svalues\sshould\sbe\spreserved.
|
||||||
D 2022-09-03T21:08:38.958
|
D 2022-09-05T15:56:09.391
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -390,9 +390,9 @@ F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f5974282
|
|||||||
F ext/recover/recover1.test a848af8c82fe0731af835ff99475724f8654d2f24f772cc4e6f7ec4eb2ab71ea
|
F ext/recover/recover1.test a848af8c82fe0731af835ff99475724f8654d2f24f772cc4e6f7ec4eb2ab71ea
|
||||||
F ext/recover/recover_common.tcl 6679af7dffc858e345053a91c9b0a897595b4a13007aceffafca75304ccb137c
|
F ext/recover/recover_common.tcl 6679af7dffc858e345053a91c9b0a897595b4a13007aceffafca75304ccb137c
|
||||||
F ext/recover/recoverold.test e7e00c78ec35b60488369ddf99e36a3b30e686566571969b05781e5063bdffe8
|
F ext/recover/recoverold.test e7e00c78ec35b60488369ddf99e36a3b30e686566571969b05781e5063bdffe8
|
||||||
F ext/recover/sqlite3recover.c 395c9f623cf84bd8c2e651ec112898d81e1908bbda66fe5f0efcfaa85ad2b262
|
F ext/recover/sqlite3recover.c 13e78c8a9d5521e06ebe5ac992a90169155e685f5c4b3cebc632c50b41e061c9
|
||||||
F ext/recover/sqlite3recover.h 35aacde3b3834d8ceefb20a2cf0ba221cbb5d802efc11a0529aafc018c462e13
|
F ext/recover/sqlite3recover.h ed34bc96befdf581a7de039d99772caabf0b338eb2a841d869acd9f7893ffce7
|
||||||
F ext/recover/test_recover.c 112c580e7cd765a20bbc94998f8b43b629db47fa6bfd696484ca722e418f4172
|
F ext/recover/test_recover.c 9b8144ac94e6a2f3aabfcd24db6416179afdd32a3d654d1ef603c570e0384b2f
|
||||||
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
||||||
F ext/repair/checkfreelist.c e21f06995ff4efdc1622dcceaea4dcba2caa83ca2f31a1607b98a8509168a996
|
F ext/repair/checkfreelist.c e21f06995ff4efdc1622dcceaea4dcba2caa83ca2f31a1607b98a8509168a996
|
||||||
F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890
|
F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890
|
||||||
@ -2005,8 +2005,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P dbd1f1efb349a9c8886e42b3f07d3f4c576924136f111558c7294d0a272e415a
|
P 253e498f5200b8b3e2bc309587af108dd1cec8a884b3d2a49d5406525c9a4b4c
|
||||||
R f1692b1a741d9ca9573411dcac80d98d
|
R e5ada01eb624b55d2f64c4994830b06d
|
||||||
U dan
|
U dan
|
||||||
Z 9a22d599f360a7b8179802a74accdf31
|
Z a7e3c99975f0369d94d22f82581262dd
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
253e498f5200b8b3e2bc309587af108dd1cec8a884b3d2a49d5406525c9a4b4c
|
69cc9aba56a196bbd159bd24868aa5ccc60bed0dc612d09ed8a3ae898f156809
|
Reference in New Issue
Block a user