mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Fix problems with TEMP indices that lead to corrupt databases. These
problems were discovered while working on ticket #317. No sure yet if that ticket is fixed. (CVS 981) FossilOrigin-Name: 01398fb78bab7e5c6f439f2b743f26e82118468a
This commit is contained in:
40
manifest
40
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Version\s2.8.1\s(CVS\s980)
|
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-17T02:44:32
|
D 2003-05-17T17:35:11
|
||||||
F Makefile.in 1ff85c27d4350c74118341024e8a4fb2a04a3a43
|
F Makefile.in 1ff85c27d4350c74118341024e8a4fb2a04a3a43
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@@ -21,19 +21,19 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
|||||||
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||||
F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
|
F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
|
||||||
F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6
|
F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6
|
||||||
F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d
|
F src/btree.c 8092dca45dcdb69c61273db0213cbb85760673c7
|
||||||
F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e
|
F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e
|
||||||
F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d
|
F src/btree_rb.c 1d809e703aab8bef916ebb0b6ba9254a1c36d9a6
|
||||||
F src/build.c e24461d42381a36de88de6af06c03d9f14588705
|
F src/build.c 95dfb188f448e6299108396546a8333ecdcb1716
|
||||||
F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263
|
F src/copy.c 5e5d558d283536592cd67b5dc1519c3152bd7e20
|
||||||
F src/delete.c f9536a75b444a21f11b7a1bc0fb8c876f691b013
|
F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc
|
||||||
F src/encode.c ed720e54ec4ef4d4de651592f1dd1c74d422bbd2
|
F src/encode.c ed720e54ec4ef4d4de651592f1dd1c74d422bbd2
|
||||||
F src/expr.c a666ef5220ca90ebcf40c8ccc783966a345a7616
|
F src/expr.c a666ef5220ca90ebcf40c8ccc783966a345a7616
|
||||||
F src/func.c 33bbce6acaf9578ac99aa1f689968ccaf2ce43a2
|
F src/func.c 33bbce6acaf9578ac99aa1f689968ccaf2ce43a2
|
||||||
F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3
|
F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3
|
||||||
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
||||||
F src/insert.c fac16589e644b2d4bb615c5e782bcfd0453a052a
|
F src/insert.c 2f26b95cc1055062411cbdea06e2e1b40a8b0d8d
|
||||||
F src/main.c 16e68905793b118552a9cf43a9f77ca1d9e395a9
|
F src/main.c 717aaf32d468667dabeaec80054e11bfdb6309b6
|
||||||
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
||||||
F src/os.c 94b618c0c0a76210e53857d77c96d2f042dc33b1
|
F src/os.c 94b618c0c0a76210e53857d77c96d2f042dc33b1
|
||||||
F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
|
F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
|
||||||
@@ -43,11 +43,11 @@ F src/parse.y 39b5240cb78047dc56d6d37c398baed7ba556779
|
|||||||
F src/pragma.c ec64704e61286948f39157617f1ce2f506dd1b74
|
F src/pragma.c ec64704e61286948f39157617f1ce2f506dd1b74
|
||||||
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
|
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
|
||||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||||
F src/select.c c06b4605bca03d8237a3fc4098179bf3a7133702
|
F src/select.c 15d921308065c9320363af6f43c01d9f09ea7118
|
||||||
F src/shell.c 2565cb32cd862024bcfd88400e05437636cf21a1
|
F src/shell.c 2565cb32cd862024bcfd88400e05437636cf21a1
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
|
F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
|
||||||
F src/sqliteInt.h 9b64d8225a26f3d5a376370b31060dd70bcc362b
|
F src/sqliteInt.h cab919e43875a561603ca6e0d060fd0690c2ee7c
|
||||||
F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95
|
F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95
|
||||||
F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d
|
F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d
|
||||||
F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325
|
F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325
|
||||||
@@ -56,14 +56,14 @@ F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
|
|||||||
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
|
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
|
||||||
F src/tokenize.c 2ba93fe10d5f57f0cc20b07417c3244a30c324b3
|
F src/tokenize.c 2ba93fe10d5f57f0cc20b07417c3244a30c324b3
|
||||||
F src/trigger.c 8ee811986080de60d9d883ad96daffea82014f27
|
F src/trigger.c 8ee811986080de60d9d883ad96daffea82014f27
|
||||||
F src/update.c dc3b680b4cf2cb6d839950b68d632850746639b9
|
F src/update.c 8e657c7b3d27b5592d8caa362d9c4765e0b3cd6a
|
||||||
F src/util.c 8065b78806a5132119452d9e0417cf071e6f02f9
|
F src/util.c 8065b78806a5132119452d9e0417cf071e6f02f9
|
||||||
F src/vacuum.c 0820984615786c9ccdaad8032a792309b354a8eb
|
F src/vacuum.c 0820984615786c9ccdaad8032a792309b354a8eb
|
||||||
F src/vdbe.c e9e560b0c568fb4ffb189d3e0d91628a33d2a367
|
F src/vdbe.c 81b9868acd7e7d54ddd26af4ffe8442c312ad374
|
||||||
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
|
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
|
||||||
F src/where.c ef11773a07cf075740378d7d1cbabf328146fdc9
|
F src/where.c 1e645d430cb4b347159c28c6085e9801160f2099
|
||||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||||
F test/attach.test b311c83e370e6b22b79a8279317039440ce64862
|
F test/attach.test ca8304e0f2236d1bf68e53ccc17cf3e8d76de0f1
|
||||||
F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d
|
F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d
|
||||||
F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678
|
F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
@@ -116,11 +116,11 @@ F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
|
|||||||
F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
|
F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
|
||||||
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
|
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
|
||||||
F test/tclsqlite.test d9bdfc0afca9ee605c50ecb39e94ae4dea8c222b
|
F test/tclsqlite.test d9bdfc0afca9ee605c50ecb39e94ae4dea8c222b
|
||||||
F test/temptable.test 6feff1960c707e924d5462356c5303943dac4a8e
|
F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692
|
||||||
F test/tester.tcl d7a5835edaf118539241145d8188f0822b673488
|
F test/tester.tcl d7a5835edaf118539241145d8188f0822b673488
|
||||||
F test/trans.test 75e7a171b5d2d94ee56766459113e2ad0e5f809d
|
F test/trans.test 75e7a171b5d2d94ee56766459113e2ad0e5f809d
|
||||||
F test/trigger1.test 61ef41666f066ac417730dc26056053a7c36cd11
|
F test/trigger1.test 61ef41666f066ac417730dc26056053a7c36cd11
|
||||||
F test/trigger2.test adf6a9cfd735bd4be4f7be19da629b0968703744
|
F test/trigger2.test 00ceb8aff6bddd511bbac7c837af2863fa0c9cb4
|
||||||
F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72
|
F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72
|
||||||
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
|
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
|
||||||
F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
|
F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
|
||||||
@@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
|
|||||||
F www/sqlite.tcl 4bd1729e320f5fa9125f0022b281fbe839192125
|
F www/sqlite.tcl 4bd1729e320f5fa9125f0022b281fbe839192125
|
||||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P baea7aca10e30f30b874e1e8b6cd3b05954ba83c
|
P 590f963b6599e4e235d7369f19c63cece4b2ad95
|
||||||
R d79117ebcf990c76ac030f81c35e1389
|
R 869048a3307d9ca8d4b394c814d0ad0e
|
||||||
U drh
|
U drh
|
||||||
Z b3ec67d7cdead0321417395bbb89e4c5
|
Z 2835ef2dc75e2e6d87e08c87fdd8ab29
|
||||||
|
@@ -1 +1 @@
|
|||||||
590f963b6599e4e235d7369f19c63cece4b2ad95
|
01398fb78bab7e5c6f439f2b743f26e82118468a
|
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** 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.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@@ -3229,7 +3229,7 @@ static void checkList(
|
|||||||
FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload;
|
FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload;
|
||||||
int n = SWAB32(pCheck->pBt, pInfo->nFree);
|
int n = SWAB32(pCheck->pBt, pInfo->nFree);
|
||||||
for(i=0; i<n; i++){
|
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;
|
N -= n;
|
||||||
}
|
}
|
||||||
|
353
src/btree_rb.c
353
src/btree_rb.c
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** 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
|
** This file implements an in-core database using Red-Black balanced
|
||||||
** binary trees.
|
** binary trees.
|
||||||
@@ -31,10 +31,12 @@
|
|||||||
typedef struct BtRbTree BtRbTree;
|
typedef struct BtRbTree BtRbTree;
|
||||||
typedef struct BtRbNode BtRbNode;
|
typedef struct BtRbNode BtRbNode;
|
||||||
typedef struct BtRollbackOp BtRollbackOp;
|
typedef struct BtRollbackOp BtRollbackOp;
|
||||||
|
typedef struct Rbtree Rbtree;
|
||||||
|
typedef struct RbtCursor RbtCursor;
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static BtOps sqliteBtreeOps;
|
static BtOps sqliteRbtreeOps;
|
||||||
static BtCursorOps sqliteBtreeCursorOps;
|
static BtCursorOps sqliteRbtreeCursorOps;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* During each transaction (or checkpoint), a linked-list of
|
* During each transaction (or checkpoint), a linked-list of
|
||||||
@@ -68,14 +70,14 @@ struct BtRollbackOp {
|
|||||||
#define ROLLBACK_CREATE 3 /* Create a table */
|
#define ROLLBACK_CREATE 3 /* Create a table */
|
||||||
#define ROLLBACK_DROP 4 /* Drop a table */
|
#define ROLLBACK_DROP 4 /* Drop a table */
|
||||||
|
|
||||||
struct Btree {
|
struct Rbtree {
|
||||||
BtOps *pOps; /* Function table */
|
BtOps *pOps; /* Function table */
|
||||||
int aMetaData[SQLITE_N_BTREE_META];
|
int aMetaData[SQLITE_N_BTREE_META];
|
||||||
|
|
||||||
int next_idx; /* next available table index */
|
int next_idx; /* next available table index */
|
||||||
Hash tblHash; /* All created tables, by index */
|
Hash tblHash; /* All created tables, by index */
|
||||||
u8 isAnonymous; /* True if this Btree is to be deleted when closed */
|
u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */
|
||||||
u8 eTransState; /* State of this Btree wrt transactions */
|
u8 eTransState; /* State of this Rbtree wrt transactions */
|
||||||
|
|
||||||
BtRollbackOp *pTransRollback;
|
BtRollbackOp *pTransRollback;
|
||||||
BtRollbackOp *pCheckRollback;
|
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_NONE 0 /* No transaction is in progress */
|
||||||
#define TRANS_INTRANSACTION 1 /* A 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
|
#define TRANS_ROLLBACK 3 /* We are currently rolling back a checkpoint or
|
||||||
* transaction. */
|
* transaction. */
|
||||||
|
|
||||||
struct BtCursor {
|
struct RbtCursor {
|
||||||
BtCursorOps *pOps; /* Function table */
|
BtCursorOps *pOps; /* Function table */
|
||||||
Btree *pBtree;
|
Rbtree *pRbtree;
|
||||||
BtRbTree *pTree;
|
BtRbTree *pTree;
|
||||||
int iTree; /* Index of pTree in pBtree */
|
int iTree; /* Index of pTree in pRbtree */
|
||||||
BtRbNode *pNode;
|
BtRbNode *pNode;
|
||||||
u8 eSkip; /* Determines if next step operation is a no-op */
|
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_NONE 0 /* Always step the cursor */
|
||||||
#define SKIP_NEXT 1 /* The next sqliteBtreeNext() is a no-op */
|
#define SKIP_NEXT 1 /* The next sqliteRbtreeNext() is a no-op */
|
||||||
#define SKIP_PREV 2 /* The next sqliteBtreePrevious() 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 */
|
#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */
|
||||||
|
|
||||||
struct BtRbTree {
|
struct BtRbTree {
|
||||||
@@ -126,11 +128,16 @@ struct BtRbNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey,int *pRes);
|
static int memRbtreeMoveto(
|
||||||
static int memBtreeClearTable(Btree* tree, int n);
|
RbtCursor* pCur,
|
||||||
static int memBtreeNext(BtCursor* pCur, int *pRes);
|
const void *pKey,
|
||||||
static int memBtreeLast(BtCursor* pCur, int *pRes);
|
int nKey,
|
||||||
static int memBtreePrevious(BtCursor* pCur, int *pRes);
|
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:
|
* 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
|
* 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
|
* of the red-black tree properties. This function performs rotations and
|
||||||
* color changes to rebalance the tree
|
* 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));
|
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.
|
* BtRollbackOp.
|
||||||
*/
|
*/
|
||||||
static void btreeLogRollbackOp(Btree* pBtree, BtRollbackOp *pRollbackOp)
|
static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp)
|
||||||
{
|
{
|
||||||
assert( pBtree->eTransState == TRANS_INCHECKPOINT ||
|
assert( pRbtree->eTransState == TRANS_INCHECKPOINT ||
|
||||||
pBtree->eTransState == TRANS_INTRANSACTION );
|
pRbtree->eTransState == TRANS_INTRANSACTION );
|
||||||
if( pBtree->eTransState == TRANS_INTRANSACTION ){
|
if( pRbtree->eTransState == TRANS_INTRANSACTION ){
|
||||||
pRollbackOp->pNext = pBtree->pTransRollback;
|
pRollbackOp->pNext = pRbtree->pTransRollback;
|
||||||
pBtree->pTransRollback = pRollbackOp;
|
pRbtree->pTransRollback = pRollbackOp;
|
||||||
}
|
}
|
||||||
if( pBtree->eTransState == TRANS_INCHECKPOINT ){
|
if( pRbtree->eTransState == TRANS_INCHECKPOINT ){
|
||||||
if( !pBtree->pCheckRollback ){
|
if( !pRbtree->pCheckRollback ){
|
||||||
pBtree->pCheckRollbackTail = pRollbackOp;
|
pRbtree->pCheckRollbackTail = pRollbackOp;
|
||||||
}
|
}
|
||||||
pRollbackOp->pNext = pBtree->pCheckRollback;
|
pRollbackOp->pNext = pRbtree->pCheckRollback;
|
||||||
pBtree->pCheckRollback = pRollbackOp;
|
pRbtree->pCheckRollback = pRollbackOp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sqliteRBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree)
|
int sqliteRbtreeOpen(
|
||||||
{
|
const char *zFilename,
|
||||||
*ppBtree = (Btree *)sqliteMalloc(sizeof(Btree));
|
int mode,
|
||||||
sqliteHashInit(&(*ppBtree)->tblHash, SQLITE_HASH_INT, 0);
|
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 */
|
/* Create a binary tree for the SQLITE_MASTER table at location 2 */
|
||||||
btreeCreateTable(*ppBtree, 2);
|
btreeCreateTable(*ppRbtree, 2);
|
||||||
(*ppBtree)->next_idx = 3;
|
(*ppRbtree)->next_idx = 3;
|
||||||
(*ppBtree)->pOps = &sqliteBtreeOps;
|
(*ppRbtree)->pOps = &sqliteRbtreeOps;
|
||||||
/* Set file type to 4; this is so that "attach ':memory:' as ...." does not
|
/* Set file type to 4; this is so that "attach ':memory:' as ...." does not
|
||||||
** think that the database in uninitialised and refuse to attach
|
** think that the database in uninitialised and refuse to attach
|
||||||
*/
|
*/
|
||||||
(*ppBtree)->aMetaData[2] = 4;
|
(*ppRbtree)->aMetaData[2] = 4;
|
||||||
|
|
||||||
return SQLITE_OK;
|
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.
|
* 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 );
|
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;
|
BtRbTree *pTree;
|
||||||
assert( tree->eTransState != TRANS_NONE );
|
assert( tree->eTransState != TRANS_NONE );
|
||||||
|
|
||||||
memBtreeClearTable(tree, n);
|
memRbtreeClearTable(tree, n);
|
||||||
pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
|
pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
|
||||||
assert(pTree);
|
assert(pTree);
|
||||||
sqliteFree(pTree);
|
sqliteFree(pTree);
|
||||||
@@ -632,7 +643,7 @@ static int memBtreeDropTable(Btree* tree, int n)
|
|||||||
return SQLITE_OK;
|
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)
|
int nIgnore, int *pRes)
|
||||||
{
|
{
|
||||||
assert(pCur);
|
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.
|
* 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);
|
assert(tree);
|
||||||
*ppCur = sqliteMalloc(sizeof(BtCursor));
|
*ppCur = sqliteMalloc(sizeof(RbtCursor));
|
||||||
(*ppCur)->pTree = sqliteHashFind(&tree->tblHash, 0, iTable);
|
(*ppCur)->pTree = sqliteHashFind(&tree->tblHash, 0, iTable);
|
||||||
(*ppCur)->pBtree = tree;
|
(*ppCur)->pRbtree = tree;
|
||||||
(*ppCur)->iTree = iTable;
|
(*ppCur)->iTree = iTable;
|
||||||
(*ppCur)->pOps = &sqliteBtreeCursorOps;
|
(*ppCur)->pOps = &sqliteRbtreeCursorOps;
|
||||||
|
|
||||||
assert( (*ppCur)->pTree );
|
assert( (*ppCur)->pTree );
|
||||||
return SQLITE_OK;
|
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
|
* 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
|
* define what database the record should be inserted into. The cursor
|
||||||
* is left pointing at the new record.
|
* is left pointing at the new record.
|
||||||
*
|
*
|
||||||
* If the key exists already in the tree, just replace the data.
|
* If the key exists already in the tree, just replace the data.
|
||||||
*/
|
*/
|
||||||
static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
|
static int memRbtreeInsert(
|
||||||
const void *pDataInput, int nData)
|
RbtCursor* pCur,
|
||||||
{
|
const void *pKey,
|
||||||
|
int nKey,
|
||||||
|
const void *pDataInput,
|
||||||
|
int nData
|
||||||
|
){
|
||||||
void * pData;
|
void * pData;
|
||||||
int match;
|
int match;
|
||||||
|
|
||||||
/* It is illegal to call sqliteBtreeInsert() if we are not in a transaction */
|
/* It is illegal to call sqliteRbtreeInsert() if we are
|
||||||
assert( pCur->pBtree->eTransState != TRANS_NONE );
|
** 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
|
/* Take a copy of the input data now, in case we need it for the
|
||||||
* replace case */
|
* replace case */
|
||||||
@@ -702,7 +722,7 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
|
|||||||
*
|
*
|
||||||
* The new node is initially red.
|
* The new node is initially red.
|
||||||
*/
|
*/
|
||||||
memBtreeMoveto( pCur, pKey, nKey, &match);
|
memRbtreeMoveto( pCur, pKey, nKey, &match);
|
||||||
if( match ){
|
if( match ){
|
||||||
BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
|
BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
|
||||||
pNode->nKey = nKey;
|
pNode->nKey = nKey;
|
||||||
@@ -736,14 +756,14 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
|
|||||||
do_insert_balancing(pCur->pTree, pNode);
|
do_insert_balancing(pCur->pTree, pNode);
|
||||||
|
|
||||||
/* Set up a rollback-op in case we have to roll this operation back */
|
/* 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) );
|
BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
|
||||||
pOp->eOp = ROLLBACK_DELETE;
|
pOp->eOp = ROLLBACK_DELETE;
|
||||||
pOp->iTab = pCur->iTree;
|
pOp->iTab = pCur->iTree;
|
||||||
pOp->nKey = pNode->nKey;
|
pOp->nKey = pNode->nKey;
|
||||||
pOp->pKey = sqliteMalloc( pOp->nKey );
|
pOp->pKey = sqliteMalloc( pOp->nKey );
|
||||||
memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
|
memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
|
||||||
btreeLogRollbackOp(pCur->pBtree, pOp);
|
btreeLogRollbackOp(pCur->pRbtree, pOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
@@ -751,7 +771,7 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
|
|||||||
* Just clobber the current nodes data. */
|
* Just clobber the current nodes data. */
|
||||||
|
|
||||||
/* Set up a rollback-op in case we have to roll this operation back */
|
/* 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) );
|
BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
|
||||||
pOp->iTab = pCur->iTree;
|
pOp->iTab = pCur->iTree;
|
||||||
pOp->nKey = pCur->pNode->nKey;
|
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->nData = pCur->pNode->nData;
|
||||||
pOp->pData = pCur->pNode->pData;
|
pOp->pData = pCur->pNode->pData;
|
||||||
pOp->eOp = ROLLBACK_INSERT;
|
pOp->eOp = ROLLBACK_INSERT;
|
||||||
btreeLogRollbackOp(pCur->pBtree, pOp);
|
btreeLogRollbackOp(pCur->pRbtree, pOp);
|
||||||
}else{
|
}else{
|
||||||
sqliteFree( pCur->pNode->pData );
|
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
|
** *pRes>0 The cursor is left pointing at an entry that
|
||||||
** is larger than pKey.
|
** 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;
|
BtRbNode *pTmp = 0;
|
||||||
|
|
||||||
pCur->pNode = pCur->pTree->pHead;
|
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
|
** The cursor is left pointing at either the next or the previous
|
||||||
** entry. If the cursor is left pointing to the next entry, then
|
** 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
|
** 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
|
** sqliteRbtreeNext() to be a no-op. That way, you can always call
|
||||||
** sqliteBtreeNext() after a delete and the cursor will be left
|
** sqliteRbtreeNext() after a delete and the cursor will be left
|
||||||
** pointing to the first entry after the deleted entry. Similarly,
|
** pointing to the first entry after the deleted entry. Similarly,
|
||||||
** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
|
** 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
|
** 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.
|
** 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 *pZ; /* The one being deleted */
|
||||||
BtRbNode *pChild; /* The child of the spliced out node */
|
BtRbNode *pChild; /* The child of the spliced out node */
|
||||||
|
|
||||||
/* It is illegal to call sqliteBtreeDelete() if we are not in a transaction */
|
/* It is illegal to call sqliteRbtreeDelete() if we are
|
||||||
assert( pCur->pBtree->eTransState != TRANS_NONE );
|
** not in a transaction */
|
||||||
|
assert( pCur->pRbtree->eTransState != TRANS_NONE );
|
||||||
|
|
||||||
pZ = pCur->pNode;
|
pZ = pCur->pNode;
|
||||||
if( !pZ ){
|
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
|
/* If we are not currently doing a rollback, set up a rollback op for this
|
||||||
* deletion */
|
* deletion */
|
||||||
if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){
|
if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
|
||||||
BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
|
BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
|
||||||
pOp->iTab = pCur->iTree;
|
pOp->iTab = pCur->iTree;
|
||||||
pOp->nKey = pZ->nKey;
|
pOp->nKey = pZ->nKey;
|
||||||
@@ -854,7 +879,7 @@ static int memBtreeDelete(BtCursor* pCur)
|
|||||||
pOp->nData = pZ->nData;
|
pOp->nData = pZ->nData;
|
||||||
pOp->pData = pZ->pData;
|
pOp->pData = pZ->pData;
|
||||||
pOp->eOp = ROLLBACK_INSERT;
|
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
|
/* 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;
|
BtRbNode *pTmp;
|
||||||
int dummy;
|
int dummy;
|
||||||
pCur->eSkip = SKIP_NONE;
|
pCur->eSkip = SKIP_NONE;
|
||||||
memBtreeNext(pCur, &dummy);
|
memRbtreeNext(pCur, &dummy);
|
||||||
assert( dummy == 0 );
|
assert( dummy == 0 );
|
||||||
if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){
|
if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
|
||||||
sqliteFree(pZ->pKey);
|
sqliteFree(pZ->pKey);
|
||||||
sqliteFree(pZ->pData);
|
sqliteFree(pZ->pData);
|
||||||
}
|
}
|
||||||
@@ -884,14 +909,14 @@ static int memBtreeDelete(BtCursor* pCur)
|
|||||||
}else{
|
}else{
|
||||||
int res;
|
int res;
|
||||||
pCur->eSkip = SKIP_NONE;
|
pCur->eSkip = SKIP_NONE;
|
||||||
memBtreeNext(pCur, &res);
|
memRbtreeNext(pCur, &res);
|
||||||
pCur->eSkip = SKIP_NEXT;
|
pCur->eSkip = SKIP_NEXT;
|
||||||
if( res ){
|
if( res ){
|
||||||
memBtreeLast(pCur, &res);
|
memRbtreeLast(pCur, &res);
|
||||||
memBtreePrevious(pCur, &res);
|
memRbtreePrevious(pCur, &res);
|
||||||
pCur->eSkip = SKIP_PREV;
|
pCur->eSkip = SKIP_PREV;
|
||||||
}
|
}
|
||||||
if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){
|
if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
|
||||||
sqliteFree(pZ->pKey);
|
sqliteFree(pZ->pKey);
|
||||||
sqliteFree(pZ->pData);
|
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;
|
BtRbTree *pTree;
|
||||||
BtRbNode *pNode;
|
BtRbNode *pNode;
|
||||||
@@ -974,7 +999,7 @@ static int memBtreeClearTable(Btree* tree, int n)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeFirst(BtCursor* pCur, int *pRes)
|
static int memRbtreeFirst(RbtCursor* pCur, int *pRes)
|
||||||
{
|
{
|
||||||
if( pCur->pTree->pHead ){
|
if( pCur->pTree->pHead ){
|
||||||
pCur->pNode = pCur->pTree->pHead;
|
pCur->pNode = pCur->pTree->pHead;
|
||||||
@@ -991,7 +1016,7 @@ static int memBtreeFirst(BtCursor* pCur, int *pRes)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeLast(BtCursor* pCur, int *pRes)
|
static int memRbtreeLast(RbtCursor* pCur, int *pRes)
|
||||||
{
|
{
|
||||||
if( pCur->pTree->pHead ){
|
if( pCur->pTree->pHead ){
|
||||||
pCur->pNode = 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
|
** was already pointing to the last entry in the database before
|
||||||
** this routine was called, then set *pRes=1.
|
** 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 && pCur->eSkip != SKIP_NEXT ){
|
||||||
if( pCur->pNode->pRight ){
|
if( pCur->pNode->pRight ){
|
||||||
@@ -1041,7 +1066,7 @@ static int memBtreeNext(BtCursor* pCur, int *pRes)
|
|||||||
return SQLITE_OK;
|
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 && pCur->eSkip != SKIP_PREV ){
|
||||||
if( pCur->pNode->pLeft ){
|
if( pCur->pNode->pLeft ){
|
||||||
@@ -1068,7 +1093,7 @@ static int memBtreePrevious(BtCursor* pCur, int *pRes)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeKeySize(BtCursor* pCur, int *pSize)
|
static int memRbtreeKeySize(RbtCursor* pCur, int *pSize)
|
||||||
{
|
{
|
||||||
if( pCur->pNode ){
|
if( pCur->pNode ){
|
||||||
*pSize = pCur->pNode->nKey;
|
*pSize = pCur->pNode->nKey;
|
||||||
@@ -1078,7 +1103,7 @@ static int memBtreeKeySize(BtCursor* pCur, int *pSize)
|
|||||||
return SQLITE_OK;
|
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 ) return 0;
|
||||||
if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){
|
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);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeDataSize(BtCursor* pCur, int *pSize)
|
static int memRbtreeDataSize(RbtCursor* pCur, int *pSize)
|
||||||
{
|
{
|
||||||
if( pCur->pNode ){
|
if( pCur->pNode ){
|
||||||
*pSize = pCur->pNode->nData;
|
*pSize = pCur->pNode->nData;
|
||||||
@@ -1101,7 +1126,7 @@ static int memBtreeDataSize(BtCursor* pCur, int *pSize)
|
|||||||
return SQLITE_OK;
|
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( !pCur->pNode ) return 0;
|
||||||
if( (amt + offset) <= pCur->pNode->nData ){
|
if( (amt + offset) <= pCur->pNode->nData ){
|
||||||
@@ -1114,30 +1139,30 @@ static int memBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeCloseCursor(BtCursor* pCur)
|
static int memRbtreeCloseCursor(RbtCursor* pCur)
|
||||||
{
|
{
|
||||||
sqliteFree(pCur);
|
sqliteFree(pCur);
|
||||||
return SQLITE_OK;
|
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 );
|
memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META );
|
||||||
return SQLITE_OK;
|
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 );
|
memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META );
|
||||||
return SQLITE_OK;
|
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
|
* binary tree. If an error is found, return an explanation of the problem in
|
||||||
* memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored.
|
* 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;
|
char * msg = 0;
|
||||||
HashElem *p;
|
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;
|
HashElem *p;
|
||||||
while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
|
while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
|
||||||
tree->eTransState = TRANS_ROLLBACK;
|
tree->eTransState = TRANS_ROLLBACK;
|
||||||
memBtreeDropTable(tree, sqliteHashKeysize(p));
|
memRbtreeDropTable(tree, sqliteHashKeysize(p));
|
||||||
}
|
}
|
||||||
sqliteHashClear(&tree->tblHash);
|
sqliteHashClear(&tree->tblHash);
|
||||||
sqliteFree(tree);
|
sqliteFree(tree);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeSetCacheSize(Btree* tree, int sz)
|
static int memRbtreeSetCacheSize(Rbtree* tree, int sz)
|
||||||
{
|
{
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeSetSafetyLevel(Btree *pBt, int level){
|
static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeBeginTrans(Btree* tree)
|
static int memRbtreeBeginTrans(Rbtree* tree)
|
||||||
{
|
{
|
||||||
if( tree->eTransState != TRANS_NONE )
|
if( tree->eTransState != TRANS_NONE )
|
||||||
return SQLITE_ERROR;
|
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 */
|
/* Just delete pTransRollback and pCheckRollback */
|
||||||
deleteRollbackList(tree->pCheckRollback);
|
deleteRollbackList(tree->pCheckRollback);
|
||||||
deleteRollbackList(tree->pTransRollback);
|
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;
|
BtRollbackOp *pTmp;
|
||||||
BtCursor cur;
|
RbtCursor cur;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
cur.pBtree = pBtree;
|
cur.pRbtree = pRbtree;
|
||||||
while( pList ){
|
while( pList ){
|
||||||
switch( pList->eOp ){
|
switch( pList->eOp ){
|
||||||
case ROLLBACK_INSERT:
|
case ROLLBACK_INSERT:
|
||||||
cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
|
cur.pTree = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
|
||||||
assert(cur.pTree);
|
assert(cur.pTree);
|
||||||
cur.iTree = pList->iTab;
|
cur.iTree = pList->iTab;
|
||||||
cur.eSkip = SKIP_NONE;
|
cur.eSkip = SKIP_NONE;
|
||||||
memBtreeInsert( &cur, pList->pKey,
|
memRbtreeInsert( &cur, pList->pKey,
|
||||||
pList->nKey, pList->pData, pList->nData );
|
pList->nKey, pList->pData, pList->nData );
|
||||||
break;
|
break;
|
||||||
case ROLLBACK_DELETE:
|
case ROLLBACK_DELETE:
|
||||||
cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
|
cur.pTree = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
|
||||||
assert(cur.pTree);
|
assert(cur.pTree);
|
||||||
cur.iTree = pList->iTab;
|
cur.iTree = pList->iTab;
|
||||||
cur.eSkip = SKIP_NONE;
|
cur.eSkip = SKIP_NONE;
|
||||||
memBtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
|
memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
|
||||||
assert(res == 0);
|
assert(res == 0);
|
||||||
memBtreeDelete( &cur );
|
memRbtreeDelete( &cur );
|
||||||
break;
|
break;
|
||||||
case ROLLBACK_CREATE:
|
case ROLLBACK_CREATE:
|
||||||
btreeCreateTable(pBtree, pList->iTab);
|
btreeCreateTable(pRbtree, pList->iTab);
|
||||||
break;
|
break;
|
||||||
case ROLLBACK_DROP:
|
case ROLLBACK_DROP:
|
||||||
memBtreeDropTable(pBtree, pList->iTab);
|
memRbtreeDropTable(pRbtree, pList->iTab);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
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;
|
tree->eTransState = TRANS_ROLLBACK;
|
||||||
execute_rollback_list(tree, tree->pCheckRollback);
|
execute_rollback_list(tree, tree->pCheckRollback);
|
||||||
@@ -1266,7 +1291,7 @@ static int memBtreeRollback(Btree* tree)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeBeginCkpt(Btree* tree)
|
static int memRbtreeBeginCkpt(Rbtree* tree)
|
||||||
{
|
{
|
||||||
if( tree->eTransState != TRANS_INTRANSACTION )
|
if( tree->eTransState != TRANS_INTRANSACTION )
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
@@ -1277,7 +1302,7 @@ static int memBtreeBeginCkpt(Btree* tree)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeCommitCkpt(Btree* tree)
|
static int memRbtreeCommitCkpt(Rbtree* tree)
|
||||||
{
|
{
|
||||||
if( tree->eTransState == TRANS_INCHECKPOINT ){
|
if( tree->eTransState == TRANS_INCHECKPOINT ){
|
||||||
if( tree->pCheckRollback ){
|
if( tree->pCheckRollback ){
|
||||||
@@ -1291,7 +1316,7 @@ static int memBtreeCommitCkpt(Btree* tree)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memBtreeRollbackCkpt(Btree* tree)
|
static int memRbtreeRollbackCkpt(Rbtree* tree)
|
||||||
{
|
{
|
||||||
if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK;
|
if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK;
|
||||||
tree->eTransState = TRANS_ROLLBACK;
|
tree->eTransState = TRANS_ROLLBACK;
|
||||||
@@ -1304,21 +1329,21 @@ static int memBtreeRollbackCkpt(Btree* tree)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
#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;
|
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;
|
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;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1326,60 +1351,60 @@ static struct Pager *memBtreePager(Btree* tree)
|
|||||||
/*
|
/*
|
||||||
** Return the full pathname of the underlying database file.
|
** 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 */
|
return 0; /* A NULL return indicates there is no underlying file */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The copy file function is not implemented for the in-memory database
|
** 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 */
|
return SQLITE_INTERNAL; /* Not implemented */
|
||||||
}
|
}
|
||||||
|
|
||||||
static BtOps sqliteBtreeOps = {
|
static BtOps sqliteRbtreeOps = {
|
||||||
memBtreeClose,
|
(int(*)(Btree*)) memRbtreeClose,
|
||||||
memBtreeSetCacheSize,
|
(int(*)(Btree*,int)) memRbtreeSetCacheSize,
|
||||||
memBtreeSetSafetyLevel,
|
(int(*)(Btree*,int)) memRbtreeSetSafetyLevel,
|
||||||
memBtreeBeginTrans,
|
(int(*)(Btree*)) memRbtreeBeginTrans,
|
||||||
memBtreeCommit,
|
(int(*)(Btree*)) memRbtreeCommit,
|
||||||
memBtreeRollback,
|
(int(*)(Btree*)) memRbtreeRollback,
|
||||||
memBtreeBeginCkpt,
|
(int(*)(Btree*)) memRbtreeBeginCkpt,
|
||||||
memBtreeCommitCkpt,
|
(int(*)(Btree*)) memRbtreeCommitCkpt,
|
||||||
memBtreeRollbackCkpt,
|
(int(*)(Btree*)) memRbtreeRollbackCkpt,
|
||||||
memBtreeCreateTable,
|
(int(*)(Btree*,int*)) memRbtreeCreateTable,
|
||||||
memBtreeCreateTable,
|
(int(*)(Btree*,int*)) memRbtreeCreateTable,
|
||||||
memBtreeDropTable,
|
(int(*)(Btree*,int)) memRbtreeDropTable,
|
||||||
memBtreeClearTable,
|
(int(*)(Btree*,int)) memRbtreeClearTable,
|
||||||
memBtreeCursor,
|
(int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor,
|
||||||
memBtreeGetMeta,
|
(int(*)(Btree*,int*)) memRbtreeGetMeta,
|
||||||
memBtreeUpdateMeta,
|
(int(*)(Btree*,int*)) memRbtreeUpdateMeta,
|
||||||
memBtreeIntegrityCheck,
|
(char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck,
|
||||||
memBtreeGetFilename,
|
(const char*(*)(Btree*)) memRbtreeGetFilename,
|
||||||
memBtreeCopyFile,
|
(int(*)(Btree*,Btree*)) memRbtreeCopyFile,
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
memBtreePageDump,
|
(int(*)(Btree*,int,int)) memRbtreePageDump,
|
||||||
memBtreePager
|
(struct Pager*(*)(Btree*)) memRbtreePager
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static BtCursorOps sqliteBtreeCursorOps = {
|
static BtCursorOps sqliteRbtreeCursorOps = {
|
||||||
memBtreeMoveto,
|
(int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto,
|
||||||
memBtreeDelete,
|
(int(*)(BtCursor*)) memRbtreeDelete,
|
||||||
memBtreeInsert,
|
(int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert,
|
||||||
memBtreeFirst,
|
(int(*)(BtCursor*,int*)) memRbtreeFirst,
|
||||||
memBtreeLast,
|
(int(*)(BtCursor*,int*)) memRbtreeLast,
|
||||||
memBtreeNext,
|
(int(*)(BtCursor*,int*)) memRbtreeNext,
|
||||||
memBtreePrevious,
|
(int(*)(BtCursor*,int*)) memRbtreePrevious,
|
||||||
memBtreeKeySize,
|
(int(*)(BtCursor*,int*)) memRbtreeKeySize,
|
||||||
memBtreeKey,
|
(int(*)(BtCursor*,int,int,char*)) memRbtreeKey,
|
||||||
memBtreeKeyCompare,
|
(int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare,
|
||||||
memBtreeDataSize,
|
(int(*)(BtCursor*,int*)) memRbtreeDataSize,
|
||||||
memBtreeData,
|
(int(*)(BtCursor*,int,int,char*)) memRbtreeData,
|
||||||
memBtreeCloseCursor,
|
(int(*)(BtCursor*)) memRbtreeCloseCursor,
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
memBtreeCursorDump,
|
(int(*)(BtCursor*,int*)) memRbtreeCursorDump,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
104
src/build.c
104
src/build.c
@@ -23,7 +23,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
*/
|
*/
|
||||||
void sqliteBeginParse(Parse *pParse, int explainFlag){
|
void sqliteBeginParse(Parse *pParse, int explainFlag){
|
||||||
sqlite *db = pParse->db;
|
sqlite *db = pParse->db;
|
||||||
|
int i;
|
||||||
pParse->explain = explainFlag;
|
pParse->explain = explainFlag;
|
||||||
if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){
|
if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){
|
||||||
int rc = sqliteInit(db, &pParse->zErrMsg);
|
int rc = sqliteInit(db, &pParse->zErrMsg);
|
||||||
@@ -44,6 +45,12 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){
|
|||||||
pParse->nErr++;
|
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->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
|
||||||
}
|
}
|
||||||
pParse->colNamesSet = 0;
|
pParse->colNamesSet = 0;
|
||||||
pParse->schemaVerified = 0;
|
|
||||||
}else if( pParse->useCallback==0 ){
|
}else if( pParse->useCallback==0 ){
|
||||||
pParse->rc = SQLITE_ERROR;
|
pParse->rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
@@ -263,7 +269,7 @@ void sqliteResetInternalSchema(sqlite *db, int iDb){
|
|||||||
sqliteDeleteTable(db, pTab);
|
sqliteDeleteTable(db, pTab);
|
||||||
}
|
}
|
||||||
sqliteHashClear(&temp1);
|
sqliteHashClear(&temp1);
|
||||||
db->aDb[i].flags &= ~SQLITE_Initialized;
|
DbClearProperty(db, i, DB_SchemaLoaded);
|
||||||
if( iDb>0 ) return;
|
if( iDb>0 ) return;
|
||||||
}
|
}
|
||||||
assert( iDb==0 );
|
assert( iDb==0 );
|
||||||
@@ -282,8 +288,9 @@ void sqliteResetInternalSchema(sqlite *db, int iDb){
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( j<i ){
|
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]));
|
memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
|
||||||
db->nDb = j;
|
db->nDb = j;
|
||||||
@@ -1137,7 +1144,7 @@ int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
|
|||||||
pSelTab->nCol = 0;
|
pSelTab->nCol = 0;
|
||||||
pSelTab->aCol = 0;
|
pSelTab->aCol = 0;
|
||||||
sqliteDeleteTable(0, pSelTab);
|
sqliteDeleteTable(0, pSelTab);
|
||||||
pParse->db->aDb[pTable->iDb].flags |= SQLITE_UnresetViews;
|
DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
|
||||||
}else{
|
}else{
|
||||||
pTable->nCol = 0;
|
pTable->nCol = 0;
|
||||||
nErr++;
|
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){
|
static void sqliteViewResetAll(sqlite *db, int idx){
|
||||||
HashElem *i;
|
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)){
|
for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
|
||||||
Table *pTab = sqliteHashData(i);
|
Table *pTab = sqliteHashData(i);
|
||||||
if( pTab->pSelect ){
|
if( pTab->pSelect ){
|
||||||
sqliteViewResetColumnNames(pTab);
|
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;
|
Index *pIdx;
|
||||||
Trigger *pTrigger;
|
Trigger *pTrigger;
|
||||||
sqliteBeginWriteOperation(pParse, 0, pTable->iDb);
|
sqliteBeginWriteOperation(pParse, 0, pTable->iDb);
|
||||||
sqliteOpenMasterTable(v, pTable->iDb);
|
|
||||||
/* Drop all triggers associated with the table being dropped */
|
/* Drop all triggers associated with the table being dropped */
|
||||||
pTrigger = pTable->pTrigger;
|
pTrigger = pTable->pTrigger;
|
||||||
while( pTrigger ){
|
while( pTrigger ){
|
||||||
SrcList *pNm;
|
SrcList *pNm;
|
||||||
assert( pTrigger->iDb==pTable->iDb );
|
assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 );
|
||||||
pNm = sqliteSrcListAppend(0, 0, 0);
|
pNm = sqliteSrcListAppend(0, 0, 0);
|
||||||
pNm->a[0].zName = sqliteStrDup(pTrigger->name);
|
pNm->a[0].zName = sqliteStrDup(pTrigger->name);
|
||||||
pNm->a[0].zDatabase = sqliteStrDup(db->aDb[pTable->iDb].zName);
|
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;
|
pTrigger = pTable->pTrigger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Drop all SQLITE_MASTER entries that refer to the table */
|
||||||
|
sqliteOpenMasterTable(v, pTable->iDb);
|
||||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
||||||
sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
|
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);
|
sqliteChangeCookie(db, v);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb);
|
sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb);
|
||||||
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
|
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);
|
sqliteEndWriteOperation(pParse);
|
||||||
@@ -2117,15 +2135,15 @@ void sqliteRollbackTransaction(Parse *pParse){
|
|||||||
** Generate VDBE code that will verify the schema cookie for all
|
** Generate VDBE code that will verify the schema cookie for all
|
||||||
** named database files.
|
** named database files.
|
||||||
*/
|
*/
|
||||||
void sqliteCodeVerifySchema(Parse *pParse){
|
void sqliteCodeVerifySchema(Parse *pParse, int iDb){
|
||||||
int i;
|
|
||||||
sqlite *db = pParse->db;
|
sqlite *db = pParse->db;
|
||||||
Vdbe *v = sqliteGetVdbe(pParse);
|
Vdbe *v = sqliteGetVdbe(pParse);
|
||||||
for(i=0; i<db->nDb; i++){
|
assert( iDb>=0 && iDb<db->nDb );
|
||||||
if( i==1 || db->aDb[i].pBt==0 ) continue;
|
assert( db->aDb[iDb].pBt!=0 );
|
||||||
sqliteVdbeAddOp(v, OP_VerifyCookie, i, db->aDb[i].schema_cookie);
|
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
|
** 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.
|
** necessary to undo a write and the checkpoint should not be set.
|
||||||
**
|
**
|
||||||
** The tempOnly flag indicates that only temporary tables will be changed
|
** Only database iDb and the temp database are made writable by this call.
|
||||||
** during this write operation. The primary database table is not
|
** If iDb==0, then the main and temp databases are made writable. If
|
||||||
** write-locked. Only the temporary database file gets a write lock.
|
** iDb==1 then only the temp database is made writable. If iDb>1 then the
|
||||||
** Other processes can continue to read or write the primary database file.
|
** 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;
|
Vdbe *v;
|
||||||
|
sqlite *db = pParse->db;
|
||||||
|
if( DbHasProperty(db, iDb, DB_Locked) ) return;
|
||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
if( v==0 ) return;
|
if( v==0 ) return;
|
||||||
if( pParse->trigStack ) return; /* if this is in a trigger */
|
if( !db->aDb[iDb].inTrans ){
|
||||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
sqliteVdbeAddOp(v, OP_Transaction, iDb, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Transaction, 1, 0);
|
DbSetProperty(db, iDb, DB_Locked);
|
||||||
if( !tempOnly ){
|
sqliteCodeVerifySchema(pParse, iDb);
|
||||||
int i;
|
if( iDb!=1 ){
|
||||||
sqlite *db = pParse->db;
|
sqliteBeginWriteOperation(pParse, setCheckpoint, 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}else if( setCheckpoint ){
|
}else if( setCheckpoint ){
|
||||||
sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
|
sqliteVdbeAddOp(v, OP_Checkpoint, iDb, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Checkpoint, 1, 0);
|
DbSetProperty(db, iDb, DB_Locked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code that concludes an operation that may have changed
|
** Generate code that concludes an operation that may have changed
|
||||||
** the database. This is a companion function to BeginWriteOperation().
|
** the database. If a statement transaction was started, then emit
|
||||||
** If a transaction was started, then commit it. If a checkpoint was
|
** an OP_Commit that will cause the changes to be committed to disk.
|
||||||
** started then commit that.
|
**
|
||||||
|
** 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){
|
void sqliteEndWriteOperation(Parse *pParse){
|
||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
|
sqlite *db = pParse->db;
|
||||||
if( pParse->trigStack ) return; /* if this is in a trigger */
|
if( pParse->trigStack ) return; /* if this is in a trigger */
|
||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
if( v==0 ) return;
|
if( v==0 ) return;
|
||||||
if( pParse->db->flags & SQLITE_InTrans ){
|
if( db->flags & SQLITE_InTrans ){
|
||||||
/* Do Nothing */
|
/* A BEGIN has executed. Do not commit until we see an explicit
|
||||||
|
** COMMIT statement. */
|
||||||
}else{
|
}else{
|
||||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0);
|
sqliteVdbeAddOp(v, OP_Commit, 0, 0);
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to implement the COPY command.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ void sqliteCopy(
|
|||||||
}
|
}
|
||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
if( v ){
|
if( v ){
|
||||||
sqliteBeginWriteOperation(pParse, 1, pTab->iDb==1);
|
sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
|
||||||
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
|
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
|
||||||
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
||||||
sqliteVdbeDequoteP3(v, addr);
|
sqliteVdbeDequoteP3(v, addr);
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle DELETE FROM statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -142,8 +142,7 @@ void sqliteDeleteFrom(
|
|||||||
if( v==0 ){
|
if( v==0 ){
|
||||||
goto delete_from_cleanup;
|
goto delete_from_cleanup;
|
||||||
}
|
}
|
||||||
sqliteBeginWriteOperation(pParse, row_triggers_exist,
|
sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
|
||||||
!row_triggers_exist && pTab->iDb==1);
|
|
||||||
|
|
||||||
/* If we are trying to delete from a view, construct that view into
|
/* If we are trying to delete from a view, construct that view into
|
||||||
** a temporary table.
|
** a temporary table.
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -159,8 +159,7 @@ void sqliteInsert(
|
|||||||
*/
|
*/
|
||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
if( v==0 ) goto insert_cleanup;
|
if( v==0 ) goto insert_cleanup;
|
||||||
sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist,
|
sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
|
||||||
!row_triggers_exist && pTab->iDb==1);
|
|
||||||
|
|
||||||
/* if there are row triggers, allocate a temp table for new.* references. */
|
/* if there are row triggers, allocate a temp table for new.* references. */
|
||||||
if( row_triggers_exist ){
|
if( row_triggers_exist ){
|
||||||
|
36
src/main.c
36
src/main.c
@@ -14,7 +14,7 @@
|
|||||||
** other files are for internal use by SQLite and should not be
|
** other files are for internal use by SQLite and should not be
|
||||||
** accessed by users of the library.
|
** 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 "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -29,6 +29,13 @@ typedef struct {
|
|||||||
char **pzErrMsg; /* Error message stored here */
|
char **pzErrMsg; /* Error message stored here */
|
||||||
} InitData;
|
} 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
|
** 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;
|
Parse sParse;
|
||||||
int nErr = 0;
|
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 );
|
assert( argc==5 );
|
||||||
|
if( argv[0]==0 ){
|
||||||
|
corruptSchema(pData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
switch( argv[0][0] ){
|
switch( argv[0][0] ){
|
||||||
case 'v':
|
case 'v':
|
||||||
case 'i':
|
case 'i':
|
||||||
case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
|
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] ){
|
if( argv[3] && argv[3][0] ){
|
||||||
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
||||||
** But because sParse.initFlag is set to 1, no VDBE code is generated
|
** 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);
|
sqliteResetInternalSchema(db, 0);
|
||||||
}
|
}
|
||||||
if( sParse.rc==SQLITE_OK ){
|
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{
|
}else{
|
||||||
sqliteResetInternalSchema(db, iDb);
|
sqliteResetInternalSchema(db, iDb);
|
||||||
}
|
}
|
||||||
@@ -368,8 +382,8 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
|
|||||||
assert( (db->flags & SQLITE_Initialized)==0 );
|
assert( (db->flags & SQLITE_Initialized)==0 );
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||||
if( db->aDb[i].flags & SQLITE_Initialized ) continue;
|
if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
|
||||||
if( i==1 ) continue; /* Skip the temp database - initialized with 0 */
|
assert( i!=1 ); /* Should have been initialized together with 0 */
|
||||||
rc = sqliteInitOne(db, i, pzErrMsg);
|
rc = sqliteInitOne(db, i, pzErrMsg);
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
@@ -961,14 +975,14 @@ int sqliteBtreeFactory(
|
|||||||
if (location == 1) {
|
if (location == 1) {
|
||||||
return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
|
return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
|
||||||
} else {
|
} else {
|
||||||
return sqliteRBtreeOpen(0, 0, 0, ppBtree);
|
return sqliteRbtreeOpen(0, 0, 0, ppBtree);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Always use in-core DB */
|
/* 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 ){
|
}else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
|
||||||
return sqliteRBtreeOpen(0, 0, 0, ppBtree);
|
return sqliteRbtreeOpen(0, 0, 0, ppBtree);
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** 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"
|
#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
|
** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
|
||||||
** or last entry in the main table.
|
** or last entry in the main table.
|
||||||
*/
|
*/
|
||||||
if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
|
sqliteCodeVerifySchema(pParse, pTab->iDb);
|
||||||
sqliteCodeVerifySchema(pParse);
|
|
||||||
}
|
|
||||||
base = p->pSrc->a[0].iCursor;
|
base = p->pSrc->a[0].iCursor;
|
||||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||||
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
|
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** 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 "config.h"
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
@@ -240,6 +240,38 @@ struct Db {
|
|||||||
u16 flags; /* Flags associated with this database */
|
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.
|
** 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_VdbeTrace 0x00000001 /* True to trace VDBE execution */
|
||||||
#define SQLITE_Initialized 0x00000002 /* True after initialization */
|
#define SQLITE_Initialized 0x00000002 /* True after initialization */
|
||||||
@@ -306,10 +342,7 @@ struct sqlite {
|
|||||||
/* the count using a callback. */
|
/* the count using a callback. */
|
||||||
#define SQLITE_NullCallback 0x00000080 /* Invoke the callback once if the */
|
#define SQLITE_NullCallback 0x00000080 /* Invoke the callback once if the */
|
||||||
/* result set is empty */
|
/* result set is empty */
|
||||||
/*#define SQLITE_ResultDetails 0x00000100 * (UNUSED -- flag free for reuse) */
|
#define SQLITE_ReportTypes 0x00000200 /* Include information on datatypes */
|
||||||
#define SQLITE_UnresetViews 0x00000200 /* True if one or more views have */
|
|
||||||
/* defined column names */
|
|
||||||
#define SQLITE_ReportTypes 0x00000400 /* Include information on datatypes */
|
|
||||||
/* in 4th argument of callback */
|
/* in 4th argument of callback */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -817,8 +850,6 @@ struct Parse {
|
|||||||
u8 nameClash; /* A permanent table name clashes with temp table name */
|
u8 nameClash; /* A permanent table name clashes with temp table name */
|
||||||
u8 useAgg; /* If true, extract field values from the aggregator
|
u8 useAgg; /* If true, extract field values from the aggregator
|
||||||
** while generating expressions. Normally false */
|
** 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 iDb; /* Index of database whose schema is being parsed */
|
||||||
u8 useCallback; /* True if callbacks should be used to report results */
|
u8 useCallback; /* True if callbacks should be used to report results */
|
||||||
int useDb; /* Restrict references to tables in this database */
|
int useDb; /* Restrict references to tables in this database */
|
||||||
@@ -1077,7 +1108,7 @@ Vdbe *sqliteGetVdbe(Parse*);
|
|||||||
int sqliteRandomByte(void);
|
int sqliteRandomByte(void);
|
||||||
int sqliteRandomInteger(void);
|
int sqliteRandomInteger(void);
|
||||||
void sqliteRollbackAll(sqlite*);
|
void sqliteRollbackAll(sqlite*);
|
||||||
void sqliteCodeVerifySchema(Parse*);
|
void sqliteCodeVerifySchema(Parse*, int);
|
||||||
void sqliteBeginTransaction(Parse*, int);
|
void sqliteBeginTransaction(Parse*, int);
|
||||||
void sqliteCommitTransaction(Parse*);
|
void sqliteCommitTransaction(Parse*);
|
||||||
void sqliteRollbackTransaction(Parse*);
|
void sqliteRollbackTransaction(Parse*);
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ void sqliteUpdate(
|
|||||||
*/
|
*/
|
||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
if( v==0 ) goto update_cleanup;
|
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
|
/* If we are trying to update a view, construct that view into
|
||||||
** a temporary table.
|
** a temporary table.
|
||||||
|
10
src/vdbe.c
10
src/vdbe.c
@@ -36,7 +36,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -3193,7 +3193,9 @@ case OP_Checkpoint: {
|
|||||||
case OP_Transaction: {
|
case OP_Transaction: {
|
||||||
int busy = 1;
|
int busy = 1;
|
||||||
int i = pOp->p1;
|
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);
|
rc = sqliteBtreeBeginTrans(db->aDb[i].pBt);
|
||||||
switch( rc ){
|
switch( rc ){
|
||||||
case SQLITE_BUSY: {
|
case SQLITE_BUSY: {
|
||||||
@@ -4547,7 +4549,7 @@ case OP_IdxGE: {
|
|||||||
** See also: Clear
|
** See also: Clear
|
||||||
*/
|
*/
|
||||||
case OP_Destroy: {
|
case OP_Destroy: {
|
||||||
sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
rc = sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4564,7 +4566,7 @@ case OP_Destroy: {
|
|||||||
** See also: Destroy
|
** See also: Destroy
|
||||||
*/
|
*/
|
||||||
case OP_Clear: {
|
case OP_Clear: {
|
||||||
sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
rc = sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This module contains C code that generates VDBE code used to process
|
** This module contains C code that generates VDBE code used to process
|
||||||
** the WHERE clause of SQL statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -680,10 +680,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||||
sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
|
sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
|
||||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||||
if( i==0 && !pParse->schemaVerified &&
|
sqliteCodeVerifySchema(pParse, pTab->iDb);
|
||||||
(pParse->db->flags & SQLITE_InTrans)==0 ){
|
|
||||||
sqliteCodeVerifySchema(pParse);
|
|
||||||
}
|
|
||||||
if( pWInfo->a[i].pIdx!=0 ){
|
if( pWInfo->a[i].pIdx!=0 ){
|
||||||
sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0);
|
sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0);
|
||||||
sqliteVdbeAddOp(v, OP_OpenRead,
|
sqliteVdbeAddOp(v, OP_OpenRead,
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
# focus of this script is testing the ATTACH and DETACH commands
|
# focus of this script is testing the ATTACH and DETACH commands
|
||||||
# and related functionality.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
@@ -237,6 +237,60 @@ do_test attach-2.6 {
|
|||||||
SELECT * FROM main.tx;
|
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} {
|
for {set i 2} {$i<=15} {incr i} {
|
||||||
catch {db$i close}
|
catch {db$i close}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#
|
#
|
||||||
# This file implements tests for temporary tables and indices.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -165,7 +165,7 @@ do_test temptable-4.3 {
|
|||||||
catchsql {
|
catchsql {
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
} db2
|
} db2
|
||||||
} {1 {database schema has changed}}
|
} {0 {10 20}}
|
||||||
do_test temptable-4.4.1 {
|
do_test temptable-4.4.1 {
|
||||||
catchsql {
|
catchsql {
|
||||||
SELECT * FROM temp.t2;
|
SELECT * FROM temp.t2;
|
||||||
@@ -175,8 +175,23 @@ do_test temptable-4.4.2 {
|
|||||||
catchsql {
|
catchsql {
|
||||||
SELECT * FROM main.t2;
|
SELECT * FROM main.t2;
|
||||||
} db2
|
} db2
|
||||||
} {0 {9 8 7}}
|
} {1 {no such table: main.t2}}
|
||||||
do_test temptable-4.4.3 {
|
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
|
# TEMP takes precedence over MAIN
|
||||||
catchsql {
|
catchsql {
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
@@ -217,11 +232,21 @@ do_test temptable-4.9 {
|
|||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
}
|
}
|
||||||
} {3 4}
|
} {3 4}
|
||||||
do_test temptable-4.10 {
|
do_test temptable-4.10.1 {
|
||||||
catchsql {
|
catchsql {
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
} db2
|
} 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}}
|
} {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 {
|
do_test temptable-4.11 {
|
||||||
execsql {
|
execsql {
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
|
@@ -52,12 +52,16 @@ source $testdir/tester.tcl
|
|||||||
|
|
||||||
# 1.
|
# 1.
|
||||||
set ii 0
|
set ii 0
|
||||||
foreach tbl_defn [ list \
|
foreach tbl_defn {
|
||||||
{CREATE TABLE tbl (a, b);} \
|
{CREATE TEMP TABLE tbl (a, b);}
|
||||||
{CREATE TEMP TABLE tbl (a, b);} \
|
{CREATE TABLE tbl (a, b);}
|
||||||
{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \
|
{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);}
|
||||||
{CREATE TABLE tbl (a, b PRIMARY KEY);} \
|
{CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b);}
|
||||||
{CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(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
|
incr ii
|
||||||
catchsql { DROP INDEX tbl_idx; }
|
catchsql { DROP INDEX tbl_idx; }
|
||||||
catchsql {
|
catchsql {
|
||||||
@@ -102,8 +106,8 @@ foreach tbl_defn [ list \
|
|||||||
END;
|
END;
|
||||||
}
|
}
|
||||||
|
|
||||||
do_test trigger2-1.1.$ii {
|
do_test trigger2-1.$ii.1 {
|
||||||
execsql {
|
execsql {
|
||||||
UPDATE tbl SET a = a * 10, b = b * 10;
|
UPDATE tbl SET a = a * 10, b = b * 10;
|
||||||
SELECT * FROM rlog ORDER BY idx;
|
SELECT * FROM rlog ORDER BY idx;
|
||||||
SELECT * FROM clog ORDER BY idx;
|
SELECT * FROM clog ORDER BY idx;
|
||||||
@@ -113,7 +117,7 @@ foreach tbl_defn [ list \
|
|||||||
3 3 4 13 24 30 40 \
|
3 3 4 13 24 30 40 \
|
||||||
4 3 4 40 60 30 40 \
|
4 3 4 40 60 30 40 \
|
||||||
1 1 2 13 24 10 20 ]
|
1 1 2 13 24 10 20 ]
|
||||||
|
|
||||||
execsql {
|
execsql {
|
||||||
DELETE FROM rlog;
|
DELETE FROM rlog;
|
||||||
DELETE FROM tbl;
|
DELETE FROM tbl;
|
||||||
@@ -135,7 +139,7 @@ foreach tbl_defn [ list \
|
|||||||
0, 0);
|
0, 0);
|
||||||
END;
|
END;
|
||||||
}
|
}
|
||||||
do_test trigger2-1.2.$ii {
|
do_test trigger2-1.$ii.2 {
|
||||||
execsql {
|
execsql {
|
||||||
DELETE FROM tbl;
|
DELETE FROM tbl;
|
||||||
SELECT * FROM rlog;
|
SELECT * FROM rlog;
|
||||||
@@ -163,7 +167,7 @@ foreach tbl_defn [ list \
|
|||||||
new.a, new.b);
|
new.a, new.b);
|
||||||
END;
|
END;
|
||||||
}
|
}
|
||||||
do_test trigger2-1.3.$ii {
|
do_test trigger2-1.$ii.3 {
|
||||||
execsql {
|
execsql {
|
||||||
|
|
||||||
CREATE TABLE other_tbl(a, b);
|
CREATE TABLE other_tbl(a, b);
|
||||||
@@ -177,6 +181,12 @@ foreach tbl_defn [ list \
|
|||||||
}
|
}
|
||||||
} [list 1 0 0 0 0 5 6 \
|
} [list 1 0 0 0 0 5 6 \
|
||||||
2 0 0 5 6 5 6 ]
|
2 0 0 5 6 5 6 ]
|
||||||
|
|
||||||
|
do_test trigger2-1.$ii.4 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
}
|
||||||
|
} {ok ok}
|
||||||
}
|
}
|
||||||
catchsql {
|
catchsql {
|
||||||
DROP TABLE rlog;
|
DROP TABLE rlog;
|
||||||
@@ -187,16 +197,15 @@ catchsql {
|
|||||||
|
|
||||||
# 2.
|
# 2.
|
||||||
set ii 0
|
set ii 0
|
||||||
foreach tr_program [ list \
|
foreach tr_program {
|
||||||
{UPDATE tbl SET b = old.b;} \
|
{UPDATE tbl SET b = old.b;}
|
||||||
{INSERT INTO log VALUES(new.c, 2, 3);} \
|
{INSERT INTO log VALUES(new.c, 2, 3);}
|
||||||
{DELETE FROM log WHERE a = 1;} \
|
{DELETE FROM log WHERE a = 1;}
|
||||||
{INSERT INTO tbl VALUES(500, new.b * 10, 700);
|
{INSERT INTO tbl VALUES(500, new.b * 10, 700);
|
||||||
UPDATE tbl SET c = old.c;
|
UPDATE tbl SET c = old.c;
|
||||||
DELETE FROM log;} \
|
DELETE FROM log;}
|
||||||
{INSERT INTO log select * from tbl;}
|
{INSERT INTO log select * from tbl;}
|
||||||
] \
|
} {
|
||||||
{
|
|
||||||
foreach test_varset [ list \
|
foreach test_varset [ list \
|
||||||
{
|
{
|
||||||
set statement {UPDATE tbl SET c = 10 WHERE a = 1;}
|
set statement {UPDATE tbl SET c = 10 WHERE a = 1;}
|
||||||
@@ -262,22 +271,25 @@ foreach tr_program [ list \
|
|||||||
DROP TABLE tbl;
|
DROP TABLE tbl;
|
||||||
DROP TABLE log;
|
DROP TABLE log;
|
||||||
}
|
}
|
||||||
|
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TABLE tbl(a PRIMARY KEY, b, c);
|
CREATE TABLE tbl(a PRIMARY KEY, b, c);
|
||||||
CREATE TABLE log(a, b, c);
|
CREATE TABLE log(a, b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
set query {SELECT * FROM tbl; SELECT * FROM log;}
|
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:
|
# Check execution of BEFORE programs:
|
||||||
|
|
||||||
set before_data [ execsql "$prep $tr_program_cooked $statement $query" ]
|
set before_data [ execsql "$prep $tr_program_cooked $statement $query" ]
|
||||||
|
|
||||||
execsql "DELETE FROM tbl; DELETE FROM log; $prep";
|
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 "DROP TRIGGER the_trigger;"
|
||||||
execsql "DELETE FROM tbl; DELETE FROM log;"
|
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" ]
|
set after_data [ execsql "$prep $statement $tr_program_cooked $query" ]
|
||||||
|
|
||||||
execsql "DELETE FROM tbl; DELETE FROM log; $prep";
|
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;"
|
execsql "DROP TRIGGER the_trigger;"
|
||||||
|
|
||||||
|
do_test trigger2-2.$ii-integrity {
|
||||||
|
execsql {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
}
|
||||||
|
} {ok ok}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catchsql {
|
catchsql {
|
||||||
@@ -361,6 +380,11 @@ execsql {
|
|||||||
DROP TABLE tbl;
|
DROP TABLE tbl;
|
||||||
DROP TABLE log;
|
DROP TABLE log;
|
||||||
}
|
}
|
||||||
|
do_test trigger2-3.3 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
}
|
||||||
|
} {ok ok}
|
||||||
|
|
||||||
# Simple cascaded trigger
|
# Simple cascaded trigger
|
||||||
execsql {
|
execsql {
|
||||||
@@ -585,9 +609,8 @@ do_test trigger2-7.1 {
|
|||||||
0, 0, 0, 0, new.a, new.b, new.c, new.d);
|
0, 0, 0, 0, new.a, new.b, new.c, new.d);
|
||||||
END;
|
END;
|
||||||
}
|
}
|
||||||
} {}
|
} {};
|
||||||
|
|
||||||
#explain {delete from abcd where a=1;}
|
|
||||||
do_test trigger2-7.2 {
|
do_test trigger2-7.2 {
|
||||||
execsql {
|
execsql {
|
||||||
UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1;
|
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}
|
} {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
|
finish_test
|
||||||
|
Reference in New Issue
Block a user