4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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
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().
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 */
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() \
64 sqlite3_free(pVtab->base.zErrMsg); \
65 pVtab->base.zErrMsg = sqlite3_mprintf("%s", pVtab->pChild->zErrMsg); \
68 /* Methods for the vtshim module */
69 static int vtshimCreate(
73 const char *const*argv
,
74 sqlite3_vtab
**ppVtab
,
77 vtshim_aux
*pAux
= (vtshim_aux
*)ppAux
;
81 assert( db
==pAux
->db
);
82 if( pAux
->bDisposed
){
84 *pzErr
= sqlite3_mprintf("virtual table was disposed: \"%s\"",
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
);
101 pNew
->ppPrev
= &pAux
->pAllVtab
;
102 pNew
->pNext
= pAux
->pAllVtab
;
103 if( pAux
->pAllVtab
) pAux
->pAllVtab
->ppPrev
= &pNew
->pNext
;
104 pAux
->pAllVtab
= pNew
;
108 static int vtshimConnect(
112 const char *const*argv
,
113 sqlite3_vtab
**ppVtab
,
116 vtshim_aux
*pAux
= (vtshim_aux
*)ppAux
;
120 assert( db
==pAux
->db
);
121 if( pAux
->bDisposed
){
123 *pzErr
= sqlite3_mprintf("virtual table was disposed: \"%s\"",
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
);
140 pNew
->ppPrev
= &pAux
->pAllVtab
;
141 pNew
->pNext
= pAux
->pAllVtab
;
142 if( pAux
->pAllVtab
) pAux
->pAllVtab
->ppPrev
= &pNew
->pNext
;
143 pAux
->pAllVtab
= pNew
;
147 static int vtshimBestIndex(
149 sqlite3_index_info
*pIdxInfo
151 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
152 vtshim_aux
*pAux
= pVtab
->pAux
;
154 if( pAux
->bDisposed
) return SQLITE_ERROR
;
155 rc
= pAux
->pMod
->xBestIndex(pVtab
->pChild
, pIdxInfo
);
157 VTSHIM_COPY_ERRMSG();
162 static int vtshimDisconnect(sqlite3_vtab
*pBase
){
163 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
164 vtshim_aux
*pAux
= pVtab
->pAux
;
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
;
175 static int vtshimDestroy(sqlite3_vtab
*pBase
){
176 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
177 vtshim_aux
*pAux
= pVtab
->pAux
;
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
;
188 static int vtshimOpen(sqlite3_vtab
*pBase
, sqlite3_vtab_cursor
**ppCursor
){
189 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
190 vtshim_aux
*pAux
= pVtab
->pAux
;
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
);
201 VTSHIM_COPY_ERRMSG();
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
;
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
;
218 if( !pAux
->bDisposed
){
219 rc
= pAux
->pMod
->xClose(pCur
->pChild
);
221 VTSHIM_COPY_ERRMSG();
224 if( pCur
->pNext
) pCur
->pNext
->ppPrev
= pCur
->ppPrev
;
225 *pCur
->ppPrev
= pCur
->pNext
;
230 static int vtshimFilter(
231 sqlite3_vtab_cursor
*pX
,
237 vtshim_cursor
*pCur
= (vtshim_cursor
*)pX
;
238 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pCur
->base
.pVtab
;
239 vtshim_aux
*pAux
= pVtab
->pAux
;
241 if( pAux
->bDisposed
) return SQLITE_ERROR
;
242 rc
= pAux
->pMod
->xFilter(pCur
->pChild
, idxNum
, idxStr
, argc
, argv
);
244 VTSHIM_COPY_ERRMSG();
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
;
254 if( pAux
->bDisposed
) return SQLITE_ERROR
;
255 rc
= pAux
->pMod
->xNext(pCur
->pChild
);
257 VTSHIM_COPY_ERRMSG();
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
;
267 if( pAux
->bDisposed
) return 1;
268 rc
= pAux
->pMod
->xEof(pCur
->pChild
);
269 VTSHIM_COPY_ERRMSG();
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
;
278 if( pAux
->bDisposed
) return SQLITE_ERROR
;
279 rc
= pAux
->pMod
->xColumn(pCur
->pChild
, ctx
, i
);
281 VTSHIM_COPY_ERRMSG();
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
;
291 if( pAux
->bDisposed
) return SQLITE_ERROR
;
292 rc
= pAux
->pMod
->xRowid(pCur
->pChild
, pRowid
);
294 VTSHIM_COPY_ERRMSG();
299 static int vtshimUpdate(
302 sqlite3_value
**argv
,
303 sqlite3_int64
*pRowid
305 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
306 vtshim_aux
*pAux
= pVtab
->pAux
;
308 if( pAux
->bDisposed
) return SQLITE_ERROR
;
309 rc
= pAux
->pMod
->xUpdate(pVtab
->pChild
, argc
, argv
, pRowid
);
311 VTSHIM_COPY_ERRMSG();
316 static int vtshimBegin(sqlite3_vtab
*pBase
){
317 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
318 vtshim_aux
*pAux
= pVtab
->pAux
;
320 if( pAux
->bDisposed
) return SQLITE_ERROR
;
321 rc
= pAux
->pMod
->xBegin(pVtab
->pChild
);
323 VTSHIM_COPY_ERRMSG();
328 static int vtshimSync(sqlite3_vtab
*pBase
){
329 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
330 vtshim_aux
*pAux
= pVtab
->pAux
;
332 if( pAux
->bDisposed
) return SQLITE_ERROR
;
333 rc
= pAux
->pMod
->xSync(pVtab
->pChild
);
335 VTSHIM_COPY_ERRMSG();
340 static int vtshimCommit(sqlite3_vtab
*pBase
){
341 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
342 vtshim_aux
*pAux
= pVtab
->pAux
;
344 if( pAux
->bDisposed
) return SQLITE_ERROR
;
345 rc
= pAux
->pMod
->xCommit(pVtab
->pChild
);
347 VTSHIM_COPY_ERRMSG();
352 static int vtshimRollback(sqlite3_vtab
*pBase
){
353 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
354 vtshim_aux
*pAux
= pVtab
->pAux
;
356 if( pAux
->bDisposed
) return SQLITE_ERROR
;
357 rc
= pAux
->pMod
->xRollback(pVtab
->pChild
);
359 VTSHIM_COPY_ERRMSG();
364 static int vtshimFindFunction(
368 void (**pxFunc
)(sqlite3_context
*,int,sqlite3_value
**),
371 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
372 vtshim_aux
*pAux
= pVtab
->pAux
;
374 if( pAux
->bDisposed
) return 0;
375 rc
= pAux
->pMod
->xFindFunction(pVtab
->pChild
, nArg
, zName
, pxFunc
, ppArg
);
376 VTSHIM_COPY_ERRMSG();
380 static int vtshimRename(sqlite3_vtab
*pBase
, const char *zNewName
){
381 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
382 vtshim_aux
*pAux
= pVtab
->pAux
;
384 if( pAux
->bDisposed
) return SQLITE_ERROR
;
385 rc
= pAux
->pMod
->xRename(pVtab
->pChild
, zNewName
);
387 VTSHIM_COPY_ERRMSG();
392 static int vtshimSavepoint(sqlite3_vtab
*pBase
, int n
){
393 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
394 vtshim_aux
*pAux
= pVtab
->pAux
;
396 if( pAux
->bDisposed
) return SQLITE_ERROR
;
397 rc
= pAux
->pMod
->xSavepoint(pVtab
->pChild
, n
);
399 VTSHIM_COPY_ERRMSG();
404 static int vtshimRelease(sqlite3_vtab
*pBase
, int n
){
405 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
406 vtshim_aux
*pAux
= pVtab
->pAux
;
408 if( pAux
->bDisposed
) return SQLITE_ERROR
;
409 rc
= pAux
->pMod
->xRelease(pVtab
->pChild
, n
);
411 VTSHIM_COPY_ERRMSG();
416 static int vtshimRollbackTo(sqlite3_vtab
*pBase
, int n
){
417 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
418 vtshim_aux
*pAux
= pVtab
->pAux
;
420 if( pAux
->bDisposed
) return SQLITE_ERROR
;
421 rc
= pAux
->pMod
->xRollbackTo(pVtab
->pChild
, n
);
423 VTSHIM_COPY_ERRMSG();
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
);
441 static int vtshimCopyModule(
442 const sqlite3_module
*pMod
, /* Source module to be copied */
443 sqlite3_module
**ppMod
/* Destination for copied module */
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
));
455 __declspec(dllexport
)
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 */
465 sqlite3_module
*pMod
;
467 pAux
= sqlite3_malloc( sizeof(*pAux
) );
469 if( xDestroy
) xDestroy(pClientData
);
472 rc
= vtshimCopyModule(p
, &pMod
);
477 pAux
->pChildAux
= pClientData
;
478 pAux
->xChildDestroy
= xDestroy
;
481 pAux
->zName
= sqlite3_mprintf("%s", zName
);
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;
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;
519 __declspec(dllexport
)
521 void sqlite3_dispose_module(void *pX
){
522 vtshim_aux
*pAux
= (vtshim_aux
*)pX
;
523 if( !pAux
->bDisposed
){
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
);
533 if( pAux
->xChildDestroy
){
534 pAux
->xChildDestroy(pAux
->pChildAux
);
535 pAux
->xChildDestroy
= 0;
541 #endif /* SQLITE_OMIT_VIRTUALTABLE */
544 __declspec(dllexport
)
546 int sqlite3_vtshim_init(
549 const sqlite3_api_routines
*pApi
551 SQLITE_EXTENSION_INIT2(pApi
);