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>
30 #if defined(INCLUDE_SQLITE_TCL_H)
31 #  include "sqlite_tcl.h"
32 #else
33 #  include "tcl.h"
34 #endif
35 
36 static struct Wrapped {
37   sqlite3_pcache_methods2 pcache;
38   sqlite3_mem_methods     mem;
39   sqlite3_mutex_methods   mutex;
40 
41   int mem_init;                /* True if mem subsystem is initalized */
42   int mem_fail;                /* True to fail mem subsystem inialization */
43   int mutex_init;              /* True if mutex subsystem is initalized */
44   int mutex_fail;              /* True to fail mutex subsystem inialization */
45   int pcache_init;             /* True if pcache subsystem is initalized */
46   int pcache_fail;             /* True to fail pcache subsystem inialization */
47 } wrapped;
48 
wrMemInit(void * pAppData)49 static int wrMemInit(void *pAppData){
50   int rc;
51   if( wrapped.mem_fail ){
52     rc = SQLITE_ERROR;
53   }else{
54     rc = wrapped.mem.xInit(wrapped.mem.pAppData);
55   }
56   if( rc==SQLITE_OK ){
57     wrapped.mem_init = 1;
58   }
59   return rc;
60 }
wrMemShutdown(void * pAppData)61 static void wrMemShutdown(void *pAppData){
62   wrapped.mem.xShutdown(wrapped.mem.pAppData);
63   wrapped.mem_init = 0;
64 }
wrMemMalloc(int n)65 static void *wrMemMalloc(int n)           {return wrapped.mem.xMalloc(n);}
wrMemFree(void * p)66 static void wrMemFree(void *p)            {wrapped.mem.xFree(p);}
wrMemRealloc(void * p,int n)67 static void *wrMemRealloc(void *p, int n) {return wrapped.mem.xRealloc(p, n);}
wrMemSize(void * p)68 static int wrMemSize(void *p)             {return wrapped.mem.xSize(p);}
wrMemRoundup(int n)69 static int wrMemRoundup(int n)            {return wrapped.mem.xRoundup(n);}
70 
71 
wrMutexInit(void)72 static int wrMutexInit(void){
73   int rc;
74   if( wrapped.mutex_fail ){
75     rc = SQLITE_ERROR;
76   }else{
77     rc = wrapped.mutex.xMutexInit();
78   }
79   if( rc==SQLITE_OK ){
80     wrapped.mutex_init = 1;
81   }
82   return rc;
83 }
wrMutexEnd(void)84 static int wrMutexEnd(void){
85   wrapped.mutex.xMutexEnd();
86   wrapped.mutex_init = 0;
87   return SQLITE_OK;
88 }
wrMutexAlloc(int e)89 static sqlite3_mutex *wrMutexAlloc(int e){
90   return wrapped.mutex.xMutexAlloc(e);
91 }
wrMutexFree(sqlite3_mutex * p)92 static void wrMutexFree(sqlite3_mutex *p){
93   wrapped.mutex.xMutexFree(p);
94 }
wrMutexEnter(sqlite3_mutex * p)95 static void wrMutexEnter(sqlite3_mutex *p){
96   wrapped.mutex.xMutexEnter(p);
97 }
wrMutexTry(sqlite3_mutex * p)98 static int wrMutexTry(sqlite3_mutex *p){
99   return wrapped.mutex.xMutexTry(p);
100 }
wrMutexLeave(sqlite3_mutex * p)101 static void wrMutexLeave(sqlite3_mutex *p){
102   wrapped.mutex.xMutexLeave(p);
103 }
wrMutexHeld(sqlite3_mutex * p)104 static int wrMutexHeld(sqlite3_mutex *p){
105   return wrapped.mutex.xMutexHeld(p);
106 }
wrMutexNotheld(sqlite3_mutex * p)107 static int wrMutexNotheld(sqlite3_mutex *p){
108   return wrapped.mutex.xMutexNotheld(p);
109 }
110 
111 
112 
wrPCacheInit(void * pArg)113 static int wrPCacheInit(void *pArg){
114   int rc;
115   if( wrapped.pcache_fail ){
116     rc = SQLITE_ERROR;
117   }else{
118     rc = wrapped.pcache.xInit(wrapped.pcache.pArg);
119   }
120   if( rc==SQLITE_OK ){
121     wrapped.pcache_init = 1;
122   }
123   return rc;
124 }
wrPCacheShutdown(void * pArg)125 static void wrPCacheShutdown(void *pArg){
126   wrapped.pcache.xShutdown(wrapped.pcache.pArg);
127   wrapped.pcache_init = 0;
128 }
129 
wrPCacheCreate(int a,int b,int c)130 static sqlite3_pcache *wrPCacheCreate(int a, int b, int c){
131   return wrapped.pcache.xCreate(a, b, c);
132 }
wrPCacheCachesize(sqlite3_pcache * p,int n)133 static void wrPCacheCachesize(sqlite3_pcache *p, int n){
134   wrapped.pcache.xCachesize(p, n);
135 }
wrPCachePagecount(sqlite3_pcache * p)136 static int wrPCachePagecount(sqlite3_pcache *p){
137   return wrapped.pcache.xPagecount(p);
138 }
wrPCacheFetch(sqlite3_pcache * p,unsigned a,int b)139 static sqlite3_pcache_page *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){
140   return wrapped.pcache.xFetch(p, a, b);
141 }
wrPCacheUnpin(sqlite3_pcache * p,sqlite3_pcache_page * a,int b)142 static void wrPCacheUnpin(sqlite3_pcache *p, sqlite3_pcache_page *a, int b){
143   wrapped.pcache.xUnpin(p, a, b);
144 }
wrPCacheRekey(sqlite3_pcache * p,sqlite3_pcache_page * a,unsigned b,unsigned c)145 static void wrPCacheRekey(
146   sqlite3_pcache *p,
147   sqlite3_pcache_page *a,
148   unsigned b,
149   unsigned c
150 ){
151   wrapped.pcache.xRekey(p, a, b, c);
152 }
wrPCacheTruncate(sqlite3_pcache * p,unsigned a)153 static void wrPCacheTruncate(sqlite3_pcache *p, unsigned a){
154   wrapped.pcache.xTruncate(p, a);
155 }
wrPCacheDestroy(sqlite3_pcache * p)156 static void wrPCacheDestroy(sqlite3_pcache *p){
157   wrapped.pcache.xDestroy(p);
158 }
159 
installInitWrappers(void)160 static void installInitWrappers(void){
161   sqlite3_mutex_methods mutexmethods = {
162     wrMutexInit,  wrMutexEnd,   wrMutexAlloc,
163     wrMutexFree,  wrMutexEnter, wrMutexTry,
164     wrMutexLeave, wrMutexHeld,  wrMutexNotheld
165   };
166   sqlite3_pcache_methods2 pcachemethods = {
167     1, 0,
168     wrPCacheInit,      wrPCacheShutdown,  wrPCacheCreate,
169     wrPCacheCachesize, wrPCachePagecount, wrPCacheFetch,
170     wrPCacheUnpin,     wrPCacheRekey,     wrPCacheTruncate,
171     wrPCacheDestroy
172   };
173   sqlite3_mem_methods memmethods = {
174     wrMemMalloc,   wrMemFree,    wrMemRealloc,
175     wrMemSize,     wrMemRoundup, wrMemInit,
176     wrMemShutdown,
177     0
178   };
179 
180   memset(&wrapped, 0, sizeof(wrapped));
181 
182   sqlite3_shutdown();
183   sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex);
184   sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem);
185   sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &wrapped.pcache);
186   sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods);
187   sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods);
188   sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods);
189 }
190 
init_wrapper_install(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])191 static int SQLITE_TCLAPI init_wrapper_install(
192   ClientData clientData, /* Unused */
193   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
194   int objc,              /* Number of arguments */
195   Tcl_Obj *CONST objv[]  /* Command arguments */
196 ){
197   int i;
198   installInitWrappers();
199   for(i=1; i<objc; i++){
200     char *z = Tcl_GetString(objv[i]);
201     if( strcmp(z, "mem")==0 ){
202       wrapped.mem_fail = 1;
203     }else if( strcmp(z, "mutex")==0 ){
204       wrapped.mutex_fail = 1;
205     }else if( strcmp(z, "pcache")==0 ){
206       wrapped.pcache_fail = 1;
207     }else{
208       Tcl_AppendResult(interp, "Unknown argument: \"", z, "\"");
209       return TCL_ERROR;
210     }
211   }
212   return TCL_OK;
213 }
214 
init_wrapper_uninstall(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])215 static int SQLITE_TCLAPI init_wrapper_uninstall(
216   ClientData clientData, /* Unused */
217   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
218   int objc,              /* Number of arguments */
219   Tcl_Obj *CONST objv[]  /* Command arguments */
220 ){
221   if( objc!=1 ){
222     Tcl_WrongNumArgs(interp, 1, objv, "");
223     return TCL_ERROR;
224   }
225 
226   sqlite3_shutdown();
227   sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex);
228   sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem);
229   sqlite3_config(SQLITE_CONFIG_PCACHE2, &wrapped.pcache);
230   return TCL_OK;
231 }
232 
init_wrapper_clear(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])233 static int SQLITE_TCLAPI init_wrapper_clear(
234   ClientData clientData, /* Unused */
235   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
236   int objc,              /* Number of arguments */
237   Tcl_Obj *CONST objv[]  /* Command arguments */
238 ){
239   if( objc!=1 ){
240     Tcl_WrongNumArgs(interp, 1, objv, "");
241     return TCL_ERROR;
242   }
243 
244   wrapped.mem_fail = 0;
245   wrapped.mutex_fail = 0;
246   wrapped.pcache_fail = 0;
247   return TCL_OK;
248 }
249 
init_wrapper_query(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])250 static int SQLITE_TCLAPI init_wrapper_query(
251   ClientData clientData, /* Unused */
252   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
253   int objc,              /* Number of arguments */
254   Tcl_Obj *CONST objv[]  /* Command arguments */
255 ){
256   Tcl_Obj *pRet;
257 
258   if( objc!=1 ){
259     Tcl_WrongNumArgs(interp, 1, objv, "");
260     return TCL_ERROR;
261   }
262 
263   pRet = Tcl_NewObj();
264   if( wrapped.mutex_init ){
265     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mutex", -1));
266   }
267   if( wrapped.mem_init ){
268     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mem", -1));
269   }
270   if( wrapped.pcache_init ){
271     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("pcache", -1));
272   }
273 
274   Tcl_SetObjResult(interp, pRet);
275   return TCL_OK;
276 }
277 
Sqlitetest_init_Init(Tcl_Interp * interp)278 int Sqlitetest_init_Init(Tcl_Interp *interp){
279   static struct {
280      char *zName;
281      Tcl_ObjCmdProc *xProc;
282   } aObjCmd[] = {
283     {"init_wrapper_install",   init_wrapper_install},
284     {"init_wrapper_query",     init_wrapper_query  },
285     {"init_wrapper_uninstall", init_wrapper_uninstall},
286     {"init_wrapper_clear",     init_wrapper_clear}
287   };
288   int i;
289 
290   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
291     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
292   }
293 
294   return TCL_OK;
295 }
296