xref: /sqlite-3.40.0/ext/misc/vtshim.c (revision 962f9669)
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 */
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   }
99   pNew->pAux = pAux;
100   pNew->ppPrev = &pAux->pAllVtab;
101   pNew->pNext = pAux->pAllVtab;
102   if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
103   pAux->pAllVtab = pNew;
104   return rc;
105 }
106 
107 static int vtshimConnect(
108   sqlite3 *db,
109   void *ppAux,
110   int argc,
111   const char *const*argv,
112   sqlite3_vtab **ppVtab,
113   char **pzErr
114 ){
115   vtshim_aux *pAux = (vtshim_aux*)ppAux;
116   vtshim_vtab *pNew;
117   int rc;
118 
119   assert( db==pAux->db );
120   if( pAux->bDisposed ){
121     if( pzErr ){
122       *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
123                                pAux->zName);
124     }
125     return SQLITE_ERROR;
126   }
127   pNew = sqlite3_malloc( sizeof(*pNew) );
128   *ppVtab = (sqlite3_vtab*)pNew;
129   if( pNew==0 ) return SQLITE_NOMEM;
130   memset(pNew, 0, sizeof(*pNew));
131   rc = pAux->pMod->xConnect(db, pAux->pChildAux, argc, argv,
132                             &pNew->pChild, pzErr);
133   if( rc ){
134     sqlite3_free(pNew);
135     *ppVtab = 0;
136   }
137   pNew->pAux = pAux;
138   pNew->ppPrev = &pAux->pAllVtab;
139   pNew->pNext = pAux->pAllVtab;
140   if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext;
141   pAux->pAllVtab = pNew;
142   return rc;
143 }
144 
145 static int vtshimBestIndex(
146   sqlite3_vtab *pBase,
147   sqlite3_index_info *pIdxInfo
148 ){
149   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
150   vtshim_aux *pAux = pVtab->pAux;
151   int rc;
152   if( pAux->bDisposed ) return SQLITE_ERROR;
153   rc = pAux->pMod->xBestIndex(pVtab->pChild, pIdxInfo);
154   if( rc!=SQLITE_OK ){
155     VTSHIM_COPY_ERRMSG();
156   }
157   return rc;
158 }
159 
160 static int vtshimDisconnect(sqlite3_vtab *pBase){
161   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
162   vtshim_aux *pAux = pVtab->pAux;
163   int rc = SQLITE_OK;
164   if( !pAux->bDisposed ){
165     rc = pAux->pMod->xDisconnect(pVtab->pChild);
166   }
167   if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
168   *pVtab->ppPrev = pVtab->pNext;
169   sqlite3_free(pVtab);
170   return rc;
171 }
172 
173 static int vtshimDestroy(sqlite3_vtab *pBase){
174   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
175   vtshim_aux *pAux = pVtab->pAux;
176   int rc = SQLITE_OK;
177   if( !pAux->bDisposed ){
178     rc = pAux->pMod->xDestroy(pVtab->pChild);
179   }
180   if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
181   *pVtab->ppPrev = pVtab->pNext;
182   sqlite3_free(pVtab);
183   return rc;
184 }
185 
186 static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
187   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
188   vtshim_aux *pAux = pVtab->pAux;
189   vtshim_cursor *pCur;
190   int rc;
191   *ppCursor = 0;
192   if( pAux->bDisposed ) return SQLITE_ERROR;
193   pCur = sqlite3_malloc( sizeof(*pCur) );
194   if( pCur==0 ) return SQLITE_NOMEM;
195   memset(pCur, 0, sizeof(*pCur));
196   rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
197   if( rc ){
198     sqlite3_free(pCur);
199     VTSHIM_COPY_ERRMSG();
200     return rc;
201   }
202   pCur->pChild->pVtab = pVtab->pChild;
203   *ppCursor = &pCur->base;
204   pCur->ppPrev = &pVtab->pAllCur;
205   if( pVtab->pAllCur ) pVtab->pAllCur->ppPrev = &pCur->pNext;
206   pCur->pNext = pVtab->pAllCur;
207   pVtab->pAllCur = pCur;
208   return SQLITE_OK;
209 }
210 
211 static int vtshimClose(sqlite3_vtab_cursor *pX){
212   vtshim_cursor *pCur = (vtshim_cursor*)pX;
213   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
214   vtshim_aux *pAux = pVtab->pAux;
215   int rc = SQLITE_OK;
216   if( !pAux->bDisposed ){
217     rc = pAux->pMod->xClose(pCur->pChild);
218     if( rc!=SQLITE_OK ){
219       VTSHIM_COPY_ERRMSG();
220     }
221   }
222   if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
223   *pCur->ppPrev = pCur->pNext;
224   sqlite3_free(pCur);
225   return rc;
226 }
227 
228 static int vtshimFilter(
229   sqlite3_vtab_cursor *pX,
230   int idxNum,
231   const char *idxStr,
232   int argc,
233   sqlite3_value **argv
234 ){
235   vtshim_cursor *pCur = (vtshim_cursor*)pX;
236   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
237   vtshim_aux *pAux = pVtab->pAux;
238   int rc;
239   if( pAux->bDisposed ) return SQLITE_ERROR;
240   rc = pAux->pMod->xFilter(pCur->pChild, idxNum, idxStr, argc, argv);
241   if( rc!=SQLITE_OK ){
242     VTSHIM_COPY_ERRMSG();
243   }
244   return rc;
245 }
246 
247 static int vtshimNext(sqlite3_vtab_cursor *pX){
248   vtshim_cursor *pCur = (vtshim_cursor*)pX;
249   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
250   vtshim_aux *pAux = pVtab->pAux;
251   int rc;
252   if( pAux->bDisposed ) return SQLITE_ERROR;
253   rc = pAux->pMod->xNext(pCur->pChild);
254   if( rc!=SQLITE_OK ){
255     VTSHIM_COPY_ERRMSG();
256   }
257   return rc;
258 }
259 
260 static int vtshimEof(sqlite3_vtab_cursor *pX){
261   vtshim_cursor *pCur = (vtshim_cursor*)pX;
262   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
263   vtshim_aux *pAux = pVtab->pAux;
264   int rc;
265   if( pAux->bDisposed ) return 1;
266   rc = pAux->pMod->xEof(pCur->pChild);
267   VTSHIM_COPY_ERRMSG();
268   return rc;
269 }
270 
271 static int vtshimColumn(sqlite3_vtab_cursor *pX, sqlite3_context *ctx, int i){
272   vtshim_cursor *pCur = (vtshim_cursor*)pX;
273   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
274   vtshim_aux *pAux = pVtab->pAux;
275   int rc;
276   if( pAux->bDisposed ) return SQLITE_ERROR;
277   rc = pAux->pMod->xColumn(pCur->pChild, ctx, i);
278   if( rc!=SQLITE_OK ){
279     VTSHIM_COPY_ERRMSG();
280   }
281   return rc;
282 }
283 
284 static int vtshimRowid(sqlite3_vtab_cursor *pX, sqlite3_int64 *pRowid){
285   vtshim_cursor *pCur = (vtshim_cursor*)pX;
286   vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab;
287   vtshim_aux *pAux = pVtab->pAux;
288   int rc;
289   if( pAux->bDisposed ) return SQLITE_ERROR;
290   rc = pAux->pMod->xRowid(pCur->pChild, pRowid);
291   if( rc!=SQLITE_OK ){
292     VTSHIM_COPY_ERRMSG();
293   }
294   return rc;
295 }
296 
297 static int vtshimUpdate(
298   sqlite3_vtab *pBase,
299   int argc,
300   sqlite3_value **argv,
301   sqlite3_int64 *pRowid
302 ){
303   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
304   vtshim_aux *pAux = pVtab->pAux;
305   int rc;
306   if( pAux->bDisposed ) return SQLITE_ERROR;
307   rc = pAux->pMod->xUpdate(pVtab->pChild, argc, argv, pRowid);
308   if( rc!=SQLITE_OK ){
309     VTSHIM_COPY_ERRMSG();
310   }
311   return rc;
312 }
313 
314 static int vtshimBegin(sqlite3_vtab *pBase){
315   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
316   vtshim_aux *pAux = pVtab->pAux;
317   int rc;
318   if( pAux->bDisposed ) return SQLITE_ERROR;
319   rc = pAux->pMod->xBegin(pVtab->pChild);
320   if( rc!=SQLITE_OK ){
321     VTSHIM_COPY_ERRMSG();
322   }
323   return rc;
324 }
325 
326 static int vtshimSync(sqlite3_vtab *pBase){
327   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
328   vtshim_aux *pAux = pVtab->pAux;
329   int rc;
330   if( pAux->bDisposed ) return SQLITE_ERROR;
331   rc = pAux->pMod->xSync(pVtab->pChild);
332   if( rc!=SQLITE_OK ){
333     VTSHIM_COPY_ERRMSG();
334   }
335   return rc;
336 }
337 
338 static int vtshimCommit(sqlite3_vtab *pBase){
339   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
340   vtshim_aux *pAux = pVtab->pAux;
341   int rc;
342   if( pAux->bDisposed ) return SQLITE_ERROR;
343   rc = pAux->pMod->xCommit(pVtab->pChild);
344   if( rc!=SQLITE_OK ){
345     VTSHIM_COPY_ERRMSG();
346   }
347   return rc;
348 }
349 
350 static int vtshimRollback(sqlite3_vtab *pBase){
351   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
352   vtshim_aux *pAux = pVtab->pAux;
353   int rc;
354   if( pAux->bDisposed ) return SQLITE_ERROR;
355   rc = pAux->pMod->xRollback(pVtab->pChild);
356   if( rc!=SQLITE_OK ){
357     VTSHIM_COPY_ERRMSG();
358   }
359   return rc;
360 }
361 
362 static int vtshimFindFunction(
363   sqlite3_vtab *pBase,
364   int nArg,
365   const char *zName,
366   void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
367   void **ppArg
368 ){
369   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
370   vtshim_aux *pAux = pVtab->pAux;
371   int rc;
372   if( pAux->bDisposed ) return 0;
373   rc = pAux->pMod->xFindFunction(pVtab->pChild, nArg, zName, pxFunc, ppArg);
374   VTSHIM_COPY_ERRMSG();
375   return rc;
376 }
377 
378 static int vtshimRename(sqlite3_vtab *pBase, const char *zNewName){
379   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
380   vtshim_aux *pAux = pVtab->pAux;
381   int rc;
382   if( pAux->bDisposed ) return SQLITE_ERROR;
383   rc = pAux->pMod->xRename(pVtab->pChild, zNewName);
384   if( rc!=SQLITE_OK ){
385     VTSHIM_COPY_ERRMSG();
386   }
387   return rc;
388 }
389 
390 static int vtshimSavepoint(sqlite3_vtab *pBase, int n){
391   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
392   vtshim_aux *pAux = pVtab->pAux;
393   int rc;
394   if( pAux->bDisposed ) return SQLITE_ERROR;
395   rc = pAux->pMod->xSavepoint(pVtab->pChild, n);
396   if( rc!=SQLITE_OK ){
397     VTSHIM_COPY_ERRMSG();
398   }
399   return rc;
400 }
401 
402 static int vtshimRelease(sqlite3_vtab *pBase, int n){
403   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
404   vtshim_aux *pAux = pVtab->pAux;
405   int rc;
406   if( pAux->bDisposed ) return SQLITE_ERROR;
407   rc = pAux->pMod->xRelease(pVtab->pChild, n);
408   if( rc!=SQLITE_OK ){
409     VTSHIM_COPY_ERRMSG();
410   }
411   return rc;
412 }
413 
414 static int vtshimRollbackTo(sqlite3_vtab *pBase, int n){
415   vtshim_vtab *pVtab = (vtshim_vtab*)pBase;
416   vtshim_aux *pAux = pVtab->pAux;
417   int rc;
418   if( pAux->bDisposed ) return SQLITE_ERROR;
419   rc = pAux->pMod->xRollbackTo(pVtab->pChild, n);
420   if( rc!=SQLITE_OK ){
421     VTSHIM_COPY_ERRMSG();
422   }
423   return rc;
424 }
425 
426 /* The destructor function for a disposible module */
427 static void vtshimAuxDestructor(void *pXAux){
428   vtshim_aux *pAux = (vtshim_aux*)pXAux;
429   assert( pAux->pAllVtab==0 );
430   if( !pAux->bDisposed && pAux->xChildDestroy ){
431     pAux->xChildDestroy(pAux->pChildAux);
432     pAux->xChildDestroy = 0;
433   }
434   sqlite3_free(pAux->zName);
435   sqlite3_free(pAux->pMod);
436   sqlite3_free(pAux);
437 }
438 
439 static int vtshimCopyModule(
440   const sqlite3_module *pMod,   /* Source module to be copied */
441   sqlite3_module **ppMod        /* Destination for copied module */
442 ){
443   sqlite3_module *p;
444   if( !pMod || !ppMod ) return SQLITE_ERROR;
445   p = sqlite3_malloc( sizeof(*p) );
446   if( p==0 ) return SQLITE_NOMEM;
447   memcpy(p, pMod, sizeof(*p));
448   *ppMod = p;
449   return SQLITE_OK;
450 }
451 
452 #ifdef _WIN32
453 __declspec(dllexport)
454 #endif
455 void *sqlite3_create_disposable_module(
456   sqlite3 *db,               /* SQLite connection to register module with */
457   const char *zName,         /* Name of the module */
458   const sqlite3_module *p,   /* Methods for the module */
459   void *pClientData,         /* Client data for xCreate/xConnect */
460   void(*xDestroy)(void*)     /* Module destructor function */
461 ){
462   vtshim_aux *pAux;
463   sqlite3_module *pMod;
464   int rc;
465   pAux = sqlite3_malloc( sizeof(*pAux) );
466   if( pAux==0 ){
467     if( xDestroy ) xDestroy(pClientData);
468     return 0;
469   }
470   rc = vtshimCopyModule(p, &pMod);
471   if( rc!=SQLITE_OK ){
472     sqlite3_free(pAux);
473     return 0;
474   }
475   pAux->pChildAux = pClientData;
476   pAux->xChildDestroy = xDestroy;
477   pAux->pMod = pMod;
478   pAux->db = db;
479   pAux->zName = sqlite3_mprintf("%s", zName);
480   pAux->bDisposed = 0;
481   pAux->pAllVtab = 0;
482   pAux->sSelf.iVersion = p->iVersion<=2 ? p->iVersion : 2;
483   pAux->sSelf.xCreate = p->xCreate ? vtshimCreate : 0;
484   pAux->sSelf.xConnect = p->xConnect ? vtshimConnect : 0;
485   pAux->sSelf.xBestIndex = p->xBestIndex ? vtshimBestIndex : 0;
486   pAux->sSelf.xDisconnect = p->xDisconnect ? vtshimDisconnect : 0;
487   pAux->sSelf.xDestroy = p->xDestroy ? vtshimDestroy : 0;
488   pAux->sSelf.xOpen = p->xOpen ? vtshimOpen : 0;
489   pAux->sSelf.xClose = p->xClose ? vtshimClose : 0;
490   pAux->sSelf.xFilter = p->xFilter ? vtshimFilter : 0;
491   pAux->sSelf.xNext = p->xNext ? vtshimNext : 0;
492   pAux->sSelf.xEof = p->xEof ? vtshimEof : 0;
493   pAux->sSelf.xColumn = p->xColumn ? vtshimColumn : 0;
494   pAux->sSelf.xRowid = p->xRowid ? vtshimRowid : 0;
495   pAux->sSelf.xUpdate = p->xUpdate ? vtshimUpdate : 0;
496   pAux->sSelf.xBegin = p->xBegin ? vtshimBegin : 0;
497   pAux->sSelf.xSync = p->xSync ? vtshimSync : 0;
498   pAux->sSelf.xCommit = p->xCommit ? vtshimCommit : 0;
499   pAux->sSelf.xRollback = p->xRollback ? vtshimRollback : 0;
500   pAux->sSelf.xFindFunction = p->xFindFunction ? vtshimFindFunction : 0;
501   pAux->sSelf.xRename = p->xRename ? vtshimRename : 0;
502   if( p->iVersion>=2 ){
503     pAux->sSelf.xSavepoint = p->xSavepoint ? vtshimSavepoint : 0;
504     pAux->sSelf.xRelease = p->xRelease ? vtshimRelease : 0;
505     pAux->sSelf.xRollbackTo = p->xRollbackTo ? vtshimRollbackTo : 0;
506   }else{
507     pAux->sSelf.xSavepoint = 0;
508     pAux->sSelf.xRelease = 0;
509     pAux->sSelf.xRollbackTo = 0;
510   }
511   rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
512                                 pAux, vtshimAuxDestructor);
513   return rc==SQLITE_OK ? (void*)pAux : 0;
514 }
515 
516 #ifdef _WIN32
517 __declspec(dllexport)
518 #endif
519 void sqlite3_dispose_module(void *pX){
520   vtshim_aux *pAux = (vtshim_aux*)pX;
521   if( !pAux->bDisposed ){
522     vtshim_vtab *pVtab;
523     vtshim_cursor *pCur;
524     for(pVtab=pAux->pAllVtab; pVtab; pVtab=pVtab->pNext){
525       for(pCur=pVtab->pAllCur; pCur; pCur=pCur->pNext){
526         pAux->pMod->xClose(pCur->pChild);
527       }
528       pAux->pMod->xDisconnect(pVtab->pChild);
529     }
530     pAux->bDisposed = 1;
531     if( pAux->xChildDestroy ){
532       pAux->xChildDestroy(pAux->pChildAux);
533       pAux->xChildDestroy = 0;
534     }
535   }
536 }
537 
538 
539 #endif /* SQLITE_OMIT_VIRTUALTABLE */
540 
541 #ifdef _WIN32
542 __declspec(dllexport)
543 #endif
544 int sqlite3_vtshim_init(
545   sqlite3 *db,
546   char **pzErrMsg,
547   const sqlite3_api_routines *pApi
548 ){
549   SQLITE_EXTENSION_INIT2(pApi);
550   return SQLITE_OK;
551 }
552