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