From bba02a95d92582227b37a2a96162e5d76be24adc Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 15 May 2012 17:15:34 +0000 Subject: [PATCH 1/5] When a connection disconnects from a shared-cache database, only delete the in-memory schema if there are no other connections. FossilOrigin-Name: 46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b --- manifest | 24 ++++++---- manifest.uuid | 2 +- src/main.c | 37 +++++++++++++-- src/sqliteInt.h | 1 + src/vtab.c | 25 ++++++++++ test/capi3.test | 9 +++- test/shared8.test | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 193 insertions(+), 18 deletions(-) create mode 100644 test/shared8.test diff --git a/manifest b/manifest index 68138a320d..ea85d284ac 100644 --- a/manifest +++ b/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 diff --git a/manifest.uuid b/manifest.uuid index d1f1a9b991..917ae6d0b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -736d6ea677f58e4aa2914fa79a3156b775c5a3f5 \ No newline at end of file +46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b \ No newline at end of file diff --git a/src/main.c b/src/main.c index d148b4b42c..869fbb376b 100644 --- a/src/main.c +++ b/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; inDb; 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; jaFunc.a); j++){ FuncDef *pNext, *pHash, *p; for(p=db->aFunc.a[j]; p; p=pHash){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index cb178ff97c..cefff07ec5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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); diff --git a/src/vtab.c b/src/vtab.c index c561f7198f..f660b54439 100644 --- a/src/vtab.c +++ b/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. diff --git a/test/capi3.test b/test/capi3.test index d9106267c5..b84ddbbf1a 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -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 diff --git a/test/shared8.test b/test/shared8.test new file mode 100644 index 0000000000..600e02bf7e --- /dev/null +++ b/test/shared8.test @@ -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 + From 81028a455de1b4e8782c3f233369515e83822bde Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 15 May 2012 18:28:27 +0000 Subject: [PATCH 2/5] The former sqlite3ResetInternalSchema() routine was really two different routines, selected by parameter, each with a confused mission. So split this routine up into three separate smaller routines, calling each separately as needed. Hopefully this will make further refactoring and schema reset collateral damage containment easier. FossilOrigin-Name: aa0c3493d3647d7efe527067e9fcccefda8e3008 --- manifest | 35 ++++++++--------- manifest.uuid | 2 +- src/attach.c | 4 +- src/backup.c | 2 +- src/build.c | 99 +++++++++++++++++++++++++------------------------ src/main.c | 4 +- src/pragma.c | 2 +- src/prepare.c | 8 ++-- src/sqliteInt.h | 4 +- src/vacuum.c | 2 +- src/vdbe.c | 8 ++-- src/vtab.c | 6 +-- 12 files changed, 88 insertions(+), 88 deletions(-) diff --git a/manifest b/manifest index ea85d284ac..2d4da7eb65 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 +C The\sformer\ssqlite3ResetInternalSchema()\sroutine\swas\sreally\stwo\sdifferent\s\nroutines,\sselected\sby\sparameter,\seach\swith\sa\sconfused\smission.\s\sSo\ssplit\nthis\sroutine\sup\sinto\sthree\sseparate\ssmaller\sroutines,\scalling\seach\nseparately\sas\sneeded.\s\sHopefully\sthis\swill\smake\sfurther\srefactoring\sand\nschema\sreset\scollateral\sdamage\scontainment\seasier. +D 2012-05-15T18:28:27.325 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -113,15 +113,15 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F src/alter.c 149cc80d9257971b0bff34e58fb2263e01998289 F src/analyze.c 70c46504c0d2543ea5cdca01140b2cd3e1d886e7 -F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f +F src/attach.c 577bf5675b0c50495fc28549f2fcbdb1bac71143 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c 6be23a344d3301ae38e92fddb3a33b91c309fce4 +F src/backup.c d7fb4c6d2ad3fe51a4ce1a897fde7b00f4de5fef F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c df800f10896bc2ddaa1125c532d6e7a7b9efc532 F src/btree.h 48a013f8964f12d944d90e4700df47b72dd6d923 F src/btreeInt.h 38a639c0542c29fe8331a221c4aed0cb8686249e -F src/build.c 95fd8aa1bf81acf15e9ef46b07d1f70111ea88d0 +F src/build.c 6da3a261958d79805df198808b35209e93acf52d F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33 @@ -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 62146c65069408bc66ad72954655c9cc14bd8f01 +F src/main.c 28804c01149c1e707418434a42dc36438acdc5c8 F src/malloc.c 15afac5e59b6584efe072e9933aefb4230e74f97 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1 @@ -167,8 +167,8 @@ F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60 -F src/pragma.c e708b3bb5704605816f617e0b1d63a5488060715 -F src/prepare.c 9a00a9612ebf80203fbb41f8a29ab8cb27a05f40 +F src/pragma.c 28d7955a9e9a27d41cb462690228d39e3cec231c +F src/prepare.c ef197444dac110ee57a5f49745368b447a8c6bd1 F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 748e75299faff345f34f0e5bd02a2bac8aa69fcd @@ -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 cef468b8f16c847c235cb9a3d06253389abe3bc9 +F src/sqliteInt.h 05b22e581622128168d786a7c852d1763dd45559 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -233,8 +233,8 @@ F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684 F src/update.c d3076782c887c10e882996550345da9c4c9f9dea F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84 F src/util.c 4f6cfad661b2e3454b0cdd5b1b9d39a54942d0e3 -F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8 -F src/vdbe.c e1d26b98288889c22f00cf4851ec351ee67ad8b9 +F src/vacuum.c 587a52bb8833d7ac15af8916f25437e2575028bd +F src/vdbe.c 6ed3e89957a0dd55e9c4ab7842949051ba8eaaa9 F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb F src/vdbeInt.h 6ff4180a05683566a8835d12f7ec504b22932c82 F src/vdbeapi.c 3662b6a468a2a4605a15dfab313baa6dff81ad91 @@ -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 1fbe133809ae542a9cf3a3d8187774b68436fa85 +F src/vtab.c 4c1d7e7206aa330da12cfbed29bbe08a5fd2c08e F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -998,10 +998,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 736d6ea677f58e4aa2914fa79a3156b775c5a3f5 -R cdb1dff646b0010ea62b89ecb700e74c -T *branch * shared-schema -T *sym-shared-schema * -T -sym-trunk * -U dan -Z 9910d0bfd0815b5cd0d4b52750333b7f +P 46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b +R 3470c7e3b0ec734f279c648e5bd9b93d +U drh +Z 93dd6b08b78f998064cdd25b32f8367e diff --git a/manifest.uuid b/manifest.uuid index 917ae6d0b9..680e37e511 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b \ No newline at end of file +aa0c3493d3647d7efe527067e9fcccefda8e3008 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 18f8823b31..e295c30111 100644 --- a/src/attach.c +++ b/src/attach.c @@ -216,7 +216,7 @@ static void attachFunc( db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; @@ -288,7 +288,7 @@ static void detachFunc( sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); return; detach_error: diff --git a/src/backup.c b/src/backup.c index 7a4047f34c..0ada33c3be 100644 --- a/src/backup.c +++ b/src/backup.c @@ -414,7 +414,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); if( rc==SQLITE_OK ){ if( p->pDestDb ){ - sqlite3ResetInternalSchema(p->pDestDb, -1); + sqlite3ResetAllSchemasOfConnection(p->pDestDb); } if( destMode==PAGER_JOURNALMODE_WAL ){ rc = sqlite3BtreeSetVersion(p->pDest, 2); diff --git a/src/build.c b/src/build.c index e02f0402fc..3eefac9391 100644 --- a/src/build.c +++ b/src/build.c @@ -394,58 +394,15 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ } /* -** Erase all schema information from the in-memory hash tables of -** a single database. This routine is called to reclaim memory -** before the database closes. It is also called during a rollback -** if there were schema changes during the transaction or if a -** schema-cookie mismatch occurs. +** Look through the list of open database files in db->aDb[] and if +** any have been closed, remove them from the list. Reallocate the +** db->aDb[] structure to a smaller size, if possible. ** -** If iDb<0 then reset the internal schema tables for all database -** files. If iDb>=0 then reset the internal schema for only the -** single file indicated. +** Entry 0 (the "main" database) and entry 1 (the "temp" database) +** are never candidates for being collapsed. */ -void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ +void sqlite3CollapseDatabaseArray(sqlite3 *db){ int i, j; - assert( iDbnDb ); - - if( iDb>=0 ){ - /* Case 1: Reset the single schema identified by iDb */ - Db *pDb = &db->aDb[iDb]; - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); - - /* If any database other than TEMP is reset, then also reset TEMP - ** since TEMP might be holding triggers that reference tables in the - ** other database. - */ - if( iDb!=1 ){ - pDb = &db->aDb[1]; - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); - } - return; - } - /* Case 2 (from here to the end): Reset all schemas for all attached - ** databases. */ - assert( iDb<0 ); - sqlite3BtreeEnterAll(db); - for(i=0; inDb; i++){ - Db *pDb = &db->aDb[i]; - if( pDb->pSchema ){ - sqlite3SchemaClear(pDb->pSchema); - } - } - db->flags &= ~SQLITE_InternChanges; - sqlite3VtabUnlockList(db); - sqlite3BtreeLeaveAll(db); - - /* If one or more of the auxiliary database files has been closed, - ** then remove them from the auxiliary database list. We take the - ** opportunity to do this here since we have just deleted all of the - ** schema hash tables and therefore do not have to make any changes - ** to any of those tables. - */ for(i=j=2; inDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ @@ -467,6 +424,50 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ } } +/* +** Reset the schema for the database at index iDb. Also reset the +** TEMP schema. +*/ +void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ + assert( iDbnDb ); + + /* Case 1: Reset the single schema identified by iDb */ + Db *pDb = &db->aDb[iDb]; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + assert( pDb->pSchema!=0 ); + sqlite3SchemaClear(pDb->pSchema); + + /* If any database other than TEMP is reset, then also reset TEMP + ** since TEMP might be holding triggers that reference tables in the + ** other database. + */ + if( iDb!=1 ){ + pDb = &db->aDb[1]; + assert( pDb->pSchema!=0 ); + sqlite3SchemaClear(pDb->pSchema); + } + return; +} + +/* +** Erase all schema information from all attached databases (including +** "main" and "temp") for a single database connection. +*/ +void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ + int i; + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Db *pDb = &db->aDb[i]; + if( pDb->pSchema ){ + sqlite3SchemaClear(pDb->pSchema); + } + } + db->flags &= ~SQLITE_InternChanges; + sqlite3VtabUnlockList(db); + sqlite3BtreeLeaveAll(db); + sqlite3CollapseDatabaseArray(db); +} + /* ** This routine is called when a commit occurs. */ diff --git a/src/main.c b/src/main.c index 869fbb376b..c0c7aa5f66 100644 --- a/src/main.c +++ b/src/main.c @@ -806,7 +806,7 @@ 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); + sqlite3ResetAllSchemasOfConnection(db); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); @@ -901,7 +901,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ if( db->flags&SQLITE_InternChanges ){ sqlite3ExpirePreparedStatements(db); - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); } /* Any deferred constraint violations have now been resolved. */ diff --git a/src/pragma.c b/src/pragma.c index 2db0b61508..3401c73c1b 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -118,7 +118,7 @@ static int invalidateTempStorage(Parse *pParse){ } sqlite3BtreeClose(db->aDb[1].pBt); db->aDb[1].pBt = 0; - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); } return SQLITE_OK; } diff --git a/src/prepare.c b/src/prepare.c index c46e55ed2c..f1dbb6b3b0 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -342,7 +342,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ } if( db->mallocFailed ){ rc = SQLITE_NOMEM; - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); } if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider @@ -395,7 +395,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; rc = sqlite3InitOne(db, i, pzErrMsg); if( rc ){ - sqlite3ResetInternalSchema(db, i); + sqlite3ResetOneSchema(db, i); } } @@ -408,7 +408,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 1, pzErrMsg); if( rc ){ - sqlite3ResetInternalSchema(db, 1); + sqlite3ResetOneSchema(db, 1); } } #endif @@ -476,7 +476,7 @@ static void schemaIsValid(Parse *pParse){ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ - sqlite3ResetInternalSchema(db, iDb); + sqlite3ResetOneSchema(db, iDb); pParse->rc = SQLITE_SCHEMA; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index cefff07ec5..8cd022d7a5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2696,7 +2696,9 @@ void sqlite3ExprListDelete(sqlite3*, ExprList*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); -void sqlite3ResetInternalSchema(sqlite3*, int); +void sqlite3ResetAllSchemasOfConnection(sqlite3*); +void sqlite3ResetOneSchema(sqlite3*,int); +void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3BeginParse(Parse*,int); void sqlite3CommitInternalChanges(sqlite3*); Table *sqlite3ResultSetOfSelect(Parse*,Select*); diff --git a/src/vacuum.c b/src/vacuum.c index c03b4500b3..401d41dfb7 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -339,7 +339,7 @@ end_of_vacuum: /* This both clears the schemas and reduces the size of the db->aDb[] ** array. */ - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); return rc; } diff --git a/src/vdbe.c b/src/vdbe.c index fa5180c9a4..aa42a0f735 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2747,7 +2747,7 @@ case OP_Savepoint: { } if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ sqlite3ExpirePreparedStatements(db); - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); } } @@ -3051,7 +3051,7 @@ case OP_VerifyCookie: { ** a v-table method. */ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ - sqlite3ResetInternalSchema(db, pOp->p1); + sqlite3ResetOneSchema(db, pOp->p1); } p->expired = 1; @@ -4864,7 +4864,7 @@ case OP_ParseSchema: { db->init.busy = 0; } } - if( rc ) sqlite3ResetInternalSchema(db, -1); + if( rc ) sqlite3ResetAllSchemasOfConnection(db); if( rc==SQLITE_NOMEM ){ goto no_mem; } @@ -6159,7 +6159,7 @@ vdbe_error_halt: if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1; rc = SQLITE_ERROR; if( resetSchemaOnFault>0 ){ - sqlite3ResetInternalSchema(db, resetSchemaOnFault-1); + sqlite3ResetOneSchema(db, resetSchemaOnFault-1); } /* This is the only way out of this procedure. We have to diff --git a/src/vtab.c b/src/vtab.c index f660b54439..24eee1a81a 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -22,8 +22,8 @@ ** are invoked only from within xCreate and xConnect methods. */ struct VtabCtx { - Table *pTab; - VTable *pVTable; + VTable *pVTable; /* The virtual table being constructed */ + Table *pTab; /* The Table object to which the virtual table belongs */ }; /* @@ -54,7 +54,7 @@ static int createModule( pMod->xDestroy = xDestroy; pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); if( pDel && pDel->xDestroy ){ - sqlite3ResetInternalSchema(db, -1); + sqlite3ResetAllSchemasOfConnection(db); pDel->xDestroy(pDel->pAux); } sqlite3DbFree(db, pDel); From 5efb3145256ed3a87a4c25ad5899e136ff132eca Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 May 2012 01:24:34 +0000 Subject: [PATCH 3/5] Avoid using sqlite3ResetAllSchemasOfConnection() purely for its side-effects. FossilOrigin-Name: 5587c73badc07d3e01a7c5c5964e178b5112dd24 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/main.c | 11 ++++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 2d4da7eb65..7f50ea50c8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sformer\ssqlite3ResetInternalSchema()\sroutine\swas\sreally\stwo\sdifferent\s\nroutines,\sselected\sby\sparameter,\seach\swith\sa\sconfused\smission.\s\sSo\ssplit\nthis\sroutine\sup\sinto\sthree\sseparate\ssmaller\sroutines,\scalling\seach\nseparately\sas\sneeded.\s\sHopefully\sthis\swill\smake\sfurther\srefactoring\sand\nschema\sreset\scollateral\sdamage\scontainment\seasier. -D 2012-05-15T18:28:27.325 +C Avoid\susing\ssqlite3ResetAllSchemasOfConnection()\spurely\sfor\sits\sside-effects. +D 2012-05-16T01:24:34.201 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 28804c01149c1e707418434a42dc36438acdc5c8 +F src/main.c 48f47554ccedb2e800aa8f5fb316835a584f709f F src/malloc.c 15afac5e59b6584efe072e9933aefb4230e74f97 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1 @@ -998,7 +998,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 46f4eb5430d7bc9a339cdf7124ff4bd518eaa39b -R 3470c7e3b0ec734f279c648e5bd9b93d +P aa0c3493d3647d7efe527067e9fcccefda8e3008 +R f77d3725cc1e7473c355856cafd6e6e6 U drh -Z 93dd6b08b78f998064cdd25b32f8367e +Z 8c590823c466df3da4ff72040b91d983 diff --git a/manifest.uuid b/manifest.uuid index 680e37e511..657abd7526 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa0c3493d3647d7efe527067e9fcccefda8e3008 \ No newline at end of file +5587c73badc07d3e01a7c5c5964e178b5112dd24 \ No newline at end of file diff --git a/src/main.c b/src/main.c index c0c7aa5f66..41adb0e932 100644 --- a/src/main.c +++ b/src/main.c @@ -793,6 +793,7 @@ int sqlite3_close(sqlite3 *db){ /* Free any outstanding Savepoint structures. */ sqlite3CloseSavepoints(db); + /* Close all database connections */ for(j=0; jnDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ @@ -803,10 +804,14 @@ int sqlite3_close(sqlite3 *db){ } } } + /* Clear the TEMP schema separately and last */ + if( db->aDb[1].pSchema ){ + sqlite3SchemaClear(db->aDb[1].pSchema); + } + sqlite3VtabUnlockList(db); - /* This call frees the schema associated with the temp database only (if - ** any). It also frees the db->aDb array, if required. */ - sqlite3ResetAllSchemasOfConnection(db); + /* Free up the array of auxiliary databases */ + sqlite3CollapseDatabaseArray(db); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); From ca8b9bac3b7d5fa457883936062fef2ee10a8ecb Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 16 May 2012 14:29:11 +0000 Subject: [PATCH 4/5] Return SQLITE_MISUSE if an application attempts to register a virtual table module with the same name as an existing module. FossilOrigin-Name: ea2cd55e098b21cd8997fd6c1978131d3ef2fab4 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/test8.c | 20 ++++++++++++++------ src/vtab.c | 46 ++++++++++++++++++++++++---------------------- test/vtab1.test | 14 ++++++++++++++ 5 files changed, 62 insertions(+), 38 deletions(-) diff --git a/manifest b/manifest index 7f50ea50c8..5ee9da6342 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\susing\ssqlite3ResetAllSchemasOfConnection()\spurely\sfor\sits\sside-effects. -D 2012-05-16T01:24:34.201 +C Return\sSQLITE_MISUSE\sif\san\sapplication\sattempts\sto\sregister\sa\svirtual\stable\smodule\swith\sthe\ssame\sname\sas\san\sexisting\smodule. +D 2012-05-16T14:29:11.421 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -189,7 +189,7 @@ F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013 F src/test6.c 417e1e214734393c24a8ee80b41485a9c4169123 F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843 -F src/test8.c 5ecbffe6712da81d5d10454e9d77d6c5bac95fe8 +F src/test8.c 235f1d19716fa768c46fc461ccbf529b2c9e4399 F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e @@ -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 4c1d7e7206aa330da12cfbed29bbe08a5fd2c08e +F src/vtab.c bb8ea3a26608bb1357538a5d2fc72beba6638998 F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -900,7 +900,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b F test/view.test b182a67ec43f490b156b5a710827a341be83dd17 -F test/vtab1.test e429a6835faa3870016c55d1178dcfead85f936a +F test/vtab1.test 331ca61ba0b5df4d2f2e55ee2b9596fde4228dbe F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 @@ -998,7 +998,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P aa0c3493d3647d7efe527067e9fcccefda8e3008 -R f77d3725cc1e7473c355856cafd6e6e6 -U drh -Z 8c590823c466df3da4ff72040b91d983 +P 5587c73badc07d3e01a7c5c5964e178b5112dd24 +R c4833805a7760d62c8726aeccbf50a1f +U dan +Z 29dbe9b5d386a5757fe1ec7bc83d13ea diff --git a/manifest.uuid b/manifest.uuid index 657abd7526..aad61d8e81 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5587c73badc07d3e01a7c5c5964e178b5112dd24 \ No newline at end of file +ea2cd55e098b21cd8997fd6c1978131d3ef2fab4 \ No newline at end of file diff --git a/src/test8.c b/src/test8.c index ba7e37372c..372eef664a 100644 --- a/src/test8.c +++ b/src/test8.c @@ -1300,6 +1300,7 @@ static sqlite3_module echoModuleV2 = { ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); +extern const char *sqlite3TestErrorName(int rc); static void moduleDestroy(void *p){ sqlite3_free(p); @@ -1314,6 +1315,7 @@ static int register_echo_module( int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ + int rc; sqlite3 *db; EchoModule *pMod; if( objc!=2 ){ @@ -1325,14 +1327,20 @@ static int register_echo_module( /* Virtual table module "echo" */ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; - sqlite3_create_module_v2(db, "echo", &echoModule, (void*)pMod, moduleDestroy); + rc = sqlite3_create_module_v2( + db, "echo", &echoModule, (void*)pMod, moduleDestroy + ); /* Virtual table module "echo_v2" */ - pMod = sqlite3_malloc(sizeof(EchoModule)); - pMod->interp = interp; - sqlite3_create_module_v2(db, "echo_v2", - &echoModuleV2, (void*)pMod, moduleDestroy - ); + if( rc==SQLITE_OK ){ + pMod = sqlite3_malloc(sizeof(EchoModule)); + pMod->interp = interp; + rc = sqlite3_create_module_v2(db, "echo_v2", + &echoModuleV2, (void*)pMod, moduleDestroy + ); + } + + Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); return TCL_OK; } diff --git a/src/vtab.c b/src/vtab.c index 24eee1a81a..0e082a05d9 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -38,33 +38,35 @@ static int createModule( void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ - int rc, nName; - Module *pMod; + int rc = SQLITE_OK; + int nName; sqlite3_mutex_enter(db->mutex); nName = sqlite3Strlen30(zName); - pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); - if( pMod ){ - Module *pDel; - char *zCopy = (char *)(&pMod[1]); - memcpy(zCopy, zName, nName+1); - pMod->zName = zCopy; - pMod->pModule = pModule; - pMod->pAux = pAux; - pMod->xDestroy = xDestroy; - pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); - if( pDel && pDel->xDestroy ){ - sqlite3ResetAllSchemasOfConnection(db); - pDel->xDestroy(pDel->pAux); + if( sqlite3HashFind(&db->aModule, zName, nName) ){ + rc = SQLITE_MISUSE_BKPT; + }else{ + Module *pMod; + pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); + if( pMod ){ + Module *pDel; + char *zCopy = (char *)(&pMod[1]); + memcpy(zCopy, zName, nName+1); + pMod->zName = zCopy; + pMod->pModule = pModule; + pMod->pAux = pAux; + pMod->xDestroy = xDestroy; + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,nName,(void*)pMod); + assert( pDel==0 || pDel==pMod ); + if( pDel ){ + db->mallocFailed = 1; + sqlite3DbFree(db, pDel); + } } - sqlite3DbFree(db, pDel); - if( pDel==pMod ){ - db->mallocFailed = 1; - } - }else if( xDestroy ){ - xDestroy(pAux); } - rc = sqlite3ApiExit(db, SQLITE_OK); + rc = sqlite3ApiExit(db, rc); + if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); + sqlite3_mutex_leave(db->mutex); return rc; } diff --git a/test/vtab1.test b/test/vtab1.test index 38aec09eae..9fb843f754 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -1275,4 +1275,18 @@ foreach {tn sql res filter} { } do_execsql_test 18.2.x { PRAGMA case_sensitive_like = OFF } +#------------------------------------------------------------------------- +# Test that an existing module may not be overridden. +# +do_test 19.1 { + sqlite3 db2 test.db + register_echo_module [sqlite3_connection_pointer db2] +} SQLITE_OK +do_test 19.2 { + register_echo_module [sqlite3_connection_pointer db2] +} SQLITE_MISUSE +do_test 19.3 { + db2 close +} {} + finish_test From a19b89627eec4c0506b98f34d5f50399c26fd8d4 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 6 Jun 2012 10:56:22 +0000 Subject: [PATCH 5/5] Make sure the Index.azColl pointers do not point to connection-specific memory. Also, remove an unnecessary reinitialization to sqlite3.pDfltColl. FossilOrigin-Name: c469850b2eb61a63150cc5fc7d2fe98f0b5abffb --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 2 +- src/prepare.c | 1 - 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 8dd687ea56..9c4e896868 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\slatest\strunk\schanges\sinto\sshared-schema\sbranch.\s\sAlso\sfix\sa\sC99-ism\s\nin\sthat\sbranch. -D 2012-06-05T19:20:03.039 +C Make\ssure\sthe\sIndex.azColl\spointers\sdo\snot\spoint\sto\sconnection-specific\smemory.\nAlso,\sremove\san\sunnecessary\sreinitialization\sto\ssqlite3.pDfltColl. +D 2012-06-06T10:56:22.535 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 4f37eb61be9d38643cdd839a74b8e3bad724cfcf F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -126,7 +126,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c f0b71054103cb77eb5e782088c16998ec4f06624 F src/btree.h 48a013f8964f12d944d90e4700df47b72dd6d923 F src/btreeInt.h 38a639c0542c29fe8331a221c4aed0cb8686249e -F src/build.c 178b24b35ada3688aa63d04cd6a2f972cb481aea +F src/build.c 47c4506afe4bcb4ed1f4b5357582d1cb3402f8ad F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33 @@ -173,7 +173,7 @@ F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60 F src/pragma.c 28d7955a9e9a27d41cb462690228d39e3cec231c -F src/prepare.c ef197444dac110ee57a5f49745368b447a8c6bd1 +F src/prepare.c 33291b83cca285718048d219c67b8298501fa3a5 F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c b3c70ab28cac60de33684c9aa9e5138dcf71d6dd @@ -1005,7 +1005,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P ea2cd55e098b21cd8997fd6c1978131d3ef2fab4 61669c95859e187618fb2fb4249306a947ae8d26 -R fc7cb647ad4d37ffcdbbdbe50e659acc +P 42338e9e6979bb497823527f8f39e96f63623c59 +R 4e8ba0ec11cbdf49789a46888b404344 U drh -Z 0c46cbc562d7f9db30fca97ff8d69c33 +Z a16a791ba70d8a38d9ba353fda40937d diff --git a/manifest.uuid b/manifest.uuid index 7d57948980..52f568de93 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42338e9e6979bb497823527f8f39e96f63623c59 \ No newline at end of file +c469850b2eb61a63150cc5fc7d2fe98f0b5abffb \ No newline at end of file diff --git a/src/build.c b/src/build.c index 7938343e81..9f13b7b11c 100644 --- a/src/build.c +++ b/src/build.c @@ -2765,7 +2765,7 @@ Index *sqlite3CreateIndex( }else{ zColl = pTab->aCol[j].zColl; if( !zColl ){ - zColl = db->pDfltColl->zName; + zColl = "BINARY"; } } if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ diff --git a/src/prepare.c b/src/prepare.c index f1dbb6b3b0..bd2cf7aafc 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -262,7 +262,6 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; ENC(db) = encoding; - db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){