Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / sqlite / src / ext / misc / vtshim.c
blob01348e8d3eebbfe3161c0b55dd6cbc3d448ea161
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;
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;
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
115 vtshim_aux *pAux = (vtshim_aux*)ppAux;
116 vtshim_vtab *pNew;
117 int rc;
119 assert( db==pAux->db );
120 if( pAux->bDisposed ){
121 if( pzErr ){
122 *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"",
123 pAux->zName);
125 return SQLITE_ERROR;
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;
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;
145 static int vtshimBestIndex(
146 sqlite3_vtab *pBase,
147 sqlite3_index_info *pIdxInfo
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();
157 return rc;
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);
167 if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
168 *pVtab->ppPrev = pVtab->pNext;
169 sqlite3_free(pVtab);
170 return rc;
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);
180 if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev;
181 *pVtab->ppPrev = pVtab->pNext;
182 sqlite3_free(pVtab);
183 return rc;
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;
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;
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();
222 if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev;
223 *pCur->ppPrev = pCur->pNext;
224 sqlite3_free(pCur);
225 return rc;
228 static int vtshimFilter(
229 sqlite3_vtab_cursor *pX,
230 int idxNum,
231 const char *idxStr,
232 int argc,
233 sqlite3_value **argv
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();
244 return rc;
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();
257 return rc;
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;
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();
281 return rc;
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();
294 return rc;
297 static int vtshimUpdate(
298 sqlite3_vtab *pBase,
299 int argc,
300 sqlite3_value **argv,
301 sqlite3_int64 *pRowid
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();
311 return rc;
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();
323 return rc;
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();
335 return rc;
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();
347 return rc;
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();
359 return rc;
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
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;
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();
387 return rc;
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();
399 return rc;
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();
411 return rc;
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();
423 return rc;
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);
436 sqlite3_free(pAux);
439 static int vtshimCopyModule(
440 const sqlite3_module *pMod, /* Source module to be copied */
441 sqlite3_module **ppMod /* Destination for copied module */
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;
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 */
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;
470 rc = vtshimCopyModule(p, &pMod);
471 if( rc!=SQLITE_OK ){
472 sqlite3_free(pAux);
473 return 0;
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;
511 rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf,
512 pAux, vtshimAuxDestructor);
513 return rc==SQLITE_OK ? (void*)pAux : 0;
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);
528 pAux->pMod->xDisconnect(pVtab->pChild);
530 pAux->bDisposed = 1;
531 if( pAux->xChildDestroy ){
532 pAux->xChildDestroy(pAux->pChildAux);
533 pAux->xChildDestroy = 0;
539 #endif /* SQLITE_OMIT_VIRTUALTABLE */
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
549 SQLITE_EXTENSION_INIT2(pApi);
550 return SQLITE_OK;