Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a memory leak that occurs when an out-of-memory error occurs while preparing a statement that has multiple virtual table updates within triggers. Other virtual table changes to support full-coverage testing. (CVS 6661) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
02b77a582c65e0eb45eb1a9abbdeef11 |
User & Date: | drh 2009-05-20 20:10:47.000 |
Context
2009-05-21
| ||
04:42 | Add conditional 'extern "C"' block to sqlite3async.h. Ticket #3866. (CVS 6662) (check-in: e4d1b117c9 user: danielk1977 tags: trunk) | |
2009-05-20
| ||
20:10 | Fix a memory leak that occurs when an out-of-memory error occurs while preparing a statement that has multiple virtual table updates within triggers. Other virtual table changes to support full-coverage testing. (CVS 6661) (check-in: 02b77a582c user: drh tags: trunk) | |
16:22 | Remove unused, undocumented, and untested error reporting logic from the xFindFunction interface in virtual tables. (CVS 6660) (check-in: 55d6ced262 user: drh tags: trunk) | |
Changes
Changes to src/vtab.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. ** ** $Id: vtab.c,v 1.89 2009/05/20 20:10:47 drh Exp $ */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" /* ** The actual function that does the work of creating a new module. ** This function implements the sqlite3_create_module() and |
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 112 113 | */ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){ assert( pVtab->nRef>0 ); pVtab->nRef--; assert(db); assert( sqlite3SafetyCheckOk(db) ); if( pVtab->nRef==0 ){ if( db->magic==SQLITE_MAGIC_BUSY ){ (void)sqlite3SafetyOff(db); pVtab->pModule->xDisconnect(pVtab); (void)sqlite3SafetyOn(db); | > | > > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | */ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){ assert( pVtab->nRef>0 ); pVtab->nRef--; assert(db); assert( sqlite3SafetyCheckOk(db) ); if( pVtab->nRef==0 ){ #ifdef SQLITE_DEBUG if( db->magic==SQLITE_MAGIC_BUSY ){ (void)sqlite3SafetyOff(db); pVtab->pModule->xDisconnect(pVtab); (void)sqlite3SafetyOn(db); } else #endif { pVtab->pModule->xDisconnect(pVtab); } } } /* ** Clear any and all virtual-table information from the Table record. |
︙ | ︙ | |||
184 185 186 187 188 189 190 | if( pParse->db->flags & SQLITE_SharedCache ){ sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode"); return; } sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); pTable = pParse->pNewTable; | | | 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | if( pParse->db->flags & SQLITE_SharedCache ){ sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode"); return; } sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); db = pParse->db; iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); pTable->tabFlags |= TF_Virtual; |
︙ | ︙ | |||
217 218 219 220 221 222 223 | /* ** This routine takes the module argument that has been accumulating ** in pParse->zArg[] and appends it to the list of arguments on the ** virtual table currently under construction in pParse->pTable. */ static void addArgumentToVtab(Parse *pParse){ | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | /* ** This routine takes the module argument that has been accumulating ** in pParse->zArg[] and appends it to the list of arguments on the ** virtual table currently under construction in pParse->pTable. */ static void addArgumentToVtab(Parse *pParse){ if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){ const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; sqlite3 *db = pParse->db; addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } |
︙ | ︙ | |||
374 375 376 377 378 379 380 | db->pVTab = pTab; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr); rc2 = sqlite3SafetyOn(db); if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; | > > | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | db->pVTab = pTab; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr); rc2 = sqlite3SafetyOn(db); if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ if( rc==SQLITE_OK && ALWAYS(pVtab) ){ pVtab->pModule = pMod->pModule; pVtab->nRef = 1; pTab->pVtab = pVtab; } if( SQLITE_OK!=rc ){ if( zErr==0 ){ |
︙ | ︙ | |||
449 450 451 452 453 454 455 | ** ** This call is a no-op if table pTab is not a virtual table. */ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ Module *pMod; int rc = SQLITE_OK; | > | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | ** ** This call is a no-op if table pTab is not a virtual table. */ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ Module *pMod; int rc = SQLITE_OK; assert( pTab ); if( (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){ return SQLITE_OK; } pMod = pTab->pMod; if( !pMod ){ const char *zModule = pTab->azModuleArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); |
︙ | ︙ | |||
525 526 527 528 529 530 531 | if( !pMod ){ *pzErr = sqlite3MPrintf(db, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); } | > > | | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | if( !pMod ){ *pzErr = sqlite3MPrintf(db, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); } /* Justification of ALWAYS(): The xConstructor method is required to ** create a valid sqlite3_vtab if it returns SQLITE_OK. */ if( rc==SQLITE_OK && ALWAYS(pTab->pVtab) ){ rc = addToVTrans(db, pTab->pVtab); } return rc; } /* |
︙ | ︙ | |||
594 595 596 597 598 599 600 | /* ** This function is invoked by the vdbe to call the xDestroy method ** of the virtual table named zTab in database iDb. This occurs ** when a DROP TABLE is mentioned. ** ** This call is a no-op if zTab is not a virtual table. */ | | < < | < < | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | /* ** This function is invoked by the vdbe to call the xDestroy method ** of the virtual table named zTab in database iDb. This occurs ** when a DROP TABLE is mentioned. ** ** This call is a no-op if zTab is not a virtual table. */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( ALWAYS(pTab!=0 && pTab->pVtab!=0) ){ int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); rc = xDestroy(pTab->pVtab); (void)sqlite3SafetyOn(db); if( rc==SQLITE_OK ){ int i; for(i=0; i<db->nVTrans; i++){ if( db->aVTrans[i]==pTab->pVtab ){ db->aVTrans[i] = db->aVTrans[--db->nVTrans]; break; |
︙ | ︙ | |||
635 636 637 638 639 640 641 | ** the offset of the method to call in the sqlite3_module structure. ** ** The array is cleared after invoking the callbacks. */ static void callFinaliser(sqlite3 *db, int offset){ int i; if( db->aVTrans ){ | | > > | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | ** the offset of the method to call in the sqlite3_module structure. ** ** The array is cleared after invoking the callbacks. */ static void callFinaliser(sqlite3 *db, int offset){ int i; if( db->aVTrans ){ for(i=0; i<db->nVTrans; i++){ sqlite3_vtab *pVtab = db->aVTrans[i]; int (*x)(sqlite3_vtab *); assert( pVtab!=0 ); x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); if( x ) x(pVtab); sqlite3VtabUnlock(db, pVtab); } sqlite3DbFree(db, db->aVTrans); db->nVTrans = 0; db->aVTrans = 0; |
︙ | ︙ | |||
664 665 666 667 668 669 670 | int i; int rc = SQLITE_OK; int rcsafety; sqlite3_vtab **aVTrans = db->aVTrans; rc = sqlite3SafetyOff(db); db->aVTrans = 0; | | > | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | int i; int rc = SQLITE_OK; int rcsafety; sqlite3_vtab **aVTrans = db->aVTrans; rc = sqlite3SafetyOff(db); db->aVTrans = 0; for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ sqlite3_vtab *pVtab = aVTrans[i]; int (*x)(sqlite3_vtab *); assert( pVtab!=0 ); x = pVtab->pModule->xSync; if( x ){ rc = x(pVtab); sqlite3DbFree(db, *pzErrmsg); *pzErrmsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; } |
︙ | ︙ | |||
717 718 719 720 721 722 723 | int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to | | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to ** virtual module tables in this case, so return SQLITE_LOCKED. */ if( sqlite3VtabInSync(db) ){ return SQLITE_LOCKED; } if( !pVtab ){ return SQLITE_OK; } pModule = pVtab->pModule; if( pModule->xBegin ){ int i; /* If pVtab is already in the aVTrans array, return early */ for(i=0; i<db->nVTrans; i++){ if( db->aVTrans[i]==pVtab ){ return SQLITE_OK; } } /* Invoke the xBegin method */ rc = pModule->xBegin(pVtab); |
︙ | ︙ | |||
778 779 780 781 782 783 784 | FuncDef *pNew; int rc = 0; char *zLowerName; unsigned char *z; /* Check to see the left operand is a column in a virtual table */ | | | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | FuncDef *pNew; int rc = 0; char *zLowerName; unsigned char *z; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->pTab; if( NEVER(pTab==0) ) return pDef; if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef; pVtab = pTab->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction==0 ) return pDef; |
︙ | ︙ | |||
828 829 830 831 832 833 834 835 836 837 838 839 | ** Make sure virtual table pTab is contained in the pParse->apVirtualLock[] ** array so that an OP_VBegin will get generated for it. Add pTab to the ** array if it is missing. If pTab is already in the array, this routine ** is a no-op. */ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ int i, n; assert( IsVirtual(pTab) ); for(i=0; i<pParse->nVtabLock; i++){ if( pTab==pParse->apVtabLock[i] ) return; } n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]); | > > | > | | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 | ** Make sure virtual table pTab is contained in the pParse->apVirtualLock[] ** array so that an OP_VBegin will get generated for it. Add pTab to the ** array if it is missing. If pTab is already in the array, this routine ** is a no-op. */ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ int i, n; Table **apVtabLock; assert( IsVirtual(pTab) ); for(i=0; i<pParse->nVtabLock; i++){ if( pTab==pParse->apVtabLock[i] ) return; } n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]); apVtabLock = sqlite3_realloc(pParse->apVtabLock, n); if( apVtabLock ){ pParse->apVtabLock = apVtabLock; pParse->apVtabLock[pParse->nVtabLock++] = pTab; }else{ pParse->db->mallocFailed = 1; } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |