1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Fixes to the locking and rollback behavior. (CVS 261)

FossilOrigin-Name: 337b3d3b2a903328d9744c111979909a284b8348
This commit is contained in:
drh
2001-09-23 02:35:53 +00:00
parent beae319476
commit ecdc7530dd
18 changed files with 504 additions and 339 deletions

View File

@ -1,5 +1,5 @@
C Put\sin\sa\sgeneric\shash\stable\ssystem\sin\splace\sof\sthe\svarious\sad-hoc\nhash\stable\sscattered\severywhere.\s\sExcept,\sthe\spage\shash\stable\sin\nthe\spager\sis\sunchanged.\s(CVS\s260) C Fixes\sto\sthe\slocking\sand\srollback\sbehavior.\s(CVS\s261)
D 2001-09-22T18:12:09 D 2001-09-23T02:35:53
F Makefile.in 18eea9a3486939fced70aa95b691be766c2c995d F Makefile.in 18eea9a3486939fced70aa95b691be766c2c995d
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
F VERSION 6942aa44940d2972bd72f671a631060106e77f7e F VERSION 6942aa44940d2972bd72f671a631060106e77f7e
@ -8,14 +8,14 @@ F configure.in 0000c0d62beb47cae1d2d81a197c7fe6efd56a45
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 39da79b5a656870aa3ab72d40374fb38bd1bd12d F src/btree.c da9b60a0b94daac0b7a231f42cb79961bf06531d
F src/btree.h fcb08daab59fd81023204ac71955233e218443c2 F src/btree.h 5e5531869e53623aad5b32c22249c5743039251e
F src/build.c 8af632a8024fa1132e4f40be48915083405614df F src/build.c 8dbdcce4b9b9cb15b0d1a7a535af622cccba6f6b
F src/delete.c ca7ca9bf8b613730821c4a755030d1a020b5e067 F src/delete.c 81002d889aae874decf507627207c5d1b3599dc2
F src/expr.c 343a515a4abaf60e9e26c7412aa8c43fd3eae97d F src/expr.c 343a515a4abaf60e9e26c7412aa8c43fd3eae97d
F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1 F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d
F src/insert.c b34860ea58525754f18bde652f74161295ca2455 F src/insert.c 061e531d19869e26ba9202c6d069385237b4c102
F src/main.c 49af06b7327c8b23b9331ce80b7e4bc9536ed2e1 F src/main.c 49af06b7327c8b23b9331ce80b7e4bc9536ed2e1
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c faf9f484f3261c7650021cae79294338491f2cfb F src/os.c faf9f484f3261c7650021cae79294338491f2cfb
@ -28,22 +28,22 @@ F src/random.c b6a57e85288470b013ad584a8813e893b60e62fe
F src/select.c 7d90a6464906419fde96c0707a4cf4f3280db318 F src/select.c 7d90a6464906419fde96c0707a4cf4f3280db318
F src/shell.c 8e573138074e0b9526fca59b3eac22bdf18ecc03 F src/shell.c 8e573138074e0b9526fca59b3eac22bdf18ecc03
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 5d78c86bd9a9b8bbba65f860fbaf71c1882d6030 F src/sqlite.h.in dbe7a1b1e1ab9bfce1a6983cfa6f53c5c2499305
F src/sqliteInt.h ae90beff6acc510bf98c80908d86b0830933e507 F src/sqliteInt.h ae90beff6acc510bf98c80908d86b0830933e507
F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
F src/tclsqlite.c 04a35d04f06046acc3944121dc6c36717f7f36d5 F src/tclsqlite.c 04a35d04f06046acc3944121dc6c36717f7f36d5
F src/test1.c 3892caa5372789a6d17329dd595724e1f06cb6de F src/test1.c 3892caa5372789a6d17329dd595724e1f06cb6de
F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e
F src/test3.c f46bad555db7a6a25be332a96ac99e4d68a1b0c5 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
F src/tokenize.c 2adf0568edf41b3d3c2fcb541ac49bd6e662da0c F src/tokenize.c 2ab07b85fde38d8fa2b4e73417b93e94f9cf8f5f
F src/update.c a1952ad5d53379fa2b2d12efae5993ddb85a1ddb F src/update.c 8de22957017e17c5e751ba71c4ea76c60f93aa2f
F src/util.c 2a3491fd761b64cca849b07095076f482d119f9c F src/util.c 9c888445c1fd7896dab38fa62efc532f2364010a
F src/vdbe.c 1cf36bea586e659995545ac8ad9534e794f4296f F src/vdbe.c 7132265f449b4bb159e77cc548e515b7b8b9398a
F src/vdbe.h 900b59b46afdfb9c048a2a31a4478f380ab8504e F src/vdbe.h dc1d441494ba560a1ff464e1c56beb8ca03844fc
F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87 F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87
F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
F test/btree.test bb1d1caf834aa22a208ce6cc7d8d8bd0e106cd59 F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
F test/btree2.test ddc13a8de33461391da8403ded3e6b091f08dab4 F test/btree2.test 20ce47ab804f15b6563736528bdd38aabe5193dc
F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e
F test/delete.test 5ebb114582457428b3e0e30b21b477fedcb85609 F test/delete.test 5ebb114582457428b3e0e30b21b477fedcb85609
F test/expr.test b3475005ea19d53bf8c4573fb6e4a4498be5b434 F test/expr.test b3475005ea19d53bf8c4573fb6e4a4498be5b434
@ -52,7 +52,7 @@ F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
F test/index.test e43e952b482c2afe938f1f31b71e2b33d43893a9 F test/index.test e43e952b482c2afe938f1f31b71e2b33d43893a9
F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8 F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
F test/lock.test 5b4d969ab92c88f8dc10d1b870a2e5fe51ee7f5f F test/lock.test 3cef6b302ae0826755ccb226fe444be42fe5d391
F test/main.test 085ece17913a487caacbc0a392638c958c83a75d F test/main.test 085ece17913a487caacbc0a392638c958c83a75d
F test/malloc.test f1400a8d002eb96f1ca0a34abe56d2ab3e324740 F test/malloc.test f1400a8d002eb96f1ca0a34abe56d2ab3e324740
F test/misc1.test 50a5ca3481fc1f3cd6b978bcd6ed04c06f26a1e6 F test/misc1.test 50a5ca3481fc1f3cd6b978bcd6ed04c06f26a1e6
@ -72,7 +72,7 @@ F test/table.test 52fdca1632580fb638c7b7dd14f4d37ecc09f994
F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37 F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37
F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a
F test/tester.tcl 957cd92fe8645b829da175d94b7ddb7ea68dac39 F test/tester.tcl 957cd92fe8645b829da175d94b7ddb7ea68dac39
F test/trans.test 997c8dcc15c479bc2cedc42220cf2d265e63d2a8 F test/trans.test 010dfe3cc7dea8bfd3b389dcadc6789f35d6df36
F test/update.test b320ea22899e80b32b4d21c54591eb7a6ba4d6bd F test/update.test b320ea22899e80b32b4d21c54591eb7a6ba4d6bd
F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91 F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91
@ -97,7 +97,7 @@ F www/opcode.tcl 60222aeb57a7855b2582c374b8753cb5bb53c4ab
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
P 13afb22409b3b58d4c4b97a9fac22c96153d77c0 P 9114420dd01d92cc8890046500a8806a297a4e65
R 453b3eb283d27c63c0996482bd747b07 R befae190f48e6ee61c8ee654bf44939d
U drh U drh
Z 39fe4015001e5b10c0870078a2610b25 Z 7d651cd9fc4593916e1eb971a253a3a2

View File

@ -1 +1 @@
9114420dd01d92cc8890046500a8806a297a4e65 337b3d3b2a903328d9744c111979909a284b8348

View File

@ -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.29 2001/09/16 00:13:26 drh Exp $ ** $Id: btree.c,v 1.30 2001/09/23 02:35:53 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
@ -312,6 +312,7 @@ struct Btree {
BtCursor *pCursor; /* A list of all open cursors */ BtCursor *pCursor; /* A list of all open cursors */
PageOne *page1; /* First page of the database */ PageOne *page1; /* First page of the database */
int inTrans; /* True if a transaction is in progress */ int inTrans; /* True if a transaction is in progress */
Hash locks; /* Key: root page number. Data: lock count */
}; };
typedef Btree Bt; typedef Btree Bt;
@ -326,6 +327,7 @@ struct BtCursor {
Pgno pgnoRoot; /* The root page of this tree */ Pgno pgnoRoot; /* The root page of this tree */
MemPage *pPage; /* Page that contains the entry */ MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->apCell[] */ int idx; /* Index of the entry in pPage->apCell[] */
u8 wrFlag; /* True if writable */
u8 bSkipNext; /* sqliteBtreeNext() is no-op if true */ u8 bSkipNext; /* sqliteBtreeNext() is no-op if true */
u8 iMatch; /* compare result from last sqliteBtreeMoveto() */ u8 iMatch; /* compare result from last sqliteBtreeMoveto() */
}; };
@ -619,6 +621,7 @@ int sqliteBtreeOpen(
sqlitepager_set_destructor(pBt->pPager, pageDestructor); sqlitepager_set_destructor(pBt->pPager, pageDestructor);
pBt->pCursor = 0; pBt->pCursor = 0;
pBt->page1 = 0; pBt->page1 = 0;
sqliteHashInit(&pBt->locks, SQLITE_HASH_INT, 0);
*ppBtree = pBt; *ppBtree = pBt;
return SQLITE_OK; return SQLITE_OK;
} }
@ -631,6 +634,7 @@ int sqliteBtreeClose(Btree *pBt){
sqliteBtreeCloseCursor(pBt->pCursor); sqliteBtreeCloseCursor(pBt->pCursor);
} }
sqlitepager_close(pBt->pPager); sqlitepager_close(pBt->pPager);
sqliteHashClear(&pBt->locks);
sqliteFree(pBt); sqliteFree(pBt);
return SQLITE_OK; return SQLITE_OK;
} }
@ -771,17 +775,25 @@ int sqliteBtreeCommit(Btree *pBt){
} }
/* /*
** Rollback the transaction in progress. All cursors must be ** Rollback the transaction in progress. All cursors will be
** closed before this routine is called. ** invalided by this operation. Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
** **
** This will release the write lock on the database file. If there ** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock. ** are no active cursors, it also releases the read lock.
*/ */
int sqliteBtreeRollback(Btree *pBt){ int sqliteBtreeRollback(Btree *pBt){
int rc; int rc;
if( pBt->pCursor!=0 ) return SQLITE_ERROR; BtCursor *pCur;
if( pBt->inTrans==0 ) return SQLITE_OK; if( pBt->inTrans==0 ) return SQLITE_OK;
pBt->inTrans = 0; pBt->inTrans = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( pCur->pPage ){
sqlitepager_unref(pCur->pPage);
pCur->pPage = 0;
}
}
rc = sqlitepager_rollback(pBt->pPager); rc = sqlitepager_rollback(pBt->pPager);
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
return rc; return rc;
@ -792,9 +804,11 @@ int sqliteBtreeRollback(Btree *pBt){
** iTable. The act of acquiring a cursor gets a read lock on ** iTable. The act of acquiring a cursor gets a read lock on
** the database file. ** the database file.
*/ */
int sqliteBtreeCursor(Btree *pBt, int iTable, BtCursor **ppCur){ int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
int rc; int rc;
BtCursor *pCur; BtCursor *pCur;
int nLock;
if( pBt->page1==0 ){ if( pBt->page1==0 ){
rc = lockBtree(pBt); rc = lockBtree(pBt);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -816,7 +830,15 @@ int sqliteBtreeCursor(Btree *pBt, int iTable, BtCursor **ppCur){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto create_cursor_exception; goto create_cursor_exception;
} }
nLock = (int)sqliteHashFind(&pBt->locks, 0, iTable);
if( nLock<0 || (nLock>0 && wrFlag) ){
rc = SQLITE_LOCKED;
goto create_cursor_exception;
}
nLock = wrFlag ? -1 : nLock+1;
sqliteHashInsert(&pBt->locks, 0, iTable, (void*)nLock);
pCur->pBt = pBt; pCur->pBt = pBt;
pCur->wrFlag = wrFlag;
pCur->idx = 0; pCur->idx = 0;
pCur->pNext = pBt->pCursor; pCur->pNext = pBt->pCursor;
if( pCur->pNext ){ if( pCur->pNext ){
@ -842,6 +864,7 @@ create_cursor_exception:
** when the last cursor is closed. ** when the last cursor is closed.
*/ */
int sqliteBtreeCloseCursor(BtCursor *pCur){ int sqliteBtreeCloseCursor(BtCursor *pCur){
int nLock;
Btree *pBt = pCur->pBt; Btree *pBt = pCur->pBt;
if( pCur->pPrev ){ if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext; pCur->pPrev->pNext = pCur->pNext;
@ -851,8 +874,14 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){
if( pCur->pNext ){ if( pCur->pNext ){
pCur->pNext->pPrev = pCur->pPrev; pCur->pNext->pPrev = pCur->pPrev;
} }
sqlitepager_unref(pCur->pPage); if( pCur->pPage ){
sqlitepager_unref(pCur->pPage);
}
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
nLock = (int)sqliteHashFind(&pBt->locks, 0, pCur->pgnoRoot);
assert( nLock!=0 );
nLock = nLock<0 ? 0 : nLock-1;
sqliteHashInsert(&pBt->locks, 0, pCur->pgnoRoot, (void*)nLock);
sqliteFree(pCur); sqliteFree(pCur);
return SQLITE_OK; return SQLITE_OK;
} }
@ -865,7 +894,9 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
memcpy(pTempCur, pCur, sizeof(*pCur)); memcpy(pTempCur, pCur, sizeof(*pCur));
pTempCur->pNext = 0; pTempCur->pNext = 0;
pTempCur->pPrev = 0; pTempCur->pPrev = 0;
sqlitepager_ref(pTempCur->pPage); if( pTempCur->pPage ){
sqlitepager_ref(pTempCur->pPage);
}
} }
/* /*
@ -873,7 +904,9 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
** function above. ** function above.
*/ */
static void releaseTempCursor(BtCursor *pCur){ static void releaseTempCursor(BtCursor *pCur){
sqlitepager_unref(pCur->pPage); if( pCur->pPage ){
sqlitepager_unref(pCur->pPage);
}
} }
/* /*
@ -888,8 +921,7 @@ int sqliteBtreeKeySize(BtCursor *pCur, int *pSize){
MemPage *pPage; MemPage *pPage;
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); if( pPage==0 || pCur->idx >= pPage->nCell ){
if( pCur->idx >= pPage->nCell ){
*pSize = 0; *pSize = 0;
}else{ }else{
pCell = pPage->apCell[pCur->idx]; pCell = pPage->apCell[pCur->idx];
@ -971,7 +1003,7 @@ int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
if( offset<0 ) return 0; if( offset<0 ) return 0;
if( amt==0 ) return 0; if( amt==0 ) return 0;
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); if( pPage==0 ) return 0;
if( pCur->idx >= pPage->nCell ){ if( pCur->idx >= pPage->nCell ){
return 0; return 0;
} }
@ -998,8 +1030,7 @@ int sqliteBtreeDataSize(BtCursor *pCur, int *pSize){
MemPage *pPage; MemPage *pPage;
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); if( pPage==0 || pCur->idx >= pPage->nCell ){
if( pCur->idx >= pPage->nCell ){
*pSize = 0; *pSize = 0;
}else{ }else{
pCell = pPage->apCell[pCur->idx]; pCell = pPage->apCell[pCur->idx];
@ -1024,8 +1055,7 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
if( offset<0 ) return 0; if( offset<0 ) return 0;
if( amt==0 ) return 0; if( amt==0 ) return 0;
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); if( pPage==0 || pCur->idx >= pPage->nCell ){
if( pCur->idx >= pPage->nCell ){
return 0; return 0;
} }
pCell = pPage->apCell[pCur->idx]; pCell = pPage->apCell[pCur->idx];
@ -1190,6 +1220,7 @@ static int moveToLeftmost(BtCursor *pCur){
*/ */
int sqliteBtreeFirst(BtCursor *pCur, int *pRes){ int sqliteBtreeFirst(BtCursor *pCur, int *pRes){
int rc; int rc;
if( pCur->pPage==0 ) return SQLITE_ABORT;
rc = moveToRoot(pCur); rc = moveToRoot(pCur);
if( rc ) return rc; if( rc ) return rc;
if( pCur->pPage->nCell==0 ){ if( pCur->pPage->nCell==0 ){
@ -1225,6 +1256,7 @@ int sqliteBtreeFirst(BtCursor *pCur, int *pRes){
*/ */
int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
int rc; int rc;
if( pCur->pPage==0 ) return SQLITE_ABORT;
pCur->bSkipNext = 0; pCur->bSkipNext = 0;
rc = moveToRoot(pCur); rc = moveToRoot(pCur);
if( rc ) return rc; if( rc ) return rc;
@ -1275,6 +1307,9 @@ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
*/ */
int sqliteBtreeNext(BtCursor *pCur, int *pRes){ int sqliteBtreeNext(BtCursor *pCur, int *pRes){
int rc; int rc;
if( pCur->pPage==0 ){
return SQLITE_ABORT;
}
if( pCur->bSkipNext ){ if( pCur->bSkipNext ){
pCur->bSkipNext = 0; pCur->bSkipNext = 0;
if( pRes ) *pRes = 0; if( pRes ) *pRes = 0;
@ -2045,9 +2080,15 @@ int sqliteBtreeInsert(
MemPage *pPage; MemPage *pPage;
Btree *pBt = pCur->pBt; Btree *pBt = pCur->pBt;
if( pCur->pPage==0 ){
return SQLITE_ABORT; /* A rollback destroyed this cursor */
}
if( !pCur->pBt->inTrans || nKey+nData==0 ){ if( !pCur->pBt->inTrans || nKey+nData==0 ){
return SQLITE_ERROR; /* Must start a transaction first */ return SQLITE_ERROR; /* Must start a transaction first */
} }
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */
}
rc = sqliteBtreeMoveto(pCur, pKey, nKey, &loc); rc = sqliteBtreeMoveto(pCur, pKey, nKey, &loc);
if( rc ) return rc; if( rc ) return rc;
pPage = pCur->pPage; pPage = pCur->pPage;
@ -2090,12 +2131,18 @@ int sqliteBtreeDelete(BtCursor *pCur){
int rc; int rc;
Pgno pgnoChild; Pgno pgnoChild;
if( pCur->pPage==0 ){
return SQLITE_ABORT; /* A rollback destroyed this cursor */
}
if( !pCur->pBt->inTrans ){ if( !pCur->pBt->inTrans ){
return SQLITE_ERROR; /* Must start a transaction first */ return SQLITE_ERROR; /* Must start a transaction first */
} }
if( pCur->idx >= pPage->nCell ){ if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR; /* The cursor is not pointing to anything */ return SQLITE_ERROR; /* The cursor is not pointing to anything */
} }
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */
}
rc = sqlitepager_write(pPage); rc = sqlitepager_write(pPage);
if( rc ) return rc; if( rc ) return rc;
pCell = pPage->apCell[pCur->idx]; pCell = pPage->apCell[pCur->idx];
@ -2207,9 +2254,14 @@ static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){
*/ */
int sqliteBtreeClearTable(Btree *pBt, int iTable){ int sqliteBtreeClearTable(Btree *pBt, int iTable){
int rc; int rc;
int nLock;
if( !pBt->inTrans ){ if( !pBt->inTrans ){
return SQLITE_ERROR; /* Must start a transaction first */ return SQLITE_ERROR; /* Must start a transaction first */
} }
nLock = (int)sqliteHashFind(&pBt->locks, 0, iTable);
if( nLock ){
return SQLITE_LOCKED;
}
rc = clearDatabasePage(pBt, (Pgno)iTable, 0); rc = clearDatabasePage(pBt, (Pgno)iTable, 0);
if( rc ){ if( rc ){
sqliteBtreeRollback(pBt); sqliteBtreeRollback(pBt);

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the sqlite B-Tree file ** This header file defines the interface that the sqlite B-Tree file
** subsystem. ** subsystem.
** **
** @(#) $Id: btree.h,v 1.14 2001/09/16 00:13:26 drh Exp $ ** @(#) $Id: btree.h,v 1.15 2001/09/23 02:35:53 drh Exp $
*/ */
#ifndef _BTREE_H_ #ifndef _BTREE_H_
#define _BTREE_H_ #define _BTREE_H_
@ -32,7 +32,7 @@ int sqliteBtreeCreateTable(Btree*, int*);
int sqliteBtreeDropTable(Btree*, int); int sqliteBtreeDropTable(Btree*, int);
int sqliteBtreeClearTable(Btree*, int); int sqliteBtreeClearTable(Btree*, int);
int sqliteBtreeCursor(Btree*, int iTable, BtCursor **ppCur); int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes); int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes);
int sqliteBtreeDelete(BtCursor*); int sqliteBtreeDelete(BtCursor*);
int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey, int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey,

View File

@ -25,7 +25,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.38 2001/09/22 18:12:10 drh Exp $ ** $Id: build.c,v 1.39 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -54,6 +54,7 @@ void sqliteExec(Parse *pParse){
rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
&pParse->zErrMsg, db->pBusyArg, &pParse->zErrMsg, db->pBusyArg,
db->xBusyCallback); db->xBusyCallback);
if( rc ) pParse->nErr++;
} }
sqliteVdbeDelete(pParse->pVdbe); sqliteVdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0; pParse->pVdbe = 0;
@ -372,6 +373,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
if( v ){ if( v ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
} }
} }
@ -502,7 +504,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) return; if( v==0 ) return;
n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1; n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
sqliteVdbeAddOp(v, OP_Open, 0, 2, MASTER_NAME, 0); sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0); sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
@ -583,7 +585,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v ){ if( v ){
static VdbeOp dropTable[] = { static VdbeOp dropTable[] = {
{ OP_Open, 0, 2, MASTER_NAME}, { OP_OpenWrite, 0, 2, MASTER_NAME},
{ OP_Rewind, 0, 0, 0}, { OP_Rewind, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */ { OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(9), 0}, /* 3 */ { OP_Next, 0, ADDR(9), 0}, /* 3 */
@ -600,6 +602,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
@ -779,14 +782,14 @@ void sqliteCreateIndex(
*/ */
else if( pParse->initFlag==0 && pTable!=0 ){ else if( pParse->initFlag==0 && pTable!=0 ){
static VdbeOp addTable[] = { static VdbeOp addTable[] = {
{ OP_Open, 2, 2, MASTER_NAME}, { OP_OpenWrite, 2, 2, MASTER_NAME},
{ OP_NewRecno, 2, 0, 0}, { OP_NewRecno, 2, 0, 0},
{ OP_String, 0, 0, "index"}, { OP_String, 0, 0, "index"},
{ OP_String, 0, 0, 0}, /* 3 */ { OP_String, 0, 0, 0}, /* 3 */
{ OP_String, 0, 0, 0}, /* 4 */ { OP_String, 0, 0, 0}, /* 4 */
{ OP_CreateIndex, 1, 0, 0}, { OP_CreateIndex, 1, 0, 0},
{ OP_Dup, 0, 0, 0}, { OP_Dup, 0, 0, 0},
{ OP_Open, 1, 0, 0}, /* 7 */ { OP_OpenWrite, 1, 0, 0}, /* 7 */
{ OP_Null, 0, 0, 0}, { OP_Null, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 9 */ { OP_String, 0, 0, 0}, /* 9 */
{ OP_MakeRecord, 6, 0, 0}, { OP_MakeRecord, 6, 0, 0},
@ -804,6 +807,7 @@ void sqliteCreateIndex(
if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){ if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
if( pStart && pEnd ){ if( pStart && pEnd ){
int base; int base;
@ -875,7 +879,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v ){ if( v ){
static VdbeOp dropIndex[] = { static VdbeOp dropIndex[] = {
{ OP_Open, 0, 2, MASTER_NAME}, { OP_OpenWrite, 0, 2, MASTER_NAME},
{ OP_Rewind, 0, 0, 0}, { OP_Rewind, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */ { OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(8), 0}, /* 3 */ { OP_Next, 0, ADDR(8), 0}, /* 3 */
@ -892,6 +896,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0); sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
@ -1065,13 +1070,14 @@ void sqliteCopy(
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0); addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr); sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0); sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
sqliteVdbeAddOp(v, OP_Open, i, pIdx->tnum, pIdx->zName, 0); sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum, pIdx->zName, 0);
} }
end = sqliteVdbeMakeLabel(v); end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0); addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
@ -1138,6 +1144,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
if( zName ){ if( zName ){
sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0); sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0);
@ -1176,6 +1183,7 @@ void sqliteBeginTransaction(Parse *pParse){
if( v ){ if( v ){
sqliteVdbeAddOp(v, OP_Transaction, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
db->flags |= SQLITE_InTrans; db->flags |= SQLITE_InTrans;
} }

View File

@ -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.14 2001/09/16 00:13:27 drh Exp $ ** $Id: delete.c,v 1.15 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -32,11 +32,13 @@ void sqliteDeleteFrom(
WhereInfo *pWInfo; /* Information about the WHERE clause */ WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */ Index *pIdx; /* For looping over indices of the table */
int base; /* Index of the first available table cursor */ int base; /* Index of the first available table cursor */
sqlite *db; /* Main database structure */
if( pParse->nErr || sqlite_malloc_failed ){ if( pParse->nErr || sqlite_malloc_failed ){
pTabList = 0; pTabList = 0;
goto delete_from_cleanup; goto delete_from_cleanup;
} }
db = pParse->db;
/* Locate the table which we want to delete. This table has to be /* Locate the table which we want to delete. This table has to be
** put in an IdList structure because some of the subroutines we ** put in an IdList structure because some of the subroutines we
@ -46,7 +48,7 @@ void sqliteDeleteFrom(
pTabList = sqliteIdListAppend(0, pTableName); pTabList = sqliteIdListAppend(0, pTableName);
if( pTabList==0 ) goto delete_from_cleanup; if( pTabList==0 ) goto delete_from_cleanup;
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName); pTabList->a[i].pTab = sqliteFindTable(db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){ if( pTabList->a[i].pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", sqliteSetString(&pParse->zErrMsg, "no such table: ",
pTabList->a[i].zName, 0); pTabList->a[i].zName, 0);
@ -78,14 +80,15 @@ void sqliteDeleteFrom(
*/ */
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto delete_from_cleanup; if( v==0 ) goto delete_from_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
/* Special case: A DELETE without a WHERE clause deletes everything. /* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to clear all information the database tables directly. ** It is easier just to erase the whole table.
*/ */
if( pWhere==0 ){ if( pWhere==0 ){
sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0); sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0);
@ -118,9 +121,9 @@ void sqliteDeleteFrom(
*/ */
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Open, base+i, pIdx->tnum, 0, 0); sqliteVdbeAddOp(v, OP_OpenWrite, base+i, pIdx->tnum, 0, 0);
} }
end = sqliteVdbeMakeLabel(v); end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
@ -140,7 +143,7 @@ void sqliteDeleteFrom(
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end); sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
} }
if( (pParse->db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
} }

View File

@ -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.18 2001/09/16 00:13:27 drh Exp $ ** $Id: insert.c,v 1.19 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -47,14 +47,16 @@ void sqliteInsert(
int nColumn; /* Number of columns in the data */ int nColumn; /* Number of columns in the data */
int base; /* First available cursor */ int base; /* First available cursor */
int iCont, iBreak; /* Beginning and end of the loop over srcTab */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */
sqlite *db; /* The main database structure */
if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
db = pParse->db;
/* Locate the table into which we will be inserting new information. /* Locate the table into which we will be inserting new information.
*/ */
zTab = sqliteTableNameFromToken(pTableName); zTab = sqliteTableNameFromToken(pTableName);
if( zTab==0 ) goto insert_cleanup; if( zTab==0 ) goto insert_cleanup;
pTab = sqliteFindTable(pParse->db, zTab); pTab = sqliteFindTable(db, zTab);
sqliteFree(zTab); sqliteFree(zTab);
if( pTab==0 ){ if( pTab==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0,
@ -73,9 +75,10 @@ void sqliteInsert(
*/ */
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto insert_cleanup; if( v==0 ) goto insert_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
/* Figure out how many columns of data are supplied. If the data /* Figure out how many columns of data are supplied. If the data
@ -152,9 +155,9 @@ void sqliteInsert(
** all indices of that table. ** all indices of that table.
*/ */
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, pTab->zName, 0); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
sqliteVdbeAddOp(v, OP_Open, idx+base, pIdx->tnum, pIdx->zName, 0); sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum, pIdx->zName, 0);
} }
/* If the data source is a SELECT statement, then we have to create /* If the data source is a SELECT statement, then we have to create
@ -237,7 +240,7 @@ void sqliteInsert(
sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0);
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, iBreak); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, iBreak);
} }
if( (pParse->db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
} }

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** presents to client programs.
** **
** @(#) $Id: sqlite.h.in,v 1.18 2001/09/20 01:44:43 drh Exp $ ** @(#) $Id: sqlite.h.in,v 1.19 2001/09/23 02:35:53 drh Exp $
*/ */
#ifndef _SQLITE_H_ #ifndef _SQLITE_H_
#define _SQLITE_H_ #define _SQLITE_H_
@ -138,19 +138,20 @@ int sqlite_exec(
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */ #define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* One or more database files are locked */ #define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_NOMEM 6 /* A malloc() failed */ #define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_READONLY 7 /* Attempt to write a readonly database */ #define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_INTERRUPT 8 /* Operation terminated by sqlite_interrupt() */ #define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_IOERR 9 /* Some kind of disk I/O error occurred */ #define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
#define SQLITE_CORRUPT 10 /* The database disk image is malformed */ #define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_NOTFOUND 11 /* (Internal Only) Table or record not found */ #define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_FULL 12 /* Insertion failed because database is full */ #define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
#define SQLITE_CANTOPEN 13 /* Unable to open the database file */ #define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_PROTOCOL 14 /* Database lock protocol error */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_EMPTY 15 /* (Internal Only) Database table is empty */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_SCHEMA 16 /* The database schema changed */ #define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
#define SQLITE_TOOBIG 17 /* Too much data for one row of a table */ #define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
/* This function causes any pending database operation to abort and /* This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically ** return at its earliest opportunity. This routine is typically

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** testing of the SQLite library.
** **
** $Id: test3.c,v 1.11 2001/09/16 00:13:27 drh Exp $ ** $Id: test3.c,v 1.12 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "pager.h" #include "pager.h"
@ -499,7 +499,7 @@ static int btree_sanity_check(
} }
/* /*
** Usage: btree_cursor ID TABLENUM ** Usage: btree_cursor ID TABLENUM WRITEABLE
** **
** Create a new cursor. Return the ID for the cursor. ** Create a new cursor. Return the ID for the cursor.
*/ */
@ -513,16 +513,18 @@ static int btree_cursor(
int iTable; int iTable;
BtCursor *pCur; BtCursor *pCur;
int rc; int rc;
int wrFlag;
char zBuf[30]; char zBuf[30];
if( argc!=3 ){ if( argc!=4 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID TABLENUM\"", 0); " ID TABLENUM WRITEABLE\"", 0);
return TCL_ERROR; return TCL_ERROR;
} }
if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
rc = sqliteBtreeCursor(pBt, iTable, &pCur); if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
rc = sqliteBtreeCursor(pBt, iTable, wrFlag, &pCur);
if( rc ){ if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0); Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR; return TCL_ERROR;

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** parser for analysis.
** **
** $Id: tokenize.c,v 1.22 2001/09/16 00:13:27 drh Exp $ ** $Id: tokenize.c,v 1.23 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -353,6 +353,9 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
nErr++; nErr++;
sqliteFree(pParse->zErrMsg); sqliteFree(pParse->zErrMsg);
pParse->zErrMsg = 0; pParse->zErrMsg = 0;
}else if( pParse->rc!=SQLITE_OK ){
sqliteSetString(pzErrMsg, sqliteErrStr(pParse->rc), 0);
nErr++;
} }
break; break;
} }

View File

@ -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.14 2001/09/16 00:13:27 drh Exp $ ** $Id: update.c,v 1.15 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -34,12 +34,14 @@ void sqliteUpdate(
Index *pIdx; /* For looping over indices */ Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */ int nIdx; /* Number of indices that need updating */
int base; /* Index of first available table cursor */ int base; /* Index of first available table cursor */
sqlite *db; /* The database structure */
Index **apIdx = 0; /* An array of indices that need updating too */ Index **apIdx = 0; /* An array of indices that need updating too */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table. ** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */ ** aXRef[i]==-1 if the i-th column is not changed. */
if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
db = pParse->db;
/* Locate the table which we want to update. This table has to be /* Locate the table which we want to update. This table has to be
** put in an IdList structure because some of the subroutines we ** put in an IdList structure because some of the subroutines we
@ -49,7 +51,7 @@ void sqliteUpdate(
pTabList = sqliteIdListAppend(0, pTableName); pTabList = sqliteIdListAppend(0, pTableName);
if( pTabList==0 ) goto update_cleanup; if( pTabList==0 ) goto update_cleanup;
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName); pTabList->a[i].pTab = sqliteFindTable(db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){ if( pTabList->a[i].pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", sqliteSetString(&pParse->zErrMsg, "no such table: ",
pTabList->a[i].zName, 0); pTabList->a[i].zName, 0);
@ -132,9 +134,10 @@ void sqliteUpdate(
*/ */
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto update_cleanup; if( v==0 ) goto update_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1;
} }
/* Begin the database scan /* Begin the database scan
@ -156,9 +159,9 @@ void sqliteUpdate(
*/ */
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0);
for(i=0; i<nIdx; i++){ for(i=0; i<nIdx; i++){
sqliteVdbeAddOp(v, OP_Open, base+i+1, apIdx[i]->tnum, 0, 0); sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, apIdx[i]->tnum, 0, 0);
} }
/* Loop over every record that needs updating. We have to load /* Loop over every record that needs updating. We have to load
@ -216,7 +219,7 @@ void sqliteUpdate(
*/ */
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end); sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
if( (pParse->db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
} }

View File

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** strings, and stuff like that.
** **
** $Id: util.c,v 1.27 2001/09/19 13:22:40 drh Exp $ ** $Id: util.c,v 1.28 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <stdarg.h> #include <stdarg.h>
@ -973,7 +973,8 @@ const char *sqliteErrStr(int rc){
case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break; case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
case SQLITE_PERM: z = "access permission denied"; break; case SQLITE_PERM: z = "access permission denied"; break;
case SQLITE_ABORT: z = "callback requested query abort"; break; case SQLITE_ABORT: z = "callback requested query abort"; break;
case SQLITE_BUSY: z = "database in use by another process"; break; case SQLITE_BUSY: z = "database is locked"; break;
case SQLITE_LOCKED: z = "database table is locked"; break;
case SQLITE_NOMEM: z = "out of memory"; break; case SQLITE_NOMEM: z = "out of memory"; break;
case SQLITE_READONLY: z = "attempt to write a readonly database"; break; case SQLITE_READONLY: z = "attempt to write a readonly database"; break;
case SQLITE_INTERRUPT: z = "interrupted"; break; case SQLITE_INTERRUPT: z = "interrupted"; break;

View File

@ -30,7 +30,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** a program instruction by instruction.
** **
** $Id: vdbe.c,v 1.73 2001/09/22 18:12:10 drh Exp $ ** $Id: vdbe.c,v 1.74 2001/09/23 02:35:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -675,6 +675,19 @@ static void cleanupCursor(Cursor *pCx){
memset(pCx, 0, sizeof(Cursor)); memset(pCx, 0, sizeof(Cursor));
} }
/*
** Close all cursors
*/
static void closeAllCursors(Vdbe *p){
int i;
for(i=0; i<p->nCursor; i++){
cleanupCursor(&p->aCsr[i]);
}
sqliteFree(p->aCsr);
p->aCsr = 0;
p->nCursor = 0;
}
/* /*
** Clean up the VM after execution. ** Clean up the VM after execution.
** **
@ -686,12 +699,7 @@ static void Cleanup(Vdbe *p){
PopStack(p, p->tos+1); PopStack(p, p->tos+1);
sqliteFree(p->azColName); sqliteFree(p->azColName);
p->azColName = 0; p->azColName = 0;
for(i=0; i<p->nCursor; i++){ closeAllCursors(p);
cleanupCursor(&p->aCsr[i]);
}
sqliteFree(p->aCsr);
p->aCsr = 0;
p->nCursor = 0;
for(i=0; i<p->nMem; i++){ for(i=0; i<p->nMem; i++){
if( p->aMem[i].s.flags & STK_Dyn ){ if( p->aMem[i].s.flags & STK_Dyn ){
sqliteFree(p->aMem[i].z); sqliteFree(p->aMem[i].z);
@ -777,30 +785,30 @@ void sqliteVdbeDelete(Vdbe *p){
static char *zOpName[] = { 0, static char *zOpName[] = { 0,
"Transaction", "Commit", "Rollback", "ReadCookie", "Transaction", "Commit", "Rollback", "ReadCookie",
"SetCookie", "VerifyCookie", "Open", "OpenTemp", "SetCookie", "VerifyCookie", "Open", "OpenTemp",
"Close", "MoveTo", "Fcnt", "NewRecno", "OpenWrite", "Close", "MoveTo", "Fcnt",
"Put", "Distinct", "Found", "NotFound", "NewRecno", "Put", "Distinct", "Found",
"Delete", "Column", "KeyAsData", "Recno", "NotFound", "Delete", "Column", "KeyAsData",
"FullKey", "Rewind", "Next", "Destroy", "Recno", "FullKey", "Rewind", "Next",
"Clear", "CreateIndex", "CreateTable", "Reorganize", "Destroy", "Clear", "CreateIndex", "CreateTable",
"BeginIdx", "NextIdx", "PutIdx", "DeleteIdx", "Reorganize", "BeginIdx", "NextIdx", "PutIdx",
"MemLoad", "MemStore", "ListOpen", "ListWrite", "DeleteIdx", "MemLoad", "MemStore", "ListOpen",
"ListRewind", "ListRead", "ListClose", "SortOpen", "ListWrite", "ListRewind", "ListRead", "ListClose",
"SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
"SortNext", "SortKey", "SortCallback", "SortClose", "Sort", "SortNext", "SortKey", "SortCallback",
"FileOpen", "FileRead", "FileColumn", "FileClose", "SortClose", "FileOpen", "FileRead", "FileColumn",
"AggReset", "AggFocus", "AggIncr", "AggNext", "FileClose", "AggReset", "AggFocus", "AggIncr",
"AggSet", "AggGet", "SetInsert", "SetFound", "AggNext", "AggSet", "AggGet", "SetInsert",
"SetNotFound", "SetClear", "MakeRecord", "MakeKey", "SetFound", "SetNotFound", "SetClear", "MakeRecord",
"MakeIdxKey", "Goto", "If", "Halt", "MakeKey", "MakeIdxKey", "Goto", "If",
"ColumnCount", "ColumnName", "Callback", "Integer", "Halt", "ColumnCount", "ColumnName", "Callback",
"String", "Null", "Pop", "Dup", "Integer", "String", "Null", "Pop",
"Pull", "Add", "AddImm", "Subtract", "Dup", "Pull", "Add", "AddImm",
"Multiply", "Divide", "Min", "Max", "Subtract", "Multiply", "Divide", "Min",
"Like", "Glob", "Eq", "Ne", "Max", "Like", "Glob", "Eq",
"Lt", "Le", "Gt", "Ge", "Ne", "Lt", "Le", "Gt",
"IsNull", "NotNull", "Negative", "And", "Ge", "IsNull", "NotNull", "Negative",
"Or", "Not", "Concat", "Noop", "And", "Or", "Not", "Concat",
"Strlen", "Substr", "Noop", "Strlen", "Substr",
}; };
/* /*
@ -1985,7 +1993,7 @@ case OP_VerifyCookie: {
/* Opcode: Open P1 P2 P3 /* Opcode: Open P1 P2 P3
** **
** Open a new cursor for the database table whose root page is ** Open a read-only cursor for the database table whose root page is
** P2 in the main database file. Give the new cursor an identifier ** P2 in the main database file. Give the new cursor an identifier
** of P1. The P1 values need not be contiguous but all P1 values ** of P1. The P1 values need not be contiguous but all P1 values
** should be small integers. It is an error for P1 to be negative. ** should be small integers. It is an error for P1 to be negative.
@ -2006,6 +2014,16 @@ case OP_VerifyCookie: {
** omitted. But the code generator usually inserts the index or ** omitted. But the code generator usually inserts the index or
** table name into P3 to make the code easier to read. ** table name into P3 to make the code easier to read.
*/ */
/* Opcode: OpenWrite P1 P2 P3
**
** Open a read/write cursor named P1 on the table or index whose root
** page is P2. If P2==0 then take the root page number from the stack.
**
** This instruction works just like Open except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only
** cursors or a single read/write cursor but not both.
*/
case OP_OpenWrite:
case OP_Open: { case OP_Open: {
int busy = 0; int busy = 0;
int i = pOp->p1; int i = pOp->p1;
@ -2035,7 +2053,8 @@ case OP_Open: {
cleanupCursor(&p->aCsr[i]); cleanupCursor(&p->aCsr[i]);
memset(&p->aCsr[i], 0, sizeof(Cursor)); memset(&p->aCsr[i], 0, sizeof(Cursor));
do{ do{
rc = sqliteBtreeCursor(pBt, p2, &p->aCsr[i].pCursor); int wrFlag = pOp->opcode==OP_OpenWrite;
rc = sqliteBtreeCursor(pBt, p2, wrFlag, &p->aCsr[i].pCursor);
switch( rc ){ switch( rc ){
case SQLITE_BUSY: { case SQLITE_BUSY: {
if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
@ -2081,7 +2100,7 @@ case OP_OpenTemp: {
memset(pCx, 0, sizeof(*pCx)); memset(pCx, 0, sizeof(*pCx));
rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt); rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqliteBtreeCursor(pCx->pBt, 2, &pCx->pCursor); rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqliteBtreeBeginTrans(pCx->pBt); rc = sqliteBtreeBeginTrans(pCx->pBt);
@ -2637,7 +2656,7 @@ case OP_PutIdx: {
BtCursor *pCrsr; BtCursor *pCrsr;
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
sqliteBtreeInsert(pCrsr, zStack[tos], aStack[tos].n, "", 0); rc = sqliteBtreeInsert(pCrsr, zStack[tos], aStack[tos].n, "", 0);
} }
POPSTACK; POPSTACK;
break; break;
@ -2657,7 +2676,7 @@ case OP_DeleteIdx: {
int rx, res; int rx, res;
rx = sqliteBtreeMoveto(pCrsr, zStack[tos], aStack[tos].n, &res); rx = sqliteBtreeMoveto(pCrsr, zStack[tos], aStack[tos].n, &res);
if( rx==SQLITE_OK && res==0 ){ if( rx==SQLITE_OK && res==0 ){
sqliteBtreeDelete(pCrsr); rc = sqliteBtreeDelete(pCrsr);
} }
} }
POPSTACK; POPSTACK;
@ -3784,7 +3803,8 @@ cleanup:
rc = SQLITE_INTERNAL; rc = SQLITE_INTERNAL;
sqliteSetString(pzErrMsg, "table or index root page not set", 0); sqliteSetString(pzErrMsg, "table or index root page not set", 0);
} }
if( rc!=SQLITE_OK && (db->flags & SQLITE_InTrans)!=0 ){ if( rc!=SQLITE_OK ){
closeAllCursors(p);
sqliteBtreeRollback(pBt); sqliteBtreeRollback(pBt);
sqliteRollbackInternalChanges(db); sqliteRollbackInternalChanges(db);
db->flags &= ~SQLITE_InTrans; db->flags &= ~SQLITE_InTrans;

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** simple program to access and modify the underlying database.
** **
** $Id: vdbe.h,v 1.23 2001/09/16 00:13:27 drh Exp $ ** $Id: vdbe.h,v 1.24 2001/09/23 02:35:53 drh Exp $
*/ */
#ifndef _SQLITE_VDBE_H_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@ -69,116 +69,117 @@ typedef struct VdbeOp VdbeOp;
#define OP_Open 7 #define OP_Open 7
#define OP_OpenTemp 8 #define OP_OpenTemp 8
#define OP_Close 9 #define OP_OpenWrite 9
#define OP_MoveTo 10 #define OP_Close 10
#define OP_Fcnt 11 #define OP_MoveTo 11
#define OP_NewRecno 12 #define OP_Fcnt 12
#define OP_Put 13 #define OP_NewRecno 13
#define OP_Distinct 14 #define OP_Put 14
#define OP_Found 15 #define OP_Distinct 15
#define OP_NotFound 16 #define OP_Found 16
#define OP_Delete 17 #define OP_NotFound 17
#define OP_Column 18 #define OP_Delete 18
#define OP_KeyAsData 19 #define OP_Column 19
#define OP_Recno 20 #define OP_KeyAsData 20
#define OP_FullKey 21 #define OP_Recno 21
#define OP_Rewind 22 #define OP_FullKey 22
#define OP_Next 23 #define OP_Rewind 23
#define OP_Next 24
#define OP_Destroy 24 #define OP_Destroy 25
#define OP_Clear 25 #define OP_Clear 26
#define OP_CreateIndex 26 #define OP_CreateIndex 27
#define OP_CreateTable 27 #define OP_CreateTable 28
#define OP_Reorganize 28 #define OP_Reorganize 29
#define OP_BeginIdx 29 #define OP_BeginIdx 30
#define OP_NextIdx 30 #define OP_NextIdx 31
#define OP_PutIdx 31 #define OP_PutIdx 32
#define OP_DeleteIdx 32 #define OP_DeleteIdx 33
#define OP_MemLoad 33 #define OP_MemLoad 34
#define OP_MemStore 34 #define OP_MemStore 35
#define OP_ListOpen 35 #define OP_ListOpen 36
#define OP_ListWrite 36 #define OP_ListWrite 37
#define OP_ListRewind 37 #define OP_ListRewind 38
#define OP_ListRead 38 #define OP_ListRead 39
#define OP_ListClose 39 #define OP_ListClose 40
#define OP_SortOpen 40 #define OP_SortOpen 41
#define OP_SortPut 41 #define OP_SortPut 42
#define OP_SortMakeRec 42 #define OP_SortMakeRec 43
#define OP_SortMakeKey 43 #define OP_SortMakeKey 44
#define OP_Sort 44 #define OP_Sort 45
#define OP_SortNext 45 #define OP_SortNext 46
#define OP_SortKey 46 #define OP_SortKey 47
#define OP_SortCallback 47 #define OP_SortCallback 48
#define OP_SortClose 48 #define OP_SortClose 49
#define OP_FileOpen 49 #define OP_FileOpen 50
#define OP_FileRead 50 #define OP_FileRead 51
#define OP_FileColumn 51 #define OP_FileColumn 52
#define OP_FileClose 52 #define OP_FileClose 53
#define OP_AggReset 53 #define OP_AggReset 54
#define OP_AggFocus 54 #define OP_AggFocus 55
#define OP_AggIncr 55 #define OP_AggIncr 56
#define OP_AggNext 56 #define OP_AggNext 57
#define OP_AggSet 57 #define OP_AggSet 58
#define OP_AggGet 58 #define OP_AggGet 59
#define OP_SetInsert 59 #define OP_SetInsert 60
#define OP_SetFound 60 #define OP_SetFound 61
#define OP_SetNotFound 61 #define OP_SetNotFound 62
#define OP_SetClear 62 #define OP_SetClear 63
#define OP_MakeRecord 63 #define OP_MakeRecord 64
#define OP_MakeKey 64 #define OP_MakeKey 65
#define OP_MakeIdxKey 65 #define OP_MakeIdxKey 66
#define OP_Goto 66 #define OP_Goto 67
#define OP_If 67 #define OP_If 68
#define OP_Halt 68 #define OP_Halt 69
#define OP_ColumnCount 69 #define OP_ColumnCount 70
#define OP_ColumnName 70 #define OP_ColumnName 71
#define OP_Callback 71 #define OP_Callback 72
#define OP_Integer 72 #define OP_Integer 73
#define OP_String 73 #define OP_String 74
#define OP_Null 74 #define OP_Null 75
#define OP_Pop 75 #define OP_Pop 76
#define OP_Dup 76 #define OP_Dup 77
#define OP_Pull 77 #define OP_Pull 78
#define OP_Add 78 #define OP_Add 79
#define OP_AddImm 79 #define OP_AddImm 80
#define OP_Subtract 80 #define OP_Subtract 81
#define OP_Multiply 81 #define OP_Multiply 82
#define OP_Divide 82 #define OP_Divide 83
#define OP_Min 83 #define OP_Min 84
#define OP_Max 84 #define OP_Max 85
#define OP_Like 85 #define OP_Like 86
#define OP_Glob 86 #define OP_Glob 87
#define OP_Eq 87 #define OP_Eq 88
#define OP_Ne 88 #define OP_Ne 89
#define OP_Lt 89 #define OP_Lt 90
#define OP_Le 90 #define OP_Le 91
#define OP_Gt 91 #define OP_Gt 92
#define OP_Ge 92 #define OP_Ge 93
#define OP_IsNull 93 #define OP_IsNull 94
#define OP_NotNull 94 #define OP_NotNull 95
#define OP_Negative 95 #define OP_Negative 96
#define OP_And 96 #define OP_And 97
#define OP_Or 97 #define OP_Or 98
#define OP_Not 98 #define OP_Not 99
#define OP_Concat 99 #define OP_Concat 100
#define OP_Noop 100 #define OP_Noop 101
#define OP_Strlen 101 #define OP_Strlen 102
#define OP_Substr 102 #define OP_Substr 103
#define OP_MAX 102 #define OP_MAX 103
/* /*
** Prototypes for the VDBE interface. See comments on the implementation ** Prototypes for the VDBE interface. See comments on the implementation

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is btree database backend # focus of this script is btree database backend
# #
# $Id: btree.test,v 1.9 2001/09/16 00:13:28 drh Exp $ # $Id: btree.test,v 1.10 2001/09/23 02:35:53 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -54,7 +54,7 @@ do_test btree-1.4.1 {
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {1} } {1}
do_test btree-1.5 { do_test btree-1.5 {
set rc [catch {btree_cursor $::b1 2} ::c1] set rc [catch {btree_cursor $::b1 2 1} ::c1]
if {$rc} {lappend rc $::c1} if {$rc} {lappend rc $::c1}
set rc set rc
} {0} } {0}
@ -86,7 +86,7 @@ do_test btree-1.12 {
# Reopen the database and attempt to read the record that we wrote. # Reopen the database and attempt to read the record that we wrote.
# #
do_test btree-2.1 { do_test btree-2.1 {
set rc [catch {btree_cursor $::b1 2} ::c1] set rc [catch {btree_cursor $::b1 2 1} ::c1]
if {$rc} {lappend rc $::c1} if {$rc} {lappend rc $::c1}
set rc set rc
} {0} } {0}
@ -209,7 +209,7 @@ do_test btree-3.24 {
file size test1.bt file size test1.bt
} {2048} } {2048}
do_test btree-3.25 { do_test btree-3.25 {
set rc [catch {btree_cursor $::b1 2} ::c1] set rc [catch {btree_cursor $::b1 2 1} ::c1]
if {$rc} {lappend rc $::c1} if {$rc} {lappend rc $::c1}
set rc set rc
} {0} } {0}
@ -339,7 +339,7 @@ do_test btree-4.7 {
do_test btree-4.8 { do_test btree-4.8 {
btree_close $::b1 btree_close $::b1
set ::b1 [btree_open test1.bt] set ::b1 [btree_open test1.bt]
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {2} } {2}
do_test btree-4.9 { do_test btree-4.9 {
@ -421,7 +421,7 @@ do_test btree-6.2.1 {
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {1} } {1}
do_test btree-6.2.2 { do_test btree-6.2.2 {
set ::c2 [btree_cursor $::b1 $::t2] set ::c2 [btree_cursor $::b1 $::t2 1]
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {2} } {2}
do_test btree-6.2.3 { do_test btree-6.2.3 {
@ -430,7 +430,7 @@ do_test btree-6.2.3 {
} {ten} } {ten}
do_test btree-6.3 { do_test btree-6.3 {
btree_commit $::b1 btree_commit $::b1
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {3} } {3}
do_test btree-6.3.1 { do_test btree-6.3.1 {
@ -465,7 +465,7 @@ do_test btree-6.8.1 {
lindex [btree_get_meta $::b1] 0 lindex [btree_get_meta $::b1] 0
} {0} } {0}
do_test btree-6.9 { do_test btree-6.9 {
set ::c2 [btree_cursor $::b1 $::t2] set ::c2 [btree_cursor $::b1 $::t2 1]
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {3} } {3}
@ -479,7 +479,7 @@ do_test btree-6.9.1 {
do_test btree-6.10 { do_test btree-6.10 {
btree_close_cursor $::c1 btree_close_cursor $::c1
btree_drop_table $::b1 2 btree_drop_table $::b1 2
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
btree_move_to $::c1 {} btree_move_to $::c1 {}
btree_key $::c1 btree_key $::c1
} {} } {}
@ -631,7 +631,7 @@ do_test btree-8.9 {
btree_close_cursor $::c1 btree_close_cursor $::c1
btree_close $::b1 btree_close $::b1
set ::b1 [btree_open test1.bt] set ::b1 [btree_open test1.bt]
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
btree_move_to $::c1 020 btree_move_to $::c1 020
btree_data $::c1 btree_data $::c1
} $::data } $::data
@ -653,7 +653,7 @@ do_test btree-8.12 {
lindex [btree_get_meta $::b1] 0 lindex [btree_get_meta $::b1] 0
} {4} } {4}
do_test btree-8.12.1 { do_test btree-8.12.1 {
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
btree_insert $::c1 ${::keyprefix}1 1 btree_insert $::c1 ${::keyprefix}1 1
btree_data $::c1 btree_data $::c1
} {1} } {1}
@ -700,7 +700,7 @@ do_test btree-8.22 {
do_test btree-8.23 { do_test btree-8.23 {
btree_close_cursor $::c1 btree_close_cursor $::c1
btree_drop_table $::b1 2 btree_drop_table $::b1 2
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
lindex [btree_get_meta $::b1] 0 lindex [btree_get_meta $::b1] 0
} {4} } {4}
do_test btree-8.24 { do_test btree-8.24 {
@ -790,7 +790,7 @@ do_test btree-10.1 {
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {1} } {1}
do_test btree-10.2 { do_test btree-10.2 {
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {2} } {2}
do_test btree-10.3 { do_test btree-10.3 {
@ -851,7 +851,7 @@ do_test btree-11.2 {
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {1} } {1}
do_test btree-11.3 { do_test btree-11.3 {
set ::c1 [btree_cursor $::b1 2] set ::c1 [btree_cursor $::b1 2 1]
lindex [btree_pager_stats $::b1] 1 lindex [btree_pager_stats $::b1] 1
} {2} } {2}
#btree_page_dump $::b1 2 #btree_page_dump $::b1 2

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is btree database backend # focus of this script is btree database backend
# #
# $Id: btree2.test,v 1.7 2001/09/16 00:13:28 drh Exp $ # $Id: btree2.test,v 1.8 2001/09/23 02:35:53 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -48,7 +48,7 @@ do_test btree2-1.4 {
btree_create_table $::b btree_create_table $::b
} {6} } {6}
do_test btree2-1.5 { do_test btree2-1.5 {
set ::c2 [btree_cursor $::b 2] set ::c2 [btree_cursor $::b 2 1]
btree_insert $::c2 {one} {1} btree_insert $::c2 {one} {1}
btree_delete $::c2 btree_delete $::c2
btree_close_cursor $::c2 btree_close_cursor $::c2
@ -95,7 +95,7 @@ proc build_db {N L} {
for {set i 2} {$i<=6} {incr i} { for {set i 2} {$i<=6} {incr i} {
catch {btree_close_cursor [set ::c$i]} catch {btree_close_cursor [set ::c$i]}
btree_clear_table $::b $i btree_clear_table $::b $i
set ::c$i [btree_cursor $::b $i] set ::c$i [btree_cursor $::b $i 1]
} }
btree_insert $::c2 N $N btree_insert $::c2 N $N
btree_insert $::c2 L $L btree_insert $::c2 L $L
@ -281,11 +281,11 @@ foreach {N L} {
puts "**** N=$N L=$L ****" puts "**** N=$N L=$L ****"
set hash [md5file test2.bt] set hash [md5file test2.bt]
do_test btree2-$testno.1 [subst -nocommands { do_test btree2-$testno.1 [subst -nocommands {
set ::c2 [btree_cursor $::b 2] set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3] set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4] set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5] set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6] set ::c6 [btree_cursor $::b 6 1]
btree_begin_transaction $::b btree_begin_transaction $::b
build_db $N $L build_db $N $L
check_invariants check_invariants
@ -301,11 +301,11 @@ foreach {N L} {
} $hash } $hash
do_test btree2-$testno.3 [subst -nocommands { do_test btree2-$testno.3 [subst -nocommands {
btree_begin_transaction $::b btree_begin_transaction $::b
set ::c2 [btree_cursor $::b 2] set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3] set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4] set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5] set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6] set ::c6 [btree_cursor $::b 6 1]
build_db $N $L build_db $N $L
check_invariants check_invariants
}] {} }] {}
@ -327,11 +327,11 @@ foreach {N L} {
do_test btree2-$testno.7 { do_test btree2-$testno.7 {
btree_close $::b btree_close $::b
set ::b [btree_open test2.bt] set ::b [btree_open test2.bt]
set ::c2 [btree_cursor $::b 2] set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3] set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4] set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5] set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6] set ::c6 [btree_cursor $::b 6 1]
check_invariants check_invariants
} {} } {}
@ -375,11 +375,11 @@ foreach {N L} {
} $hash } $hash
# exec cp test2.bt test2.bt.bu2 # exec cp test2.bt test2.bt.bu2
btree_begin_transaction $::b btree_begin_transaction $::b
set ::c2 [btree_cursor $::b 2] set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3] set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4] set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5] set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6] set ::c6 [btree_cursor $::b 6 1]
do_test $testid.5 [subst { do_test $testid.5 [subst {
random_changes $n $I $K $D random_changes $n $I $K $D
}] {} }] {}
@ -402,11 +402,11 @@ foreach {N L} {
do_test $testid.9 { do_test $testid.9 {
btree_close $::b btree_close $::b
set ::b [btree_open test2.bt] set ::b [btree_open test2.bt]
set ::c2 [btree_cursor $::b 2] set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3] set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4] set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5] set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6] set ::c6 [btree_cursor $::b 6 1]
check_invariants check_invariants
} {} } {}
incr num2 incr num2

View File

@ -11,82 +11,150 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is database locks. # focus of this script is database locks.
# #
# $Id: lock.test,v 1.10 2001/09/16 00:13:28 drh Exp $ # $Id: lock.test,v 1.11 2001/09/23 02:35:53 drh Exp $
if {0} {
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
# Create a largish table # Create an alternative connection to the database
# #
do_test lock-1.0 { do_test lock-1.0 {
execsql {CREATE TABLE big(f1 int, f2 int, f3 int)} sqlite db2 ./test.db
set f [open ./testdata1.txt w]
for {set i 1} {$i<=500} {incr i} {
puts $f "$i\t[expr {$i*2}]\t[expr {$i*3}]"
}
close $f
execsql {COPY big FROM './testdata1.txt'}
file delete -force ./testdata1.txt
} {} } {}
do_test lock-1.1 { do_test lock-1.1 {
# Create a background query that gives us a read lock on the big table execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
#
set f [open slow.sql w]
puts $f "SELECT a.f1, b.f1 FROM big AS a, big AS B"
puts $f "WHERE a.f1+b.f1==0.5;"
close $f
set ::lock_pid [exec ./sqlite testdb <slow.sql &]
after 250
set v {}
} {} } {}
do_test lock-1.2 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
execsql {CREATE TABLE t1(a int, b int)}
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
do_test lock-1.4 {
set r [catch {execsql {
SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
} db2} msg]
lappend r $msg
} {1 {database schema has changed}}
do_test lock-1.5 {
set r [catch {execsql {
SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
} db2} msg]
lappend r $msg
} {0 t1}
do_probtest lock-1.2 { do_test lock-1.6 {
# Now try to update the database execsql {INSERT INTO t1 VALUES(1,2)}
# execsql {SELECT * FROM t1}
set v [catch {execsql {UPDATE big SET f2='xyz' WHERE f1=11}} msg] } {1 2}
lappend v $msg do_test lock-1.7 {
} {1 {table big is locked}} execsql {SELECT * FROM t1} db2
} {1 2}
do_test lock-1.8 {
execsql {UPDATE t1 SET a=b, b=a} db2
execsql {SELECT * FROM t1} db2
} {2 1}
do_test lock-1.9 {
execsql {SELECT * FROM t1}
} {2 1}
do_probtest lock-1.3 { do_test lock-1.10 {
# Try to update the database in a separate process execsql {BEGIN TRANSACTION}
# execsql {SELECT * FROM t1}
set f [open update.sql w] } {2 1}
puts $f ".timeout 0" do_test lock-1.11 {
puts $f "UPDATE big SET f2='xyz' WHERE f1=11;" set r [catch {execsql {SELECT * FROM t1} db2} msg]
puts $f "SELECT f2 FROM big WHERE f1=11;" lappend r $msg
close $f } {1 {database is locked}}
exec ./sqlite testdb <update.sql do_test lock-1.12 {
} "UPDATE big SET f2='xyz' WHERE f1=11;\nSQL error: table big is locked\n22" execsql {ROLLBACK}
set r [catch {execsql {SELECT * FROM t1} db2} msg]
lappend r $msg
} {0 {2 1}}
do_probtest lock-1.4 { do_test lock-1.13 {
# Try to update the database using a timeout execsql {CREATE TABLE t2(x int, y int)}
# execsql {INSERT INTO t2 VALUES(8,9)}
set f [open update.sql w] execsql {SELECT * FROM t2}
puts $f ".timeout 1000" } {8 9}
puts $f "UPDATE big SET f2='xyz' WHERE f1=11;" do_test lock-1.14 {
puts $f "SELECT f2 FROM big WHERE f1=11;" set r [catch {execsql {SELECT * FROM t1} db2} msg]
close $f lappend r $msg
exec ./sqlite testdb <update.sql } {1 {database schema has changed}}
} "UPDATE big SET f2='xyz' WHERE f1=11;\nSQL error: table big is locked\n22" do_test lock-1.15 {
set r [catch {execsql {SELECT * FROM t2} db2} msg]
lappend r $msg
} {0 {8 9}}
do_probtest lock-1.5 { do_test lock-1.16 {
# Try to update the database using a timeout db eval {SELECT * FROM t1} qv {
# set x [db eval {SELECT * FROM t1}]
set f [open update.sql w] }
puts $f ".timeout 10000" set x
puts $f "UPDATE big SET f2='xyz' WHERE f1=11;" } {2 1}
puts $f "SELECT f2 FROM big WHERE f1=11;" do_test lock-1.17 {
close $f db eval {SELECT * FROM t1} qv {
exec ./sqlite testdb <update.sql set x [db eval {SELECT * FROM t2}]
} {xyz} }
set x
} {8 9}
catch {exec ps -uax | grep $::lock_pid} # You cannot UPDATE a table from within the callback of a SELECT
catch {exec kill -HUP $::lock_pid} # on that same table because the SELECT has the table locked.
catch {exec kill -9 $::lock_pid} #
do_test lock-1.18 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
lappend r $msg
}
set r
} {1 {database table is locked}}
# But you can UPDATE a different table from the one that is used in
# the SELECT.
#
do_test lock-1.19 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
lappend r $msg
}
set r
} {0 {}}
do_test lock-1.20 {
execsql {SELECT * FROM t2}
} {9 8}
# It is possible to do a SELECT of the same table within the
# callback of another SELECT on that same table because two
# or more read-only cursors can be open at once.
#
do_test lock-1.21 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {SELECT a FROM t1}} msg]
lappend r $msg
}
set r
} {0 2}
# Under UNIX you can do two SELECTs at once with different database
# connections, because UNIX supports reader/writer locks. Under windows,
# this is not possible.
#
if {$::tcl_platform(platform)=="unix"} {
do_test lock-1.22 {
db eval {SELECT * FROM t1} qv {
set r [catch {db2 eval {SELECT a FROM t1}} msg]
lappend r $msg
}
set r
} {0 2}
}
do_test lock-999.1 {
rename db2 {}
} {}
finish_test finish_test
}

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is database locks. # focus of this script is database locks.
# #
# $Id: trans.test,v 1.5 2001/09/17 20:48:30 drh Exp $ # $Id: trans.test,v 1.6 2001/09/23 02:35:53 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -94,13 +94,13 @@ do_test trans-3.2 {
SELECT a FROM two ORDER BY a; SELECT a FROM two ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-3.3 { do_test trans-3.3 {
set v [catch {execsql { set v [catch {execsql {
SELECT a FROM one ORDER BY a; SELECT a FROM one ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-3.4 { do_test trans-3.4 {
set v [catch {execsql { set v [catch {execsql {
INSERT INTO one VALUES(4,'four'); INSERT INTO one VALUES(4,'four');
@ -112,13 +112,13 @@ do_test trans-3.5 {
SELECT a FROM two ORDER BY a; SELECT a FROM two ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-3.6 { do_test trans-3.6 {
set v [catch {execsql { set v [catch {execsql {
SELECT a FROM one ORDER BY a; SELECT a FROM one ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-3.7 { do_test trans-3.7 {
set v [catch {execsql { set v [catch {execsql {
INSERT INTO two VALUES(4,'IV'); INSERT INTO two VALUES(4,'IV');
@ -130,13 +130,13 @@ do_test trans-3.8 {
SELECT a FROM two ORDER BY a; SELECT a FROM two ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-3.9 { do_test trans-3.9 {
set v [catch {execsql { set v [catch {execsql {
SELECT a FROM one ORDER BY a; SELECT a FROM one ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-3.10 { do_test trans-3.10 {
execsql {END TRANSACTION} execsql {END TRANSACTION}
} {} } {}
@ -189,13 +189,13 @@ do_test trans-4.4 {
SELECT a FROM two ORDER BY a; SELECT a FROM two ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-4.5 { do_test trans-4.5 {
set v [catch {execsql { set v [catch {execsql {
SELECT a FROM one ORDER BY a; SELECT a FROM one ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-4.6 { do_test trans-4.6 {
set v [catch {execsql { set v [catch {execsql {
BEGIN TRANSACTION; BEGIN TRANSACTION;
@ -208,13 +208,13 @@ do_test trans-4.7 {
SELECT a FROM two ORDER BY a; SELECT a FROM two ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-4.8 { do_test trans-4.8 {
set v [catch {execsql { set v [catch {execsql {
SELECT a FROM one ORDER BY a; SELECT a FROM one ORDER BY a;
} altdb} msg] } altdb} msg]
lappend v $msg lappend v $msg
} {1 {database in use by another process}} } {1 {database is locked}}
do_test trans-4.9 { do_test trans-4.9 {
set v [catch {execsql { set v [catch {execsql {
END TRANSACTION; END TRANSACTION;