dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 1 | /* |
| 2 | ** 2009 August 17 |
| 3 | ** |
| 4 | ** The author disclaims copyright to this source code. In place of |
| 5 | ** a legal notice, here is a blessing: |
| 6 | ** |
| 7 | ** May you do good and not evil. |
| 8 | ** May you find forgiveness for yourself and forgive others. |
| 9 | ** May you share freely, never taking more than you give. |
| 10 | ** |
| 11 | ************************************************************************* |
| 12 | ** |
| 13 | ** The code in this file is used for testing SQLite. It is not part of |
| 14 | ** the source code used in production systems. |
| 15 | ** |
| 16 | ** Specifically, this file tests the effect of errors while initializing |
| 17 | ** the various pluggable sub-systems from within sqlite3_initialize(). |
| 18 | ** If an error occurs in sqlite3_initialize() the following should be |
| 19 | ** true: |
| 20 | ** |
| 21 | ** 1) An error code is returned to the user, and |
| 22 | ** 2) A subsequent call to sqlite3_shutdown() calls the shutdown method |
| 23 | ** of those subsystems that were initialized, and |
| 24 | ** 3) A subsequent call to sqlite3_initialize() attempts to initialize |
| 25 | ** the remaining, uninitialized, subsystems. |
| 26 | */ |
| 27 | |
| 28 | #include "sqliteInt.h" |
| 29 | #include <string.h> |
drh | 064b681 | 2024-07-30 15:49:02 | [diff] [blame] | 30 | #include "tclsqlite.h" |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 31 | |
| 32 | static struct Wrapped { |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 33 | sqlite3_pcache_methods2 pcache; |
| 34 | sqlite3_mem_methods mem; |
| 35 | sqlite3_mutex_methods mutex; |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 36 | |
larrybr | bc91738 | 2023-06-07 08:40:31 | [diff] [blame] | 37 | int mem_init; /* True if mem subsystem is initialized */ |
| 38 | int mem_fail; /* True to fail mem subsystem initialization */ |
| 39 | int mutex_init; /* True if mutex subsystem is initialized */ |
| 40 | int mutex_fail; /* True to fail mutex subsystem initialization */ |
| 41 | int pcache_init; /* True if pcache subsystem is initialized */ |
| 42 | int pcache_fail; /* True to fail pcache subsystem initialization */ |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 43 | } wrapped; |
| 44 | |
| 45 | static int wrMemInit(void *pAppData){ |
| 46 | int rc; |
| 47 | if( wrapped.mem_fail ){ |
| 48 | rc = SQLITE_ERROR; |
| 49 | }else{ |
| 50 | rc = wrapped.mem.xInit(wrapped.mem.pAppData); |
| 51 | } |
| 52 | if( rc==SQLITE_OK ){ |
| 53 | wrapped.mem_init = 1; |
| 54 | } |
| 55 | return rc; |
| 56 | } |
| 57 | static void wrMemShutdown(void *pAppData){ |
| 58 | wrapped.mem.xShutdown(wrapped.mem.pAppData); |
| 59 | wrapped.mem_init = 0; |
| 60 | } |
| 61 | static void *wrMemMalloc(int n) {return wrapped.mem.xMalloc(n);} |
| 62 | static void wrMemFree(void *p) {wrapped.mem.xFree(p);} |
| 63 | static void *wrMemRealloc(void *p, int n) {return wrapped.mem.xRealloc(p, n);} |
| 64 | static int wrMemSize(void *p) {return wrapped.mem.xSize(p);} |
| 65 | static int wrMemRoundup(int n) {return wrapped.mem.xRoundup(n);} |
| 66 | |
| 67 | |
| 68 | static int wrMutexInit(void){ |
| 69 | int rc; |
| 70 | if( wrapped.mutex_fail ){ |
| 71 | rc = SQLITE_ERROR; |
| 72 | }else{ |
| 73 | rc = wrapped.mutex.xMutexInit(); |
| 74 | } |
| 75 | if( rc==SQLITE_OK ){ |
| 76 | wrapped.mutex_init = 1; |
| 77 | } |
| 78 | return rc; |
| 79 | } |
| 80 | static int wrMutexEnd(void){ |
| 81 | wrapped.mutex.xMutexEnd(); |
| 82 | wrapped.mutex_init = 0; |
| 83 | return SQLITE_OK; |
| 84 | } |
| 85 | static sqlite3_mutex *wrMutexAlloc(int e){ |
| 86 | return wrapped.mutex.xMutexAlloc(e); |
| 87 | } |
| 88 | static void wrMutexFree(sqlite3_mutex *p){ |
| 89 | wrapped.mutex.xMutexFree(p); |
| 90 | } |
| 91 | static void wrMutexEnter(sqlite3_mutex *p){ |
| 92 | wrapped.mutex.xMutexEnter(p); |
| 93 | } |
| 94 | static int wrMutexTry(sqlite3_mutex *p){ |
| 95 | return wrapped.mutex.xMutexTry(p); |
| 96 | } |
| 97 | static void wrMutexLeave(sqlite3_mutex *p){ |
| 98 | wrapped.mutex.xMutexLeave(p); |
| 99 | } |
| 100 | static int wrMutexHeld(sqlite3_mutex *p){ |
| 101 | return wrapped.mutex.xMutexHeld(p); |
| 102 | } |
| 103 | static int wrMutexNotheld(sqlite3_mutex *p){ |
| 104 | return wrapped.mutex.xMutexNotheld(p); |
| 105 | } |
| 106 | |
| 107 | |
| 108 | |
| 109 | static int wrPCacheInit(void *pArg){ |
| 110 | int rc; |
| 111 | if( wrapped.pcache_fail ){ |
| 112 | rc = SQLITE_ERROR; |
| 113 | }else{ |
| 114 | rc = wrapped.pcache.xInit(wrapped.pcache.pArg); |
| 115 | } |
| 116 | if( rc==SQLITE_OK ){ |
| 117 | wrapped.pcache_init = 1; |
| 118 | } |
| 119 | return rc; |
| 120 | } |
| 121 | static void wrPCacheShutdown(void *pArg){ |
| 122 | wrapped.pcache.xShutdown(wrapped.pcache.pArg); |
| 123 | wrapped.pcache_init = 0; |
| 124 | } |
| 125 | |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 126 | static sqlite3_pcache *wrPCacheCreate(int a, int b, int c){ |
| 127 | return wrapped.pcache.xCreate(a, b, c); |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 128 | } |
| 129 | static void wrPCacheCachesize(sqlite3_pcache *p, int n){ |
| 130 | wrapped.pcache.xCachesize(p, n); |
| 131 | } |
| 132 | static int wrPCachePagecount(sqlite3_pcache *p){ |
| 133 | return wrapped.pcache.xPagecount(p); |
| 134 | } |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 135 | static sqlite3_pcache_page *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){ |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 136 | return wrapped.pcache.xFetch(p, a, b); |
| 137 | } |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 138 | static void wrPCacheUnpin(sqlite3_pcache *p, sqlite3_pcache_page *a, int b){ |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 139 | wrapped.pcache.xUnpin(p, a, b); |
| 140 | } |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 141 | static void wrPCacheRekey( |
| 142 | sqlite3_pcache *p, |
| 143 | sqlite3_pcache_page *a, |
| 144 | unsigned b, |
| 145 | unsigned c |
| 146 | ){ |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 147 | wrapped.pcache.xRekey(p, a, b, c); |
| 148 | } |
| 149 | static void wrPCacheTruncate(sqlite3_pcache *p, unsigned a){ |
| 150 | wrapped.pcache.xTruncate(p, a); |
| 151 | } |
| 152 | static void wrPCacheDestroy(sqlite3_pcache *p){ |
| 153 | wrapped.pcache.xDestroy(p); |
| 154 | } |
| 155 | |
| 156 | static void installInitWrappers(void){ |
| 157 | sqlite3_mutex_methods mutexmethods = { |
| 158 | wrMutexInit, wrMutexEnd, wrMutexAlloc, |
| 159 | wrMutexFree, wrMutexEnter, wrMutexTry, |
| 160 | wrMutexLeave, wrMutexHeld, wrMutexNotheld |
| 161 | }; |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 162 | sqlite3_pcache_methods2 pcachemethods = { |
drh | 81ef0f9 | 2011-11-13 21:44:03 | [diff] [blame] | 163 | 1, 0, |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 164 | wrPCacheInit, wrPCacheShutdown, wrPCacheCreate, |
| 165 | wrPCacheCachesize, wrPCachePagecount, wrPCacheFetch, |
| 166 | wrPCacheUnpin, wrPCacheRekey, wrPCacheTruncate, |
| 167 | wrPCacheDestroy |
| 168 | }; |
| 169 | sqlite3_mem_methods memmethods = { |
| 170 | wrMemMalloc, wrMemFree, wrMemRealloc, |
| 171 | wrMemSize, wrMemRoundup, wrMemInit, |
| 172 | wrMemShutdown, |
| 173 | 0 |
| 174 | }; |
| 175 | |
| 176 | memset(&wrapped, 0, sizeof(wrapped)); |
| 177 | |
| 178 | sqlite3_shutdown(); |
| 179 | sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex); |
| 180 | sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem); |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 181 | sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &wrapped.pcache); |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 182 | sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods); |
| 183 | sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods); |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 184 | sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods); |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 185 | } |
| 186 | |
mistachkin | 7617e4a | 2016-07-28 17:11:20 | [diff] [blame] | 187 | static int SQLITE_TCLAPI init_wrapper_install( |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 188 | ClientData clientData, /* Unused */ |
| 189 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
| 190 | int objc, /* Number of arguments */ |
| 191 | Tcl_Obj *CONST objv[] /* Command arguments */ |
| 192 | ){ |
| 193 | int i; |
| 194 | installInitWrappers(); |
| 195 | for(i=1; i<objc; i++){ |
| 196 | char *z = Tcl_GetString(objv[i]); |
| 197 | if( strcmp(z, "mem")==0 ){ |
| 198 | wrapped.mem_fail = 1; |
| 199 | }else if( strcmp(z, "mutex")==0 ){ |
| 200 | wrapped.mutex_fail = 1; |
| 201 | }else if( strcmp(z, "pcache")==0 ){ |
| 202 | wrapped.pcache_fail = 1; |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 203 | }else{ |
stephan | 065c0a6 | 2025-03-08 06:53:06 | [diff] [blame] | 204 | Tcl_AppendResult(interp, "Unknown argument: \"", z, "\"", NULL); |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 205 | return TCL_ERROR; |
| 206 | } |
| 207 | } |
| 208 | return TCL_OK; |
| 209 | } |
| 210 | |
mistachkin | 7617e4a | 2016-07-28 17:11:20 | [diff] [blame] | 211 | static int SQLITE_TCLAPI init_wrapper_uninstall( |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 212 | ClientData clientData, /* Unused */ |
| 213 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
| 214 | int objc, /* Number of arguments */ |
| 215 | Tcl_Obj *CONST objv[] /* Command arguments */ |
| 216 | ){ |
| 217 | if( objc!=1 ){ |
| 218 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 219 | return TCL_ERROR; |
| 220 | } |
| 221 | |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 222 | sqlite3_shutdown(); |
| 223 | sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex); |
| 224 | sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem); |
dan | 22e21ff | 2011-11-08 20:08:44 | [diff] [blame] | 225 | sqlite3_config(SQLITE_CONFIG_PCACHE2, &wrapped.pcache); |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 226 | return TCL_OK; |
| 227 | } |
| 228 | |
mistachkin | 7617e4a | 2016-07-28 17:11:20 | [diff] [blame] | 229 | static int SQLITE_TCLAPI init_wrapper_clear( |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 230 | ClientData clientData, /* Unused */ |
| 231 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
| 232 | int objc, /* Number of arguments */ |
| 233 | Tcl_Obj *CONST objv[] /* Command arguments */ |
| 234 | ){ |
| 235 | if( objc!=1 ){ |
| 236 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 237 | return TCL_ERROR; |
| 238 | } |
| 239 | |
| 240 | wrapped.mem_fail = 0; |
| 241 | wrapped.mutex_fail = 0; |
| 242 | wrapped.pcache_fail = 0; |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 243 | return TCL_OK; |
| 244 | } |
| 245 | |
mistachkin | 7617e4a | 2016-07-28 17:11:20 | [diff] [blame] | 246 | static int SQLITE_TCLAPI init_wrapper_query( |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 247 | ClientData clientData, /* Unused */ |
| 248 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
| 249 | int objc, /* Number of arguments */ |
| 250 | Tcl_Obj *CONST objv[] /* Command arguments */ |
| 251 | ){ |
| 252 | Tcl_Obj *pRet; |
| 253 | |
| 254 | if( objc!=1 ){ |
| 255 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 256 | return TCL_ERROR; |
| 257 | } |
| 258 | |
| 259 | pRet = Tcl_NewObj(); |
| 260 | if( wrapped.mutex_init ){ |
| 261 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mutex", -1)); |
| 262 | } |
| 263 | if( wrapped.mem_init ){ |
| 264 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mem", -1)); |
| 265 | } |
| 266 | if( wrapped.pcache_init ){ |
| 267 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("pcache", -1)); |
| 268 | } |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 269 | |
| 270 | Tcl_SetObjResult(interp, pRet); |
| 271 | return TCL_OK; |
| 272 | } |
| 273 | |
dan | e1ab219 | 2009-08-17 15:16:19 | [diff] [blame] | 274 | int Sqlitetest_init_Init(Tcl_Interp *interp){ |
| 275 | static struct { |
| 276 | char *zName; |
| 277 | Tcl_ObjCmdProc *xProc; |
| 278 | } aObjCmd[] = { |
| 279 | {"init_wrapper_install", init_wrapper_install}, |
| 280 | {"init_wrapper_query", init_wrapper_query }, |
| 281 | {"init_wrapper_uninstall", init_wrapper_uninstall}, |
| 282 | {"init_wrapper_clear", init_wrapper_clear} |
| 283 | }; |
| 284 | int i; |
| 285 | |
| 286 | for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |
| 287 | Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); |
| 288 | } |
| 289 | |
| 290 | return TCL_OK; |
| 291 | } |