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