mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Prepared statements now work with CREATE and DROP. All tests pass.
No memory leaks. (CVS 1866) FossilOrigin-Name: ebdb661e0eefe123c422d3c1c371e325bb6cf673
This commit is contained in:
24
manifest
24
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
|
||||
|
@ -1 +1 @@
|
||||
6db3f122aad25b5226670ce682b7263d55c0d301
|
||||
ebdb661e0eefe123c422d3c1c371e325bb6cf673
|
160
src/build.c
160
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 <ctype.h>
|
||||
@ -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; i<pTable->nCol; 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; i<pTable->nCol; 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 && iDb<db->nDb );
|
||||
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; i<pTable->nCol; 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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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*);
|
||||
|
@ -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->iDb<db->nDb );
|
||||
pTable = sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
|
||||
iDb = pTrigger->iDb;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
38
src/vdbe.c
38
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 *
|
||||
**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user