-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
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
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
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
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
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
-590f963b6599e4e235d7369f19c63cece4b2ad95
\ No newline at end of file
+01398fb78bab7e5c6f439f2b743f26e82118468a
\ No newline at end of file
** 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
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;
}
** 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
#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;
};
/*
-** 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 */
#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 {
};
/* 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:
}
/*
- * 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
}
/*
- * 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 );
}
/*
- * 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);
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);
}
/*
- * 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 */
*
* 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;
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{
* 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;
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 );
}
** *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;
** 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 ){
/* 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;
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
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);
}
}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);
}
}
/*
- * 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;
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;
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;
** 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 ){
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 ){
return SQLITE_OK;
}
-static int memBtreeKeySize(BtCursor* pCur, int *pSize)
+static int memRbtreeKeySize(RbtCursor* pCur, int *pSize)
{
if( pCur->pNode ){
*pSize = pCur->pNode->nKey;
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) ){
assert(0);
}
-static int memBtreeDataSize(BtCursor* pCur, int *pSize)
+static int memRbtreeDataSize(RbtCursor* pCur, int *pSize)
{
if( pCur->pNode ){
*pSize = pCur->pNode->nData;
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 ){
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;
}
/*
- * 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;
}
}
-static int memBtreeCommit(Btree* tree){
+static int memRbtreeCommit(Rbtree* tree){
/* Just delete pTransRollback and pCheckRollback */
deleteRollbackList(tree->pCheckRollback);
deleteRollbackList(tree->pTransRollback);
}
/*
- * 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);
}
}
-static int memBtreeRollback(Btree* tree)
+static int memRbtreeRollback(Rbtree* tree)
{
tree->eTransState = TRANS_ROLLBACK;
execute_rollback_list(tree, tree->pCheckRollback);
return SQLITE_OK;
}
-static int memBtreeBeginCkpt(Btree* tree)
+static int memRbtreeBeginCkpt(Rbtree* tree)
{
if( tree->eTransState != TRANS_INTRANSACTION )
return SQLITE_ERROR;
return SQLITE_OK;
}
-static int memBtreeCommitCkpt(Btree* tree)
+static int memRbtreeCommitCkpt(Rbtree* tree)
{
if( tree->eTransState == TRANS_INCHECKPOINT ){
if( tree->pCheckRollback ){
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;
}
#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
/*
** 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
};
** 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>
*/
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);
pParse->nErr++;
}
}
+ for(i=0; i<db->nDb; i++){
+ DbClearProperty(db, i, DB_Locked);
+ if( !db->aDb[i].inTrans ){
+ DbClearProperty(db, i, DB_Cookie);
+ }
+ }
}
/*
pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
}
pParse->colNamesSet = 0;
- pParse->schemaVerified = 0;
}else if( pParse->useCallback==0 ){
pParse->rc = SQLITE_ERROR;
}
sqliteDeleteTable(db, pTab);
}
sqliteHashClear(&temp1);
- db->aDb[i].flags &= ~SQLITE_Initialized;
+ DbClearProperty(db, i, DB_SchemaLoaded);
if( iDb>0 ) return;
}
assert( iDb==0 );
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;
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++;
}
/*
-** 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);
}
/*
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);
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);
** 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;
}
/*
** 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);
}
*************************************************************************
** 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"
}
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);
** 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"
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.
** 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"
*/
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 ){
** 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"
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
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
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);
}
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 ){
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
{
** 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"
** 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);
*************************************************************************
** 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"
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.
**
};
/*
-** 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 */
/* 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 */
/*
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 */
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*);
** 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"
*/
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.
** 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>
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: {
** See also: Clear
*/
case OP_Destroy: {
- sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
+ rc = sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
** See also: Destroy
*/
case OP_Clear: {
- sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
+ rc = sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
** 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"
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,
# 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]
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}
#
# 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
catchsql {
SELECT * FROM t2;
} db2
-} {1 {database schema has changed}}
+} {0 {10 20}}
do_test temptable-4.4.1 {
catchsql {
SELECT * FROM temp.t2;
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;
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;
# 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 {
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;
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;
0, 0);
END;
}
- do_test trigger2-1.2.$ii {
+ do_test trigger2-1.$ii.2 {
execsql {
DELETE FROM tbl;
SELECT * FROM rlog;
new.a, new.b);
END;
}
- do_test trigger2-1.3.$ii {
+ do_test trigger2-1.$ii.3 {
execsql {
CREATE TABLE other_tbl(a, b);
}
} [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;
# 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;}
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;"
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 {
DROP TABLE tbl;
DROP TABLE log;
}
+do_test trigger2-3.3 {
+ execsql {
+ PRAGMA integrity_check;
+ }
+} {ok ok}
# Simple cascaded trigger
execsql {
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;
}
} {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