Enhance the command-line completion extension to return the names of
[sqlite.git] / ext / misc / vtshim.c
blob0709a26a7f16a6969dddbd4a28eb4670eedea316
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.
11 *************************************************************************
13 ** A shim that sits between the SQLite virtual table interface and
14 ** runtimes with garbage collector based memory management.
16 #include "sqlite3ext.h"
17 SQLITE_EXTENSION_INIT1
18 #include <assert.h>
19 #include <string.h>
21 #ifndef SQLITE_OMIT_VIRTUALTABLE
23 /* Forward references */
24 typedef struct vtshim_aux vtshim_aux;
25 typedef struct vtshim_vtab vtshim_vtab;
26 typedef struct vtshim_cursor vtshim_cursor;
29 /* The vtshim_aux argument is the auxiliary parameter that is passed
30 ** into sqlite3_create_module_v2().
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 */
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 */
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 */
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)
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
77 vtshim_aux *pAux = (vtshim_aux*)ppAux;
78 vtshim_vtab *pNew;
79 int rc;
81 assert( db==pAux->db );
82 if( pAux->bDisposed ){
83 if( pzErr ){
84 *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
85 pAux->zName);
87 return SQLITE_ERROR;
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;
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;
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
116 vtshim_aux *pAux = (vtshim_aux*)ppAux;
117 vtshim_vtab *pNew;
118 int rc;
120 assert( db==pAux->db );
121 if( pAux->bDisposed ){
122 if( pzErr ){
123 *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
124 pAux->zName);
126 return SQLITE_ERROR;
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;
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;
147 static int vtshimBestIndex(
148 sqlite3_vtab *pBase,
149 sqlite3_index_info *pIdxInfo
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();
159 return rc;
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);
169 if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
170 *pVtab->ppPrev = pVtab->pNext;
171 sqlite3_free(pVtab);
172 return rc;
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);
182 if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
183 *pVtab->ppPrev = pVtab->pNext;
184 sqlite3_free(pVtab);
185 return rc;
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;
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;
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();
224 if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
225 *pCur->ppPrev = pCur->pNext;
226 sqlite3_free(pCur);
227 return rc;
230 static int vtshimFilter(
231 sqlite3_vtab_cursor *pX,
232 int idxNum,
233 const char *idxStr,
234 int argc,
235 sqlite3_value **argv
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();
246 return rc;
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();
259 return rc;
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;
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();
283 return rc;
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();
296 return rc;
299 static int vtshimUpdate(
300 sqlite3_vtab *pBase,
301 int argc,
302 sqlite3_value **argv,
303 sqlite3_int64 *pRowid
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();
313 return rc;
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();
325 return rc;
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();
337 return rc;
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();
349 return rc;
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();
361 return rc;
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
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;
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();
389 return rc;
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();
401 return rc;
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();
413 return rc;
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();
425 return rc;
428 /* The destructor function for a disposible module */
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;
436 sqlite3_free(pAux->zName);
437 sqlite3_free(pAux->pMod);
438 sqlite3_free(pAux);
441 static int vtshimCopyModule(
442 const sqlite3_module *pMod, /* Source module to be copied */
443 sqlite3_module **ppMod /* Destination for copied module */
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;
454 #ifdef _WIN32
455 __declspec(dllexport)
456 #endif
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 */
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;
472 rc = vtshimCopyModule(p, &pMod);
473 if( rc!=SQLITE_OK ){
474 sqlite3_free(pAux);
475 return 0;
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;
513 rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
514 pAux, vtshimAuxDestructor);
515 return rc==SQLITE_OK ? (void*)pAux : 0;
518 #ifdef _WIN32
519 __declspec(dllexport)
520 #endif
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);
530 pAux->pMod->xDisconnect(pVtab->pChild);
532 pAux->bDisposed = 1;
533 if( pAux->xChildDestroy ){
534 pAux->xChildDestroy(pAux->pChildAux);
535 pAux->xChildDestroy = 0;
541 #endif /* SQLITE_OMIT_VIRTUALTABLE */
543 #ifdef _WIN32
544 __declspec(dllexport)
545 #endif
546 int sqlite3_vtshim_init(
547 sqlite3 *db,
548 char **pzErrMsg,
549 const sqlite3_api_routines *pApi
551 SQLITE_EXTENSION_INIT2(pApi);
552 return SQLITE_OK;