When a connection disconnects from a shared-cache database, only delete the in-memory schema if there are no other connections.
FossilOrigin-Name: 46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b
This commit is contained in:
parent
29ddd3acdd
commit
bba02a95d9
24
manifest
24
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sassert()s\sto\sverify\sthat\sTable\sobjects\sin\sthe\sschema\snever\suse\nlookaside\smemory.
|
||||
D 2012-05-15T12:49:32.294
|
||||
C When\sa\sconnection\sdisconnects\sfrom\sa\sshared-cache\sdatabase,\sonly\sdelete\sthe\sin-memory\sschema\sif\sthere\sare\sno\sother\sconnections.
|
||||
D 2012-05-15T17:15:34.812
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -140,7 +140,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
|
||||
F src/main.c 91458c713e9b7f8dbc98d79e78f1150f0ca9c2a1
|
||||
F src/main.c 62146c65069408bc66ad72954655c9cc14bd8f01
|
||||
F src/malloc.c 15afac5e59b6584efe072e9933aefb4230e74f97
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1
|
||||
@ -177,7 +177,7 @@ F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335
|
||||
F src/shell.c 04399b2f9942bd02ed5ffee3b84bcdb39c52a1e6
|
||||
F src/sqlite.h.in 4f4d4792f6fb00387c877af013cb09d955643f12
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h c5e917c4f1453f3972b1fd0c81105dfe4f09cc32
|
||||
F src/sqliteInt.h cef468b8f16c847c235cb9a3d06253389abe3bc9
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -243,7 +243,7 @@ F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
|
||||
F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9
|
||||
F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843
|
||||
F src/vtab.c ae657b1c22cff43863458e768a44f915c07bc0e4
|
||||
F src/vtab.c 1fbe133809ae542a9cf3a3d8187774b68436fa85
|
||||
F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146
|
||||
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
@ -309,7 +309,7 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7
|
||||
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
|
||||
F test/capi3.test 8dedb0050610e9ff95cd9d487beb0ce5f33a31ee
|
||||
F test/capi3.test 8a33b82c4a2469977aed91b6eb99ae3ca1546444
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 01f197d73f4d4d66316483662f475cab7ab5bd60
|
||||
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
|
||||
@ -688,6 +688,7 @@ F test/shared3.test ebf77f023f4bdaa8f74f65822b559e86ce5c6257
|
||||
F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d
|
||||
F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
|
||||
F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e
|
||||
F test/shared8.test b27befbefbe7f4517f1d6b7ff8f64a41ec74165d
|
||||
F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de
|
||||
F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
|
||||
F test/shell1.test cd9f846702d1d471225a988fee590a153be8192c
|
||||
@ -997,7 +998,10 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P 0bb1cfc63f982db7b29c8e6be6698a6dad100f70
|
||||
R 040b7c6409bc9c8d46165baae8f02a6f
|
||||
U drh
|
||||
Z 46fb04131884f3e5ee0e8870b1bd5af5
|
||||
P 736d6ea677f58e4aa2914fa79a3156b775c5a3f5
|
||||
R cdb1dff646b0010ea62b89ecb700e74c
|
||||
T *branch * shared-schema
|
||||
T *sym-shared-schema *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 9910d0bfd0815b5cd0d4b52750333b7f
|
||||
|
@ -1 +1 @@
|
||||
736d6ea677f58e4aa2914fa79a3156b775c5a3f5
|
||||
46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b
|
37
src/main.c
37
src/main.c
@ -720,6 +720,30 @@ static void functionDestroy(sqlite3 *db, FuncDef *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Disconnect all sqlite3_vtab objects that belong to database connection
|
||||
** db. This is called when db is being closed.
|
||||
*/
|
||||
static void disconnectAllVtab(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Schema *pSchema = db->aDb[i].pSchema;
|
||||
if( db->aDb[i].pSchema ){
|
||||
HashElem *p;
|
||||
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
|
||||
Table *pTab = (Table *)sqliteHashData(p);
|
||||
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an existing SQLite database
|
||||
*/
|
||||
@ -735,10 +759,10 @@ int sqlite3_close(sqlite3 *db){
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
/* Force xDestroy calls on all virtual tables */
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
/* Force xDisconnect calls on all virtual tables */
|
||||
disconnectAllVtab(db);
|
||||
|
||||
/* If a transaction is open, the ResetInternalSchema() call above
|
||||
/* If a transaction is open, the disconnectAllVtab() call above
|
||||
** will not have called the xDisconnect() method on any virtual
|
||||
** tables in the db->aVTrans[] array. The following sqlite3VtabRollback()
|
||||
** call will do so. We need to do this before the check for active
|
||||
@ -779,15 +803,18 @@ int sqlite3_close(sqlite3 *db){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This call frees the schema associated with the temp database only (if
|
||||
** any). It also frees the db->aDb array, if required. */
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
assert( db->nDb<=2 );
|
||||
assert( db->aDb==db->aDbStatic );
|
||||
|
||||
/* Tell the code in notify.c that the connection no longer holds any
|
||||
** locks and does not require any further unlock-notify callbacks.
|
||||
*/
|
||||
sqlite3ConnectionClosed(db);
|
||||
|
||||
assert( db->nDb<=2 );
|
||||
assert( db->aDb==db->aDbStatic );
|
||||
for(j=0; j<ArraySize(db->aFunc.a); j++){
|
||||
FuncDef *pNext, *pHash, *p;
|
||||
for(p=db->aFunc.a[j]; p; p=pHash){
|
||||
|
@ -3101,6 +3101,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
# define sqlite3GetVTable(X,Y) ((VTable*)0)
|
||||
#else
|
||||
void sqlite3VtabClear(sqlite3 *db, Table*);
|
||||
void sqlite3VtabDisconnect(sqlite3 *db, Table *p);
|
||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||
int sqlite3VtabRollback(sqlite3 *db);
|
||||
int sqlite3VtabCommit(sqlite3 *db);
|
||||
|
25
src/vtab.c
25
src/vtab.c
@ -180,6 +180,31 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Table *p is a virtual table. This function removes the VTable object
|
||||
** for table *p associated with database connection db from the linked
|
||||
** list in p->pVTab. It also decrements the VTable ref count. This is
|
||||
** used when closing database connection db to free all of its VTable
|
||||
** objects without disturbing the rest of the Schema object (which may
|
||||
** be being used by other shared-cache connections).
|
||||
*/
|
||||
void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
|
||||
VTable **ppVTab;
|
||||
|
||||
assert( IsVirtual(p) );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
||||
for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){
|
||||
if( (*ppVTab)->db==db ){
|
||||
VTable *pVTab = *ppVTab;
|
||||
*ppVTab = pVTab->pNext;
|
||||
sqlite3VtabUnlock(pVTab);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
|
||||
|
@ -649,13 +649,18 @@ do_test capi3-6.1 {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
} {SQLITE_BUSY}
|
||||
|
||||
# 6.2 and 6.3 used to return SQLITE_ERROR and SQLITE_SCHEMA, respectively.
|
||||
# But since attempting to close a connection no longer resets the internal
|
||||
# schema and expires all statements, this is no longer the case.
|
||||
do_test capi3-6.2 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ERROR}
|
||||
} {SQLITE_ROW}
|
||||
#check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
|
||||
do_test capi3-6.3 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test capi3-6.4-misuse {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
|
113
test/shared8.test
Normal file
113
test/shared8.test
Normal file
@ -0,0 +1,113 @@
|
||||
# 2012 May 15
|
||||
#
|
||||
# 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 that closing one database
|
||||
# connection to a shared-cache while there exist other connections (a)
|
||||
# does not cause the schema to be reloaded and (b) does not cause any
|
||||
# other problems.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !shared_cache { finish_test ; return }
|
||||
set testprefix shared8
|
||||
|
||||
db close
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
do_test 0.0 { sqlite3_enable_shared_cache } {1}
|
||||
|
||||
proc roman {n} {
|
||||
array set R {1 i 2 ii 3 iii 4 iv 5 v 6 vi 7 vii 8 viii 9 ix 10 x}
|
||||
set R($n)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests work as follows:
|
||||
#
|
||||
# 1.0: Open connection [db1] and populate the database.
|
||||
#
|
||||
# 1.1: Using "PRAGMA writable_schema", destroy the database schema on
|
||||
# disk. The schema is still in memory, so it is possible to keep
|
||||
# using it, but any attempt to reload it from disk will fail.
|
||||
#
|
||||
# 1.3-4: Open connection db2. Check that it can see the db schema. Then
|
||||
# close db1 and check that db2 still works. This shows that closing
|
||||
# db1 did not reset the in-memory schema.
|
||||
#
|
||||
# 1.5-7: Similar to 1.3-4.
|
||||
#
|
||||
# 1.8: Close all database connections (deleting the in-memory schema).
|
||||
# Then open a new connection and check that it cannot read the db.
|
||||
#
|
||||
do_test 1.0 {
|
||||
sqlite3 db1 test.db
|
||||
db1 func roman roman
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4);
|
||||
CREATE VIEW v1 AS SELECT a, roman(b) FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} db1
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.1 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
DELETE FROM sqlite_master WHERE 1;
|
||||
PRAGMA writable_schema = 0;
|
||||
SELECT * FROM sqlite_master;
|
||||
} db1
|
||||
} {}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql { SELECT * FROM v1 } db1
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 func roman roman
|
||||
execsql { SELECT * FROM v1 } db2
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.4 {
|
||||
db1 close
|
||||
execsql { SELECT * FROM v1 } db2
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.5 {
|
||||
sqlite3 db3 test.db
|
||||
db3 func roman roman
|
||||
execsql { SELECT * FROM v1 } db3
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.6 {
|
||||
execsql { SELECT * FROM v1 } db2
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.7 {
|
||||
db2 close
|
||||
execsql { SELECT * FROM v1 } db3
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.8 {
|
||||
db3 close
|
||||
sqlite3 db4 test.db
|
||||
catchsql { SELECT * FROM v1 } db4
|
||||
} {1 {no such table: v1}}
|
||||
|
||||
|
||||
foreach db {db1 db2 db3 db4} { catch { $db close } }
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
|
Loading…
x
Reference in New Issue
Block a user