diff --git a/manifest b/manifest index a5660db4bb..1acb5b20bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s2.8.1\s(CVS\s980) -D 2003-05-17T02:44:32 +C Fix\sproblems\swith\sTEMP\sindices\sthat\slead\sto\scorrupt\sdatabases.\s\sThese\nproblems\swere\sdiscovered\swhile\sworking\son\sticket\s#317.\s\sNo\ssure\syet\sif\nthat\sticket\sis\sfixed.\s(CVS\s981) +D 2003-05-17T17:35:11 F Makefile.in 1ff85c27d4350c74118341024e8a4fb2a04a3a43 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -21,19 +21,19 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183 F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6 -F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d +F src/btree.c 8092dca45dcdb69c61273db0213cbb85760673c7 F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e -F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d -F src/build.c e24461d42381a36de88de6af06c03d9f14588705 -F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263 -F src/delete.c f9536a75b444a21f11b7a1bc0fb8c876f691b013 +F src/btree_rb.c 1d809e703aab8bef916ebb0b6ba9254a1c36d9a6 +F src/build.c 95dfb188f448e6299108396546a8333ecdcb1716 +F src/copy.c 5e5d558d283536592cd67b5dc1519c3152bd7e20 +F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc F src/encode.c ed720e54ec4ef4d4de651592f1dd1c74d422bbd2 F src/expr.c a666ef5220ca90ebcf40c8ccc783966a345a7616 F src/func.c 33bbce6acaf9578ac99aa1f689968ccaf2ce43a2 F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 -F src/insert.c fac16589e644b2d4bb615c5e782bcfd0453a052a -F src/main.c 16e68905793b118552a9cf43a9f77ca1d9e395a9 +F src/insert.c 2f26b95cc1055062411cbdea06e2e1b40a8b0d8d +F src/main.c 717aaf32d468667dabeaec80054e11bfdb6309b6 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c 94b618c0c0a76210e53857d77c96d2f042dc33b1 F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49 @@ -43,11 +43,11 @@ F src/parse.y 39b5240cb78047dc56d6d37c398baed7ba556779 F src/pragma.c ec64704e61286948f39157617f1ce2f506dd1b74 F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe -F src/select.c c06b4605bca03d8237a3fc4098179bf3a7133702 +F src/select.c 15d921308065c9320363af6f43c01d9f09ea7118 F src/shell.c 2565cb32cd862024bcfd88400e05437636cf21a1 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e -F src/sqliteInt.h 9b64d8225a26f3d5a376370b31060dd70bcc362b +F src/sqliteInt.h cab919e43875a561603ca6e0d060fd0690c2ee7c F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95 F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325 @@ -56,14 +56,14 @@ F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e F src/tokenize.c 2ba93fe10d5f57f0cc20b07417c3244a30c324b3 F src/trigger.c 8ee811986080de60d9d883ad96daffea82014f27 -F src/update.c dc3b680b4cf2cb6d839950b68d632850746639b9 +F src/update.c 8e657c7b3d27b5592d8caa362d9c4765e0b3cd6a F src/util.c 8065b78806a5132119452d9e0417cf071e6f02f9 F src/vacuum.c 0820984615786c9ccdaad8032a792309b354a8eb -F src/vdbe.c e9e560b0c568fb4ffb189d3e0d91628a33d2a367 +F src/vdbe.c 81b9868acd7e7d54ddd26af4ffe8442c312ad374 F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21 -F src/where.c ef11773a07cf075740378d7d1cbabf328146fdc9 +F src/where.c 1e645d430cb4b347159c28c6085e9801160f2099 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 -F test/attach.test b311c83e370e6b22b79a8279317039440ce64862 +F test/attach.test ca8304e0f2236d1bf68e53ccc17cf3e8d76de0f1 F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 @@ -116,11 +116,11 @@ F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4 F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6 F test/tclsqlite.test d9bdfc0afca9ee605c50ecb39e94ae4dea8c222b -F test/temptable.test 6feff1960c707e924d5462356c5303943dac4a8e +F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692 F test/tester.tcl d7a5835edaf118539241145d8188f0822b673488 F test/trans.test 75e7a171b5d2d94ee56766459113e2ad0e5f809d F test/trigger1.test 61ef41666f066ac417730dc26056053a7c36cd11 -F test/trigger2.test adf6a9cfd735bd4be4f7be19da629b0968703744 +F test/trigger2.test 00ceb8aff6bddd511bbac7c837af2863fa0c9cb4 F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72 F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818 F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f @@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be F www/sqlite.tcl 4bd1729e320f5fa9125f0022b281fbe839192125 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P baea7aca10e30f30b874e1e8b6cd3b05954ba83c -R d79117ebcf990c76ac030f81c35e1389 +P 590f963b6599e4e235d7369f19c63cece4b2ad95 +R 869048a3307d9ca8d4b394c814d0ad0e U drh -Z b3ec67d7cdead0321417395bbb89e4c5 +Z 2835ef2dc75e2e6d87e08c87fdd8ab29 diff --git a/manifest.uuid b/manifest.uuid index 4d8362fb5f..ca05ec7a6b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -590f963b6599e4e235d7369f19c63cece4b2ad95 \ No newline at end of file +01398fb78bab7e5c6f439f2b743f26e82118468a \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index dccb960594..a7936e9180 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.92 2003/04/25 15:37:58 drh Exp $ +** $Id: btree.c,v 1.93 2003/05/17 17:35:11 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -3229,7 +3229,7 @@ static void checkList( FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload; int n = SWAB32(pCheck->pBt, pInfo->nFree); for(i=0; ipBt, pInfo->aFree[i]), zMsg); + checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zContext); } N -= n; } diff --git a/src/btree_rb.c b/src/btree_rb.c index f072332c57..288a53eb84 100644 --- a/src/btree_rb.c +++ b/src/btree_rb.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree_rb.c,v 1.9 2003/04/25 13:22:53 drh Exp $ +** $Id: btree_rb.c,v 1.10 2003/05/17 17:35:11 drh Exp $ ** ** This file implements an in-core database using Red-Black balanced ** binary trees. @@ -31,10 +31,12 @@ typedef struct BtRbTree BtRbTree; typedef struct BtRbNode BtRbNode; typedef struct BtRollbackOp BtRollbackOp; +typedef struct Rbtree Rbtree; +typedef struct RbtCursor RbtCursor; /* Forward declarations */ -static BtOps sqliteBtreeOps; -static BtCursorOps sqliteBtreeCursorOps; +static BtOps sqliteRbtreeOps; +static BtCursorOps sqliteRbtreeCursorOps; /* * During each transaction (or checkpoint), a linked-list of @@ -68,14 +70,14 @@ struct BtRollbackOp { #define ROLLBACK_CREATE 3 /* Create a table */ #define ROLLBACK_DROP 4 /* Drop a table */ -struct Btree { +struct Rbtree { BtOps *pOps; /* Function table */ int aMetaData[SQLITE_N_BTREE_META]; int next_idx; /* next available table index */ Hash tblHash; /* All created tables, by index */ - u8 isAnonymous; /* True if this Btree is to be deleted when closed */ - u8 eTransState; /* State of this Btree wrt transactions */ + u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */ + u8 eTransState; /* State of this Rbtree wrt transactions */ BtRollbackOp *pTransRollback; BtRollbackOp *pCheckRollback; @@ -83,7 +85,7 @@ struct Btree { }; /* -** Legal values for Btree.eTransState. +** Legal values for Rbtree.eTransState. */ #define TRANS_NONE 0 /* No transaction is in progress */ #define TRANS_INTRANSACTION 1 /* A transaction is in progress */ @@ -91,21 +93,21 @@ struct Btree { #define TRANS_ROLLBACK 3 /* We are currently rolling back a checkpoint or * transaction. */ -struct BtCursor { +struct RbtCursor { BtCursorOps *pOps; /* Function table */ - Btree *pBtree; + Rbtree *pRbtree; BtRbTree *pTree; - int iTree; /* Index of pTree in pBtree */ + int iTree; /* Index of pTree in pRbtree */ BtRbNode *pNode; u8 eSkip; /* Determines if next step operation is a no-op */ }; /* -** Legal values for BtCursor.eSkip. +** Legal values for RbtCursor.eSkip. */ #define SKIP_NONE 0 /* Always step the cursor */ -#define SKIP_NEXT 1 /* The next sqliteBtreeNext() is a no-op */ -#define SKIP_PREV 2 /* The next sqliteBtreePrevious() is a no-op */ +#define SKIP_NEXT 1 /* The next sqliteRbtreeNext() is a no-op */ +#define SKIP_PREV 2 /* The next sqliteRbtreePrevious() is a no-op */ #define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */ struct BtRbTree { @@ -126,11 +128,16 @@ struct BtRbNode { }; /* Forward declarations */ -static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey,int *pRes); -static int memBtreeClearTable(Btree* tree, int n); -static int memBtreeNext(BtCursor* pCur, int *pRes); -static int memBtreeLast(BtCursor* pCur, int *pRes); -static int memBtreePrevious(BtCursor* pCur, int *pRes); +static int memRbtreeMoveto( + RbtCursor* pCur, + const void *pKey, + int nKey, + int *pRes +); +static int memRbtreeClearTable(Rbtree* tree, int n); +static int memRbtreeNext(RbtCursor* pCur, int *pRes); +static int memRbtreeLast(RbtCursor* pCur, int *pRes); +static int memRbtreePrevious(RbtCursor* pCur, int *pRes); /* * The key-compare function for the red-black trees. Returns as follows: @@ -359,7 +366,7 @@ static void check_redblack_tree(BtRbTree * tree, char ** msg) } /* - * Node pX has just been inserted into pTree (by code in sqliteBtreeInsert()). + * Node pX has just been inserted into pTree (by code in sqliteRbtreeInsert()). * It is possible that pX is a red node with a red parent, which is a violation * of the red-black tree properties. This function performs rotations and * color changes to rebalance the tree @@ -540,57 +547,61 @@ void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent) } /* - * Create table n in tree pBtree. Table n must not exist. + * Create table n in tree pRbtree. Table n must not exist. */ -static void btreeCreateTable(Btree* pBtree, int n) +static void btreeCreateTable(Rbtree* pRbtree, int n) { BtRbTree *pNewTbl = sqliteMalloc(sizeof(BtRbTree)); - sqliteHashInsert(&pBtree->tblHash, 0, n, pNewTbl); + sqliteHashInsert(&pRbtree->tblHash, 0, n, pNewTbl); } /* - * Log a single "rollback-op" for the given Btree. See comments for struct + * Log a single "rollback-op" for the given Rbtree. See comments for struct * BtRollbackOp. */ -static void btreeLogRollbackOp(Btree* pBtree, BtRollbackOp *pRollbackOp) +static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp) { - assert( pBtree->eTransState == TRANS_INCHECKPOINT || - pBtree->eTransState == TRANS_INTRANSACTION ); - if( pBtree->eTransState == TRANS_INTRANSACTION ){ - pRollbackOp->pNext = pBtree->pTransRollback; - pBtree->pTransRollback = pRollbackOp; + assert( pRbtree->eTransState == TRANS_INCHECKPOINT || + pRbtree->eTransState == TRANS_INTRANSACTION ); + if( pRbtree->eTransState == TRANS_INTRANSACTION ){ + pRollbackOp->pNext = pRbtree->pTransRollback; + pRbtree->pTransRollback = pRollbackOp; } - if( pBtree->eTransState == TRANS_INCHECKPOINT ){ - if( !pBtree->pCheckRollback ){ - pBtree->pCheckRollbackTail = pRollbackOp; + if( pRbtree->eTransState == TRANS_INCHECKPOINT ){ + if( !pRbtree->pCheckRollback ){ + pRbtree->pCheckRollbackTail = pRollbackOp; } - pRollbackOp->pNext = pBtree->pCheckRollback; - pBtree->pCheckRollback = pRollbackOp; + pRollbackOp->pNext = pRbtree->pCheckRollback; + pRbtree->pCheckRollback = pRollbackOp; } } -int sqliteRBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree) -{ - *ppBtree = (Btree *)sqliteMalloc(sizeof(Btree)); - sqliteHashInit(&(*ppBtree)->tblHash, SQLITE_HASH_INT, 0); +int sqliteRbtreeOpen( + const char *zFilename, + int mode, + int nPg, + Rbtree **ppRbtree +){ + *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree)); + sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0); /* Create a binary tree for the SQLITE_MASTER table at location 2 */ - btreeCreateTable(*ppBtree, 2); - (*ppBtree)->next_idx = 3; - (*ppBtree)->pOps = &sqliteBtreeOps; + btreeCreateTable(*ppRbtree, 2); + (*ppRbtree)->next_idx = 3; + (*ppRbtree)->pOps = &sqliteRbtreeOps; /* Set file type to 4; this is so that "attach ':memory:' as ...." does not ** think that the database in uninitialised and refuse to attach */ - (*ppBtree)->aMetaData[2] = 4; + (*ppRbtree)->aMetaData[2] = 4; return SQLITE_OK; } /* - * Create a new table in the supplied Btree. Set *n to the new table number. + * Create a new table in the supplied Rbtree. Set *n to the new table number. * Return SQLITE_OK if the operation is a success. */ -static int memBtreeCreateTable(Btree* tree, int* n) +static int memRbtreeCreateTable(Rbtree* tree, int* n) { assert( tree->eTransState != TRANS_NONE ); @@ -610,14 +621,14 @@ static int memBtreeCreateTable(Btree* tree, int* n) } /* - * Delete table n from the supplied Btree. + * Delete table n from the supplied Rbtree. */ -static int memBtreeDropTable(Btree* tree, int n) +static int memRbtreeDropTable(Rbtree* tree, int n) { BtRbTree *pTree; assert( tree->eTransState != TRANS_NONE ); - memBtreeClearTable(tree, n); + memRbtreeClearTable(tree, n); pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0); assert(pTree); sqliteFree(pTree); @@ -632,7 +643,7 @@ static int memBtreeDropTable(Btree* tree, int n) return SQLITE_OK; } -static int memBtreeKeyCompare(BtCursor* pCur, const void *pKey, int nKey, +static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey, int nIgnore, int *pRes) { assert(pCur); @@ -651,40 +662,49 @@ static int memBtreeKeyCompare(BtCursor* pCur, const void *pKey, int nKey, } /* - * Get a new cursor for table iTable of the supplied Btree. The wrFlag + * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag * parameter is ignored, all cursors are capable of write-operations. * - * Note that BtCursor.eSkip and BtCursor.pNode both initialize to 0. + * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0. */ -static int memBtreeCursor(Btree* tree, int iTable, int wrFlag, BtCursor **ppCur) -{ +static int memRbtreeCursor( + Rbtree* tree, + int iTable, + int wrFlag, + RbtCursor **ppCur +){ assert(tree); - *ppCur = sqliteMalloc(sizeof(BtCursor)); + *ppCur = sqliteMalloc(sizeof(RbtCursor)); (*ppCur)->pTree = sqliteHashFind(&tree->tblHash, 0, iTable); - (*ppCur)->pBtree = tree; + (*ppCur)->pRbtree = tree; (*ppCur)->iTree = iTable; - (*ppCur)->pOps = &sqliteBtreeCursorOps; + (*ppCur)->pOps = &sqliteRbtreeCursorOps; assert( (*ppCur)->pTree ); return SQLITE_OK; } /* - * Insert a new record into the Btree. The key is given by (pKey,nKey) + * Insert a new record into the Rbtree. The key is given by (pKey,nKey) * and the data is given by (pData,nData). The cursor is used only to * define what database the record should be inserted into. The cursor * is left pointing at the new record. * * If the key exists already in the tree, just replace the data. */ -static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey, - const void *pDataInput, int nData) -{ +static int memRbtreeInsert( + RbtCursor* pCur, + const void *pKey, + int nKey, + const void *pDataInput, + int nData +){ void * pData; int match; - /* It is illegal to call sqliteBtreeInsert() if we are not in a transaction */ - assert( pCur->pBtree->eTransState != TRANS_NONE ); + /* It is illegal to call sqliteRbtreeInsert() if we are + ** not in a transaction */ + assert( pCur->pRbtree->eTransState != TRANS_NONE ); /* Take a copy of the input data now, in case we need it for the * replace case */ @@ -702,7 +722,7 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey, * * The new node is initially red. */ - memBtreeMoveto( pCur, pKey, nKey, &match); + memRbtreeMoveto( pCur, pKey, nKey, &match); if( match ){ BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode)); pNode->nKey = nKey; @@ -736,14 +756,14 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey, do_insert_balancing(pCur->pTree, pNode); /* Set up a rollback-op in case we have to roll this operation back */ - if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){ + if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); pOp->eOp = ROLLBACK_DELETE; pOp->iTab = pCur->iTree; pOp->nKey = pNode->nKey; pOp->pKey = sqliteMalloc( pOp->nKey ); memcpy( pOp->pKey, pNode->pKey, pOp->nKey ); - btreeLogRollbackOp(pCur->pBtree, pOp); + btreeLogRollbackOp(pCur->pRbtree, pOp); } }else{ @@ -751,7 +771,7 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey, * Just clobber the current nodes data. */ /* Set up a rollback-op in case we have to roll this operation back */ - if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){ + if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); pOp->iTab = pCur->iTree; pOp->nKey = pCur->pNode->nKey; @@ -760,7 +780,7 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey, pOp->nData = pCur->pNode->nData; pOp->pData = pCur->pNode->pData; pOp->eOp = ROLLBACK_INSERT; - btreeLogRollbackOp(pCur->pBtree, pOp); + btreeLogRollbackOp(pCur->pRbtree, pOp); }else{ sqliteFree( pCur->pNode->pData ); } @@ -786,8 +806,12 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey, ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. */ -static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey, int *pRes) -{ +static int memRbtreeMoveto( + RbtCursor* pCur, + const void *pKey, + int nKey, + int *pRes +){ BtRbNode *pTmp = 0; pCur->pNode = pCur->pTree->pHead; @@ -823,21 +847,22 @@ static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey, int *pRes) ** The cursor is left pointing at either the next or the previous ** entry. If the cursor is left pointing to the next entry, then ** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to -** sqliteBtreeNext() to be a no-op. That way, you can always call -** sqliteBtreeNext() after a delete and the cursor will be left +** sqliteRbtreeNext() to be a no-op. That way, you can always call +** sqliteRbtreeNext() after a delete and the cursor will be left ** pointing to the first entry after the deleted entry. Similarly, ** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to ** the entry prior to the deleted entry so that a subsequent call to -** sqliteBtreePrevious() will always leave the cursor pointing at the +** sqliteRbtreePrevious() will always leave the cursor pointing at the ** entry immediately before the one that was deleted. */ -static int memBtreeDelete(BtCursor* pCur) +static int memRbtreeDelete(RbtCursor* pCur) { BtRbNode *pZ; /* The one being deleted */ BtRbNode *pChild; /* The child of the spliced out node */ - /* It is illegal to call sqliteBtreeDelete() if we are not in a transaction */ - assert( pCur->pBtree->eTransState != TRANS_NONE ); + /* It is illegal to call sqliteRbtreeDelete() if we are + ** not in a transaction */ + assert( pCur->pRbtree->eTransState != TRANS_NONE ); pZ = pCur->pNode; if( !pZ ){ @@ -846,7 +871,7 @@ static int memBtreeDelete(BtCursor* pCur) /* If we are not currently doing a rollback, set up a rollback op for this * deletion */ - if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){ + if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); pOp->iTab = pCur->iTree; pOp->nKey = pZ->nKey; @@ -854,7 +879,7 @@ static int memBtreeDelete(BtCursor* pCur) pOp->nData = pZ->nData; pOp->pData = pZ->pData; pOp->eOp = ROLLBACK_INSERT; - btreeLogRollbackOp(pCur->pBtree, pOp); + btreeLogRollbackOp(pCur->pRbtree, pOp); } /* First do a standard binary-tree delete (node pZ is to be deleted). How @@ -867,9 +892,9 @@ static int memBtreeDelete(BtCursor* pCur) BtRbNode *pTmp; int dummy; pCur->eSkip = SKIP_NONE; - memBtreeNext(pCur, &dummy); + memRbtreeNext(pCur, &dummy); assert( dummy == 0 ); - if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){ + if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){ sqliteFree(pZ->pKey); sqliteFree(pZ->pData); } @@ -884,14 +909,14 @@ static int memBtreeDelete(BtCursor* pCur) }else{ int res; pCur->eSkip = SKIP_NONE; - memBtreeNext(pCur, &res); + memRbtreeNext(pCur, &res); pCur->eSkip = SKIP_NEXT; if( res ){ - memBtreeLast(pCur, &res); - memBtreePrevious(pCur, &res); + memRbtreeLast(pCur, &res); + memRbtreePrevious(pCur, &res); pCur->eSkip = SKIP_PREV; } - if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){ + if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){ sqliteFree(pZ->pKey); sqliteFree(pZ->pData); } @@ -928,9 +953,9 @@ static int memBtreeDelete(BtCursor* pCur) } /* - * Empty table n of the Btree. + * Empty table n of the Rbtree. */ -static int memBtreeClearTable(Btree* tree, int n) +static int memRbtreeClearTable(Rbtree* tree, int n) { BtRbTree *pTree; BtRbNode *pNode; @@ -974,7 +999,7 @@ static int memBtreeClearTable(Btree* tree, int n) return SQLITE_OK; } -static int memBtreeFirst(BtCursor* pCur, int *pRes) +static int memRbtreeFirst(RbtCursor* pCur, int *pRes) { if( pCur->pTree->pHead ){ pCur->pNode = pCur->pTree->pHead; @@ -991,7 +1016,7 @@ static int memBtreeFirst(BtCursor* pCur, int *pRes) return SQLITE_OK; } -static int memBtreeLast(BtCursor* pCur, int *pRes) +static int memRbtreeLast(RbtCursor* pCur, int *pRes) { if( pCur->pTree->pHead ){ pCur->pNode = pCur->pTree->pHead; @@ -1014,7 +1039,7 @@ static int memBtreeLast(BtCursor* pCur, int *pRes) ** was already pointing to the last entry in the database before ** this routine was called, then set *pRes=1. */ -static int memBtreeNext(BtCursor* pCur, int *pRes) +static int memRbtreeNext(RbtCursor* pCur, int *pRes) { if( pCur->pNode && pCur->eSkip != SKIP_NEXT ){ if( pCur->pNode->pRight ){ @@ -1041,7 +1066,7 @@ static int memBtreeNext(BtCursor* pCur, int *pRes) return SQLITE_OK; } -static int memBtreePrevious(BtCursor* pCur, int *pRes) +static int memRbtreePrevious(RbtCursor* pCur, int *pRes) { if( pCur->pNode && pCur->eSkip != SKIP_PREV ){ if( pCur->pNode->pLeft ){ @@ -1068,7 +1093,7 @@ static int memBtreePrevious(BtCursor* pCur, int *pRes) return SQLITE_OK; } -static int memBtreeKeySize(BtCursor* pCur, int *pSize) +static int memRbtreeKeySize(RbtCursor* pCur, int *pSize) { if( pCur->pNode ){ *pSize = pCur->pNode->nKey; @@ -1078,7 +1103,7 @@ static int memBtreeKeySize(BtCursor* pCur, int *pSize) return SQLITE_OK; } -static int memBtreeKey(BtCursor* pCur, int offset, int amt, char *zBuf) +static int memRbtreeKey(RbtCursor* pCur, int offset, int amt, char *zBuf) { if( !pCur->pNode ) return 0; if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){ @@ -1091,7 +1116,7 @@ static int memBtreeKey(BtCursor* pCur, int offset, int amt, char *zBuf) assert(0); } -static int memBtreeDataSize(BtCursor* pCur, int *pSize) +static int memRbtreeDataSize(RbtCursor* pCur, int *pSize) { if( pCur->pNode ){ *pSize = pCur->pNode->nData; @@ -1101,7 +1126,7 @@ static int memBtreeDataSize(BtCursor* pCur, int *pSize) return SQLITE_OK; } -static int memBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf) +static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf) { if( !pCur->pNode ) return 0; if( (amt + offset) <= pCur->pNode->nData ){ @@ -1114,30 +1139,30 @@ static int memBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf) assert(0); } -static int memBtreeCloseCursor(BtCursor* pCur) +static int memRbtreeCloseCursor(RbtCursor* pCur) { sqliteFree(pCur); return SQLITE_OK; } -static int memBtreeGetMeta(Btree* tree, int* aMeta) +static int memRbtreeGetMeta(Rbtree* tree, int* aMeta) { memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META ); return SQLITE_OK; } -static int memBtreeUpdateMeta(Btree* tree, int* aMeta) +static int memRbtreeUpdateMeta(Rbtree* tree, int* aMeta) { memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META ); return SQLITE_OK; } /* - * Check that each table in the Btree meets the requirements for a red-black + * Check that each table in the Rbtree meets the requirements for a red-black * binary tree. If an error is found, return an explanation of the problem in * memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored. */ -static char *memBtreeIntegrityCheck(Btree* tree, int* aRoot, int nRoot) +static char *memRbtreeIntegrityCheck(Rbtree* tree, int* aRoot, int nRoot) { char * msg = 0; HashElem *p; @@ -1151,30 +1176,30 @@ static char *memBtreeIntegrityCheck(Btree* tree, int* aRoot, int nRoot) } /* - * Close the supplied Btree. Delete everything associated with it. + * Close the supplied Rbtree. Delete everything associated with it. */ -static int memBtreeClose(Btree* tree) +static int memRbtreeClose(Rbtree* tree) { HashElem *p; while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){ tree->eTransState = TRANS_ROLLBACK; - memBtreeDropTable(tree, sqliteHashKeysize(p)); + memRbtreeDropTable(tree, sqliteHashKeysize(p)); } sqliteHashClear(&tree->tblHash); sqliteFree(tree); return SQLITE_OK; } -static int memBtreeSetCacheSize(Btree* tree, int sz) +static int memRbtreeSetCacheSize(Rbtree* tree, int sz) { return SQLITE_OK; } -static int memBtreeSetSafetyLevel(Btree *pBt, int level){ +static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){ return SQLITE_OK; } -static int memBtreeBeginTrans(Btree* tree) +static int memRbtreeBeginTrans(Rbtree* tree) { if( tree->eTransState != TRANS_NONE ) return SQLITE_ERROR; @@ -1197,7 +1222,7 @@ static void deleteRollbackList(BtRollbackOp *pOp){ } } -static int memBtreeCommit(Btree* tree){ +static int memRbtreeCommit(Rbtree* tree){ /* Just delete pTransRollback and pCheckRollback */ deleteRollbackList(tree->pCheckRollback); deleteRollbackList(tree->pTransRollback); @@ -1209,39 +1234,39 @@ static int memBtreeCommit(Btree* tree){ } /* - * Execute and delete the supplied rollback-list on pBtree. + * Execute and delete the supplied rollback-list on pRbtree. */ -static void execute_rollback_list(Btree *pBtree, BtRollbackOp *pList) +static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList) { BtRollbackOp *pTmp; - BtCursor cur; + RbtCursor cur; int res; - cur.pBtree = pBtree; + cur.pRbtree = pRbtree; while( pList ){ switch( pList->eOp ){ case ROLLBACK_INSERT: - cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab ); + cur.pTree = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab ); assert(cur.pTree); cur.iTree = pList->iTab; cur.eSkip = SKIP_NONE; - memBtreeInsert( &cur, pList->pKey, + memRbtreeInsert( &cur, pList->pKey, pList->nKey, pList->pData, pList->nData ); break; case ROLLBACK_DELETE: - cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab ); + cur.pTree = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab ); assert(cur.pTree); cur.iTree = pList->iTab; cur.eSkip = SKIP_NONE; - memBtreeMoveto(&cur, pList->pKey, pList->nKey, &res); + memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res); assert(res == 0); - memBtreeDelete( &cur ); + memRbtreeDelete( &cur ); break; case ROLLBACK_CREATE: - btreeCreateTable(pBtree, pList->iTab); + btreeCreateTable(pRbtree, pList->iTab); break; case ROLLBACK_DROP: - memBtreeDropTable(pBtree, pList->iTab); + memRbtreeDropTable(pRbtree, pList->iTab); break; default: assert(0); @@ -1254,7 +1279,7 @@ static void execute_rollback_list(Btree *pBtree, BtRollbackOp *pList) } } -static int memBtreeRollback(Btree* tree) +static int memRbtreeRollback(Rbtree* tree) { tree->eTransState = TRANS_ROLLBACK; execute_rollback_list(tree, tree->pCheckRollback); @@ -1266,7 +1291,7 @@ static int memBtreeRollback(Btree* tree) return SQLITE_OK; } -static int memBtreeBeginCkpt(Btree* tree) +static int memRbtreeBeginCkpt(Rbtree* tree) { if( tree->eTransState != TRANS_INTRANSACTION ) return SQLITE_ERROR; @@ -1277,7 +1302,7 @@ static int memBtreeBeginCkpt(Btree* tree) return SQLITE_OK; } -static int memBtreeCommitCkpt(Btree* tree) +static int memRbtreeCommitCkpt(Rbtree* tree) { if( tree->eTransState == TRANS_INCHECKPOINT ){ if( tree->pCheckRollback ){ @@ -1291,7 +1316,7 @@ static int memBtreeCommitCkpt(Btree* tree) return SQLITE_OK; } -static int memBtreeRollbackCkpt(Btree* tree) +static int memRbtreeRollbackCkpt(Rbtree* tree) { if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK; tree->eTransState = TRANS_ROLLBACK; @@ -1304,21 +1329,21 @@ static int memBtreeRollbackCkpt(Btree* tree) } #ifdef SQLITE_TEST -static int memBtreePageDump(Btree* tree, int pgno, int rec) +static int memRbtreePageDump(Rbtree* tree, int pgno, int rec) { - assert(!"Cannot call sqliteBtreePageDump"); + assert(!"Cannot call sqliteRbtreePageDump"); return SQLITE_OK; } -static int memBtreeCursorDump(BtCursor* pCur, int* aRes) +static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes) { - assert(!"Cannot call sqliteBtreeCursorDump"); + assert(!"Cannot call sqliteRbtreeCursorDump"); return SQLITE_OK; } -static struct Pager *memBtreePager(Btree* tree) +static struct Pager *memRbtreePager(Rbtree* tree) { - assert(!"Cannot call sqliteBtreePager"); + assert(!"Cannot call sqliteRbtreePager"); return SQLITE_OK; } #endif @@ -1326,60 +1351,60 @@ static struct Pager *memBtreePager(Btree* tree) /* ** Return the full pathname of the underlying database file. */ -static const char *memBtreeGetFilename(Btree *pBt){ +static const char *memRbtreeGetFilename(Rbtree *pBt){ return 0; /* A NULL return indicates there is no underlying file */ } /* ** The copy file function is not implemented for the in-memory database */ -static int memBtreeCopyFile(Btree *pBt, Btree *pBt2){ +static int memRbtreeCopyFile(Rbtree *pBt, Rbtree *pBt2){ return SQLITE_INTERNAL; /* Not implemented */ } -static BtOps sqliteBtreeOps = { - memBtreeClose, - memBtreeSetCacheSize, - memBtreeSetSafetyLevel, - memBtreeBeginTrans, - memBtreeCommit, - memBtreeRollback, - memBtreeBeginCkpt, - memBtreeCommitCkpt, - memBtreeRollbackCkpt, - memBtreeCreateTable, - memBtreeCreateTable, - memBtreeDropTable, - memBtreeClearTable, - memBtreeCursor, - memBtreeGetMeta, - memBtreeUpdateMeta, - memBtreeIntegrityCheck, - memBtreeGetFilename, - memBtreeCopyFile, +static BtOps sqliteRbtreeOps = { + (int(*)(Btree*)) memRbtreeClose, + (int(*)(Btree*,int)) memRbtreeSetCacheSize, + (int(*)(Btree*,int)) memRbtreeSetSafetyLevel, + (int(*)(Btree*)) memRbtreeBeginTrans, + (int(*)(Btree*)) memRbtreeCommit, + (int(*)(Btree*)) memRbtreeRollback, + (int(*)(Btree*)) memRbtreeBeginCkpt, + (int(*)(Btree*)) memRbtreeCommitCkpt, + (int(*)(Btree*)) memRbtreeRollbackCkpt, + (int(*)(Btree*,int*)) memRbtreeCreateTable, + (int(*)(Btree*,int*)) memRbtreeCreateTable, + (int(*)(Btree*,int)) memRbtreeDropTable, + (int(*)(Btree*,int)) memRbtreeClearTable, + (int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor, + (int(*)(Btree*,int*)) memRbtreeGetMeta, + (int(*)(Btree*,int*)) memRbtreeUpdateMeta, + (char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck, + (const char*(*)(Btree*)) memRbtreeGetFilename, + (int(*)(Btree*,Btree*)) memRbtreeCopyFile, #ifdef SQLITE_TEST - memBtreePageDump, - memBtreePager + (int(*)(Btree*,int,int)) memRbtreePageDump, + (struct Pager*(*)(Btree*)) memRbtreePager #endif }; -static BtCursorOps sqliteBtreeCursorOps = { - memBtreeMoveto, - memBtreeDelete, - memBtreeInsert, - memBtreeFirst, - memBtreeLast, - memBtreeNext, - memBtreePrevious, - memBtreeKeySize, - memBtreeKey, - memBtreeKeyCompare, - memBtreeDataSize, - memBtreeData, - memBtreeCloseCursor, +static BtCursorOps sqliteRbtreeCursorOps = { + (int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto, + (int(*)(BtCursor*)) memRbtreeDelete, + (int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert, + (int(*)(BtCursor*,int*)) memRbtreeFirst, + (int(*)(BtCursor*,int*)) memRbtreeLast, + (int(*)(BtCursor*,int*)) memRbtreeNext, + (int(*)(BtCursor*,int*)) memRbtreePrevious, + (int(*)(BtCursor*,int*)) memRbtreeKeySize, + (int(*)(BtCursor*,int,int,char*)) memRbtreeKey, + (int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare, + (int(*)(BtCursor*,int*)) memRbtreeDataSize, + (int(*)(BtCursor*,int,int,char*)) memRbtreeData, + (int(*)(BtCursor*)) memRbtreeCloseCursor, #ifdef SQLITE_TEST - memBtreeCursorDump, + (int(*)(BtCursor*,int*)) memRbtreeCursorDump, #endif }; diff --git a/src/build.c b/src/build.c index a4091d81f7..b160a32ee9 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.152 2003/05/02 14:32:13 drh Exp $ +** $Id: build.c,v 1.153 2003/05/17 17:35:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -36,6 +36,7 @@ */ void sqliteBeginParse(Parse *pParse, int explainFlag){ sqlite *db = pParse->db; + int i; pParse->explain = explainFlag; if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){ int rc = sqliteInit(db, &pParse->zErrMsg); @@ -44,6 +45,12 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){ pParse->nErr++; } } + for(i=0; inDb; i++){ + DbClearProperty(db, i, DB_Locked); + if( !db->aDb[i].inTrans ){ + DbClearProperty(db, i, DB_Cookie); + } + } } /* @@ -96,7 +103,6 @@ void sqliteExec(Parse *pParse){ pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE; } pParse->colNamesSet = 0; - pParse->schemaVerified = 0; }else if( pParse->useCallback==0 ){ pParse->rc = SQLITE_ERROR; } @@ -263,7 +269,7 @@ void sqliteResetInternalSchema(sqlite *db, int iDb){ sqliteDeleteTable(db, pTab); } sqliteHashClear(&temp1); - db->aDb[i].flags &= ~SQLITE_Initialized; + DbClearProperty(db, i, DB_SchemaLoaded); if( iDb>0 ) return; } assert( iDb==0 ); @@ -282,8 +288,9 @@ void sqliteResetInternalSchema(sqlite *db, int iDb){ continue; } if( jaDb[j++] = db->aDb[i]; + db->aDb[j] = db->aDb[i]; } + j++; } memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j])); db->nDb = j; @@ -1137,7 +1144,7 @@ int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){ pSelTab->nCol = 0; pSelTab->aCol = 0; sqliteDeleteTable(0, pSelTab); - pParse->db->aDb[pTable->iDb].flags |= SQLITE_UnresetViews; + DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews); }else{ pTable->nCol = 0; nErr++; @@ -1171,18 +1178,18 @@ static void sqliteViewResetColumnNames(Table *pTable){ } /* -** Clear the column names from every VIEW. +** Clear the column names from every VIEW in database idx. */ static void sqliteViewResetAll(sqlite *db, int idx){ HashElem *i; - if( (db->aDb[idx].flags & SQLITE_UnresetViews)==0 ) return; + if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ sqliteViewResetColumnNames(pTab); } } - db->aDb[idx].flags &= ~SQLITE_UnresetViews; + DbClearProperty(db, idx, DB_UnresetViews); } /* @@ -1286,12 +1293,12 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){ Index *pIdx; Trigger *pTrigger; sqliteBeginWriteOperation(pParse, 0, pTable->iDb); - sqliteOpenMasterTable(v, pTable->iDb); + /* Drop all triggers associated with the table being dropped */ pTrigger = pTable->pTrigger; while( pTrigger ){ SrcList *pNm; - assert( pTrigger->iDb==pTable->iDb ); + assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 ); pNm = sqliteSrcListAppend(0, 0, 0); pNm->a[0].zName = sqliteStrDup(pTrigger->name); pNm->a[0].zDatabase = sqliteStrDup(db->aDb[pTable->iDb].zName); @@ -1302,16 +1309,27 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){ pTrigger = pTable->pTrigger; } } + + /* Drop all SQLITE_MASTER entries that refer to the table */ + sqliteOpenMasterTable(v, pTable->iDb); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); - if( !pTable->iDb ){ + + /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */ + if( pTable->iDb!=1 ){ + sqliteOpenMasterTable(v, 1); + base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); + sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); + } + + if( pTable->iDb==0 ){ sqliteChangeCookie(db, v); } sqliteVdbeAddOp(v, OP_Close, 0, 0); if( !isView ){ sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb); for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ - sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->iDb); + sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb); } } sqliteEndWriteOperation(pParse); @@ -2117,15 +2135,15 @@ void sqliteRollbackTransaction(Parse *pParse){ ** Generate VDBE code that will verify the schema cookie for all ** named database files. */ -void sqliteCodeVerifySchema(Parse *pParse){ - int i; +void sqliteCodeVerifySchema(Parse *pParse, int iDb){ sqlite *db = pParse->db; Vdbe *v = sqliteGetVdbe(pParse); - for(i=0; inDb; i++){ - if( i==1 || db->aDb[i].pBt==0 ) continue; - sqliteVdbeAddOp(v, OP_VerifyCookie, i, db->aDb[i].schema_cookie); + assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pBt!=0 ); + if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){ + sqliteVdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie); + DbSetProperty(db, iDb, DB_Cookie); } - pParse->schemaVerified = 1; } /* @@ -2141,47 +2159,49 @@ void sqliteCodeVerifySchema(Parse *pParse){ ** can be checked before any changes are made to the database, it is never ** necessary to undo a write and the checkpoint should not be set. ** -** The tempOnly flag indicates that only temporary tables will be changed -** during this write operation. The primary database table is not -** write-locked. Only the temporary database file gets a write lock. -** Other processes can continue to read or write the primary database file. +** Only database iDb and the temp database are made writable by this call. +** If iDb==0, then the main and temp databases are made writable. If +** iDb==1 then only the temp database is made writable. If iDb>1 then the +** specified auxiliary database and the temp database are made writable. */ -void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int tempOnly){ +void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int iDb){ Vdbe *v; + sqlite *db = pParse->db; + if( DbHasProperty(db, iDb, DB_Locked) ) return; v = sqliteGetVdbe(pParse); if( v==0 ) return; - if( pParse->trigStack ) return; /* if this is in a trigger */ - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 1, 0); - if( !tempOnly ){ - int i; - sqlite *db = pParse->db; - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - for(i=2; inDb; i++){ - if( db->aDb[i].pBt==0 ) continue; - sqliteVdbeAddOp(v, OP_Transaction, i, 0); - } - sqliteCodeVerifySchema(pParse); + if( !db->aDb[iDb].inTrans ){ + sqliteVdbeAddOp(v, OP_Transaction, iDb, 0); + DbSetProperty(db, iDb, DB_Locked); + sqliteCodeVerifySchema(pParse, iDb); + if( iDb!=1 ){ + sqliteBeginWriteOperation(pParse, setCheckpoint, 1); } }else if( setCheckpoint ){ - sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0); - sqliteVdbeAddOp(v, OP_Checkpoint, 1, 0); + sqliteVdbeAddOp(v, OP_Checkpoint, iDb, 0); + DbSetProperty(db, iDb, DB_Locked); } } /* ** Generate code that concludes an operation that may have changed -** the database. This is a companion function to BeginWriteOperation(). -** If a transaction was started, then commit it. If a checkpoint was -** started then commit that. +** the database. If a statement transaction was started, then emit +** an OP_Commit that will cause the changes to be committed to disk. +** +** Note that checkpoints are automatically committed at the end of +** a statement. Note also that there can be multiple calls to +** sqliteBeginWriteOperation() but there should only be a single +** call to sqliteEndWriteOperation() at the conclusion of the statement. */ void sqliteEndWriteOperation(Parse *pParse){ Vdbe *v; + sqlite *db = pParse->db; if( pParse->trigStack ) return; /* if this is in a trigger */ v = sqliteGetVdbe(pParse); if( v==0 ) return; - if( pParse->db->flags & SQLITE_InTrans ){ - /* Do Nothing */ + if( db->flags & SQLITE_InTrans ){ + /* A BEGIN has executed. Do not commit until we see an explicit + ** COMMIT statement. */ }else{ sqliteVdbeAddOp(v, OP_Commit, 0, 0); } diff --git a/src/copy.c b/src/copy.c index 44fd471421..95849ab048 100644 --- a/src/copy.c +++ b/src/copy.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the COPY command. ** -** $Id: copy.c,v 1.4 2003/04/24 01:45:04 drh Exp $ +** $Id: copy.c,v 1.5 2003/05/17 17:35:11 drh Exp $ */ #include "sqliteInt.h" @@ -57,7 +57,7 @@ void sqliteCopy( } v = sqliteGetVdbe(pParse); if( v ){ - sqliteBeginWriteOperation(pParse, 1, pTab->iDb==1); + sqliteBeginWriteOperation(pParse, 1, pTab->iDb); addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeDequoteP3(v, addr); diff --git a/src/delete.c b/src/delete.c index 6c46c122d8..9046c5e067 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.56 2003/05/02 14:32:13 drh Exp $ +** $Id: delete.c,v 1.57 2003/05/17 17:35:11 drh Exp $ */ #include "sqliteInt.h" @@ -142,8 +142,7 @@ void sqliteDeleteFrom( if( v==0 ){ goto delete_from_cleanup; } - sqliteBeginWriteOperation(pParse, row_triggers_exist, - !row_triggers_exist && pTab->iDb==1); + sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb); /* If we are trying to delete from a view, construct that view into ** a temporary table. diff --git a/src/insert.c b/src/insert.c index ce48425355..5124e8aead 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.84 2003/05/16 02:30:27 drh Exp $ +** $Id: insert.c,v 1.85 2003/05/17 17:35:12 drh Exp $ */ #include "sqliteInt.h" @@ -159,8 +159,7 @@ void sqliteInsert( */ v = sqliteGetVdbe(pParse); if( v==0 ) goto insert_cleanup; - sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, - !row_triggers_exist && pTab->iDb==1); + sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb); /* if there are row triggers, allocate a temp table for new.* references. */ if( row_triggers_exist ){ diff --git a/src/main.c b/src/main.c index d7c71f7e51..a4c1b69c32 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.130 2003/05/04 17:58:26 drh Exp $ +** $Id: main.c,v 1.131 2003/05/17 17:35:12 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -29,6 +29,13 @@ typedef struct { char **pzErrMsg; /* Error message stored here */ } InitData; +/* +** Fill the InitData structure with an error message that indicates +** that the database is corrupt. +*/ +static void corruptSchema(InitData *pData){ + sqliteSetString(pData->pzErrMsg, "malformed database schema", 0); +} /* ** This is the callback routine for the code that initializes the @@ -50,15 +57,19 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){ Parse sParse; int nErr = 0; - /* TODO: Do some validity checks on all fields. In particular, - ** make sure fields do not contain NULLs. Otherwise we might core - ** when attempting to initialize from a corrupt database file. */ - assert( argc==5 ); + if( argv[0]==0 ){ + corruptSchema(pData); + return 1; + } switch( argv[0][0] ){ case 'v': case 'i': case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */ + if( argv[2]==0 || argv[4]==0 ){ + corruptSchema(pData); + return 1; + } if( argv[3] && argv[3][0] ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because sParse.initFlag is set to 1, no VDBE code is generated @@ -342,7 +353,10 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ sqliteResetInternalSchema(db, 0); } if( sParse.rc==SQLITE_OK ){ - db->aDb[iDb].flags |= SQLITE_Initialized; + DbSetProperty(db, iDb, DB_SchemaLoaded); + if( iDb==0 ){ + DbSetProperty(db, 1, DB_SchemaLoaded); + } }else{ sqliteResetInternalSchema(db, iDb); } @@ -368,8 +382,8 @@ int sqliteInit(sqlite *db, char **pzErrMsg){ assert( (db->flags & SQLITE_Initialized)==0 ); rc = SQLITE_OK; for(i=0; rc==SQLITE_OK && inDb; i++){ - if( db->aDb[i].flags & SQLITE_Initialized ) continue; - if( i==1 ) continue; /* Skip the temp database - initialized with 0 */ + if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue; + assert( i!=1 ); /* Should have been initialized together with 0 */ rc = sqliteInitOne(db, i, pzErrMsg); } if( rc==SQLITE_OK ){ @@ -961,14 +975,14 @@ int sqliteBtreeFactory( if (location == 1) { return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree); } else { - return sqliteRBtreeOpen(0, 0, 0, ppBtree); + return sqliteRbtreeOpen(0, 0, 0, ppBtree); } } else { /* Always use in-core DB */ - return sqliteRBtreeOpen(0, 0, 0, ppBtree); + return sqliteRbtreeOpen(0, 0, 0, ppBtree); } }else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){ - return sqliteRBtreeOpen(0, 0, 0, ppBtree); + return sqliteRbtreeOpen(0, 0, 0, ppBtree); }else #endif { diff --git a/src/select.c b/src/select.c index 82138a108e..a4b300508f 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.138 2003/05/06 20:35:16 drh Exp $ +** $Id: select.c,v 1.139 2003/05/17 17:35:12 drh Exp $ */ #include "sqliteInt.h" @@ -1845,9 +1845,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first ** or last entry in the main table. */ - if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){ - sqliteCodeVerifySchema(pParse); - } + sqliteCodeVerifySchema(pParse, pTab->iDb); base = p->pSrc->a[0].iCursor; sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 18d1d991ce..93b4dcc28d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.184 2003/05/10 03:04:34 jplyon Exp $ +** @(#) $Id: sqliteInt.h,v 1.185 2003/05/17 17:35:12 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -240,6 +240,38 @@ struct Db { u16 flags; /* Flags associated with this database */ }; +/* +** These macros can be used to test, set, or clear bits in the +** Db.flags field. +*/ +#define DbHasProperty(D,I,P) (((D)->aDb[I].flags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].flags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].flags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].flags&=~(P) + +/* +** Allowed values for the DB.flags field. +** +** The DB_Locked flag is set when the first OP_Transaction or OP_Checkpoint +** opcode is emitted for a database. This prevents multiple occurances +** of those opcodes for the same database in the same program. Similarly, +** the DB_Cookie flag is set when the OP_VerifyCookie opcode is emitted, +** and prevents duplicate OP_VerifyCookies from taking up space and slowing +** down execution. +** +** The DB_SchemaLoaded flag is set after the database schema has been +** read into internal hash tables. +** +** DB_UnresetViews means that one or more views have column names that +** have been filled out. If the schema changes, these column names might +** changes and so the view will need to be reset. +*/ +#define DB_Locked 0x0001 /* OP_Transaction opcode has been emitted */ +#define DB_Cookie 0x0002 /* OP_VerifyCookie opcode has been emiited */ +#define DB_SchemaLoaded 0x0004 /* The schema has been loaded */ +#define DB_UnresetViews 0x0008 /* Some views have defined column names */ + + /* ** Each database is an instance of the following structure. ** @@ -293,7 +325,11 @@ struct sqlite { }; /* -** Possible values for the sqlite.flags. +** Possible values for the sqlite.flags and or Db.flags fields. +** +** On sqlite.flags, the SQLITE_InTrans value means that we have +** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement +** transaction is active on that particular database file. */ #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ #define SQLITE_Initialized 0x00000002 /* True after initialization */ @@ -306,10 +342,7 @@ struct sqlite { /* the count using a callback. */ #define SQLITE_NullCallback 0x00000080 /* Invoke the callback once if the */ /* result set is empty */ -/*#define SQLITE_ResultDetails 0x00000100 * (UNUSED -- flag free for reuse) */ -#define SQLITE_UnresetViews 0x00000200 /* True if one or more views have */ - /* defined column names */ -#define SQLITE_ReportTypes 0x00000400 /* Include information on datatypes */ +#define SQLITE_ReportTypes 0x00000200 /* Include information on datatypes */ /* in 4th argument of callback */ /* @@ -817,8 +850,6 @@ struct Parse { u8 nameClash; /* A permanent table name clashes with temp table name */ u8 useAgg; /* If true, extract field values from the aggregator ** while generating expressions. Normally false */ - u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace - ** other than after an OP_Transaction */ u8 iDb; /* Index of database whose schema is being parsed */ u8 useCallback; /* True if callbacks should be used to report results */ int useDb; /* Restrict references to tables in this database */ @@ -1077,7 +1108,7 @@ Vdbe *sqliteGetVdbe(Parse*); int sqliteRandomByte(void); int sqliteRandomInteger(void); void sqliteRollbackAll(sqlite*); -void sqliteCodeVerifySchema(Parse*); +void sqliteCodeVerifySchema(Parse*, int); void sqliteBeginTransaction(Parse*, int); void sqliteCommitTransaction(Parse*); void sqliteRollbackTransaction(Parse*); diff --git a/src/update.c b/src/update.c index 56021b7460..109bbb629e 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.65 2003/05/02 14:32:14 drh Exp $ +** $Id: update.c,v 1.66 2003/05/17 17:35:12 drh Exp $ */ #include "sqliteInt.h" @@ -203,7 +203,7 @@ void sqliteUpdate( */ v = sqliteGetVdbe(pParse); if( v==0 ) goto update_cleanup; - sqliteBeginWriteOperation(pParse, 1, !row_triggers_exist && pTab->iDb==1); + sqliteBeginWriteOperation(pParse, 1, pTab->iDb); /* If we are trying to update a view, construct that view into ** a temporary table. diff --git a/src/vdbe.c b/src/vdbe.c index c67bd423ea..9c07b7025e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -36,7 +36,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.222 2003/05/10 03:36:54 drh Exp $ +** $Id: vdbe.c,v 1.223 2003/05/17 17:35:12 drh Exp $ */ #include "sqliteInt.h" #include @@ -3193,7 +3193,9 @@ case OP_Checkpoint: { case OP_Transaction: { int busy = 1; int i = pOp->p1; - while( i>=0 && inDb && db->aDb[i].pBt!=0 && busy ){ + assert( i>=0 && inDb ); + if( db->aDb[i].inTrans ) break; + while( db->aDb[i].pBt!=0 && busy ){ rc = sqliteBtreeBeginTrans(db->aDb[i].pBt); switch( rc ){ case SQLITE_BUSY: { @@ -4547,7 +4549,7 @@ case OP_IdxGE: { ** See also: Clear */ case OP_Destroy: { - sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1); + rc = sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1); break; } @@ -4564,7 +4566,7 @@ case OP_Destroy: { ** See also: Destroy */ case OP_Clear: { - sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1); + rc = sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1); break; } diff --git a/src/where.c b/src/where.c index fda6b299d8..1400c62858 100644 --- a/src/where.c +++ b/src/where.c @@ -12,7 +12,7 @@ ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** -** $Id: where.c,v 1.78 2003/05/02 14:32:14 drh Exp $ +** $Id: where.c,v 1.79 2003/05/17 17:35:13 drh Exp $ */ #include "sqliteInt.h" @@ -680,10 +680,7 @@ WhereInfo *sqliteWhereBegin( sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); - if( i==0 && !pParse->schemaVerified && - (pParse->db->flags & SQLITE_InTrans)==0 ){ - sqliteCodeVerifySchema(pParse); - } + sqliteCodeVerifySchema(pParse, pTab->iDb); if( pWInfo->a[i].pIdx!=0 ){ sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0); sqliteVdbeAddOp(v, OP_OpenRead, diff --git a/test/attach.test b/test/attach.test index e132f771de..6611bc6e49 100644 --- a/test/attach.test +++ b/test/attach.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # -# $Id: attach.test,v 1.3 2003/04/17 22:57:55 drh Exp $ +# $Id: attach.test,v 1.4 2003/05/17 17:35:13 drh Exp $ # set testdir [file dirname $argv0] @@ -237,6 +237,60 @@ do_test attach-2.6 { SELECT * FROM main.tx; } } {} +do_test attach-2.7 { + execsql { + SELECT type, name, tbl_name FROM db2.sqlite_master; + } +} {table t2 t2 table tx tx trigger r1 t2} +do_test attach-2.8 { + execsql { + PRAGMA database_list + } +} {0 main 1 temp 2 db2} +do_test attach-2.9 { + execsql { + CREATE INDEX i2 ON t2(x); + SELECT * FROM t2 WHERE x>5; + } db2 +} {21 x 22 y} +do_test attach-2.10 { + execsql { + SELECT type, name, tbl_name FROM sqlite_master; + } db2 +} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} +do_test attach-2.11 { + catchsql { pragma vdbe_trace=on; + SELECT * FROM t2 WHERE x>5; + } +} {1 {database schema has changed}} +do_test attach-2.12 { + execsql { + PRAGMA database_list + } +} {0 main 1 temp 2 db2} +do_test attach-2.13 { + catchsql { + SELECT * FROM t2 WHERE x>5; + } +} {0 {21 x 22 y}} +do_test attach-2.14 { + execsql { + SELECT type, name, tbl_name FROM sqlite_master; + } +} {table t1 t1 table tx tx} +do_test attach-2.15 { + execsql { + SELECT type, name, tbl_name FROM db2.sqlite_master; + } +} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} +do_test attach-2.16 { + db close + sqlite db test.db + execsql { + ATTACH 'test2.db' AS db2; + SELECT type, name, tbl_name FROM db2.sqlite_master; + } +} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} for {set i 2} {$i<=15} {incr i} { catch {db$i close} diff --git a/test/temptable.test b/test/temptable.test index 1c427a19ad..8a1b70a709 100644 --- a/test/temptable.test +++ b/test/temptable.test @@ -12,7 +12,7 @@ # # This file implements tests for temporary tables and indices. # -# $Id: temptable.test,v 1.9 2003/03/30 00:19:50 drh Exp $ +# $Id: temptable.test,v 1.10 2003/05/17 17:35:13 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -165,7 +165,7 @@ do_test temptable-4.3 { catchsql { SELECT * FROM t2; } db2 -} {1 {database schema has changed}} +} {0 {10 20}} do_test temptable-4.4.1 { catchsql { SELECT * FROM temp.t2; @@ -175,8 +175,23 @@ do_test temptable-4.4.2 { catchsql { SELECT * FROM main.t2; } db2 -} {0 {9 8 7}} +} {1 {no such table: main.t2}} do_test temptable-4.4.3 { + catchsql { + SELECT name FROM main.sqlite_master WHERE type='table'; + } db2 +} {1 {database schema has changed}} +do_test temptable-4.4.4 { + catchsql { + SELECT name FROM main.sqlite_master WHERE type='table'; + } db2 +} {0 {t1 t2}} +do_test temptable-4.4.5 { + catchsql { + SELECT * FROM main.t2; + } db2 +} {0 {9 8 7}} +do_test temptable-4.4.6 { # TEMP takes precedence over MAIN catchsql { SELECT * FROM t2; @@ -217,11 +232,21 @@ do_test temptable-4.9 { SELECT * FROM t2; } } {3 4} -do_test temptable-4.10 { +do_test temptable-4.10.1 { catchsql { SELECT * FROM t2; } db2 +} {0 {1 2}} +do_test temptable-4.10.2 { + catchsql { + SELECT name FROM sqlite_master WHERE type='table' + } db2 } {1 {database schema has changed}} +do_test temptable-4.10.3 { + catchsql { + SELECT name FROM sqlite_master WHERE type='table' + } db2 +} {0 {t1 t2}} do_test temptable-4.11 { execsql { SELECT * FROM t2; diff --git a/test/trigger2.test b/test/trigger2.test index 8cefb75674..06aa11ce4d 100644 --- a/test/trigger2.test +++ b/test/trigger2.test @@ -52,12 +52,16 @@ source $testdir/tester.tcl # 1. set ii 0 -foreach tbl_defn [ list \ - {CREATE TABLE tbl (a, b);} \ - {CREATE TEMP TABLE tbl (a, b);} \ - {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \ - {CREATE TABLE tbl (a, b PRIMARY KEY);} \ - {CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} ] { +foreach tbl_defn { + {CREATE TEMP TABLE tbl (a, b);} + {CREATE TABLE tbl (a, b);} + {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} + {CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b);} + {CREATE TABLE tbl (a, b PRIMARY KEY);} + {CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} + {CREATE TEMP TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} + {CREATE TABLE tbl (a, b); CREATE TEMP INDEX tbl_idx ON tbl(b);} +} { incr ii catchsql { DROP INDEX tbl_idx; } catchsql { @@ -102,8 +106,8 @@ foreach tbl_defn [ list \ END; } - do_test trigger2-1.1.$ii { - execsql { + do_test trigger2-1.$ii.1 { + execsql { UPDATE tbl SET a = a * 10, b = b * 10; SELECT * FROM rlog ORDER BY idx; SELECT * FROM clog ORDER BY idx; @@ -113,7 +117,7 @@ foreach tbl_defn [ list \ 3 3 4 13 24 30 40 \ 4 3 4 40 60 30 40 \ 1 1 2 13 24 10 20 ] - + execsql { DELETE FROM rlog; DELETE FROM tbl; @@ -135,7 +139,7 @@ foreach tbl_defn [ list \ 0, 0); END; } - do_test trigger2-1.2.$ii { + do_test trigger2-1.$ii.2 { execsql { DELETE FROM tbl; SELECT * FROM rlog; @@ -163,7 +167,7 @@ foreach tbl_defn [ list \ new.a, new.b); END; } - do_test trigger2-1.3.$ii { + do_test trigger2-1.$ii.3 { execsql { CREATE TABLE other_tbl(a, b); @@ -177,6 +181,12 @@ foreach tbl_defn [ list \ } } [list 1 0 0 0 0 5 6 \ 2 0 0 5 6 5 6 ] + + do_test trigger2-1.$ii.4 { + execsql { + PRAGMA integrity_check; + } + } {ok ok} } catchsql { DROP TABLE rlog; @@ -187,16 +197,15 @@ catchsql { # 2. set ii 0 -foreach tr_program [ list \ - {UPDATE tbl SET b = old.b;} \ - {INSERT INTO log VALUES(new.c, 2, 3);} \ - {DELETE FROM log WHERE a = 1;} \ +foreach tr_program { + {UPDATE tbl SET b = old.b;} + {INSERT INTO log VALUES(new.c, 2, 3);} + {DELETE FROM log WHERE a = 1;} {INSERT INTO tbl VALUES(500, new.b * 10, 700); UPDATE tbl SET c = old.c; - DELETE FROM log;} \ + DELETE FROM log;} {INSERT INTO log select * from tbl;} - ] \ -{ +} { foreach test_varset [ list \ { set statement {UPDATE tbl SET c = 10 WHERE a = 1;} @@ -262,22 +271,25 @@ foreach tr_program [ list \ DROP TABLE tbl; DROP TABLE log; } + execsql { CREATE TABLE tbl(a PRIMARY KEY, b, c); CREATE TABLE log(a, b, c); } set query {SELECT * FROM tbl; SELECT * FROM log;} - set prep "$prep; INSERT INTO log VALUES(1, 2, 3); INSERT INTO log VALUES(10, 20, 30);" + set prep "$prep; INSERT INTO log VALUES(1, 2, 3);\ + INSERT INTO log VALUES(10, 20, 30);" # Check execution of BEFORE programs: set before_data [ execsql "$prep $tr_program_cooked $statement $query" ] execsql "DELETE FROM tbl; DELETE FROM log; $prep"; - execsql "CREATE TRIGGER the_trigger BEFORE [string range $statement 0 6] ON tbl BEGIN $tr_program_fixed END;" + execsql "CREATE TRIGGER the_trigger BEFORE [string range $statement 0 6]\ + ON tbl BEGIN $tr_program_fixed END;" - do_test trigger2-2-$ii-before "execsql {$statement $query}" $before_data + do_test trigger2-2.$ii-before "execsql {$statement $query}" $before_data execsql "DROP TRIGGER the_trigger;" execsql "DELETE FROM tbl; DELETE FROM log;" @@ -286,11 +298,18 @@ foreach tr_program [ list \ set after_data [ execsql "$prep $statement $tr_program_cooked $query" ] execsql "DELETE FROM tbl; DELETE FROM log; $prep"; + execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6]\ + ON tbl BEGIN $tr_program_fixed END;" - execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6] ON tbl BEGIN $tr_program_fixed END;" - - do_test trigger2-2-$ii-after "execsql {$statement $query}" $after_data + do_test trigger2-2.$ii-after "execsql {$statement $query}" $after_data execsql "DROP TRIGGER the_trigger;" + + do_test trigger2-2.$ii-integrity { + execsql { + PRAGMA integrity_check; + } + } {ok ok} + } } catchsql { @@ -361,6 +380,11 @@ execsql { DROP TABLE tbl; DROP TABLE log; } +do_test trigger2-3.3 { + execsql { + PRAGMA integrity_check; + } +} {ok ok} # Simple cascaded trigger execsql { @@ -585,9 +609,8 @@ do_test trigger2-7.1 { 0, 0, 0, 0, new.a, new.b, new.c, new.d); END; } -} {} +} {}; -#explain {delete from abcd where a=1;} do_test trigger2-7.2 { execsql { UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1; @@ -689,5 +712,8 @@ do_test trigger2-8.6 { } } {3 103 5 205 4 304 9 109 11 211 10 310} +do_test trigger2-9.9 { + execsql {PRAGMA integrity_check} +} {ok ok} finish_test