Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Shared-cache mode fixes for views and virtual tables. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | shared-cache-fix |
Files: | files | file ages | folders |
SHA1: |
2b370dea704b59262c604af0efcef566 |
User & Date: | dan 2012-10-04 19:33:00.992 |
Context
2012-10-05
| ||
16:30 | Fix a problem with shared-cache mode and CHECK constraints causing one db handle to invoke a collation sequence function registered with another. (check-in: c2c776ab73 user: dan tags: shared-cache-fix) | |
2012-10-04
| ||
19:33 | Shared-cache mode fixes for views and virtual tables. (check-in: 2b370dea70 user: dan tags: shared-cache-fix) | |
2012-10-03
| ||
18:09 | Fix an out-of-order memset() that occurs before all variable declarations are finished. Also fix a line that exceeds the 80-character line length limit. (check-in: ba2f492f95 user: drh tags: trunk) | |
Changes
Changes to src/alter.c.
︙ | ︙ | |||
410 411 412 413 414 415 416 | int savedDbFlags; /* Saved value of db->flags */ savedDbFlags = db->flags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | int savedDbFlags; /* Saved value of db->flags */ savedDbFlags = db->flags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zName; db->flags |= SQLITE_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); |
︙ | ︙ | |||
753 754 755 756 757 758 759 | int nAlloc; sqlite3 *db = pParse->db; /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); if( db->mallocFailed ) goto exit_begin_add_column; | | | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | int nAlloc; sqlite3 *db = pParse->db; /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); if( db->mallocFailed ) goto exit_begin_add_column; pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_begin_add_column; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); goto exit_begin_add_column; } |
︙ | ︙ |
Changes to src/attach.c.
︙ | ︙ | |||
430 431 432 433 434 435 436 437 438 439 440 441 442 443 | sqlite3 *db; if( NEVER(iDb<0) || iDb==1 ) return 0; db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zName; pFix->zType = zType; pFix->pName = pName; return 1; } /* ** The following set of routines walk through the parse tree and assign | > | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | sqlite3 *db; if( NEVER(iDb<0) || iDb==1 ) return 0; db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; return 1; } /* ** The following set of routines walk through the parse tree and assign |
︙ | ︙ | |||
460 461 462 463 464 465 466 | int i; const char *zDb; struct SrcList_item *pItem; if( NEVER(pList==0) ) return 0; zDb = pFix->zDb; for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ | | < < > > > | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | int i; const char *zDb; struct SrcList_item *pItem; if( NEVER(pList==0) ) return 0; zDb = pFix->zDb; for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); return 1; } sqlite3_free(pItem->zDatabase); pItem->zDatabase = 0; pItem->pSchema = pFix->pSchema; #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; #endif } return 0; } |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 | }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } return p; } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. ** | > > > > > > > > > > > > > > > > > > > > > > > > > | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } return p; } /* ** Locate the table identified by *p. ** ** This is a wrapper around sqlite3LocateTable(). The difference between ** sqlite3LocateTable() and this function is that this function restricts ** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be ** non-NULL if it is part of a view or trigger program definition. See ** sqlite3FixSrcList() for details. */ Table *sqlite3LocateTableItem( Parse *pParse, int isView, struct SrcList_item *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); zDb = pParse->db->aDb[iDb].zName; }else{ zDb = p->zDatabase; } return sqlite3LocateTable(pParse, isView, p->zName, zDb); } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. ** |
︙ | ︙ | |||
2110 2111 2112 2113 2114 2115 2116 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( noErr ) db->suppressErr++; | | < | 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( noErr ) db->suppressErr++; pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
︙ | ︙ | |||
2551 2552 2553 2554 2555 2556 2557 | if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) && sqlite3FixSrcList(&sFix, pTblName) ){ /* Because the parser constructs pTblName from a single identifier, ** sqlite3FixSrcList can never fail. */ assert(0); } | | < | 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 | if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) && sqlite3FixSrcList(&sFix, pTblName) ){ /* Because the parser constructs pTblName from a single identifier, ** sqlite3FixSrcList can never fail. */ assert(0); } pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]); if( !pTab || db->mallocFailed ) goto exit_create_index; assert( db->aDb[iDb].pSchema==pTab->pSchema ); }else{ assert( pName==0 ); assert( pStart==0 ); pTab = pParse->pNewTable; if( !pTab ) goto exit_create_index; |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** */ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ struct SrcList_item *pItem = pSrc->a; Table *pTab; assert( pItem && pSrc->nSrc==1 ); | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** */ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ struct SrcList_item *pItem = pSrc->a; Table *pTab; assert( pItem && pSrc->nSrc==1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; if( pTab ){ pTab->nRef++; } if( sqlite3IndexedByLookup(pParse, pItem) ){ pTab = 0; |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
926 927 928 929 930 931 932 933 934 935 936 937 938 939 | pNew = sqlite3DbMallocRaw(db, nByte ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; i<p->nSrc; i++){ struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *pOldItem = &p->a[i]; Table *pTab; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; | > | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | pNew = sqlite3DbMallocRaw(db, nByte ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; i<p->nSrc; i++){ struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 | } /* At this point we have established that the statement is of the ** correct syntactic form to participate in this optimization. Now ** we have to check the semantics. */ pItem = pSelect->pSrc->a; | | | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 | } /* At this point we have established that the statement is of the ** correct syntactic form to participate in this optimization. Now ** we have to check the semantics. */ pItem = pSelect->pSrc->a; pSrc = sqlite3LocateTableItem(pParse, 0, pItem); if( pSrc==0 ){ return 0; /* FROM clause does not contain a real table */ } if( pSrc==pDest ){ return 0; /* tab1 and tab2 may not be the same table */ } #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
3328 3329 3330 3331 3332 3333 3334 | pTab->iPKey = -1; pTab->nRowEst = 1000000; pTab->tabFlags |= TF_Ephemeral; #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); | | < | 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 | pTab->iPKey = -1; pTab->nRowEst = 1000000; pTab->tabFlags |= TF_Ephemeral; #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; pTab->nRef++; #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) if( pTab->pSelect || IsVirtual(pTab) ){ /* We reach here if the named table is a really a view */ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 | ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. */ struct SrcList { i16 nSrc; /* Number of tables or subqueries in the FROM clause */ i16 nAlloc; /* Number of entries allocated in a[] below */ struct SrcList_item { char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ | > | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 | ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. */ struct SrcList { i16 nSrc; /* Number of tables or subqueries in the FROM clause */ i16 nAlloc; /* Number of entries allocated in a[] below */ struct SrcList_item { Schema *pSchema; /* Schema to which this item is fixed */ char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ |
︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 | ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references ** explicit. */ typedef struct DbFixer DbFixer; struct DbFixer { Parse *pParse; /* The parsing context. Error messages written here */ const char *zDb; /* Make sure all objects are contained in this database */ const char *zType; /* Type of the container - used for error messages */ const Token *pName; /* Name of the container - used for error messages */ }; /* ** An objected used to accumulate the text of a string where we | > | 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 | ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references ** explicit. */ typedef struct DbFixer DbFixer; struct DbFixer { Parse *pParse; /* The parsing context. Error messages written here */ Schema *pSchema; /* Fix items to this schema */ const char *zDb; /* Make sure all objects are contained in this database */ const char *zType; /* Type of the container - used for error messages */ const Token *pName; /* Name of the container - used for error messages */ }; /* ** An objected used to accumulate the text of a string where we |
︙ | ︙ | |||
2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 | int sqlite3ExprCodeAndCache(Parse*, Expr*, int); void sqlite3ExprCodeConstants(Parse*, Expr*); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); | > | 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 | int sqlite3ExprCodeAndCache(Parse*, Expr*, int); void sqlite3ExprCodeConstants(Parse*, Expr*); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
259 260 261 262 263 264 265 266 267 268 269 270 271 272 | ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); if( p->azModuleArg ){ int i; for(i=0; i<p->nModuleArg; i++){ sqlite3DbFree(db, p->azModuleArg[i]); } sqlite3DbFree(db, p->azModuleArg); } } | > | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); if( p->azModuleArg ){ int i; assert( p->nModuleArg<2 || p->azModuleArg[1]==0 ); for(i=0; i<p->nModuleArg; i++){ sqlite3DbFree(db, p->azModuleArg[i]); } sqlite3DbFree(db, p->azModuleArg); } } |
︙ | ︙ | |||
320 321 322 323 324 325 326 | db = pParse->db; iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); pTable->tabFlags |= TF_Virtual; pTable->nModuleArg = 0; addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | db = pParse->db; iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); pTable->tabFlags |= TF_Virtual; pTable->nModuleArg = 0; addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(db, pTable, 0); addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z); #ifndef SQLITE_OMIT_AUTHORIZATION /* Creating a virtual table invokes the authorization callback twice. ** The first invocation, to obtain permission to INSERT a row into the ** sqlite_master table, has already been made by sqlite3StartTable(). |
︙ | ︙ | |||
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | VtabCtx sCtx, *pPriorCtx; VTable *pVTable; int rc; const char *const*azArg = (const char *const*)pTab->azModuleArg; int nArg = pTab->nModuleArg; char *zErr = 0; char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM; } pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); if( !pVTable ){ sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM; } pVTable->db = db; pVTable->pMod = pMod; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); assert( xConstruct ); sCtx.pTab = pTab; sCtx.pVTable = pVTable; pPriorCtx = db->pVtabCtx; db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); db->pVtabCtx = pPriorCtx; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; if( SQLITE_OK!=rc ){ if( zErr==0 ){ *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); }else { *pzErr = sqlite3MPrintf(db, "%s", zErr); sqlite3_free(zErr); | > > > > > > | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | VtabCtx sCtx, *pPriorCtx; VTable *pVTable; int rc; const char *const*azArg = (const char *const*)pTab->azModuleArg; int nArg = pTab->nModuleArg; char *zErr = 0; char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); int iDb; if( !zModuleName ){ return SQLITE_NOMEM; } pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); if( !pVTable ){ sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM; } pVTable->db = db; pVTable->pMod = pMod; assert( pTab->azModuleArg[1]==0 ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->azModuleArg[1] = db->aDb[iDb].zName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); assert( xConstruct ); sCtx.pTab = pTab; sCtx.pVTable = pVTable; pPriorCtx = db->pVtabCtx; db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); db->pVtabCtx = pPriorCtx; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; pTab->azModuleArg[1] = 0; if( SQLITE_OK!=rc ){ if( zErr==0 ){ *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); }else { *pzErr = sqlite3MPrintf(db, "%s", zErr); sqlite3_free(zErr); |
︙ | ︙ |
Added test/shared9.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | # 2012 October 5 # # 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. # #*********************************************************************** # # The tests in this file are intended to show if two connections attach # to the same shared cache using different database names, views and # virtual tables may still be accessed. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix shared9 db close set enable_shared_cache [sqlite3_enable_shared_cache 1] # Test organization: # # 1.* - Views. # 2.* - Virtual tables. # sqlite3 db1 test.db sqlite3 db2 test.db forcedelete test.db2 do_test 1.1 { db1 eval { ATTACH 'test.db2' AS 'fred'; CREATE TABLE fred.t1(a, b, c); CREATE VIEW fred.v1 AS SELECT * FROM t1; CREATE TABLE fred.t2(a, b); CREATE TABLE fred.t3(a, b); CREATE TRIGGER fred.trig AFTER INSERT ON t2 BEGIN DELETE FROM t3; INSERT INTO t3 SELECT * FROM t2; END; INSERT INTO t2 VALUES(1, 2); SELECT * FROM t3; } } {1 2} do_test 1.2 { db2 eval "ATTACH 'test.db2' AS 'jones'" } {} do_test 1.2 { db2 eval "SELECT * FROM v1" } {} do_test 1.3 { db2 eval "INSERT INTO t2 VALUES(3, 4)" } {} do_test 2.1 { db1 eval { CREATE VIRTUAL TABLE fred.t4 USING fts4; INSERT INTO t4 VALUES('hello world'); } } {} do_test 2.2 { db2 eval { INSERT INTO t4 VALUES('shared cache'); SELECT * FROM t4 WHERE t4 MATCH 'hello'; } } {{hello world}} do_test 2.3 { db1 eval { SELECT * FROM t4 WHERE t4 MATCH 'c*'; } } {{shared cache}} db1 close db2 close sqlite3_enable_shared_cache $::enable_shared_cache finish_test |
Changes to test/trigger1.test.
︙ | ︙ | |||
206 207 208 209 210 211 212 | do_test trigger1-1.12 { catchsql { create table t1(a,b); create trigger t1t instead of update on t1 for each row begin delete from t1 WHERE a=old.a+2; end; } | | | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | do_test trigger1-1.12 { catchsql { create table t1(a,b); create trigger t1t instead of update on t1 for each row begin delete from t1 WHERE a=old.a+2; end; } } {1 {cannot create INSTEAD OF trigger on table: t1}} ifcapable view { # Ensure that we cannot create BEFORE triggers on views do_test trigger1-1.13 { catchsql { create view v1 as select * from t1; create trigger v1t before update on v1 for each row begin delete from t1 WHERE a=old.a+2; end; } } {1 {cannot create BEFORE trigger on view: v1}} # Ensure that we cannot create AFTER triggers on views do_test trigger1-1.14 { catchsql { drop view v1; create view v1 as select * from t1; create trigger v1t AFTER update on v1 for each row begin delete from t1 WHERE a=old.a+2; end; } } {1 {cannot create AFTER trigger on view: v1}} } ;# ifcapable view # Check for memory leaks in the trigger parser # do_test trigger1-2.1 { catchsql { CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN |
︙ | ︙ |