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