]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix problems with TEMP indices that lead to corrupt databases. These
authordrh <drh@noemail.net>
Sat, 17 May 2003 17:35:10 +0000 (17:35 +0000)
committerdrh <drh@noemail.net>
Sat, 17 May 2003 17:35:10 +0000 (17:35 +0000)
problems were discovered while working on ticket #317.  No sure yet if
that ticket is fixed. (CVS 981)

FossilOrigin-Name: 01398fb78bab7e5c6f439f2b743f26e82118468a

17 files changed:
manifest
manifest.uuid
src/btree.c
src/btree_rb.c
src/build.c
src/copy.c
src/delete.c
src/insert.c
src/main.c
src/select.c
src/sqliteInt.h
src/update.c
src/vdbe.c
src/where.c
test/attach.test
test/temptable.test
test/trigger2.test

index a5660db4bbd515a30de63079570a2ae833b78c32..1acb5b20bd5ac412b1c317be66a884fd4ca2b733 100644 (file)
--- 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
index 4d8362fb5f587b32a568ed70ed62f874c364b190..ca05ec7a6b48bc6713cbe7e42b44b09d5374b338 100644 (file)
@@ -1 +1 @@
-590f963b6599e4e235d7369f19c63cece4b2ad95
\ No newline at end of file
+01398fb78bab7e5c6f439f2b743f26e82118468a
\ No newline at end of file
index dccb96059411402b0af7f2cdb58a3815aafe4f21..a7936e91801c696b85b9e3056b71e2f2ab46f344 100644 (file)
@@ -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; i<n; i++){
-        checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zMsg);
+        checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zContext);
       }
       N -= n;
     }
index f072332c5778113c52419056dee705ee20fad2c3..288a53eb84642bc8e5e163703abbfad354b9eac2 100644 (file)
@@ -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.
 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
 
 };
index a4091d81f7b2c18e8e512cd3dea81a6ac71f712a..b160a32ee9b9f4c2f441d6e73dae41dcb0a10a1f 100644 (file)
@@ -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 <ctype.h>
@@ -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; i<db->nDb; 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( j<i ){
-      db->aDb[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; i<db->nDb; i++){
-    if( i==1 || db->aDb[i].pBt==0 ) continue;
-    sqliteVdbeAddOp(v, OP_VerifyCookie, i, db->aDb[i].schema_cookie);
+  assert( iDb>=0 && iDb<db->nDb );
+  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; i<db->nDb; 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);
   }
index 44fd471421f2d494db114be07c2cb32542c74850..95849ab048cd36c78c14b0ad08ebf6ef47839c74 100644 (file)
@@ -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);
index 6c46c122d830b08c8d10c82a68cb2397100a3e43..9046c5e067b791e7774a8034df69604a7977b7f8 100644 (file)
@@ -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.
index ce4842535533d4fbbfcfff992f90addae58b80fc..5124e8aead48ec439ac54b396d8df91957d1cbbf 100644 (file)
@@ -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 ){
index d7c71f7e51f63ba6cc652991eed2b66e352f1564..a4c1b69c32c0e9f1030983ad3dc6f5615b2fb08c 100644 (file)
@@ -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 && i<db->nDb; 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
   {
index 82138a108e116b136281b1ad20821c49cb4b7f49..a4b300508f10d3e720c29cf7ff9ea1e644693636 100644 (file)
@@ -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);
index 18d1d991cebd4eee46302cdec547883a944dd51c..93b4dcc28d3b7d35e6dcbc090199708c970ff226 100644 (file)
@@ -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*);
index 56021b7460d334b2296937a6eb21132359d621ac..109bbb629e200727878ca485e6b355abbfe74349 100644 (file)
@@ -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.
index c67bd423ea87b455d1c828acb6dd4d88ffea1695..9c07b7025e571bf609e5c964b7b6f8e9d3b28bb0 100644 (file)
@@ -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 <ctype.h>
@@ -3193,7 +3193,9 @@ case OP_Checkpoint: {
 case OP_Transaction: {
   int busy = 1;
   int i = pOp->p1;
-  while( i>=0 && i<db->nDb && db->aDb[i].pBt!=0 && busy ){
+  assert( i>=0 && i<db->nDb );
+  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;
 }
 
index fda6b299d8be314140396e0af964aed9eb1f487f..1400c62858cd0dc9e3bb18297ee520eab18989a2 100644 (file)
@@ -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,
index e132f771de1e0d5f6089c3700f8830c211eb5e67..6611bc6e49b7acc0a630e464306276f300d90bbc 100644 (file)
@@ -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}
index 1c427a19ad8cadcdcae1c47ccd39e367592179fb..8a1b70a709a6a58875d06ff5c27e9c98aac98cfe 100644 (file)
@@ -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;
index 8cefb756746d295a163ddccd9d646cd06d7693d6..06aa11ce4d6aef31f9da6d5cbe04f7de11a9504b 100644 (file)
@@ -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