Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -1755,35 +1755,40 @@ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* ** If this Btree is a candidate for shared cache, try to find an ** existing BtShared object that we can share with */ - if( isMemdb==0 && isTempDb==0 ){ + if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){ if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ int nFullPathname = pVfs->mxPathname+1; char *zFullPathname = sqlite3Malloc(nFullPathname); MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) p->sharable = 1; if( !zFullPathname ){ sqlite3_free(p); return SQLITE_NOMEM; } - rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); - if( rc ){ - sqlite3_free(zFullPathname); - sqlite3_free(p); - return rc; + if( isMemdb ){ + memcpy(zFullPathname, zFilename, sqlite3Strlen30(zFilename)+1); + }else{ + rc = sqlite3OsFullPathname(pVfs, zFilename, + nFullPathname, zFullPathname); + if( rc ){ + sqlite3_free(zFullPathname); + sqlite3_free(p); + return rc; + } } #if SQLITE_THREADSAFE mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); sqlite3_mutex_enter(mutexOpen); mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(mutexShared); #endif for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ assert( pBt->nRef>0 ); - if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) + if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager, 0)) && sqlite3PagerVfs(pBt->pPager)==pVfs ){ int iDb; for(iDb=db->nDb-1; iDb>=0; iDb--){ Btree *pExisting = db->aDb[iDb].pBt; if( pExisting && pExisting->pBt==pBt ){ @@ -8044,18 +8049,19 @@ return sqlite3StrAccumFinish(&sCheck.errMsg); } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* -** Return the full pathname of the underlying database file. +** Return the full pathname of the underlying database file. Return +** an empty string if the database is in-memory or a TEMP database. ** ** The pager filename is invariant as long as the pager is ** open so it is safe to access without the BtShared mutex. */ const char *sqlite3BtreeGetFilename(Btree *p){ assert( p->pBt->pPager!=0 ); - return sqlite3PagerFilename(p->pBt->pPager); + return sqlite3PagerFilename(p->pBt->pPager, 1); } /* ** Return the pathname of the journal file for this database. The return ** value of this routine is the same regardless of whether the journal file Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -2053,10 +2053,11 @@ zFile = sqlite3_malloc(nUri+2); if( !zFile ) return SQLITE_NOMEM; memcpy(zFile, zUri, nUri); zFile[nUri] = '\0'; zFile[nUri+1] = '\0'; + flags &= ~SQLITE_OPEN_URI; } *ppVfs = sqlite3_vfs_find(zVfs); if( *ppVfs==0 ){ *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -4358,11 +4358,16 @@ *ppPager = 0; #ifndef SQLITE_OMIT_MEMORYDB if( flags & PAGER_MEMORY ){ memDb = 1; - zFilename = 0; + if( zFilename && zFilename[0] ){ + zPathname = sqlite3DbStrDup(0, zFilename); + if( zPathname==0 ) return SQLITE_NOMEM; + nPathname = sqlite3Strlen30(zPathname); + zFilename = 0; + } } #endif /* Compute and store the full pathname in an allocated buffer pointed ** to by zPathname, length nPathname. Or, if this is a temporary file, @@ -6294,13 +6299,20 @@ return rc; } /* ** Return the full pathname of the database file. +** +** Except, if the pager is in-memory only, then return an empty string if +** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when +** used to report the filename to the user, for compatibility with legacy +** behavior. But when the Btree needs to know the filename for matching to +** shared cache, it uses nullIfMemDb==0 so that in-memory databases can +** participate in shared-cache. */ -const char *sqlite3PagerFilename(Pager *pPager){ - return pPager->zFilename; +const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){ + return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename; } /* ** Return the VFS structure for the pager. */ Index: src/pager.h ================================================================== --- src/pager.h +++ src/pager.h @@ -149,11 +149,11 @@ /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); int sqlite3PagerRefcount(Pager*); int sqlite3PagerMemUsed(Pager*); -const char *sqlite3PagerFilename(Pager*); +const char *sqlite3PagerFilename(Pager*, int); const sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); const char *sqlite3PagerJournalname(Pager*); int sqlite3PagerNosync(Pager*); void *sqlite3PagerTempSpace(Pager*); Index: src/test_btree.c ================================================================== --- src/test_btree.c +++ src/test_btree.c @@ -31,11 +31,11 @@ #ifndef SQLITE_OMIT_SHARED_CACHE extern BtShared *sqlite3SharedCacheList; BtShared *pBt; Tcl_Obj *pRet = Tcl_NewObj(); for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ - const char *zFile = sqlite3PagerFilename(pBt->pPager); + const char *zFile = sqlite3PagerFilename(pBt->pPager, 1); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1)); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef)); } Tcl_SetObjResult(interp, pRet); #endif Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -5509,11 +5509,11 @@ eOld = sqlite3PagerGetJournalMode(pPager); if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL - zFilename = sqlite3PagerFilename(pPager); + zFilename = sqlite3PagerFilename(pPager, 1); /* Do not allow a transition to journal_mode=WAL for a database ** in temporary storage or if the VFS does not support shared memory */ if( eNew==PAGER_JOURNALMODE_WAL Index: test/shared.test ================================================================== --- test/shared.test +++ test/shared.test @@ -1054,9 +1054,49 @@ execsql { DROP TABLE t1 } db2 } {} db close db2 close -} +# Shared cache on a :memory: database. This only works for URI filenames. +# +do_test shared-$av-16.1 { + sqlite3 db1 file::memory: -uri 1 + sqlite3 db2 file::memory: -uri 1 + db1 eval { + CREATE TABLE t1(x); INSERT INTO t1 VALUES(1),(2),(3); + } + db2 eval { + SELECT x FROM t1 ORDER BY x; + } +} {1 2 3} +do_test shared-$av-16.2 { + db2 eval { + INSERT INTO t1 VALUES(99); + DELETE FROM t1 WHERE x=2; + } + db1 eval { + SELECT x FROM t1 ORDER BY x; + } +} {1 3 99} + +# Verify that there is no cache sharing ordinary (non-URI) filenames are +# used. +# +do_test shared-$av-16.3 { + db1 close + db2 close + sqlite3 db1 :memory: + sqlite3 db2 :memory: + db1 eval { + CREATE TABLE t1(x); INSERT INTO t1 VALUES(4),(5),(6); + } + catchsql { + SELECT * FROM t1; + } db2 +} {1 {no such table: t1}} +db1 close +db2 close + +} ;# end of autovacuum on/off loop sqlite3_enable_shared_cache $::enable_shared_cache finish_test