| /* | |
| ** 2009 August 17 | |
| ** | |
| ** 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. | |
| ** | |
| ************************************************************************* | |
| ** | |
| ** The code in this file is used for testing SQLite. It is not part of | |
| ** the source code used in production systems. | |
| ** | |
| ** Specifically, this file tests the effect of errors while initializing | |
| ** the various pluggable sub-systems from within sqlite3_initialize(). | |
| ** If an error occurs in sqlite3_initialize() the following should be | |
| ** true: | |
| ** | |
| ** 1) An error code is returned to the user, and | |
| ** 2) A subsequent call to sqlite3_shutdown() calls the shutdown method | |
| ** of those subsystems that were initialized, and | |
| ** 3) A subsequent call to sqlite3_initialize() attempts to initialize | |
| ** the remaining, uninitialized, subsystems. | |
| */ | |
| #include "sqliteInt.h" | |
| #include <string.h> | |
| #if defined(INCLUDE_SQLITE_TCL_H) | |
| # include "sqlite_tcl.h" | |
| #else | |
| # include "tcl.h" | |
| #endif | |
| static struct Wrapped { | |
| sqlite3_pcache_methods2 pcache; | |
| sqlite3_mem_methods mem; | |
| sqlite3_mutex_methods mutex; | |
| int mem_init; /* True if mem subsystem is initalized */ | |
| int mem_fail; /* True to fail mem subsystem inialization */ | |
| int mutex_init; /* True if mutex subsystem is initalized */ | |
| int mutex_fail; /* True to fail mutex subsystem inialization */ | |
| int pcache_init; /* True if pcache subsystem is initalized */ | |
| int pcache_fail; /* True to fail pcache subsystem inialization */ | |
| } wrapped; | |
| static int wrMemInit(void *pAppData){ | |
| int rc; | |
| if( wrapped.mem_fail ){ | |
| rc = SQLITE_ERROR; | |
| }else{ | |
| rc = wrapped.mem.xInit(wrapped.mem.pAppData); | |
| } | |
| if( rc==SQLITE_OK ){ | |
| wrapped.mem_init = 1; | |
| } | |
| return rc; | |
| } | |
| static void wrMemShutdown(void *pAppData){ | |
| wrapped.mem.xShutdown(wrapped.mem.pAppData); | |
| wrapped.mem_init = 0; | |
| } | |
| static void *wrMemMalloc(int n) {return wrapped.mem.xMalloc(n);} | |
| static void wrMemFree(void *p) {wrapped.mem.xFree(p);} | |
| static void *wrMemRealloc(void *p, int n) {return wrapped.mem.xRealloc(p, n);} | |
| static int wrMemSize(void *p) {return wrapped.mem.xSize(p);} | |
| static int wrMemRoundup(int n) {return wrapped.mem.xRoundup(n);} | |
| static int wrMutexInit(void){ | |
| int rc; | |
| if( wrapped.mutex_fail ){ | |
| rc = SQLITE_ERROR; | |
| }else{ | |
| rc = wrapped.mutex.xMutexInit(); | |
| } | |
| if( rc==SQLITE_OK ){ | |
| wrapped.mutex_init = 1; | |
| } | |
| return rc; | |
| } | |
| static int wrMutexEnd(void){ | |
| wrapped.mutex.xMutexEnd(); | |
| wrapped.mutex_init = 0; | |
| return SQLITE_OK; | |
| } | |
| static sqlite3_mutex *wrMutexAlloc(int e){ | |
| return wrapped.mutex.xMutexAlloc(e); | |
| } | |
| static void wrMutexFree(sqlite3_mutex *p){ | |
| wrapped.mutex.xMutexFree(p); | |
| } | |
| static void wrMutexEnter(sqlite3_mutex *p){ | |
| wrapped.mutex.xMutexEnter(p); | |
| } | |
| static int wrMutexTry(sqlite3_mutex *p){ | |
| return wrapped.mutex.xMutexTry(p); | |
| } | |
| static void wrMutexLeave(sqlite3_mutex *p){ | |
| wrapped.mutex.xMutexLeave(p); | |
| } | |
| static int wrMutexHeld(sqlite3_mutex *p){ | |
| return wrapped.mutex.xMutexHeld(p); | |
| } | |
| static int wrMutexNotheld(sqlite3_mutex *p){ | |
| return wrapped.mutex.xMutexNotheld(p); | |
| } | |
| static int wrPCacheInit(void *pArg){ | |
| int rc; | |
| if( wrapped.pcache_fail ){ | |
| rc = SQLITE_ERROR; | |
| }else{ | |
| rc = wrapped.pcache.xInit(wrapped.pcache.pArg); | |
| } | |
| if( rc==SQLITE_OK ){ | |
| wrapped.pcache_init = 1; | |
| } | |
| return rc; | |
| } | |
| static void wrPCacheShutdown(void *pArg){ | |
| wrapped.pcache.xShutdown(wrapped.pcache.pArg); | |
| wrapped.pcache_init = 0; | |
| } | |
| static sqlite3_pcache *wrPCacheCreate(int a, int b, int c){ | |
| return wrapped.pcache.xCreate(a, b, c); | |
| } | |
| static void wrPCacheCachesize(sqlite3_pcache *p, int n){ | |
| wrapped.pcache.xCachesize(p, n); | |
| } | |
| static int wrPCachePagecount(sqlite3_pcache *p){ | |
| return wrapped.pcache.xPagecount(p); | |
| } | |
| static sqlite3_pcache_page *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){ | |
| return wrapped.pcache.xFetch(p, a, b); | |
| } | |
| static void wrPCacheUnpin(sqlite3_pcache *p, sqlite3_pcache_page *a, int b){ | |
| wrapped.pcache.xUnpin(p, a, b); | |
| } | |
| static void wrPCacheRekey( | |
| sqlite3_pcache *p, | |
| sqlite3_pcache_page *a, | |
| unsigned b, | |
| unsigned c | |
| ){ | |
| wrapped.pcache.xRekey(p, a, b, c); | |
| } | |
| static void wrPCacheTruncate(sqlite3_pcache *p, unsigned a){ | |
| wrapped.pcache.xTruncate(p, a); | |
| } | |
| static void wrPCacheDestroy(sqlite3_pcache *p){ | |
| wrapped.pcache.xDestroy(p); | |
| } | |
| static void installInitWrappers(void){ | |
| sqlite3_mutex_methods mutexmethods = { | |
| wrMutexInit, wrMutexEnd, wrMutexAlloc, | |
| wrMutexFree, wrMutexEnter, wrMutexTry, | |
| wrMutexLeave, wrMutexHeld, wrMutexNotheld | |
| }; | |
| sqlite3_pcache_methods2 pcachemethods = { | |
| 1, 0, | |
| wrPCacheInit, wrPCacheShutdown, wrPCacheCreate, | |
| wrPCacheCachesize, wrPCachePagecount, wrPCacheFetch, | |
| wrPCacheUnpin, wrPCacheRekey, wrPCacheTruncate, | |
| wrPCacheDestroy | |
| }; | |
| sqlite3_mem_methods memmethods = { | |
| wrMemMalloc, wrMemFree, wrMemRealloc, | |
| wrMemSize, wrMemRoundup, wrMemInit, | |
| wrMemShutdown, | |
| 0 | |
| }; | |
| memset(&wrapped, 0, sizeof(wrapped)); | |
| sqlite3_shutdown(); | |
| sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex); | |
| sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem); | |
| sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &wrapped.pcache); | |
| sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods); | |
| sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods); | |
| sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods); | |
| } | |
| static int SQLITE_TCLAPI init_wrapper_install( | |
| ClientData clientData, /* Unused */ | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int objc, /* Number of arguments */ | |
| Tcl_Obj *CONST objv[] /* Command arguments */ | |
| ){ | |
| int i; | |
| installInitWrappers(); | |
| for(i=1; i<objc; i++){ | |
| char *z = Tcl_GetString(objv[i]); | |
| if( strcmp(z, "mem")==0 ){ | |
| wrapped.mem_fail = 1; | |
| }else if( strcmp(z, "mutex")==0 ){ | |
| wrapped.mutex_fail = 1; | |
| }else if( strcmp(z, "pcache")==0 ){ | |
| wrapped.pcache_fail = 1; | |
| }else{ | |
| Tcl_AppendResult(interp, "Unknown argument: \"", z, "\""); | |
| return TCL_ERROR; | |
| } | |
| } | |
| return TCL_OK; | |
| } | |
| static int SQLITE_TCLAPI init_wrapper_uninstall( | |
| ClientData clientData, /* Unused */ | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int objc, /* Number of arguments */ | |
| Tcl_Obj *CONST objv[] /* Command arguments */ | |
| ){ | |
| if( objc!=1 ){ | |
| Tcl_WrongNumArgs(interp, 1, objv, ""); | |
| return TCL_ERROR; | |
| } | |
| sqlite3_shutdown(); | |
| sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex); | |
| sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem); | |
| sqlite3_config(SQLITE_CONFIG_PCACHE2, &wrapped.pcache); | |
| return TCL_OK; | |
| } | |
| static int SQLITE_TCLAPI init_wrapper_clear( | |
| ClientData clientData, /* Unused */ | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int objc, /* Number of arguments */ | |
| Tcl_Obj *CONST objv[] /* Command arguments */ | |
| ){ | |
| if( objc!=1 ){ | |
| Tcl_WrongNumArgs(interp, 1, objv, ""); | |
| return TCL_ERROR; | |
| } | |
| wrapped.mem_fail = 0; | |
| wrapped.mutex_fail = 0; | |
| wrapped.pcache_fail = 0; | |
| return TCL_OK; | |
| } | |
| static int SQLITE_TCLAPI init_wrapper_query( | |
| ClientData clientData, /* Unused */ | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int objc, /* Number of arguments */ | |
| Tcl_Obj *CONST objv[] /* Command arguments */ | |
| ){ | |
| Tcl_Obj *pRet; | |
| if( objc!=1 ){ | |
| Tcl_WrongNumArgs(interp, 1, objv, ""); | |
| return TCL_ERROR; | |
| } | |
| pRet = Tcl_NewObj(); | |
| if( wrapped.mutex_init ){ | |
| Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mutex", -1)); | |
| } | |
| if( wrapped.mem_init ){ | |
| Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mem", -1)); | |
| } | |
| if( wrapped.pcache_init ){ | |
| Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("pcache", -1)); | |
| } | |
| Tcl_SetObjResult(interp, pRet); | |
| return TCL_OK; | |
| } | |
| int Sqlitetest_init_Init(Tcl_Interp *interp){ | |
| static struct { | |
| char *zName; | |
| Tcl_ObjCmdProc *xProc; | |
| } aObjCmd[] = { | |
| {"init_wrapper_install", init_wrapper_install}, | |
| {"init_wrapper_query", init_wrapper_query }, | |
| {"init_wrapper_uninstall", init_wrapper_uninstall}, | |
| {"init_wrapper_clear", init_wrapper_clear} | |
| }; | |
| int i; | |
| for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ | |
| Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); | |
| } | |
| return TCL_OK; | |
| } |