Add test code to drop an fts5 table with corrupt records in its shadow tables.
FossilOrigin-Name: ca21c942c30a3dbff0e7d118e105b847d80b5388c74d19c2eeea71581f8f40b8
This commit is contained in:
+96
-15
@@ -96,14 +96,14 @@ static int SQLITE_TCLAPI f5tDbAndApi(
|
||||
|
||||
rc = sqlite3_prepare_v2(db, "SELECT fts5(?1)", -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_bind_pointer(pStmt, 1, (void*)&pApi, "fts5_api_ptr", 0);
|
||||
sqlite3_step(pStmt);
|
||||
|
||||
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ static int SQLITE_TCLAPI xF5tApi(
|
||||
CASE(12, "xSetAuxdata") {
|
||||
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData));
|
||||
if( pData==0 ){
|
||||
Tcl_AppendResult(interp, "out of memory", 0);
|
||||
Tcl_AppendResult(interp, "out of memory", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pData->pObj = objv[2];
|
||||
@@ -452,7 +452,7 @@ static int SQLITE_TCLAPI xF5tApi(
|
||||
|
||||
rc = p->pApi->xPhraseFirst(p->pFts, iPhrase, &iter, &iCol, &iOff);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
|
||||
Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
for( ;iCol>=0; p->pApi->xPhraseNext(p->pFts, &iter, &iCol, &iOff) ){
|
||||
@@ -683,7 +683,7 @@ static int SQLITE_TCLAPI f5tCreateFunction(
|
||||
pApi, zName, (void*)pCtx, xF5tFunction, xF5tDestroy
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -750,7 +750,7 @@ static int SQLITE_TCLAPI f5tTokenize(
|
||||
if( objc==5 ){
|
||||
char *zOpt = Tcl_GetString(objv[1]);
|
||||
if( strcmp("-subst", zOpt) ){
|
||||
Tcl_AppendResult(interp, "unrecognized option: ", zOpt, 0);
|
||||
Tcl_AppendResult(interp, "unrecognized option: ", zOpt, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -759,7 +759,7 @@ static int SQLITE_TCLAPI f5tTokenize(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( nArg==0 ){
|
||||
Tcl_AppendResult(interp, "no such tokenizer: ", 0);
|
||||
Tcl_AppendResult(interp, "no such tokenizer: ", (char*)0);
|
||||
Tcl_Free((void*)azArg);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -767,13 +767,13 @@ static int SQLITE_TCLAPI f5tTokenize(
|
||||
|
||||
rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0);
|
||||
Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
|
||||
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -787,7 +787,7 @@ static int SQLITE_TCLAPI f5tTokenize(
|
||||
);
|
||||
tokenizer.xDelete(pTok);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0);
|
||||
Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", (char*)0);
|
||||
Tcl_DecrRefCount(pRet);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ static int SQLITE_TCLAPI f5tTokenizerLocale(
|
||||
|
||||
if( p->xToken==0 ){
|
||||
Tcl_AppendResult(interp,
|
||||
"sqlite3_fts5_locale may only be used by tokenizer callback", 0
|
||||
"sqlite3_fts5_locale may only be used by tokenizer callback", (char*)0
|
||||
);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -1098,7 +1098,7 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
|
||||
|
||||
if( p->xToken==0 ){
|
||||
Tcl_AppendResult(interp,
|
||||
"sqlite3_fts5_token may only be used by tokenizer callback", 0
|
||||
"sqlite3_fts5_token may only be used by tokenizer callback", (char*)0
|
||||
);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -1250,7 +1250,7 @@ static int SQLITE_TCLAPI f5tCreateTokenizer(
|
||||
Tcl_AppendResult(interp, (
|
||||
bV2 ? "error in fts5_api.xCreateTokenizer_v2()"
|
||||
: "error in fts5_api.xCreateTokenizer()"
|
||||
), 0);
|
||||
), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -1540,12 +1540,92 @@ static int SQLITE_TCLAPI f5tRegisterOriginText(
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to DROP an fts5 table. It works even if the data
|
||||
** structures fts5 stores within the database are corrupt, which sometimes
|
||||
** prevents a straight "DROP TABLE" command from succeeding.
|
||||
**
|
||||
** The first parameter is the database handle to use for the DROP TABLE
|
||||
** operation. The second is the name of the database to drop the fts5 table
|
||||
** from (i.e. "main", "temp" or the name of an attached database). The
|
||||
** third parameter is the name of the fts5 table to drop.
|
||||
**
|
||||
** SQLITE_OK is returned if the table is successfully dropped. Or, if an
|
||||
** error occurs, an SQLite error code.
|
||||
*/
|
||||
static int sqlite3_fts5_drop_corrupt_table(
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zDb, /* Database name ("main", "temp" etc.) */
|
||||
const char *zTab /* Name of fts5 table to drop */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
int bDef = 0;
|
||||
|
||||
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, -1, &bDef);
|
||||
if( rc==SQLITE_OK ){
|
||||
char *zScript = sqlite3_mprintf(
|
||||
"DELETE FROM %Q.'%q_data';"
|
||||
"DELETE FROM %Q.'%q_config';"
|
||||
"INSERT INTO %Q.'%q_data' VALUES(10, X'0000000000');"
|
||||
"INSERT INTO %Q.'%q_config' VALUES('version', 4);"
|
||||
"DROP TABLE %Q.'%q';",
|
||||
zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab
|
||||
);
|
||||
|
||||
if( zScript==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
|
||||
rc = sqlite3_exec(db, zScript, 0, 0, 0);
|
||||
if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, 0);
|
||||
sqlite3_free(zScript);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_fts5_drop_corrupt_table DB DATABASE TABLE
|
||||
**
|
||||
** Description...
|
||||
*/
|
||||
static int SQLITE_TCLAPI f5tDropCorruptTable(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db = 0;
|
||||
const char *zDb = 0;
|
||||
const char *zTab = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DATABASE TABLE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( f5tDbPointer(interp, objv[1], &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
zTab = Tcl_GetString(objv[3]);
|
||||
|
||||
rc = sqlite3_fts5_drop_corrupt_table(db, zDb, zTab);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Entry point.
|
||||
*/
|
||||
@@ -1564,7 +1644,8 @@ int Fts5tcl_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_fts5_token_hash", f5tTokenHash, 0 },
|
||||
{ "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 },
|
||||
{ "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 },
|
||||
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 }
|
||||
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 },
|
||||
{ "sqlite3_fts5_drop_corrupt_table", f5tDropCorruptTable, 0 }
|
||||
};
|
||||
int i;
|
||||
F5tTokenizerContext *pContext;
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# 2024 Aug 28
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5corrupt8
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
UPDATE t1_data SET block='hello world' WHERE id=10
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_catchsql_test 1.2 {
|
||||
SELECT * FROM t1
|
||||
} {1 {vtable constructor failed: t1}}
|
||||
do_catchsql_test 1.3 {
|
||||
DROP TABLE t1
|
||||
} {1 {vtable constructor failed: t1}}
|
||||
do_test 1.4 {
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
} {0}
|
||||
do_test 1.5 {
|
||||
sqlite3_fts5_drop_corrupt_table db main t1
|
||||
} {}
|
||||
do_test 1.6 {
|
||||
sqlite3_db_config db DEFENSIVE -1
|
||||
} {0}
|
||||
do_execsql_test 1.7 {
|
||||
SELECT * FROM sqlite_schema
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
}
|
||||
do_execsql_test 2.1 {
|
||||
UPDATE t1_config SET v=555 WHERE k='version'
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_catchsql_test 2.2 {
|
||||
SELECT * FROM t1
|
||||
} {1 {invalid fts5 file format (found 555, expected 4 or 5) - run 'rebuild'}}
|
||||
do_catchsql_test 2.3 {
|
||||
DROP TABLE t1
|
||||
} {1 {invalid fts5 file format (found 555, expected 4 or 5) - run 'rebuild'}}
|
||||
do_test 2.4 {
|
||||
sqlite3_fts5_drop_corrupt_table db main t1
|
||||
} {}
|
||||
do_execsql_test 2.5 {
|
||||
SELECT * FROM sqlite_schema
|
||||
}
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
DELETE FROM t1_config;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_catchsql_test 3.2 {
|
||||
SELECT * FROM t1
|
||||
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
|
||||
do_catchsql_test 3.3 {
|
||||
DROP TABLE t1
|
||||
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
|
||||
|
||||
|
||||
do_test 3.4 {
|
||||
sqlite3_db_config db DEFENSIVE 1
|
||||
} {1}
|
||||
do_test 3.5 {
|
||||
sqlite3_fts5_drop_corrupt_table db main t1
|
||||
} {}
|
||||
do_test 3.6 {
|
||||
sqlite3_db_config db DEFENSIVE -1
|
||||
} {1}
|
||||
do_execsql_test 3.7 {
|
||||
SELECT * FROM sqlite_schema
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Updates\sto\stestrunner:\s\s(1)\sOmit\sall\stesting\sof\sUser-Auth.\n(2)\sAutomatically\sadd\sthe\s"*"\swildcard\sbefore\sand\safter\sall\spattern\narguments.\s\s(3)\sBuild\sthe\ssqlite3\sCLI\sfor\srelease\stests.
|
||||
D 2024-08-27T17:38:26.497
|
||||
C Add\stest\scode\sto\sdrop\san\sfts5\stable\swith\scorrupt\srecords\sin\sits\sshadow\stables.
|
||||
D 2024-08-27T18:25:04.935
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -102,7 +102,7 @@ F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a
|
||||
F ext/fts5/fts5_index.c eb9a0dda3bc6ef969a6be8d2746af56856e67251810ddba08622b45be8477abe
|
||||
F ext/fts5/fts5_main.c 3d8b778f65fe5be218f6a8e4019048f092c0c09621b035ce3e8804093036b578
|
||||
F ext/fts5/fts5_storage.c 9a9b880be12901f1962ae2a5a7e1b74348b3099a1e728764e419f75d98e3e612
|
||||
F ext/fts5/fts5_tcl.c 1dcf08028141c40a32634bdcf2d5601622ce4edc48f82ac4ce0cbe0a92a6961d
|
||||
F ext/fts5/fts5_tcl.c 4db9258a7882c5eac0da4433042132aaf15b87dd1e1636c7a6ca203abd2c8bfe
|
||||
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
|
||||
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
|
||||
F ext/fts5/fts5_tokenize.c ae9c4fa93174ef06ffc138bd4280a1c37f7e13624d3d2706aad4b80573f23c41
|
||||
@@ -153,6 +153,7 @@ F ext/fts5/test/fts5corrupt4.test dc08d19f5b8943e95a7778a7d8da592042504faf18dd93
|
||||
F ext/fts5/test/fts5corrupt5.test 11b47126f5772cc37b67e3e8b2ed05895c4d07c05338bc07e4eea225bfe32c76
|
||||
F ext/fts5/test/fts5corrupt6.test 2d72db743db7b5d9c9a6d0cfef24d799ed1aa5e8192b66c40e871a37ed9eed06
|
||||
F ext/fts5/test/fts5corrupt7.test 4e830875c33b9ea3c4cf1ba71e692b63893cbb4faae8c69b1071889dc26e211c
|
||||
F ext/fts5/test/fts5corrupt8.test f78b6de9e4327e16ba7a7958b1ce576f9b5d886b4b97690f90b7f3cf654da458
|
||||
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
|
||||
F ext/fts5/test/fts5detail.test 54015e9c43ec4ba542cfb93268abdf280e0300f350efd08ee411284b03595cc4
|
||||
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
|
||||
@@ -2210,8 +2211,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P e9b03b082dcf141695140a6c2c50bf0dc577c3d64ab76f81dd22f0084eca26d6
|
||||
R 4a4a4d707423caa7361c65011daf0aec
|
||||
U drh
|
||||
Z 9d66ab840eaa6125582be7511985f53f
|
||||
P d03d35eebaf82709414c87cfa6abc9d2baf8d7e64c2627bad0fd5bbda3e78d60
|
||||
R eae9b17364855941c00e92c86d398a4e
|
||||
U dan
|
||||
Z d07b6efd95ad4c9798aced1dad6099da
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
d03d35eebaf82709414c87cfa6abc9d2baf8d7e64c2627bad0fd5bbda3e78d60
|
||||
ca21c942c30a3dbff0e7d118e105b847d80b5388c74d19c2eeea71581f8f40b8
|
||||
|
||||
Reference in New Issue
Block a user