From de0fe3e4c3b05a8ee4db376d84d44d949474fcb6 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Fri, 6 Jan 2006 06:33:12 +0000 Subject: [PATCH] Fix a bug that was emptying shared-schema tables during an ATTACH. (CVS 2867) FossilOrigin-Name: 752a2754879becc32da9f9b910f3330f8c7145e4 --- manifest | 22 +++++++++---------- manifest.uuid | 2 +- src/btree.c | 3 ++- src/build.c | 27 ++++------------------- src/main.c | 32 +++++++++++++++++++++++---- src/util.c | 6 +++++- test/shared.test | 56 +++++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 106 insertions(+), 42 deletions(-) diff --git a/manifest b/manifest index 0d8eee7060..6efbaf3a6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enable\sasync\stesting.\s\sModify\sthe\sOS\slayer\sinterface.\s\sAdd\sthe\ssqlite3_aux.h\sinclude\sfile.\s\sAdd\stests\sfor\sboolean\svalue\srepresentation\sin\sfile\sformat\s4.\s(CVS\s2866) -D 2006-01-06T03:29:57 +C Fix\sa\sbug\sthat\swas\semptying\sshared-schema\stables\sduring\san\sATTACH.\s(CVS\s2867) +D 2006-01-06T06:33:12 F Makefile.in 899551ac1dfad4131a4480176eab9e03c64b71ea F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -34,9 +34,9 @@ F src/alter.c e9deb3f4fd7c663a0d1f235d541bc5ea1f2cfa8b F src/analyze.c d821684cdb4d0403e327e4a3440a832e9e54fa3a F src/attach.c 999104c56a60b88eab11ef9c8f40dedf1650b287 F src/auth.c cdec356a5cd8b217c346f816c5912221537fe87f -F src/btree.c 88a60d2af49daed01316cafbe93777d4d9ba2800 +F src/btree.c d1402f4e1cfc500b31d13990f36dd8d3d27443bc F src/btree.h 96b8c00c6e11ff92f8d3d6a7a0ff358bd10d8f19 -F src/build.c 6b14101f1ed5328c815e12baec11dcec97eed096 +F src/build.c 715ac7d49bbfcae5f3fdfd60885397b2133c283b F src/callback.c 62066afd516f220575e81b1a1239ab92a2eae252 F src/complete.c df1681cef40dec33a286006981845f87b194e7a4 F src/date.c bb079317bff6a2b78aba5c0d2ddae5f6f03acfb7 @@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c d167f9d41932ddaff9162f116e2abc514b0680b6 F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7 -F src/main.c c1d8d2022a65104c847880882fbce9ba32381530 +F src/main.c 244a346ae0d1953c4c872b3429b8712b32f590a1 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/os.c a1953975771e1afa161a96e720e58a6f77f946e4 F src/os.h 1f825a8ec854abe8f4cd3a1851c5f6c43e58fbf8 @@ -84,7 +84,7 @@ F src/tokenize.c 7a3a3d3cc734f684a77c4dfd09eb46fcee25394c F src/trigger.c 858c0a4974035b002fd2192399c6076ac7b75e1f F src/update.c c72e9cbbc0adf8d728c1c39ace03d4adb29b5cfb F src/utf.c b7bffac4260177ae7f83c01d025fe0f5ed70ce71 -F src/util.c a690bbf549fc5c465384f624e90c009935b6d18b +F src/util.c f79eb05721e7b20d1d323f903ea866ed2670c2a4 F src/vacuum.c fbfdd3967fd34e2f260fafed88dcbf3c10856b94 F src/vdbe.c 4dab34666edca29b937180965ad32120e98c8054 F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13 @@ -223,7 +223,7 @@ F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca F test/select5.test 07a90ab3c7e3f0a241a9cdea1d997b2c8a89ff0b F test/select6.test f459a19bdac0501c4d3eb1a4df4b7a76f1bb8ad4 F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6 -F test/shared.test aa054381c8fe21d7f46dc1d460ac85f675297b26 +F test/shared.test ee5a4154d257e4c2ce1ae418783b87847473de90 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 F test/subquery.test e6de53332c0301b3cfa34edc3f3cd5fa1e859efd F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2 @@ -338,7 +338,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P f1922da2d20c5091678e47cc4f43a2a9d141a3b1 -R cef6c464b1bd96d585319f7184eaa0c9 -U drh -Z 3e96ca4b789b1816bc110ed7eb3a7071 +P b8332aa8b83142898779972b3dff13cbe3c78623 +R cf41b9057439725670e2ff912b4af45d +U danielk1977 +Z c046cce8ff38eee9570320533f1a9c01 diff --git a/manifest.uuid b/manifest.uuid index 1483c938e8..bfefadee9e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b8332aa8b83142898779972b3dff13cbe3c78623 \ No newline at end of file +752a2754879becc32da9f9b910f3330f8c7145e4 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 7af9fc4b15..79de82c8d5 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.280 2006/01/06 01:42:58 drh Exp $ +** $Id: btree.c,v 1.281 2006/01/06 06:33:12 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -1722,6 +1722,7 @@ int sqlite3BtreeClose(Btree *p){ if( pBt->xFreeSchema && pBt->pSchema ){ pBt->xFreeSchema(pBt->pSchema); } + sqliteFree(pBt->pSchema); sqliteFree(pBt); return SQLITE_OK; } diff --git a/src/build.c b/src/build.c index 3170bcf2d8..528058a597 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.367 2006/01/05 11:34:34 danielk1977 Exp $ +** $Id: build.c,v 1.368 2006/01/06 06:33:13 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -258,7 +258,6 @@ static void sqliteDeleteIndex(sqlite3 *db, Index *p){ Index *pOld; const char *zName = p->zName; - assert( db!=0 && zName!=0 ); pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0); assert( pOld==0 || pOld==p ); freeIndex(p); @@ -304,9 +303,6 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ ** single file indicated. */ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ - HashElem *pElem; - Hash temp1; - Hash temp2; int i, j; assert( iDb>=0 && iDbnDb ); @@ -314,23 +310,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ for(i=iDb; inDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ - temp1 = pDb->pSchema->tblHash; - temp2 = pDb->pSchema->trigHash; - sqlite3HashInit(&pDb->pSchema->trigHash, SQLITE_HASH_STRING, 0); - sqlite3HashClear(&pDb->pSchema->aFKey); - sqlite3HashClear(&pDb->pSchema->idxHash); - for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ - sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); - } - sqlite3HashClear(&temp2); - sqlite3HashInit(&pDb->pSchema->tblHash, SQLITE_HASH_STRING, 0); - for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ - Table *pTab = sqliteHashData(pElem); - sqlite3DeleteTable(db, pTab); - } - sqlite3HashClear(&temp1); - pDb->pSchema->pSeqTab = 0; - DbClearProperty(db, i, DB_SchemaLoaded); + sqlite3SchemaFree(pDb->pSchema); } if( iDb>0 ) return; } @@ -427,6 +407,8 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; FKey *pFKey, *pNextFKey; + db = 0; + if( pTable==0 ) return; /* Do not delete the table until the reference count reaches zero. */ @@ -450,7 +432,6 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ */ for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ pNextFKey = pFKey->pNextFrom; - assert( sqlite3SchemaToIndex(db, pTable->pSchema)nDb ); assert( sqlite3HashFind(&pTable->pSchema->aFKey, pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey ); sqliteFree(pFKey); diff --git a/src/main.c b/src/main.c index ebf2a3480c..6f4a2c07bf 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.315 2006/01/05 13:48:29 danielk1977 Exp $ +** $Id: main.c,v 1.316 2006/01/06 06:33:13 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -96,10 +96,34 @@ int sqlite3_total_changes(sqlite3 *db){ } /* -** Free a schema structure. +** Free all resources held by the schema structure. The void* argument points +** at a DbSchema struct. This function does not call sqliteFree() on the +** pointer itself, it just cleans up subsiduary resources (i.e. the contents +** of the schema hash tables). */ void sqlite3SchemaFree(void *p){ - sqliteFree(p); + Hash temp1; + Hash temp2; + HashElem *pElem; + DbSchema *pSchema = (DbSchema *)p; + + temp1 = pSchema->tblHash; + temp2 = pSchema->trigHash; + sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0); + sqlite3HashClear(&pSchema->aFKey); + sqlite3HashClear(&pSchema->idxHash); + for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ + sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); + } + sqlite3HashClear(&temp2); + sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0); + for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ + Table *pTab = sqliteHashData(pElem); + sqlite3DeleteTable(0, pTab); + } + sqlite3HashClear(&temp1); + pSchema->pSeqTab = 0; + pSchema->flags &= ~DB_SchemaLoaded; } DbSchema *sqlite3SchemaGet(Btree *pBt){ @@ -109,7 +133,7 @@ DbSchema *sqlite3SchemaGet(Btree *pBt){ }else{ p = (DbSchema *)sqliteMalloc(sizeof(DbSchema)); } - if( p ){ + if( p && 0==p->file_format ){ sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); diff --git a/src/util.c b/src/util.c index 898d3dedb7..82fe9ecf01 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.159 2005/12/29 01:11:37 drh Exp $ +** $Id: util.c,v 1.160 2006/01/06 06:33:13 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -289,6 +289,10 @@ static void applyGuards(u32 *p) checkGuards(p); } +/* +** The argument is a malloc()ed pointer as returned by the test-wrapper. +** Return a pointer to the Os level allocation. +*/ static void *getOsPointer(void *p) { char *z = (char *)p; diff --git a/test/shared.test b/test/shared.test index 0abadc3ef8..cc32aa0190 100644 --- a/test/shared.test +++ b/test/shared.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # -# $Id: shared.test,v 1.2 2006/01/05 11:34:34 danielk1977 Exp $ +# $Id: shared.test,v 1.3 2006/01/06 06:33:13 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -32,6 +32,8 @@ set ::enable_shared_cache [sqlite3_enable_shared_cache 1] # external locking protocol is still working. # shared-3.*: Simple test of read-uncommitted mode. # +# shared-4.*: Check that the schema is locked and unlocked correctly. +# do_test shared-1.1 { # Open a second database on the file test.db. It should use the same pager @@ -218,6 +220,58 @@ catch {db close} catch {db2 close} catch {db3 close} +#-------------------------------------------------------------------------- +# Tests shared-4.* test that the schema locking rules are applied +# correctly. i.e.: +# +# 1. All transactions require a read-lock on the schemas of databases they +# access. +# 2. Transactions that modify a database schema require a write-lock on that +# schema. +# 3. It is not possible to compile a statement while another handle has a +# write-lock on the schema. +# + +# Open two database handles db and db2. Each has a single attach database +# (as well as main): +# +# db.main -> ./test.db +# db.test2 -> ./test2.db +# db2.main -> ./test2.db +# db2.test -> ./test.db +# +file delete -force test.db +file delete -force test2.db +file delete -force test2.db-journal +sqlite3 db test.db +sqlite3 db2 test2.db +do_test shared-4.1.1 { + set sqlite_open_file_count +} {2} +do_test shared-4.1.2 { + execsql {ATTACH 'test2.db' AS test2} + set sqlite_open_file_count +} {2} +do_test shared-4.1.3 { + execsql {ATTACH 'test.db' AS test} db2 + set sqlite_open_file_count +} {2} + +do_test shared-4.2.1 { + execsql { + CREATE TABLE abc(a, b, c); + INSERT INTO abc VALUES('i', 'ii', 'iii'); + } +} {} +do_test shared-4.2.2 { + execsql { + SELECT * FROM test.abc; + } db2 +} {i ii iii} + +catch {db2 close} +catch {db close} + finish_test sqlite3_enable_shared_cache $::enable_shared_cache -- 2.47.2