From 956bc92cde3863fc23923e83f775ecc440547f89 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 24 Jul 2004 17:38:29 +0000 Subject: [PATCH] Prepared statements now work with CREATE and DROP. All tests pass. No memory leaks. (CVS 1866) FossilOrigin-Name: ebdb661e0eefe123c422d3c1c371e325bb6cf673 --- manifest | 24 +++---- manifest.uuid | 2 +- src/build.c | 160 ++++++++++++++++++++++------------------------- src/insert.c | 6 +- src/sqliteInt.h | 6 +- src/trigger.c | 67 +++++++++++++------- src/vdbe.c | 38 ++++++++++- test/misc4.test | 6 +- test/pragma.test | 3 +- 9 files changed, 178 insertions(+), 134 deletions(-) diff --git a/manifest b/manifest index bda594b98f..13627fa0c4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\smore\sproblems\swith\sdeferred\sexecution\sof\sCREATE.\s\sStill\sneed\sto\sdo\sDROP.\nThere\sis\snow\sa\smemory\sleak.\s(CVS\s1865) -D 2004-07-24T14:35:58 +C Prepared\sstatements\snow\swork\swith\sCREATE\sand\sDROP.\s\sAll\stests\spass.\nNo\smemory\sleaks.\s(CVS\s1866) +D 2004-07-24T17:38:29 F Makefile.in 4a5e570a9e2d35b09c31b3cf01b78cea764ade4b F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -29,7 +29,7 @@ F src/attach.c 784456629b3d7e50e4691f496700658fd1f16441 F src/auth.c 60db23b98bb94c8b0178180faaf49dc116674217 F src/btree.c edf4ece708350dec7f28ebd4620c6d33afe6993a F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029 -F src/build.c 3075ca2e66d6da3f98840d18f6e2bc4d15ced569 +F src/build.c 7d2981666b6d0c530766dbf1284aabc328e1ec71 F src/date.c e1bb384a7856c18dce9cadb0afbe6934ba5ddb00 F src/delete.c e81545e546f6bc87d7508a93a09ca70695265af3 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 @@ -37,7 +37,7 @@ F src/expr.c a4e8ac69c872f86bc207364be0e32d0638f61e90 F src/func.c b163fb49efec999eb7bf982f7de5b9be388301f3 F src/hash.c f0a2f22c2a7052d67053b5f4690ea3010bb3fb9f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb -F src/insert.c d99ffe87e1e1397f4233afcd06841d52d6b17b18 +F src/insert.c bedcba371401395033a1a1c578d8fdc3fec87bec F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f F src/main.c 49ea4a45223a002d06b5a4a5db36327acafc1779 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 @@ -60,7 +60,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c aefda626660086addca4ce85c34aeef5d0f44c25 F src/shell.c 93c96c847228c02fb84bb381875d87ee71fbbeb4 F src/sqlite.h.in 80de11cde2c9f78eff4dab0aad1eb5196d6e2a3f -F src/sqliteInt.h 31d5887a802b5f218f604a1fd44fe989873cf2bc +F src/sqliteInt.h d2aebb8c8941bc9cab4506de313f304d358c93b8 F src/table.c 4521c278892f60e4d630788c0ea5cf4db1e75c49 F src/tclsqlite.c 3ce001b3c301876a9c8163472077a4c10e0d49f3 F src/test1.c ef00096c283ccfec1b2ae5fdaccb85fb06e24281 @@ -69,12 +69,12 @@ F src/test3.c 94d0a2a90bccd85802488cb42c69ec8afd2e4646 F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2 F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1 F src/tokenize.c bc7a80e4cf54f42ea4b030c62261c4243133af84 -F src/trigger.c 6aaf6d79cc2157c70a06031dd1531707d644cfb4 +F src/trigger.c 360cf8f12edd4eb3a8a2895b136aac238c3cf44e F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a F src/utf.c f03535db72bfa09e24202ccdd245f21d2fc65f0a F src/util.c 2aacc79b7bf5df5859813dafd3bf3258f67a5234 F src/vacuum.c 23ec8c5f3134c6315f883d648fa63b72d8c3ead3 -F src/vdbe.c cad659a06b30c03b870c4a00a828d78f7a69bbcf +F src/vdbe.c f40f4ca4d9a7ba7c330e5673419f32dd3512547c F src/vdbe.h 75b241c02431b9c0f16eaa9cdbb34146c6287f52 F src/vdbeInt.h 3d8e08c54dcb5ca2169db8bb3a37b81a12efaecd F src/vdbeapi.c c5c6d8f162a9581dde497b1a4034f9a0bf54c355 @@ -140,13 +140,13 @@ F test/minmax.test 6513f9a1bb85fd35ff72b34b7b6634fad6b1e69c F test/misc1.test 72768ec8cabc952a4cfcddca43d566f9e0bce899 F test/misc2.test 703734f5817215ca54e364833b3bf5ff36fcc21e F test/misc3.test eb488314990bfc0959221a1acc465013238bf168 -F test/misc4.test b31a0a08077038b03a9320fd5d9731093da708a8 +F test/misc4.test 9f8ab4896dd627f5f9ba893a7b57c9f0a95dfd64 F test/misuse.test 2a64ce711419f2fd12806ed95af930fd4e7bb8f3 F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0 F test/null.test c14d0f4739f21e929b8115b72bf0c765b6bb1721 F test/pager.test 059cc5c58d3b5a851343dff8c56cf7286425d03a F test/pager2.test 55469c7c1c1a54d6b32d7b3cc99001e90101a1ce -F test/pragma.test f7414c1d902688825ca11f7f5e03628704d903b5 +F test/pragma.test 66a66b7f3b273b93325c9a5794acb418f52fdcbf F test/printf.test 428ad9be92963b68ba222dac4c19724cc4e304ea F test/progress.test 76c722f090b1ccb575e7e4e203a71608c5763beb x F test/quick.test 5bb4afdb204c57329c86fa11f3f0a5296675fd7f @@ -240,7 +240,7 @@ F www/tclsqlite.tcl 06a86cba4d7fc88e2bcd633b57702d3d16abebb5 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 49b991492496e104f5eca620a5d465a742b7ff3a -R 360d271fab96b9095f5b4369737eb03f +P 6db3f122aad25b5226670ce682b7263d55c0d301 +R 987e7be0c6defafac7646ce8c68bde8c U drh -Z e2b908232fc8aa315ba06b1f36120ee8 +Z 4bf2f79f0d58a1ba844cc564cece29c1 diff --git a/manifest.uuid b/manifest.uuid index 32b7dfe7eb..2870753522 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6db3f122aad25b5226670ce682b7263d55c0d301 \ No newline at end of file +ebdb661e0eefe123c422d3c1c371e325bb6cf673 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 4494c43a0d..56a59d4df1 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.242 2004/07/24 14:35:58 drh Exp $ +** $Id: build.c,v 1.243 2004/07/24 17:38:29 drh Exp $ */ #include "sqliteInt.h" #include @@ -191,6 +191,14 @@ Index *sqlite3FindIndex(sqlite *db, const char *zName, const char *zDb){ return p; } +/* +** Reclaim the memory used by an index +*/ +static void freeIndex(Index *p){ + sqliteFree(p->zColAff); + sqliteFree(p); +} + /* ** Remove the given index from the index hash table, and free ** its memory structures. @@ -209,10 +217,7 @@ static void sqliteDeleteIndex(sqlite *db, Index *p){ sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName, strlen(pOld->zName)+1, pOld); } - if( p->zColAff ){ - sqliteFree(p->zColAff); - } - sqliteFree(p); + freeIndex(p); } /* @@ -220,17 +225,25 @@ static void sqliteDeleteIndex(sqlite *db, Index *p){ ** the index from the index hash table and free its memory ** structures. */ -void sqlite3UnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ - if( pIndex->pTable->pIndex==pIndex ){ - pIndex->pTable->pIndex = pIndex->pNext; - }else{ - Index *p; - for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){} - if( p && p->pNext==pIndex ){ - p->pNext = pIndex->pNext; +void sqlite3UnlinkAndDeleteIndex(sqlite *db, int iDb, const char *zIdxName){ + Index *pIndex; + int len; + + len = strlen(zIdxName); + pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0); + if( pIndex ){ + if( pIndex->pTable->pIndex==pIndex ){ + pIndex->pTable->pIndex = pIndex->pNext; + }else{ + Index *p; + for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){} + if( p && p->pNext==pIndex ){ + p->pNext = pIndex->pNext; + } } + freeIndex(pIndex); } - sqliteDeleteIndex(db, pIndex); + db->flags |= SQLITE_InternChanges; } /* @@ -328,6 +341,23 @@ void sqlite3CommitInternalChanges(sqlite *db){ db->flags &= ~SQLITE_InternChanges; } +/* +** Clear the column names from a table or view. +*/ +static void sqliteResetColumnNames(Table *pTable){ + int i; + Column *pCol; + assert( pTable!=0 ); + for(i=0, pCol=pTable->aCol; inCol; i++, pCol++){ + sqliteFree(pCol->zName); + sqliteFree(pCol->zDflt); + sqliteFree(pCol->zType); + } + sqliteFree(pTable->aCol); + pTable->aCol = 0; + pTable->nCol = 0; +} + /* ** Remove the memory data structures associated with the given ** Table. No changes are made to disk by this routine. @@ -344,7 +374,6 @@ void sqlite3CommitInternalChanges(sqlite *db){ ** unlinked. */ void sqlite3DeleteTable(sqlite *db, Table *pTable){ - int i; Index *pIndex, *pNext; FKey *pFKey, *pNextFKey; @@ -371,17 +400,9 @@ void sqlite3DeleteTable(sqlite *db, Table *pTable){ /* Delete the Table structure itself. */ - for(i=0; inCol; i++){ - Column *pCol = &pTable->aCol[i]; - sqliteFree(pCol->zName); - sqliteFree(pCol->zDflt); - sqliteFree(pCol->zType); - } + sqliteResetColumnNames(pTable); sqliteFree(pTable->zName); - sqliteFree(pTable->aCol); - if( pTable->zColAff ){ - sqliteFree(pTable->zColAff); - } + sqliteFree(pTable->zColAff); sqlite3SelectDelete(pTable->pSelect); sqliteFree(pTable); } @@ -390,26 +411,32 @@ void sqlite3DeleteTable(sqlite *db, Table *pTable){ ** Unlink the given table from the hash tables and the delete the ** table structure with all its indices and foreign keys. */ -static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){ - Table *pOld; +void sqlite3UnlinkAndDeleteTable(sqlite *db, int iDb, const char *zTabName){ + Table *p; FKey *pF1, *pF2; - int i = p->iDb; + Db *pDb; + assert( db!=0 ); - pOld = sqlite3HashInsert(&db->aDb[i].tblHash, p->zName, strlen(p->zName)+1,0); - assert( pOld==0 || pOld==p ); - for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ - int nTo = strlen(pF1->zTo) + 1; - pF2 = sqlite3HashFind(&db->aDb[i].aFKey, pF1->zTo, nTo); - if( pF2==pF1 ){ - sqlite3HashInsert(&db->aDb[i].aFKey, pF1->zTo, nTo, pF1->pNextTo); - }else{ - while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } - if( pF2 ){ - pF2->pNextTo = pF1->pNextTo; + assert( iDb>=0 && iDbnDb ); + assert( zTabName && zTabName[0] ); + pDb = &db->aDb[iDb]; + p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0); + if( p ){ + for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ + int nTo = strlen(pF1->zTo) + 1; + pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo); + if( pF2==pF1 ){ + sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo); + }else{ + while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } + if( pF2 ){ + pF2->pNextTo = pF1->pNextTo; + } } } + sqlite3DeleteTable(db, p); } - sqlite3DeleteTable(db, p); + db->flags |= SQLITE_InternChanges; } /* @@ -1530,28 +1557,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ return nErr; } -/* -** Clear the column names from the VIEW pTable. -** -** This routine is called whenever any other table or view is modified. -** The view passed into this routine might depend directly or indirectly -** on the modified or deleted table so we need to clear the old column -** names so that they will be recomputed. -*/ -static void sqliteViewResetColumnNames(Table *pTable){ - int i; - Column *pCol; - assert( pTable!=0 && pTable->pSelect!=0 ); - for(i=0, pCol=pTable->aCol; inCol; i++, pCol++){ - sqliteFree(pCol->zName); - sqliteFree(pCol->zDflt); - sqliteFree(pCol->zType); - } - sqliteFree(pTable->aCol); - pTable->aCol = 0; - pTable->nCol = 0; -} - /* ** Clear the column names from every VIEW in database idx. */ @@ -1561,7 +1566,7 @@ static void sqliteViewResetAll(sqlite *db, int idx){ for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ - sqliteViewResetColumnNames(pTab); + sqliteResetColumnNames(pTab); } } DbClearProperty(db, idx, DB_UnresetViews); @@ -1660,11 +1665,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ while( pTrigger ){ assert( pTrigger->iDb==pTab->iDb || pTrigger->iDb==1 ); sqlite3DropTriggerPtr(pParse, pTrigger, 1); - if( pParse->explain ){ - pTrigger = pTrigger->pNext; - }else{ - pTrigger = pTab->pTrigger; - } + pTrigger = pTrigger->pNext; } /* Drop all SQLITE_MASTER table and index entries that refer to the @@ -1685,18 +1686,9 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ sqlite3VdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb); } } + sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0); sqlite3EndWriteOperation(pParse); } - - /* Delete the in-memory description of the table. - ** - ** Exception: if the SQL statement began with the EXPLAIN keyword, - ** then no changes should be made. - */ - if( !pParse->explain ){ - sqliteUnlinkAndDeleteTable(db, pTab); - db->flags |= SQLITE_InternChanges; - } sqliteViewResetAll(db, iDb); exit_drop_table: @@ -2192,7 +2184,9 @@ void sqlite3CreateIndex( /* Clean up before exiting */ exit_create_index: - if( pIndex ) sqliteFree(pIndex); + if( pIndex ){ + freeIndex(pIndex); + } sqlite3ExprListDelete(pList); sqlite3SrcListDelete(pTblName); sqliteFree(zName); @@ -2261,16 +2255,10 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){ sqlite3ChangeCookie(db, v, pIndex->iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb); + sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0); sqlite3EndWriteOperation(pParse); } - /* Delete the in-memory description of this index. - */ - if( !pParse->explain ){ - sqlite3UnlinkAndDeleteIndex(db, pIndex); - db->flags |= SQLITE_InternChanges; - } - exit_drop_index: sqlite3SrcListDelete(pName); } diff --git a/src/insert.c b/src/insert.c index 7a79df20e1..7959947d15 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.113 2004/06/21 06:50:28 danielk1977 Exp $ +** $Id: insert.c,v 1.114 2004/07/24 17:38:29 drh Exp $ */ #include "sqliteInt.h" @@ -50,7 +50,7 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ pIdx->zColAff[pIdx->nColumn] = '\0'; } - sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, P3_STATIC); + sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, 0); } /* @@ -91,7 +91,7 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){ pTab->zColAff = zColAff; } - sqlite3VdbeChangeP3(v, -1, pTab->zColAff, P3_STATIC); + sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 94656ab414..39561702a3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.310 2004/07/24 14:35:58 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.311 2004/07/24 17:38:29 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1272,7 +1272,9 @@ void sqlite3ExprIfFalse(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite*,const char*, const char*); Table *sqlite3LocateTable(Parse*,const char*, const char*); Index *sqlite3FindIndex(sqlite*,const char*, const char*); -void sqlite3UnlinkAndDeleteIndex(sqlite*,Index*); +void sqlite3UnlinkAndDeleteTable(sqlite*,int,const char*); +void sqlite3UnlinkAndDeleteIndex(sqlite*,int,const char*); +void sqlite3UnlinkAndDeleteTrigger(sqlite*,int,const char*); void sqlite3Vacuum(Parse*, Token*); int sqlite3RunVacuum(char**, sqlite*); int sqlite3GlobCompare(const unsigned char*,const unsigned char*); diff --git a/src/trigger.c b/src/trigger.c index 4ece0557b5..49bd0768cd 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -141,7 +141,7 @@ void sqlite3BeginTrigger( if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; } - if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb), 0, zDb)){ + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){ goto trigger_cleanup; } } @@ -213,13 +213,13 @@ void sqlite3FinishTrigger( if( !db->init.busy ){ static VdbeOpList insertTrig[] = { { OP_NewRecno, 0, 0, 0 }, - { OP_String8, 0, 0, "trigger" }, - { OP_String8, 0, 0, 0 }, /* 2: trigger name */ - { OP_String8, 0, 0, 0 }, /* 3: table name */ + { OP_String8, 0, 0, "trigger" }, + { OP_String8, 0, 0, 0 }, /* 2: trigger name */ + { OP_String8, 0, 0, 0 }, /* 3: table name */ { OP_Integer, 0, 0, 0 }, - { OP_String8, 0, 0, "CREATE TRIGGER "}, - { OP_String8, 0, 0, 0 }, /* 6: SQL */ - { OP_Concat8, 2, 0, 0 }, + { OP_String8, 0, 0, "CREATE TRIGGER "}, + { OP_String8, 0, 0, 0 }, /* 6: SQL */ + { OP_Concat8, 2, 0, 0 }, { OP_MakeRecord, 5, 0, "tttit" }, { OP_PutIntKey, 0, 0, 0 }, }; @@ -239,10 +239,12 @@ void sqlite3FinishTrigger( sqlite3ChangeCookie(db, v, nt->iDb); } sqlite3VdbeAddOp(v, OP_Close, 0, 0); + sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0, + sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC); sqlite3EndWriteOperation(pParse); } - if( !pParse->explain ){ + if( db->init.busy ){ Table *pTab; sqlite3HashInsert(&db->aDb[nt->iDb].trigHash, nt->name, strlen(nt->name)+1, nt); @@ -444,6 +446,15 @@ drop_trigger_cleanup: sqlite3SrcListDelete(pName); } +/* +** Return a pointer to the Table structure for the table that a trigger +** is set on. +*/ +static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){ + return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName); +} + + /* ** Drop a trigger given a pointer to that trigger. If nested is false, ** then also generate code to remove the trigger from the SQLITE_MASTER @@ -453,17 +464,19 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ Table *pTable; Vdbe *v; sqlite *db = pParse->db; + int iDb; - assert( pTrigger->iDbnDb ); - pTable = sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName); + iDb = pTrigger->iDb; + assert( iDb>=0 && iDbnDb ); + pTable = tableOfTrigger(db, pTrigger); assert(pTable); - assert( pTable->iDb==pTrigger->iDb || pTrigger->iDb==1 ); + assert( pTable->iDb==iDb || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; - const char *zDb = db->aDb[pTrigger->iDb].zName; - const char *zTab = SCHEMA_TABLE(pTrigger->iDb); - if( pTrigger->iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; + const char *zDb = db->aDb[iDb].zName; + const char *zTab = SCHEMA_TABLE(iDb); + if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) || sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ return; @@ -487,20 +500,26 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ { OP_Next, 0, ADDR(1), 0}, /* 8 */ }; - sqlite3BeginWriteOperation(pParse, 0, pTrigger->iDb); - sqlite3OpenMasterTable(v, pTrigger->iDb); + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3OpenMasterTable(v, iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0); - sqlite3ChangeCookie(db, v, pTrigger->iDb); + sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); + sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0); } +} - /* - ** If this is not an "explain", then delete the trigger structure. - */ - if( !pParse->explain ){ - const char *zName = pTrigger->name; - int nName = strlen(zName); +/* +** Remove a trigger from the hash tables of the sqlite* pointer. +*/ +void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ + Trigger *pTrigger; + int nName = strlen(zName); + pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0); + if( pTrigger ){ + Table *pTable = tableOfTrigger(db, pTrigger); + assert( pTable!=0 ); if( pTable->pTrigger == pTrigger ){ pTable->pTrigger = pTrigger->pNext; }else{ @@ -514,8 +533,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ } assert(cc); } - sqlite3HashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0); sqlite3DeleteTrigger(pTrigger); + db->flags |= SQLITE_InternChanges; } } diff --git a/src/vdbe.c b/src/vdbe.c index 390576d639..aab44e30dc 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.405 2004/07/24 14:35:59 drh Exp $ +** $Id: vdbe.c,v 1.406 2004/07/24 17:38:29 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -3764,6 +3764,42 @@ case OP_ParseSchema: { break; } +/* Opcode: DropTable P1 * P3 +** +** Remove the internal (in-memory) data structures that describe +** the table named P3 in database P1. This is called after a table +** is dropped in order to keep the internal representation of the +** schema consistent with what is on disk. +*/ +case OP_DropTable: { + sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p3); + break; +} + +/* Opcode: DropIndex P1 * P3 +** +** Remove the internal (in-memory) data structures that describe +** the index named P3 in database P1. This is called after an index +** is dropped in order to keep the internal representation of the +** schema consistent with what is on disk. +*/ +case OP_DropIndex: { + sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p3); + break; +} + +/* Opcode: DropTrigger P1 * P3 +** +** Remove the internal (in-memory) data structures that describe +** the trigger named P3 in database P1. This is called after a trigger +** is dropped in order to keep the internal representation of the +** schema consistent with what is on disk. +*/ +case OP_DropTrigger: { + sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3); + break; +} + /* Opcode: IntegrityCk * P2 * ** diff --git a/test/misc4.test b/test/misc4.test index 23cd465fb9..75c9e20c84 100644 --- a/test/misc4.test +++ b/test/misc4.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc4.test,v 1.5 2004/07/24 14:35:59 drh Exp $ +# $Id: misc4.test,v 1.6 2004/07/24 17:38:30 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -64,11 +64,9 @@ do_test misc4-1.6 { # those statements are executed, try to use the tables, indices, views, # are triggers that were created. # -if 0 { do_test misc4-2.1 { set stmt [sqlite3_prepare $DB {CREATE TABLE t3(x);} -1 TAIL] catchsql { -pragma vdbe_trace=on; INSERT INTO t3 VALUES(1); } } {1 {no such table: t3}} @@ -83,6 +81,6 @@ do_test misc4-2.4 { INSERT INTO t3 VALUES(1); } } {0 {}} -} + finish_test diff --git a/test/pragma.test b/test/pragma.test index 9cea4c0c5c..490851f106 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -12,7 +12,7 @@ # # This file implements tests for the PRAGMA command. # -# $Id: pragma.test,v 1.16 2004/07/22 15:02:26 drh Exp $ +# $Id: pragma.test,v 1.17 2004/07/24 17:38:30 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -306,6 +306,7 @@ catchsql {COMMIT;} # Test schema-query pragmas # do_test pragma-6.1 { + set res {} foreach {idx name file} [execsql {pragma database_list}] { lappend res $idx $name }