123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /*
- ** 2022-08-27
- **
- ** 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.
- **
- *************************************************************************
- **
- */
- #include "sqlite3recover.h"
- #include "sqliteInt.h"
- #include "tclsqlite.h"
- #include <assert.h>
- #ifndef SQLITE_OMIT_VIRTUALTABLE
- typedef struct TestRecover TestRecover;
- struct TestRecover {
- sqlite3_recover *p;
- Tcl_Interp *interp;
- Tcl_Obj *pScript;
- };
- static int xSqlCallback(void *pSqlArg, const char *zSql){
- TestRecover *p = (TestRecover*)pSqlArg;
- Tcl_Obj *pEval = 0;
- int res = 0;
- pEval = Tcl_DuplicateObj(p->pScript);
- Tcl_IncrRefCount(pEval);
- res = Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zSql, -1));
- if( res==TCL_OK ){
- res = Tcl_EvalObjEx(p->interp, pEval, 0);
- }
- Tcl_DecrRefCount(pEval);
- if( res ){
- Tcl_BackgroundError(p->interp);
- return TCL_ERROR;
- }else{
- Tcl_Obj *pObj = Tcl_GetObjResult(p->interp);
- if( Tcl_GetCharLength(pObj)==0 ){
- res = 0;
- }else if( Tcl_GetIntFromObj(p->interp, pObj, &res) ){
- Tcl_BackgroundError(p->interp);
- return TCL_ERROR;
- }
- }
- return res;
- }
- static int getDbPointer(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){
- Tcl_CmdInfo info;
- if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(pObj), &info) ){
- Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(pObj), NULL);
- return TCL_ERROR;
- }
- *pDb = *(sqlite3 **)info.objClientData;
- return TCL_OK;
- }
- /*
- ** Implementation of the command created by [sqlite3_recover_init]:
- **
- ** $cmd config OP ARG
- ** $cmd run
- ** $cmd errmsg
- ** $cmd errcode
- ** $cmd finalize
- */
- static int testRecoverCmd(
- void *clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
- ){
- static struct RecoverSub {
- const char *zSub;
- int nArg;
- const char *zMsg;
- } aSub[] = {
- { "config", 2, "ARG" }, /* 0 */
- { "run", 0, "" }, /* 1 */
- { "errmsg", 0, "" }, /* 2 */
- { "errcode", 0, "" }, /* 3 */
- { "finish", 0, "" }, /* 4 */
- { "step", 0, "" }, /* 5 */
- { 0 }
- };
- int rc = TCL_OK;
- int iSub = 0;
- TestRecover *pTest = (TestRecover*)clientData;
- if( objc<2 ){
- Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
- return TCL_ERROR;
- }
- rc = Tcl_GetIndexFromObjStruct(interp,
- objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub
- );
- if( rc!=TCL_OK ) return rc;
- if( (objc-2)!=aSub[iSub].nArg ){
- Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg);
- return TCL_ERROR;
- }
- switch( iSub ){
- case 0: assert( sqlite3_stricmp("config", aSub[iSub].zSub)==0 ); {
- const char *aOp[] = {
- "testdb", /* 0 */
- "lostandfound", /* 1 */
- "freelistcorrupt", /* 2 */
- "rowids", /* 3 */
- "slowindexes", /* 4 */
- "invalid", /* 5 */
- 0
- };
- int iOp = 0;
- int res = 0;
- if( Tcl_GetIndexFromObj(interp, objv[2], aOp, "option", 0, &iOp) ){
- return TCL_ERROR;
- }
- switch( iOp ){
- case 0:
- res = sqlite3_recover_config(pTest->p,
- 789, (void*)Tcl_GetString(objv[3]) /* MAGIC NUMBER! */
- );
- break;
- case 1: {
- const char *zStr = Tcl_GetString(objv[3]);
- res = sqlite3_recover_config(pTest->p,
- SQLITE_RECOVER_LOST_AND_FOUND, (void*)(zStr[0] ? zStr : 0)
- );
- break;
- }
- case 2: {
- int iVal = 0;
- if( Tcl_GetBooleanFromObj(interp, objv[3], &iVal) ) return TCL_ERROR;
- res = sqlite3_recover_config(pTest->p,
- SQLITE_RECOVER_FREELIST_CORRUPT, (void*)&iVal
- );
- 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;
- }
- case 4: {
- int iVal = 0;
- if( Tcl_GetBooleanFromObj(interp, objv[3], &iVal) ) return TCL_ERROR;
- res = sqlite3_recover_config(pTest->p,
- SQLITE_RECOVER_SLOWINDEXES, (void*)&iVal
- );
- break;
- }
- case 5: {
- res = sqlite3_recover_config(pTest->p, 12345, 0);
- break;
- }
- }
- Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
- break;
- }
- case 1: assert( sqlite3_stricmp("run", aSub[iSub].zSub)==0 ); {
- int res = sqlite3_recover_run(pTest->p);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
- break;
- }
- case 2: assert( sqlite3_stricmp("errmsg", aSub[iSub].zSub)==0 ); {
- const char *zErr = sqlite3_recover_errmsg(pTest->p);
- Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
- break;
- }
- case 3: assert( sqlite3_stricmp("errcode", aSub[iSub].zSub)==0 ); {
- int errCode = sqlite3_recover_errcode(pTest->p);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(errCode));
- break;
- }
- case 4: assert( sqlite3_stricmp("finish", aSub[iSub].zSub)==0 ); {
- int res = sqlite3_recover_errcode(pTest->p);
- int res2;
- if( res!=SQLITE_OK ){
- const char *zErr = sqlite3_recover_errmsg(pTest->p);
- Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
- }
- res2 = sqlite3_recover_finish(pTest->p);
- assert( res2==res );
- if( res ) return TCL_ERROR;
- break;
- }
- case 5: assert( sqlite3_stricmp("step", aSub[iSub].zSub)==0 ); {
- int res = sqlite3_recover_step(pTest->p);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
- break;
- }
- }
- return TCL_OK;
- }
- /*
- ** sqlite3_recover_init DB DBNAME URI
- */
- static int test_sqlite3_recover_init(
- void *clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
- ){
- static int iTestRecoverCmd = 1;
- TestRecover *pNew = 0;
- sqlite3 *db = 0;
- const char *zDb = 0;
- const char *zUri = 0;
- char zCmd[128];
- int bSql = clientData ? 1 : 0;
- if( objc!=4 ){
- const char *zErr = (bSql ? "DB DBNAME SCRIPT" : "DB DBNAME URI");
- Tcl_WrongNumArgs(interp, 1, objv, zErr);
- return TCL_ERROR;
- }
- if( getDbPointer(interp, objv[1], &db) ) return TCL_ERROR;
- zDb = Tcl_GetString(objv[2]);
- if( zDb[0]=='\0' ) zDb = 0;
- pNew = (TestRecover*)ckalloc(sizeof(TestRecover));
- if( bSql==0 ){
- zUri = Tcl_GetString(objv[3]);
- pNew->p = sqlite3_recover_init(db, zDb, zUri);
- }else{
- pNew->interp = interp;
- pNew->pScript = objv[3];
- Tcl_IncrRefCount(pNew->pScript);
- pNew->p = sqlite3_recover_init_sql(db, zDb, xSqlCallback, (void*)pNew);
- }
- sprintf(zCmd, "sqlite_recover%d", iTestRecoverCmd++);
- Tcl_CreateObjCommand(interp, zCmd, testRecoverCmd, (void*)pNew, 0);
- Tcl_SetObjResult(interp, Tcl_NewStringObj(zCmd, -1));
- return TCL_OK;
- }
- /*
- ** Declaration for public API function in file dbdata.c. This may be called
- ** with NULL as the final two arguments to register the sqlite_dbptr and
- ** sqlite_dbdata virtual tables with a database handle.
- */
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- int sqlite3_dbdata_init(sqlite3*, char**, const sqlite3_api_routines*);
- /*
- ** sqlite3_recover_init DB DBNAME URI
- */
- static int test_sqlite3_dbdata_init(
- void *clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
- ){
- sqlite3 *db = 0;
- if( objc!=2 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DB");
- return TCL_ERROR;
- }
- if( getDbPointer(interp, objv[1], &db) ) return TCL_ERROR;
- sqlite3_dbdata_init(db, 0, 0);
- Tcl_ResetResult(interp);
- return TCL_OK;
- }
- #endif /* SQLITE_OMIT_VIRTUALTABLE */
- int TestRecover_Init(Tcl_Interp *interp){
- #ifndef SQLITE_OMIT_VIRTUALTABLE
- struct Cmd {
- const char *zCmd;
- Tcl_ObjCmdProc *xProc;
- void *pArg;
- } aCmd[] = {
- { "sqlite3_recover_init", test_sqlite3_recover_init, 0 },
- { "sqlite3_recover_init_sql", test_sqlite3_recover_init, (void*)1 },
- { "sqlite3_dbdata_init", test_sqlite3_dbdata_init, (void*)1 },
- };
- int i;
- for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){
- struct Cmd *p = &aCmd[i];
- Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, p->pArg, 0);
- }
- #endif
- return TCL_OK;
- }
|