diff --git a/ext/intck/sqlite3intck.c b/ext/intck/sqlite3intck.c index b08b499a43..05eaa81a93 100644 --- a/ext/intck/sqlite3intck.c +++ b/ext/intck/sqlite3intck.c @@ -19,15 +19,11 @@ struct sqlite3_intck { sqlite3 *db; const char *zDb; /* Copy of zDb parameter to _open() */ - char *zObj; /* Current object. Or NULL. */ - char *zKey; /* Key saved by _suspect() call. */ - - sqlite3_stmt *pCheck; - - int rc; /* SQLite error code */ + char *zKey; /* Key saved by _intck_suspend() call. */ + sqlite3_stmt *pCheck; /* Current check statement */ + int rc; /* Error code */ char *zErr; /* Error message */ - char *zTestSql; /* Returned by sqlite3_intck_test_sql() */ }; @@ -109,7 +105,7 @@ static void intckFindObject(sqlite3_intck *p){ pStmt = intckPrepare(p, "WITH tables(table_name) AS (" " SELECT name" - " FROM %Q.sqlite_schema WHERE type='table' OR type='index'" + " FROM %Q.sqlite_schema WHERE (type='table' OR type='index') AND rootpage" " UNION ALL " " SELECT 'sqlite_schema'" ")" @@ -400,9 +396,9 @@ static char *intckCheckObjectSql( "" ", idx(name, match_expr, partial, partial_alias, idx_ps, idx_idx) AS (" " SELECT idx_name," - " format('(%s) IS (%s)', " - " group_concat(i.col_expr, ', ')," - " group_concat('o.'||i.col_alias, ', ')" + " format('(%s,%s) IS (%s,%s)', " + " group_concat(i.col_expr, ', '), i_pk," + " group_concat('o.'||i.col_alias, ', '), o_pk" " ), " " parse_create_index(" " (SELECT sql FROM sqlite_schema WHERE name=idx_name), -1" @@ -512,13 +508,12 @@ static char *intckCheckObjectSql( ** is set to an expression that evaluates to NULL if the required ** entry is present in the index, or an error message otherwise. */ ", expr(e, p) AS (" - " SELECT format('CASE WHEN (%%s) IN\n" - " (SELECT %%s FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n" + " SELECT format('CASE WHEN EXISTS \n" + " (SELECT 1 FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n" " THEN NULL\n" " ELSE format(''entry (%%s,%%s) missing from index %%s'', %%s, %%s)\n" " END\n'" - " , t.o_pk, t.i_pk, t.db, t.tab, i.name, i.match_expr, " - " ' AND (' || partial || ')'," + " , t.db, t.tab, i.name, i.match_expr, ' AND (' || partial || ')'," " i.idx_ps, t.ps_pk, i.name, i.idx_idx, t.pk_pk)," " CASE WHEN partial IS NULL THEN NULL ELSE i.partial_alias END" " FROM tabpk t, idx i" @@ -626,30 +621,35 @@ int sqlite3_intck_open( if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ + sqlite3_create_function(db, "parse_create_index", + 2, SQLITE_UTF8, 0, parseCreateIndexFunc, 0, 0 + ); memset(pNew, 0, sizeof(*pNew)); pNew->db = db; pNew->zDb = (const char*)&pNew[1]; memcpy(&pNew[1], zDb, nDb+1); - sqlite3_create_function(db, "parse_create_index", - 2, SQLITE_UTF8, 0, parseCreateIndexFunc, 0, 0 - ); } *ppOut = pNew; return rc; } -void sqlite3_intck_close(sqlite3_intck *p){ - if( p && p->db ){ - sqlite3_create_function( - p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0 - ); +int sqlite3_intck_close(sqlite3_intck *p){ + int rc = SQLITE_OK; + if( p ){ + rc = (p->rc==SQLITE_DONE ? SQLITE_OK : p->rc); + if( p->db ){ + sqlite3_create_function( + p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0 + ); + } + sqlite3_free(p->zObj); + sqlite3_free(p->zKey); + sqlite3_free(p->zTestSql); + sqlite3_free(p->zErr); + sqlite3_free(p); } - sqlite3_free(p->zObj); - sqlite3_free(p->zKey); - sqlite3_free(p->zTestSql); - sqlite3_free(p->zErr); - sqlite3_free(p); + return rc; } int sqlite3_intck_step(sqlite3_intck *p){ diff --git a/ext/intck/sqlite3intck.h b/ext/intck/sqlite3intck.h index 8846812e75..c7c24e42c9 100644 --- a/ext/intck/sqlite3intck.h +++ b/ext/intck/sqlite3intck.h @@ -29,7 +29,7 @@ int sqlite3_intck_open( sqlite3_intck **ppOut ); -void sqlite3_intck_close(sqlite3_intck*); +int sqlite3_intck_close(sqlite3_intck*); int sqlite3_intck_step(sqlite3_intck *pCk); diff --git a/ext/intck/test_intck.c b/ext/intck/test_intck.c index d14fc92a6c..75bcfa298a 100644 --- a/ext/intck/test_intck.c +++ b/ext/intck/test_intck.c @@ -179,7 +179,60 @@ static int test_sqlite3_intck( return TCL_OK; } +/* +** tclcmd: test_do_intck DB DBNAME +*/ +static int test_do_intck( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3 *db = 0; + const char *zDb = 0; + int rc = SQLITE_OK; + sqlite3_intck *pCk = 0; + Tcl_Obj *pRet = 0; + const char *zErr = 0; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ + return TCL_ERROR; + } + zDb = Tcl_GetString(objv[2]); + + pRet = Tcl_NewObj(); + Tcl_IncrRefCount(pRet); + + rc = sqlite3_intck_open(db, zDb, 0, &pCk); + if( rc==SQLITE_OK ){ + while( sqlite3_intck_step(pCk)==SQLITE_OK ){ + const char *zMsg = sqlite3_intck_message(pCk); + if( zMsg ){ + Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zMsg, -1)); + } + } + rc = sqlite3_intck_error(pCk, &zErr); + } + if( rc!=SQLITE_OK ){ + if( zErr ){ + Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); + }else{ + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); + } + }else{ + Tcl_SetObjResult(interp, pRet); + } + Tcl_DecrRefCount(pRet); + sqlite3_intck_close(pCk); + return rc ? TCL_ERROR : TCL_OK; +} + int Sqlitetestintck_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlite3_intck", test_sqlite3_intck, 0, 0); + Tcl_CreateObjCommand(interp, "test_do_intck", test_do_intck, 0, 0); return TCL_OK; } diff --git a/manifest b/manifest index bb8e46b123..cf37766470 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\simplementation\sof\ssqlite3_intck_suspend(). -D 2024-02-19T18:03:53.963 +C Use\smore\sefficient\sSQL\sto\sverify\sthat\sindexes\scontain\sentries\sthat\smatch\stheir\stables. +D 2024-02-19T20:15:44.802 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -251,9 +251,9 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/intck/intck1.test c831bc6ff67da3c5b6c9568640f87ad0442d4fc98ef97bc837133b94bcc645b3 F ext/intck/intck2.test b65d7f627342f767e1d2c447d25619666cec36f516786dd56568bd741e5d7e67 F ext/intck/intck_common.tcl 2895854e7aaf5e199a15f6f82538a00999fd8fc55553bc1f04619af7aa86c0d0 -F ext/intck/sqlite3intck.c 703ff16bc936192cff20d06b015d66279f4594e88371c00b18d17fec4f01ff5c -F ext/intck/sqlite3intck.h 342ee2e2c7636b4daf29fa195d0a3a658272b76b283d586fba50f6bc80fc143d -F ext/intck/test_intck.c eb596269c4a690a9b8ee689b1e52ff6e3306013ec706e319d5b97af05a08f0b9 +F ext/intck/sqlite3intck.c 5f319b7c72b0c01cfa28bb5fdd19be5781eb11f5a5216af2a0870dc7e001414d +F ext/intck/sqlite3intck.h d9501ea480b7c41c0555f39f4f1b7c3e8d54fc1ea6d115de5e1211e0bc11d3e7 +F ext/intck/test_intck.c 06206b35f1428961015c060dd35201246c849625cfdff461e0eeaaf76bda545c F ext/jni/GNUmakefile 59eb05f2a363bdfac8d15d66bed624bfe1ff289229184f3861b95f98a19cf4b2 F ext/jni/README.md d899789a9082a07b99bf30b1bbb6204ae57c060efcaa634536fa669323918f42 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa @@ -2168,8 +2168,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 444e3c9210026da7eae1ed98850722e002433aa2cc77dbc6b6f80327a6b7a390 -R 6b69910b5d388b58f98078e173b37781 +P c36ada868da74e030ff5002de1f3b31b639b0c43714b91c2e5ca0eda16bb6bc2 +R 830041ceb0564db12655be53580aeb6a U dan -Z 3045521be4122627d743cbd6c4ab9b9c +Z f8e44044aacffa331f677c80763fe8b6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fa3faa50cd..eb805d0954 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c36ada868da74e030ff5002de1f3b31b639b0c43714b91c2e5ca0eda16bb6bc2 \ No newline at end of file +c01e008c28895e50b14531b2a1f3f1110aab3b54df41ebdbd416fbac7b1bba94 \ No newline at end of file