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
);
100 pNew
->ppPrev
= &pAux
->pAllVtab
;
101 pNew
->pNext
= pAux
->pAllVtab
;
102 if( pAux
->pAllVtab
) pAux
->pAllVtab
->ppPrev
= &pNew
->pNext
;
103 pAux
->pAllVtab
= pNew
;
107 static int vtshimConnect(
111 const char *const*argv
,
112 sqlite3_vtab
**ppVtab
,
115 vtshim_aux
*pAux
= (vtshim_aux
*)ppAux
;
119 assert( db
==pAux
->db
);
120 if( pAux
->bDisposed
){
122 *pzErr
= sqlite3_mprintf("virtual table was disposed: \"%s\"",
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
);
138 pNew
->ppPrev
= &pAux
->pAllVtab
;
139 pNew
->pNext
= pAux
->pAllVtab
;
140 if( pAux
->pAllVtab
) pAux
->pAllVtab
->ppPrev
= &pNew
->pNext
;
141 pAux
->pAllVtab
= pNew
;
145 static int vtshimBestIndex(
147 sqlite3_index_info
*pIdxInfo
149 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
150 vtshim_aux
*pAux
= pVtab
->pAux
;
152 if( pAux
->bDisposed
) return SQLITE_ERROR
;
153 rc
= pAux
->pMod
->xBestIndex(pVtab
->pChild
, pIdxInfo
);
155 VTSHIM_COPY_ERRMSG();
160 static int vtshimDisconnect(sqlite3_vtab
*pBase
){
161 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
162 vtshim_aux
*pAux
= pVtab
->pAux
;
164 if( !pAux
->bDisposed
){
165 rc
= pAux
->pMod
->xDisconnect(pVtab
->pChild
);
167 if( pVtab
->pNext
) pVtab
->pNext
->ppPrev
= pVtab
->ppPrev
;
168 *pVtab
->ppPrev
= pVtab
->pNext
;
173 static int vtshimDestroy(sqlite3_vtab
*pBase
){
174 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
175 vtshim_aux
*pAux
= pVtab
->pAux
;
177 if( !pAux
->bDisposed
){
178 rc
= pAux
->pMod
->xDestroy(pVtab
->pChild
);
180 if( pVtab
->pNext
) pVtab
->pNext
->ppPrev
= pVtab
->ppPrev
;
181 *pVtab
->ppPrev
= pVtab
->pNext
;
186 static int vtshimOpen(sqlite3_vtab
*pBase
, sqlite3_vtab_cursor
**ppCursor
){
187 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
188 vtshim_aux
*pAux
= pVtab
->pAux
;
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
);
199 VTSHIM_COPY_ERRMSG();
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
;
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
;
216 if( !pAux
->bDisposed
){
217 rc
= pAux
->pMod
->xClose(pCur
->pChild
);
219 VTSHIM_COPY_ERRMSG();
222 if( pCur
->pNext
) pCur
->pNext
->ppPrev
= pCur
->ppPrev
;
223 *pCur
->ppPrev
= pCur
->pNext
;
228 static int vtshimFilter(
229 sqlite3_vtab_cursor
*pX
,
235 vtshim_cursor
*pCur
= (vtshim_cursor
*)pX
;
236 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pCur
->base
.pVtab
;
237 vtshim_aux
*pAux
= pVtab
->pAux
;
239 if( pAux
->bDisposed
) return SQLITE_ERROR
;
240 rc
= pAux
->pMod
->xFilter(pCur
->pChild
, idxNum
, idxStr
, argc
, argv
);
242 VTSHIM_COPY_ERRMSG();
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
;
252 if( pAux
->bDisposed
) return SQLITE_ERROR
;
253 rc
= pAux
->pMod
->xNext(pCur
->pChild
);
255 VTSHIM_COPY_ERRMSG();
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
;
265 if( pAux
->bDisposed
) return 1;
266 rc
= pAux
->pMod
->xEof(pCur
->pChild
);
267 VTSHIM_COPY_ERRMSG();
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
;
276 if( pAux
->bDisposed
) return SQLITE_ERROR
;
277 rc
= pAux
->pMod
->xColumn(pCur
->pChild
, ctx
, i
);
279 VTSHIM_COPY_ERRMSG();
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
;
289 if( pAux
->bDisposed
) return SQLITE_ERROR
;
290 rc
= pAux
->pMod
->xRowid(pCur
->pChild
, pRowid
);
292 VTSHIM_COPY_ERRMSG();
297 static int vtshimUpdate(
300 sqlite3_value
**argv
,
301 sqlite3_int64
*pRowid
303 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
304 vtshim_aux
*pAux
= pVtab
->pAux
;
306 if( pAux
->bDisposed
) return SQLITE_ERROR
;
307 rc
= pAux
->pMod
->xUpdate(pVtab
->pChild
, argc
, argv
, pRowid
);
309 VTSHIM_COPY_ERRMSG();
314 static int vtshimBegin(sqlite3_vtab
*pBase
){
315 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
316 vtshim_aux
*pAux
= pVtab
->pAux
;
318 if( pAux
->bDisposed
) return SQLITE_ERROR
;
319 rc
= pAux
->pMod
->xBegin(pVtab
->pChild
);
321 VTSHIM_COPY_ERRMSG();
326 static int vtshimSync(sqlite3_vtab
*pBase
){
327 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
328 vtshim_aux
*pAux
= pVtab
->pAux
;
330 if( pAux
->bDisposed
) return SQLITE_ERROR
;
331 rc
= pAux
->pMod
->xSync(pVtab
->pChild
);
333 VTSHIM_COPY_ERRMSG();
338 static int vtshimCommit(sqlite3_vtab
*pBase
){
339 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
340 vtshim_aux
*pAux
= pVtab
->pAux
;
342 if( pAux
->bDisposed
) return SQLITE_ERROR
;
343 rc
= pAux
->pMod
->xCommit(pVtab
->pChild
);
345 VTSHIM_COPY_ERRMSG();
350 static int vtshimRollback(sqlite3_vtab
*pBase
){
351 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
352 vtshim_aux
*pAux
= pVtab
->pAux
;
354 if( pAux
->bDisposed
) return SQLITE_ERROR
;
355 rc
= pAux
->pMod
->xRollback(pVtab
->pChild
);
357 VTSHIM_COPY_ERRMSG();
362 static int vtshimFindFunction(
366 void (**pxFunc
)(sqlite3_context
*,int,sqlite3_value
**),
369 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
370 vtshim_aux
*pAux
= pVtab
->pAux
;
372 if( pAux
->bDisposed
) return 0;
373 rc
= pAux
->pMod
->xFindFunction(pVtab
->pChild
, nArg
, zName
, pxFunc
, ppArg
);
374 VTSHIM_COPY_ERRMSG();
378 static int vtshimRename(sqlite3_vtab
*pBase
, const char *zNewName
){
379 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
380 vtshim_aux
*pAux
= pVtab
->pAux
;
382 if( pAux
->bDisposed
) return SQLITE_ERROR
;
383 rc
= pAux
->pMod
->xRename(pVtab
->pChild
, zNewName
);
385 VTSHIM_COPY_ERRMSG();
390 static int vtshimSavepoint(sqlite3_vtab
*pBase
, int n
){
391 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
392 vtshim_aux
*pAux
= pVtab
->pAux
;
394 if( pAux
->bDisposed
) return SQLITE_ERROR
;
395 rc
= pAux
->pMod
->xSavepoint(pVtab
->pChild
, n
);
397 VTSHIM_COPY_ERRMSG();
402 static int vtshimRelease(sqlite3_vtab
*pBase
, int n
){
403 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
404 vtshim_aux
*pAux
= pVtab
->pAux
;
406 if( pAux
->bDisposed
) return SQLITE_ERROR
;
407 rc
= pAux
->pMod
->xRelease(pVtab
->pChild
, n
);
409 VTSHIM_COPY_ERRMSG();
414 static int vtshimRollbackTo(sqlite3_vtab
*pBase
, int n
){
415 vtshim_vtab
*pVtab
= (vtshim_vtab
*)pBase
;
416 vtshim_aux
*pAux
= pVtab
->pAux
;
418 if( pAux
->bDisposed
) return SQLITE_ERROR
;
419 rc
= pAux
->pMod
->xRollbackTo(pVtab
->pChild
, n
);
421 VTSHIM_COPY_ERRMSG();
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;
434 sqlite3_free(pAux
->zName
);
435 sqlite3_free(pAux
->pMod
);
439 static int vtshimCopyModule(
440 const sqlite3_module
*pMod
, /* Source module to be copied */
441 sqlite3_module
**ppMod
/* Destination for copied module */
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
));
453 __declspec(dllexport
)
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 */
463 sqlite3_module
*pMod
;
465 pAux
= sqlite3_malloc( sizeof(*pAux
) );
467 if( xDestroy
) xDestroy(pClientData
);
470 rc
= vtshimCopyModule(p
, &pMod
);
475 pAux
->pChildAux
= pClientData
;
476 pAux
->xChildDestroy
= xDestroy
;
479 pAux
->zName
= sqlite3_mprintf("%s", zName
);
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;
507 pAux
->sSelf
.xSavepoint
= 0;
508 pAux
->sSelf
.xRelease
= 0;
509 pAux
->sSelf
.xRollbackTo
= 0;
511 rc
= sqlite3_create_module_v2(db
, zName
, &pAux
->sSelf
,
512 pAux
, vtshimAuxDestructor
);
513 return rc
==SQLITE_OK
? (void*)pAux
: 0;
517 __declspec(dllexport
)
519 void sqlite3_dispose_module(void *pX
){
520 vtshim_aux
*pAux
= (vtshim_aux
*)pX
;
521 if( !pAux
->bDisposed
){
524 for(pVtab
=pAux
->pAllVtab
; pVtab
; pVtab
=pVtab
->pNext
){
525 for(pCur
=pVtab
->pAllCur
; pCur
; pCur
=pCur
->pNext
){
526 pAux
->pMod
->xClose(pCur
->pChild
);
528 pAux
->pMod
->xDisconnect(pVtab
->pChild
);
531 if( pAux
->xChildDestroy
){
532 pAux
->xChildDestroy(pAux
->pChildAux
);
533 pAux
->xChildDestroy
= 0;
539 #endif /* SQLITE_OMIT_VIRTUALTABLE */
542 __declspec(dllexport
)
544 int sqlite3_vtshim_init(
547 const sqlite3_api_routines
*pApi
549 SQLITE_EXTENSION_INIT2(pApi
);