modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/misc/vtshim.c (about) 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 return rc; 99 } 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; 106 } 107 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 115 ){ 116 vtshim_aux *pAux = (vtshim_aux*)ppAux; 117 vtshim_vtab *pNew; 118 int rc; 119 120 assert( db==pAux->db ); 121 if( pAux->bDisposed ){ 122 if( pzErr ){ 123 *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"", 124 pAux->zName); 125 } 126 return SQLITE_ERROR; 127 } 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; 138 } 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; 145 } 146 147 static int vtshimBestIndex( 148 sqlite3_vtab *pBase, 149 sqlite3_index_info *pIdxInfo 150 ){ 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(); 158 } 159 return rc; 160 } 161 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); 168 } 169 if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev; 170 *pVtab->ppPrev = pVtab->pNext; 171 sqlite3_free(pVtab); 172 return rc; 173 } 174 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); 181 } 182 if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev; 183 *pVtab->ppPrev = pVtab->pNext; 184 sqlite3_free(pVtab); 185 return rc; 186 } 187 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; 203 } 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; 211 } 212 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(); 222 } 223 } 224 if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev; 225 *pCur->ppPrev = pCur->pNext; 226 sqlite3_free(pCur); 227 return rc; 228 } 229 230 static int vtshimFilter( 231 sqlite3_vtab_cursor *pX, 232 int idxNum, 233 const char *idxStr, 234 int argc, 235 sqlite3_value **argv 236 ){ 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(); 245 } 246 return rc; 247 } 248 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(); 258 } 259 return rc; 260 } 261 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; 271 } 272 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(); 282 } 283 return rc; 284 } 285 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(); 295 } 296 return rc; 297 } 298 299 static int vtshimUpdate( 300 sqlite3_vtab *pBase, 301 int argc, 302 sqlite3_value **argv, 303 sqlite3_int64 *pRowid 304 ){ 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(); 312 } 313 return rc; 314 } 315 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(); 324 } 325 return rc; 326 } 327 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(); 336 } 337 return rc; 338 } 339 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(); 348 } 349 return rc; 350 } 351 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(); 360 } 361 return rc; 362 } 363 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 370 ){ 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; 378 } 379 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(); 388 } 389 return rc; 390 } 391 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(); 400 } 401 return rc; 402 } 403 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(); 412 } 413 return rc; 414 } 415 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(); 424 } 425 return rc; 426 } 427 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; 435 } 436 sqlite3_free(pAux->zName); 437 sqlite3_free(pAux->pMod); 438 sqlite3_free(pAux); 439 } 440 441 static int vtshimCopyModule( 442 const sqlite3_module *pMod, /* Source module to be copied */ 443 sqlite3_module **ppMod /* Destination for copied module */ 444 ){ 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; 452 } 453 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 */ 463 ){ 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; 471 } 472 rc = vtshimCopyModule(p, &pMod); 473 if( rc!=SQLITE_OK ){ 474 sqlite3_free(pAux); 475 return 0; 476 } 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; 512 } 513 rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf, 514 pAux, vtshimAuxDestructor); 515 return rc==SQLITE_OK ? (void*)pAux : 0; 516 } 517 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); 529 } 530 pAux->pMod->xDisconnect(pVtab->pChild); 531 } 532 pAux->bDisposed = 1; 533 if( pAux->xChildDestroy ){ 534 pAux->xChildDestroy(pAux->pChildAux); 535 pAux->xChildDestroy = 0; 536 } 537 } 538 } 539 540 541 #endif /* SQLITE_OMIT_VIRTUALTABLE */ 542 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 550 ){ 551 SQLITE_EXTENSION_INIT2(pApi); 552 return SQLITE_OK; 553 }