1 /*
2 ** 2013-06-12
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 ** A shim that sits between the SQLite virtual table interface and
14 ** runtimes with garbage collector based memory management.
15 */
16 #include "sqlite3ext.h"
17 SQLITE_EXTENSION_INIT1
18 #include <assert.h>
19 #include <string.h>
20 
21 #ifndef SQLITE_OMIT_VIRTUALTABLE
22 
23 /* Forward references */
24 typedef struct vtshim_aux vtshim_aux;
25 typedef struct vtshim_vtab vtshim_vtab;
26 typedef struct vtshim_cursor vtshim_cursor;
27 
28 
29 /* The vtshim_aux argument is the auxiliary parameter that is passed
30 ** into sqlite3_create_module_v2().
31 */
32 struct vtshim_aux {
33   void *pChildAux;              /* pAux for child virtual tables */
34   void (*xChildDestroy)(void*); /* Destructor for pChildAux */
35   sqlite3_module *pMod;         /* Methods for child virtual tables */
36   sqlite3 *db;                  /* The database to which we are attached */
37   char *zName;                  /* Name of the module */
38   int bDisposed;                /* True if disposed */
39   vtshim_vtab *pAllVtab;        /* List of all vtshim_vtab objects */
40   sqlite3_module sSelf;         /* Methods used by this shim */
41 };
42 
43 /* A vtshim virtual table object */
44 struct vtshim_vtab {
45   sqlite3_vtab base;       /* Base class - must be first */
46   sqlite3_vtab *pChild;    /* Child virtual table */
47   vtshim_aux *pAux;        /* Pointer to vtshim_aux object */
48   vtshim_cursor *pAllCur;  /* List of all cursors */
49   vtshim_vtab **ppPrev;    /* Previous on list */
50   vtshim_vtab *pNext;      /* Next on list */
51 };
52 
53 /* A vtshim cursor object */
54 struct vtshim_cursor {
55   sqlite3_vtab_cursor base;    /* Base class - must be first */
56   sqlite3_vtab_cursor *pChild; /* Cursor generated by the managed subclass */
57   vtshim_cursor **ppPrev;      /* Previous on list of all cursors */
58   vtshim_cursor *pNext;        /* Next on list of all cursors */
59 };
60 
61 /* Macro used to copy the child vtable error message to outer vtable */
62 #define VTSHIM_COPY_ERRMSG()                                             \
63   do {                                                                   \
64     sqlite3_free(pVtab->base.zErrMsg);                                   \
65     pVtab->base.zErrMsg = sqlite3_mprintf("%s", pVtab->pChild->zErrMsg); \
66   } while (0)
67 
68 /* Methods for the vtshim module */
vtshimCreate(sqlite3 * db,void * ppAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)69 static int vtshimCreate(
70   sqlite3 *db,
71   void *ppAux,
72   int argc,
73   const char *const*argv,
74   sqlite3_vtab **ppVtab,
75   char **pzErr
76 ){
77   vtshim_aux *pAux = (vtshim_aux*)ppAux;
78   vtshim_vtab *pNew;
79   int rc;
80 
81   assert( db==pAux->db );
82   if( pAux->bDisposed ){
83     if( pzErr ){
84       *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
85                                pAux->zName);
86     }
87     return SQLITE_ERROR;
88   }
89   pNew = sqlite3_malloc( sizeof(*pNew) );
90   *ppVtab = (sqlite3_vtab*)pNew;
91   if( pNew==0 ) return SQLITE_NOMEM;
92   memset(pNew, 0, sizeof(*pNew));
93   rc = pAux->pMod->xCreate(db, pAux->pChildAux, argc, argv,
94                            &pNew->pChild, pzErr);
95   if( rc ){
96     sqlite3_free(pNew);
97     *ppVtab = 0;
98     return rc;
99   }
100   pNew->pAux = pAux;
101   pNew->ppPrev = &pAux->pAllVtab;
102   pNew->pNext = pAux->pAllVtab;
103   if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
104   pAux->pAllVtab = pNew;
105   return rc;
106 }
107 
vtshimConnect(sqlite3 * db,void * ppAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)108 static int vtshimConnect(
109   sqlite3 *db,
110   void *ppAux,
111   int argc,
112   const char *const*argv,
113   sqlite3_vtab **ppVtab,
114   char **pzErr
115 ){
116   vtshim_aux *pAux = (vtshim_aux*)ppAux;
117   vtshim_vtab *pNew;
118   int rc;
119 
120   assert( db==pAux->db );
121   if( pAux->bDisposed ){
122     if( pzErr ){
123       *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
124                                pAux->zName);
125     }
126     return SQLITE_ERROR;
127   }
128   pNew = sqlite3_malloc( sizeof(*pNew) );
129   *ppVtab = (sqlite3_vtab*)pNew;
130   if( pNew==0 ) return SQLITE_NOMEM;
131   memset(pNew, 0, sizeof(*pNew));
132   rc = pAux->pMod->xConnect(db, pAux->pChildAux, argc, argv,
133                             &pNew->pChild, pzErr);
134   if( rc ){
135     sqlite3_free(pNew);
136     *ppVtab = 0;
137     return rc;
138   }
139   pNew->pAux = pAux;
140   pNew->ppPrev = &pAux->pAllVtab;
141   pNew->pNext = pAux->pAllVtab;
142   if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
143   pAux->pAllVtab = pNew;
144   return rc;
145 }
146 
vtshimBestIndex(sqlite3_vtab * pBase,sqlite3_index_info * pIdxInfo)147 static int vtshimBestIndex(
148   sqlite3_vtab *pBase,
149   sqlite3_index_info *pIdxInfo
150 ){
151   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
152   vtshim_aux *pAux = pVtab->pAux;
153   int rc;
154   if( pAux->bDisposed ) return SQLITE_ERROR;
155   rc = pAux->pMod->xBestIndex(pVtab->pChild, pIdxInfo);
156   if( rc!=SQLITE_OK ){
157     VTSHIM_COPY_ERRMSG();
158   }
159   return rc;
160 }
161 
vtshimDisconnect(sqlite3_vtab * pBase)162 static int vtshimDisconnect(sqlite3_vtab *pBase){
163   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
164   vtshim_aux *pAux = pVtab->pAux;
165   int rc = SQLITE_OK;
166   if( !pAux->bDisposed ){
167     rc = pAux->pMod->xDisconnect(pVtab->pChild);
168   }
169   if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
170   *pVtab->ppPrev = pVtab->pNext;
171   sqlite3_free(pVtab);
172   return rc;
173 }
174 
vtshimDestroy(sqlite3_vtab * pBase)175 static int vtshimDestroy(sqlite3_vtab *pBase){
176   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
177   vtshim_aux *pAux = pVtab->pAux;
178   int rc = SQLITE_OK;
179   if( !pAux->bDisposed ){
180     rc = pAux->pMod->xDestroy(pVtab->pChild);
181   }
182   if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
183   *pVtab->ppPrev = pVtab->pNext;
184   sqlite3_free(pVtab);
185   return rc;
186 }
187 
vtshimOpen(sqlite3_vtab * pBase,sqlite3_vtab_cursor ** ppCursor)188 static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
189   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
190   vtshim_aux *pAux = pVtab->pAux;
191   vtshim_cursor *pCur;
192   int rc;
193   *ppCursor = 0;
194   if( pAux->bDisposed ) return SQLITE_ERROR;
195   pCur = sqlite3_malloc( sizeof(*pCur) );
196   if( pCur==0 ) return SQLITE_NOMEM;
197   memset(pCur, 0, sizeof(*pCur));
198   rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
199   if( rc ){
200     sqlite3_free(pCur);
201     VTSHIM_COPY_ERRMSG();
202     return rc;
203   }
204   pCur->pChild->pVtab = pVtab->pChild;
205   *ppCursor = &pCur->base;
206   pCur->ppPrev = &pVtab->pAllCur;
207   if( pVtab->pAllCur ) pVtab->pAllCur->ppPrev = &pCur->pNext;
208   pCur->pNext = pVtab->pAllCur;
209   pVtab->pAllCur = pCur;
210   return SQLITE_OK;
211 }
212 
vtshimClose(sqlite3_vtab_cursor * pX)213 static int vtshimClose(sqlite3_vtab_cursor *pX){
214   vtshim_cursor *pCur = (vtshim_cursor*)pX;
215   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
216   vtshim_aux *pAux = pVtab->pAux;
217   int rc = SQLITE_OK;
218   if( !pAux->bDisposed ){
219     rc = pAux->pMod->xClose(pCur->pChild);
220     if( rc!=SQLITE_OK ){
221       VTSHIM_COPY_ERRMSG();
222     }
223   }
224   if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
225   *pCur->ppPrev = pCur->pNext;
226   sqlite3_free(pCur);
227   return rc;
228 }
229 
vtshimFilter(sqlite3_vtab_cursor * pX,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)230 static int vtshimFilter(
231   sqlite3_vtab_cursor *pX,
232   int idxNum,
233   const char *idxStr,
234   int argc,
235   sqlite3_value **argv
236 ){
237   vtshim_cursor *pCur = (vtshim_cursor*)pX;
238   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
239   vtshim_aux *pAux = pVtab->pAux;
240   int rc;
241   if( pAux->bDisposed ) return SQLITE_ERROR;
242   rc = pAux->pMod->xFilter(pCur->pChild, idxNum, idxStr, argc, argv);
243   if( rc!=SQLITE_OK ){
244     VTSHIM_COPY_ERRMSG();
245   }
246   return rc;
247 }
248 
vtshimNext(sqlite3_vtab_cursor * pX)249 static int vtshimNext(sqlite3_vtab_cursor *pX){
250   vtshim_cursor *pCur = (vtshim_cursor*)pX;
251   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
252   vtshim_aux *pAux = pVtab->pAux;
253   int rc;
254   if( pAux->bDisposed ) return SQLITE_ERROR;
255   rc = pAux->pMod->xNext(pCur->pChild);
256   if( rc!=SQLITE_OK ){
257     VTSHIM_COPY_ERRMSG();
258   }
259   return rc;
260 }
261 
vtshimEof(sqlite3_vtab_cursor * pX)262 static int vtshimEof(sqlite3_vtab_cursor *pX){
263   vtshim_cursor *pCur = (vtshim_cursor*)pX;
264   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
265   vtshim_aux *pAux = pVtab->pAux;
266   int rc;
267   if( pAux->bDisposed ) return 1;
268   rc = pAux->pMod->xEof(pCur->pChild);
269   VTSHIM_COPY_ERRMSG();
270   return rc;
271 }
272 
vtshimColumn(sqlite3_vtab_cursor * pX,sqlite3_context * ctx,int i)273 static int vtshimColumn(sqlite3_vtab_cursor *pX, sqlite3_context *ctx, int i){
274   vtshim_cursor *pCur = (vtshim_cursor*)pX;
275   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
276   vtshim_aux *pAux = pVtab->pAux;
277   int rc;
278   if( pAux->bDisposed ) return SQLITE_ERROR;
279   rc = pAux->pMod->xColumn(pCur->pChild, ctx, i);
280   if( rc!=SQLITE_OK ){
281     VTSHIM_COPY_ERRMSG();
282   }
283   return rc;
284 }
285 
vtshimRowid(sqlite3_vtab_cursor * pX,sqlite3_int64 * pRowid)286 static int vtshimRowid(sqlite3_vtab_cursor *pX, sqlite3_int64 *pRowid){
287   vtshim_cursor *pCur = (vtshim_cursor*)pX;
288   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
289   vtshim_aux *pAux = pVtab->pAux;
290   int rc;
291   if( pAux->bDisposed ) return SQLITE_ERROR;
292   rc = pAux->pMod->xRowid(pCur->pChild, pRowid);
293   if( rc!=SQLITE_OK ){
294     VTSHIM_COPY_ERRMSG();
295   }
296   return rc;
297 }
298 
vtshimUpdate(sqlite3_vtab * pBase,int argc,sqlite3_value ** argv,sqlite3_int64 * pRowid)299 static int vtshimUpdate(
300   sqlite3_vtab *pBase,
301   int argc,
302   sqlite3_value **argv,
303   sqlite3_int64 *pRowid
304 ){
305   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
306   vtshim_aux *pAux = pVtab->pAux;
307   int rc;
308   if( pAux->bDisposed ) return SQLITE_ERROR;
309   rc = pAux->pMod->xUpdate(pVtab->pChild, argc, argv, pRowid);
310   if( rc!=SQLITE_OK ){
311     VTSHIM_COPY_ERRMSG();
312   }
313   return rc;
314 }
315 
vtshimBegin(sqlite3_vtab * pBase)316 static int vtshimBegin(sqlite3_vtab *pBase){
317   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
318   vtshim_aux *pAux = pVtab->pAux;
319   int rc;
320   if( pAux->bDisposed ) return SQLITE_ERROR;
321   rc = pAux->pMod->xBegin(pVtab->pChild);
322   if( rc!=SQLITE_OK ){
323     VTSHIM_COPY_ERRMSG();
324   }
325   return rc;
326 }
327 
vtshimSync(sqlite3_vtab * pBase)328 static int vtshimSync(sqlite3_vtab *pBase){
329   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
330   vtshim_aux *pAux = pVtab->pAux;
331   int rc;
332   if( pAux->bDisposed ) return SQLITE_ERROR;
333   rc = pAux->pMod->xSync(pVtab->pChild);
334   if( rc!=SQLITE_OK ){
335     VTSHIM_COPY_ERRMSG();
336   }
337   return rc;
338 }
339 
vtshimCommit(sqlite3_vtab * pBase)340 static int vtshimCommit(sqlite3_vtab *pBase){
341   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
342   vtshim_aux *pAux = pVtab->pAux;
343   int rc;
344   if( pAux->bDisposed ) return SQLITE_ERROR;
345   rc = pAux->pMod->xCommit(pVtab->pChild);
346   if( rc!=SQLITE_OK ){
347     VTSHIM_COPY_ERRMSG();
348   }
349   return rc;
350 }
351 
vtshimRollback(sqlite3_vtab * pBase)352 static int vtshimRollback(sqlite3_vtab *pBase){
353   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
354   vtshim_aux *pAux = pVtab->pAux;
355   int rc;
356   if( pAux->bDisposed ) return SQLITE_ERROR;
357   rc = pAux->pMod->xRollback(pVtab->pChild);
358   if( rc!=SQLITE_OK ){
359     VTSHIM_COPY_ERRMSG();
360   }
361   return rc;
362 }
363 
vtshimFindFunction(sqlite3_vtab * pBase,int nArg,const char * zName,void (** pxFunc)(sqlite3_context *,int,sqlite3_value **),void ** ppArg)364 static int vtshimFindFunction(
365   sqlite3_vtab *pBase,
366   int nArg,
367   const char *zName,
368   void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
369   void **ppArg
370 ){
371   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
372   vtshim_aux *pAux = pVtab->pAux;
373   int rc;
374   if( pAux->bDisposed ) return 0;
375   rc = pAux->pMod->xFindFunction(pVtab->pChild, nArg, zName, pxFunc, ppArg);
376   VTSHIM_COPY_ERRMSG();
377   return rc;
378 }
379 
vtshimRename(sqlite3_vtab * pBase,const char * zNewName)380 static int vtshimRename(sqlite3_vtab *pBase, const char *zNewName){
381   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
382   vtshim_aux *pAux = pVtab->pAux;
383   int rc;
384   if( pAux->bDisposed ) return SQLITE_ERROR;
385   rc = pAux->pMod->xRename(pVtab->pChild, zNewName);
386   if( rc!=SQLITE_OK ){
387     VTSHIM_COPY_ERRMSG();
388   }
389   return rc;
390 }
391 
vtshimSavepoint(sqlite3_vtab * pBase,int n)392 static int vtshimSavepoint(sqlite3_vtab *pBase, int n){
393   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
394   vtshim_aux *pAux = pVtab->pAux;
395   int rc;
396   if( pAux->bDisposed ) return SQLITE_ERROR;
397   rc = pAux->pMod->xSavepoint(pVtab->pChild, n);
398   if( rc!=SQLITE_OK ){
399     VTSHIM_COPY_ERRMSG();
400   }
401   return rc;
402 }
403 
vtshimRelease(sqlite3_vtab * pBase,int n)404 static int vtshimRelease(sqlite3_vtab *pBase, int n){
405   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
406   vtshim_aux *pAux = pVtab->pAux;
407   int rc;
408   if( pAux->bDisposed ) return SQLITE_ERROR;
409   rc = pAux->pMod->xRelease(pVtab->pChild, n);
410   if( rc!=SQLITE_OK ){
411     VTSHIM_COPY_ERRMSG();
412   }
413   return rc;
414 }
415 
vtshimRollbackTo(sqlite3_vtab * pBase,int n)416 static int vtshimRollbackTo(sqlite3_vtab *pBase, int n){
417   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
418   vtshim_aux *pAux = pVtab->pAux;
419   int rc;
420   if( pAux->bDisposed ) return SQLITE_ERROR;
421   rc = pAux->pMod->xRollbackTo(pVtab->pChild, n);
422   if( rc!=SQLITE_OK ){
423     VTSHIM_COPY_ERRMSG();
424   }
425   return rc;
426 }
427 
428 /* The destructor function for a disposible module */
vtshimAuxDestructor(void * pXAux)429 static void vtshimAuxDestructor(void *pXAux){
430   vtshim_aux *pAux = (vtshim_aux*)pXAux;
431   assert( pAux->pAllVtab==0 );
432   if( !pAux->bDisposed && pAux->xChildDestroy ){
433     pAux->xChildDestroy(pAux->pChildAux);
434     pAux->xChildDestroy = 0;
435   }
436   sqlite3_free(pAux->zName);
437   sqlite3_free(pAux->pMod);
438   sqlite3_free(pAux);
439 }
440 
vtshimCopyModule(const sqlite3_module * pMod,sqlite3_module ** ppMod)441 static int vtshimCopyModule(
442   const sqlite3_module *pMod,   /* Source module to be copied */
443   sqlite3_module **ppMod        /* Destination for copied module */
444 ){
445   sqlite3_module *p;
446   if( !pMod || !ppMod ) return SQLITE_ERROR;
447   p = sqlite3_malloc( sizeof(*p) );
448   if( p==0 ) return SQLITE_NOMEM;
449   memcpy(p, pMod, sizeof(*p));
450   *ppMod = p;
451   return SQLITE_OK;
452 }
453 
454 #ifdef _WIN32
455 __declspec(dllexport)
456 #endif
sqlite3_create_disposable_module(sqlite3 * db,const char * zName,const sqlite3_module * p,void * pClientData,void (* xDestroy)(void *))457 void *sqlite3_create_disposable_module(
458   sqlite3 *db,               /* SQLite connection to register module with */
459   const char *zName,         /* Name of the module */
460   const sqlite3_module *p,   /* Methods for the module */
461   void *pClientData,         /* Client data for xCreate/xConnect */
462   void(*xDestroy)(void*)     /* Module destructor function */
463 ){
464   vtshim_aux *pAux;
465   sqlite3_module *pMod;
466   int rc;
467   pAux = sqlite3_malloc( sizeof(*pAux) );
468   if( pAux==0 ){
469     if( xDestroy ) xDestroy(pClientData);
470     return 0;
471   }
472   rc = vtshimCopyModule(p, &pMod);
473   if( rc!=SQLITE_OK ){
474     sqlite3_free(pAux);
475     return 0;
476   }
477   pAux->pChildAux = pClientData;
478   pAux->xChildDestroy = xDestroy;
479   pAux->pMod = pMod;
480   pAux->db = db;
481   pAux->zName = sqlite3_mprintf("%s", zName);
482   pAux->bDisposed = 0;
483   pAux->pAllVtab = 0;
484   pAux->sSelf.iVersion = p->iVersion<=2 ? p->iVersion : 2;
485   pAux->sSelf.xCreate = p->xCreate ? vtshimCreate : 0;
486   pAux->sSelf.xConnect = p->xConnect ? vtshimConnect : 0;
487   pAux->sSelf.xBestIndex = p->xBestIndex ? vtshimBestIndex : 0;
488   pAux->sSelf.xDisconnect = p->xDisconnect ? vtshimDisconnect : 0;
489   pAux->sSelf.xDestroy = p->xDestroy ? vtshimDestroy : 0;
490   pAux->sSelf.xOpen = p->xOpen ? vtshimOpen : 0;
491   pAux->sSelf.xClose = p->xClose ? vtshimClose : 0;
492   pAux->sSelf.xFilter = p->xFilter ? vtshimFilter : 0;
493   pAux->sSelf.xNext = p->xNext ? vtshimNext : 0;
494   pAux->sSelf.xEof = p->xEof ? vtshimEof : 0;
495   pAux->sSelf.xColumn = p->xColumn ? vtshimColumn : 0;
496   pAux->sSelf.xRowid = p->xRowid ? vtshimRowid : 0;
497   pAux->sSelf.xUpdate = p->xUpdate ? vtshimUpdate : 0;
498   pAux->sSelf.xBegin = p->xBegin ? vtshimBegin : 0;
499   pAux->sSelf.xSync = p->xSync ? vtshimSync : 0;
500   pAux->sSelf.xCommit = p->xCommit ? vtshimCommit : 0;
501   pAux->sSelf.xRollback = p->xRollback ? vtshimRollback : 0;
502   pAux->sSelf.xFindFunction = p->xFindFunction ? vtshimFindFunction : 0;
503   pAux->sSelf.xRename = p->xRename ? vtshimRename : 0;
504   if( p->iVersion>=2 ){
505     pAux->sSelf.xSavepoint = p->xSavepoint ? vtshimSavepoint : 0;
506     pAux->sSelf.xRelease = p->xRelease ? vtshimRelease : 0;
507     pAux->sSelf.xRollbackTo = p->xRollbackTo ? vtshimRollbackTo : 0;
508   }else{
509     pAux->sSelf.xSavepoint = 0;
510     pAux->sSelf.xRelease = 0;
511     pAux->sSelf.xRollbackTo = 0;
512   }
513   rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
514                                 pAux, vtshimAuxDestructor);
515   return rc==SQLITE_OK ? (void*)pAux : 0;
516 }
517 
518 #ifdef _WIN32
519 __declspec(dllexport)
520 #endif
sqlite3_dispose_module(void * pX)521 void sqlite3_dispose_module(void *pX){
522   vtshim_aux *pAux = (vtshim_aux*)pX;
523   if( !pAux->bDisposed ){
524     vtshim_vtab *pVtab;
525     vtshim_cursor *pCur;
526     for(pVtab=pAux->pAllVtab; pVtab; pVtab=pVtab->pNext){
527       for(pCur=pVtab->pAllCur; pCur; pCur=pCur->pNext){
528         pAux->pMod->xClose(pCur->pChild);
529       }
530       pAux->pMod->xDisconnect(pVtab->pChild);
531     }
532     pAux->bDisposed = 1;
533     if( pAux->xChildDestroy ){
534       pAux->xChildDestroy(pAux->pChildAux);
535       pAux->xChildDestroy = 0;
536     }
537   }
538 }
539 
540 
541 #endif /* SQLITE_OMIT_VIRTUALTABLE */
542 
543 #ifdef _WIN32
544 __declspec(dllexport)
545 #endif
sqlite3_vtshim_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)546 int sqlite3_vtshim_init(
547   sqlite3 *db,
548   char **pzErrMsg,
549   const sqlite3_api_routines *pApi
550 ){
551   SQLITE_EXTENSION_INIT2(pApi);
552   return SQLITE_OK;
553 }
554