mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Removed the direct btree tests - part of the ongoing effort to test by
calling only public interfaces. Modify the sqlite3VdbeRecordCompare interface to used a pre-parsed second key - resulting in a 13% performance improvement on speed1p.test. (CVS 4911) FossilOrigin-Name: 0e1d84f2f456e7680bb667266745b629ddf3605f
This commit is contained in:
38
manifest
38
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Improved\sdocumentation\sof\ssqlite3_blob_open().\s(CVS\s4910)
|
C Removed\sthe\sdirect\sbtree\stests\s-\spart\sof\sthe\songoing\seffort\sto\stest\sby\ncalling\sonly\spublic\sinterfaces.\s\sModify\sthe\ssqlite3VdbeRecordCompare\ninterface\sto\sused\sa\spre-parsed\ssecond\skey\s-\sresulting\sin\sa\s13%\nperformance\simprovement\son\sspeed1p.test.\s(CVS\s4911)
|
||||||
D 2008-03-24T12:51:46
|
D 2008-03-25T00:22:21
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa
|
F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -86,9 +86,9 @@ F src/attach.c bdc75e759ca25a16f4dc7fbdbc6d37ad2561bb24
|
|||||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||||
F src/bitvec.c 49817d442e51e4123585f3cf3c2afc293a3c91e2
|
F src/bitvec.c 49817d442e51e4123585f3cf3c2afc293a3c91e2
|
||||||
F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2
|
F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2
|
||||||
F src/btree.c 15424f41344ad96ab56a3322f5930cfb7a8ee24e
|
F src/btree.c 984962aa403be49d79784f01cc9887d16cd841ed
|
||||||
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
|
F src/btree.h ca065a5910e6dd3b91b88ff9d729450a8b8eda1f
|
||||||
F src/btreeInt.h d7d2f4d9d7f2e72c455326d48b2b478b842a81f6
|
F src/btreeInt.h c2deca3e778e2a1e6196343b8087a868f4faa19a
|
||||||
F src/build.c 31ed5af4e8ac40c30bb0f88d7fec75e72cc16e0e
|
F src/build.c 31ed5af4e8ac40c30bb0f88d7fec75e72cc16e0e
|
||||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||||
@@ -132,7 +132,7 @@ F src/pager.c 22241b59c80ca083a96816df434adb8c097afcd4
|
|||||||
F src/pager.h b1e2258f03878c14b06a95bfa362e8c5c9638170
|
F src/pager.h b1e2258f03878c14b06a95bfa362e8c5c9638170
|
||||||
F src/parse.y b0ee84d94218046ea88c2a6561005710d127ca7d
|
F src/parse.y b0ee84d94218046ea88c2a6561005710d127ca7d
|
||||||
F src/pragma.c f64eed914518c28d1863356163dea1e6f58e28f2
|
F src/pragma.c f64eed914518c28d1863356163dea1e6f58e28f2
|
||||||
F src/prepare.c 1b71b5d43ba3d88f2d3c2a6d084f28ac209df956
|
F src/prepare.c f7fc2eb7418dcaa63e22b66c5ecf478e658ecd8f
|
||||||
F src/printf.c 05d2b44d7b5b80c8a4a09108ddad9c20e254370d
|
F src/printf.c 05d2b44d7b5b80c8a4a09108ddad9c20e254370d
|
||||||
F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a
|
F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a
|
||||||
F src/select.c 35063b078beafe9aa35344a8ce039210920d7fea
|
F src/select.c 35063b078beafe9aa35344a8ce039210920d7fea
|
||||||
@@ -146,7 +146,7 @@ F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a
|
|||||||
F src/tclsqlite.c d42912617d4734b8f9195416badf5b27e512ded2
|
F src/tclsqlite.c d42912617d4734b8f9195416badf5b27e512ded2
|
||||||
F src/test1.c 342a2628310fa709074d979e695a28a3bb570834
|
F src/test1.c 342a2628310fa709074d979e695a28a3bb570834
|
||||||
F src/test2.c f0808cc643528b9620e4059ca9bda8346f526121
|
F src/test2.c f0808cc643528b9620e4059ca9bda8346f526121
|
||||||
F src/test3.c 5c7452038ab27aa698070799b10132f26cdd2a80
|
F src/test3.c 9bf750645412effca0b2567b8b833e1e91377b47
|
||||||
F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071
|
F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071
|
||||||
F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4
|
F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4
|
||||||
F src/test6.c 62281c0a9ac0265e579065942f7de4e080f8eb05
|
F src/test6.c 62281c0a9ac0265e579065942f7de4e080f8eb05
|
||||||
@@ -174,11 +174,11 @@ F src/update.c d2c59643af98f966c2a04d392463089b715ca18f
|
|||||||
F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4
|
F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4
|
||||||
F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2
|
F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2
|
||||||
F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30
|
F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30
|
||||||
F src/vdbe.c 43b261f50be60c758430a9072f960715f2ff0852
|
F src/vdbe.c d81771c67e67f9a25af1d53e5c22299becef1322
|
||||||
F src/vdbe.h 93acc03fe8002173cb6affad2bf5d5c5305ba229
|
F src/vdbe.h 0fef6798be121ed2b5a547a5cb85e0824ec3971f
|
||||||
F src/vdbeInt.h 76c81d057a39813de0fda3cad1498655d53ec69d
|
F src/vdbeInt.h 4bbec80d55d179ab8438ac9822416d9111638919
|
||||||
F src/vdbeapi.c b9e9d7a58690c1e1ae66de7232edccf4793ad817
|
F src/vdbeapi.c b9e9d7a58690c1e1ae66de7232edccf4793ad817
|
||||||
F src/vdbeaux.c 82f3c8913e68b4928de28c3fa117464356d59df6
|
F src/vdbeaux.c f3ee532bfdf191f0d2a8c4d1a50816cdd1a235d2
|
||||||
F src/vdbeblob.c 63c750acc7b5012479f508c0e9627372a82cb65d
|
F src/vdbeblob.c 63c750acc7b5012479f508c0e9627372a82cb65d
|
||||||
F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736
|
F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736
|
||||||
F src/vdbemem.c 67662aac917b627356262f9501591206db2a8845
|
F src/vdbemem.c 67662aac917b627356262f9501591206db2a8845
|
||||||
@@ -215,14 +215,6 @@ F test/bind.test 261fd1603613e7f877a516d29f281c9d8c2ecf52
|
|||||||
F test/bindxfer.test 995d2cf8df61204d748cde6960443121c4ccd2e1
|
F test/bindxfer.test 995d2cf8df61204d748cde6960443121c4ccd2e1
|
||||||
F test/bitvec.test 62a512c3f7041d1df12558eb25990e5a19820571
|
F test/bitvec.test 62a512c3f7041d1df12558eb25990e5a19820571
|
||||||
F test/blob.test f2dbdbf1159674283645c2636436839313ee7131
|
F test/blob.test f2dbdbf1159674283645c2636436839313ee7131
|
||||||
F test/btree.test d22b1b2cc9becc36f6b1f2f91b9fca1e48060979
|
|
||||||
F test/btree2.test 4b56a2a4a4f84d68c77aef271223a713bf5ebafc
|
|
||||||
F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
|
|
||||||
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
|
|
||||||
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
|
|
||||||
F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f
|
|
||||||
F test/btree8.test fadc112bcbd6a0c622d34c813fc8a648eacf8804
|
|
||||||
F test/btree9.test 5d8711b241145b90f65dd1795d5dd8290846fa5e
|
|
||||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||||
F test/cache.test 3ff445c445742a7b6b9ba6e1d62a25263f9424b9
|
F test/cache.test 3ff445c445742a7b6b9ba6e1d62a25263f9424b9
|
||||||
F test/capi2.test cc64df7560a96f848f919ea2926c60acf639684b
|
F test/capi2.test cc64df7560a96f848f919ea2926c60acf639684b
|
||||||
@@ -419,7 +411,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
|||||||
F test/printf.test c3405535b418d454e8a52196a0fc592ec9eec58d
|
F test/printf.test c3405535b418d454e8a52196a0fc592ec9eec58d
|
||||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
||||||
F test/ptrchng.test 83150cb7b513e33cce90fdc68f4b1817551857c0
|
F test/ptrchng.test 83150cb7b513e33cce90fdc68f4b1817551857c0
|
||||||
F test/quick.test 037a953ccc4e5419c89528e7b93742db29bc3ec1
|
F test/quick.test fcd8fb7aeee4b8bc7a5be56c25104f6f39258eb1
|
||||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||||
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
|
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
|
||||||
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
||||||
@@ -625,7 +617,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P a807e7184b857414ce203af129ac1adf2012096c
|
P 1ed695f560a58786f2a8467c601f281c67034fd4
|
||||||
R 4101d535e06a9619e1c68b648b338bf6
|
R 4b7a149e165aca7212e2405c0ae3196c
|
||||||
U drh
|
U drh
|
||||||
Z c87ff7d608d92b0ae8912212b9742706
|
Z f27434cb523b0af2e9a84163450beba5
|
||||||
|
@@ -1 +1 @@
|
|||||||
1ed695f560a58786f2a8467c601f281c67034fd4
|
0e1d84f2f456e7680bb667266745b629ddf3605f
|
89
src/btree.c
89
src/btree.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.c,v 1.442 2008/03/23 00:20:36 drh Exp $
|
** $Id: btree.c,v 1.443 2008/03/25 00:22:21 drh Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** See the header comment on "btreeInt.h" for additional information.
|
** See the header comment on "btreeInt.h" for additional information.
|
||||||
@@ -2649,23 +2649,6 @@ int sqlite3BtreeRollbackStmt(Btree *p){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** Default key comparison function to be used if no comparison function
|
|
||||||
** is specified on the sqlite3BtreeCursor() call.
|
|
||||||
*/
|
|
||||||
static int dfltCompare(
|
|
||||||
void *NotUsed, /* User data is not used */
|
|
||||||
int n1, const void *p1, /* First key to compare */
|
|
||||||
int n2, const void *p2 /* Second key to compare */
|
|
||||||
){
|
|
||||||
int c;
|
|
||||||
c = memcmp(p1, p2, n1<n2 ? n1 : n2);
|
|
||||||
if( c==0 ){
|
|
||||||
c = n1 - n2;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Create a new cursor for the BTree whose root is on the page
|
** Create a new cursor for the BTree whose root is on the page
|
||||||
** iTable. The act of acquiring a cursor gets a read lock on
|
** iTable. The act of acquiring a cursor gets a read lock on
|
||||||
@@ -2692,20 +2675,13 @@ static int dfltCompare(
|
|||||||
** No checking is done to make sure that page iTable really is the
|
** No checking is done to make sure that page iTable really is the
|
||||||
** root page of a b-tree. If it is not, then the cursor acquired
|
** root page of a b-tree. If it is not, then the cursor acquired
|
||||||
** will not work correctly.
|
** will not work correctly.
|
||||||
**
|
|
||||||
** The comparison function must be logically the same for every cursor
|
|
||||||
** on a particular table. Changing the comparison function will result
|
|
||||||
** in incorrect operations. If the comparison function is NULL, a
|
|
||||||
** default comparison function is used. The comparison function is
|
|
||||||
** always ignored for INTKEY tables.
|
|
||||||
*/
|
*/
|
||||||
static int btreeCursor(
|
static int btreeCursor(
|
||||||
Btree *p, /* The btree */
|
Btree *p, /* The btree */
|
||||||
int iTable, /* Root page of table to open */
|
int iTable, /* Root page of table to open */
|
||||||
int wrFlag, /* 1 to write. 0 read-only */
|
int wrFlag, /* 1 to write. 0 read-only */
|
||||||
int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
|
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||||
void *pArg, /* First arg to xCompare() */
|
BtCursor **ppCur /* Write new cursor here */
|
||||||
BtCursor **ppCur /* Write new cursor here */
|
|
||||||
){
|
){
|
||||||
int rc;
|
int rc;
|
||||||
BtCursor *pCur;
|
BtCursor *pCur;
|
||||||
@@ -2750,8 +2726,7 @@ static int btreeCursor(
|
|||||||
** variables, link the cursor into the BtShared list and set *ppCur (the
|
** variables, link the cursor into the BtShared list and set *ppCur (the
|
||||||
** output argument to this function).
|
** output argument to this function).
|
||||||
*/
|
*/
|
||||||
pCur->xCompare = xCmp ? xCmp : dfltCompare;
|
pCur->pKeyInfo = pKeyInfo;
|
||||||
pCur->pArg = pArg;
|
|
||||||
pCur->pBtree = p;
|
pCur->pBtree = p;
|
||||||
pCur->pBt = pBt;
|
pCur->pBt = pBt;
|
||||||
pCur->wrFlag = wrFlag;
|
pCur->wrFlag = wrFlag;
|
||||||
@@ -2774,17 +2749,16 @@ create_cursor_exception:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
int sqlite3BtreeCursor(
|
int sqlite3BtreeCursor(
|
||||||
Btree *p, /* The btree */
|
Btree *p, /* The btree */
|
||||||
int iTable, /* Root page of table to open */
|
int iTable, /* Root page of table to open */
|
||||||
int wrFlag, /* 1 to write. 0 read-only */
|
int wrFlag, /* 1 to write. 0 read-only */
|
||||||
int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
|
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
||||||
void *pArg, /* First arg to xCompare() */
|
BtCursor **ppCur /* Write new cursor here */
|
||||||
BtCursor **ppCur /* Write new cursor here */
|
|
||||||
){
|
){
|
||||||
int rc;
|
int rc;
|
||||||
sqlite3BtreeEnter(p);
|
sqlite3BtreeEnter(p);
|
||||||
p->pBt->db = p->db;
|
p->pBt->db = p->db;
|
||||||
rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur);
|
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, ppCur);
|
||||||
sqlite3BtreeLeave(p);
|
sqlite3BtreeLeave(p);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -3578,8 +3552,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
|||||||
**
|
**
|
||||||
** For INTKEY tables, only the nKey parameter is used. pKey is
|
** For INTKEY tables, only the nKey parameter is used. pKey is
|
||||||
** ignored. For other tables, nKey is the number of bytes of data
|
** ignored. For other tables, nKey is the number of bytes of data
|
||||||
** in pKey. The comparison function specified when the cursor was
|
** in pKey.
|
||||||
** created is used to compare keys.
|
|
||||||
**
|
**
|
||||||
** If an exact match is not found, then the cursor is always
|
** If an exact match is not found, then the cursor is always
|
||||||
** left pointing at a leaf page which would hold the entry if it
|
** left pointing at a leaf page which would hold the entry if it
|
||||||
@@ -3609,6 +3582,8 @@ int sqlite3BtreeMoveto(
|
|||||||
int *pRes /* Search result flag */
|
int *pRes /* Search result flag */
|
||||||
){
|
){
|
||||||
int rc;
|
int rc;
|
||||||
|
VdbeParsedRecord *pPKey;
|
||||||
|
char aSpace[200];
|
||||||
|
|
||||||
assert( cursorHoldsMutex(pCur) );
|
assert( cursorHoldsMutex(pCur) );
|
||||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||||
@@ -3623,6 +3598,13 @@ int sqlite3BtreeMoveto(
|
|||||||
assert( pCur->pPage->nCell==0 );
|
assert( pCur->pPage->nCell==0 );
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
if( pCur->pPage->intKey ){
|
||||||
|
pPKey = 0;
|
||||||
|
}else{
|
||||||
|
pPKey = sqlite3VdbeRecordParse(pCur->pKeyInfo, nKey, pKey,
|
||||||
|
aSpace, sizeof(aSpace));
|
||||||
|
if( pPKey==0 ) return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
for(;;){
|
for(;;){
|
||||||
int lwr, upr;
|
int lwr, upr;
|
||||||
Pgno chldPg;
|
Pgno chldPg;
|
||||||
@@ -3631,7 +3613,8 @@ int sqlite3BtreeMoveto(
|
|||||||
lwr = 0;
|
lwr = 0;
|
||||||
upr = pPage->nCell-1;
|
upr = pPage->nCell-1;
|
||||||
if( !pPage->intKey && pKey==0 ){
|
if( !pPage->intKey && pKey==0 ){
|
||||||
return SQLITE_CORRUPT_BKPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
|
goto moveto_finish;
|
||||||
}
|
}
|
||||||
if( biasRight ){
|
if( biasRight ){
|
||||||
pCur->idx = upr;
|
pCur->idx = upr;
|
||||||
@@ -3662,16 +3645,14 @@ int sqlite3BtreeMoveto(
|
|||||||
pCellKey = (void *)fetchPayload(pCur, &available, 0);
|
pCellKey = (void *)fetchPayload(pCur, &available, 0);
|
||||||
nCellKey = pCur->info.nKey;
|
nCellKey = pCur->info.nKey;
|
||||||
if( available>=nCellKey ){
|
if( available>=nCellKey ){
|
||||||
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
|
c = sqlite3VdbeRecordCompareParsed(nCellKey, pCellKey, pPKey);
|
||||||
}else{
|
}else{
|
||||||
pCellKey = sqlite3_malloc( nCellKey );
|
pCellKey = sqlite3_malloc( nCellKey );
|
||||||
if( pCellKey==0 ) return SQLITE_NOMEM;
|
if( pCellKey==0 ) return SQLITE_NOMEM;
|
||||||
rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
|
rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
|
||||||
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
|
c = sqlite3VdbeRecordCompareParsed(nCellKey, pCellKey, pPKey);
|
||||||
sqlite3_free(pCellKey);
|
sqlite3_free(pCellKey);
|
||||||
if( rc ){
|
if( rc ) goto moveto_finish;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( c==0 ){
|
if( c==0 ){
|
||||||
@@ -3681,7 +3662,8 @@ int sqlite3BtreeMoveto(
|
|||||||
break;
|
break;
|
||||||
}else{
|
}else{
|
||||||
if( pRes ) *pRes = 0;
|
if( pRes ) *pRes = 0;
|
||||||
return SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
|
goto moveto_finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( c<0 ){
|
if( c<0 ){
|
||||||
@@ -3706,16 +3688,17 @@ int sqlite3BtreeMoveto(
|
|||||||
if( chldPg==0 ){
|
if( chldPg==0 ){
|
||||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||||
if( pRes ) *pRes = c;
|
if( pRes ) *pRes = c;
|
||||||
return SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
|
goto moveto_finish;
|
||||||
}
|
}
|
||||||
pCur->idx = lwr;
|
pCur->idx = lwr;
|
||||||
pCur->info.nSize = 0;
|
pCur->info.nSize = 0;
|
||||||
rc = moveToChild(pCur, chldPg);
|
rc = moveToChild(pCur, chldPg);
|
||||||
if( rc ){
|
if( rc ) goto moveto_finish;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* NOT REACHED */
|
moveto_finish:
|
||||||
|
sqlite3VdbeRecordUnparse(pPKey);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
13
src/btree.h
13
src/btree.h
@@ -13,7 +13,7 @@
|
|||||||
** subsystem. See comments in the source code for a detailed description
|
** subsystem. See comments in the source code for a detailed description
|
||||||
** of what each interface routine does.
|
** of what each interface routine does.
|
||||||
**
|
**
|
||||||
** @(#) $Id: btree.h,v 1.94 2007/12/07 18:55:28 drh Exp $
|
** @(#) $Id: btree.h,v 1.95 2008/03/25 00:22:21 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _BTREE_H_
|
#ifndef _BTREE_H_
|
||||||
#define _BTREE_H_
|
#define _BTREE_H_
|
||||||
@@ -128,12 +128,11 @@ int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
|||||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||||
|
|
||||||
int sqlite3BtreeCursor(
|
int sqlite3BtreeCursor(
|
||||||
Btree*, /* BTree containing table to open */
|
Btree*, /* BTree containing table to open */
|
||||||
int iTable, /* Index of root page */
|
int iTable, /* Index of root page */
|
||||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||||
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
|
struct KeyInfo*, /* First argument to compare function */
|
||||||
void*, /* First argument to compare function */
|
BtCursor **ppCursor /* Returned cursor */
|
||||||
BtCursor **ppCursor /* Returned cursor */
|
|
||||||
);
|
);
|
||||||
|
|
||||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||||
|
@@ -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: btreeInt.h,v 1.17 2008/03/04 17:45:01 mlcreech Exp $
|
** $Id: btreeInt.h,v 1.18 2008/03/25 00:22:21 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
|
||||||
@@ -435,8 +435,7 @@ struct BtCursor {
|
|||||||
Btree *pBtree; /* The Btree to which this cursor belongs */
|
Btree *pBtree; /* The Btree to which this cursor belongs */
|
||||||
BtShared *pBt; /* The BtShared this cursor points to */
|
BtShared *pBt; /* The BtShared this cursor points to */
|
||||||
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
|
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
|
||||||
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
|
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
|
||||||
void *pArg; /* First arg to xCompare() */
|
|
||||||
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->aCell[] */
|
int idx; /* Index of the entry in pPage->aCell[] */
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
** interface, and routines that contribute to loading the database schema
|
** interface, and routines that contribute to loading the database schema
|
||||||
** from disk.
|
** from disk.
|
||||||
**
|
**
|
||||||
** $Id: prepare.c,v 1.80 2008/03/20 14:03:29 drh Exp $
|
** $Id: prepare.c,v 1.81 2008/03/25 00:22:21 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -208,7 +208,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
sqlite3BtreeEnter(pDb->pBt);
|
sqlite3BtreeEnter(pDb->pBt);
|
||||||
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain);
|
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, &curMain);
|
||||||
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
|
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
|
||||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||||
sqlite3BtreeLeave(pDb->pBt);
|
sqlite3BtreeLeave(pDb->pBt);
|
||||||
@@ -446,7 +446,7 @@ static int schemaIsValid(sqlite3 *db){
|
|||||||
Btree *pBt;
|
Btree *pBt;
|
||||||
pBt = db->aDb[iDb].pBt;
|
pBt = db->aDb[iDb].pBt;
|
||||||
if( pBt==0 ) continue;
|
if( pBt==0 ) continue;
|
||||||
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
|
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, &curTemp);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
|
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
|
||||||
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||||
|
@@ -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.91 2008/03/04 17:45:02 mlcreech Exp $
|
** $Id: test3.c,v 1.92 2008/03/25 00:22:21 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "btreeInt.h"
|
#include "btreeInt.h"
|
||||||
@@ -712,7 +712,7 @@ static int btree_cursor(
|
|||||||
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
|
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
|
||||||
if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
|
if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
|
||||||
sqlite3BtreeEnter(pBt);
|
sqlite3BtreeEnter(pBt);
|
||||||
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur);
|
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, &pCur);
|
||||||
sqlite3BtreeLeave(pBt);
|
sqlite3BtreeLeave(pBt);
|
||||||
if( rc ){
|
if( rc ){
|
||||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||||
|
19
src/vdbe.c
19
src/vdbe.c
@@ -43,7 +43,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.715 2008/03/21 17:13:13 drh Exp $
|
** $Id: vdbe.c,v 1.716 2008/03/25 00:22:21 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -2054,9 +2054,8 @@ op_column_out:
|
|||||||
** Convert P2 registers beginning with P1 into a single entry
|
** Convert P2 registers beginning with P1 into a single entry
|
||||||
** suitable for use as a data record in a database table or as a key
|
** suitable for use as a data record in a database table or as a key
|
||||||
** in an index. The details of the format are irrelavant as long as
|
** in an index. The details of the format are irrelavant as long as
|
||||||
** the OP_Column opcode can decode the record later and as long as the
|
** the OP_Column opcode can decode the record later.
|
||||||
** sqlite3VdbeRecordCompare function will correctly compare two encoded
|
** Refer to source code comments for the details of the record
|
||||||
** records. Refer to source code comments for the details of the record
|
|
||||||
** format.
|
** format.
|
||||||
**
|
**
|
||||||
** P4 may be a string that is P1 characters long. The nth character of the
|
** P4 may be a string that is P1 characters long. The nth character of the
|
||||||
@@ -2519,11 +2518,7 @@ case OP_OpenWrite: {
|
|||||||
pCur = allocateCursor(p, i, iDb);
|
pCur = allocateCursor(p, i, iDb);
|
||||||
if( pCur==0 ) goto no_mem;
|
if( pCur==0 ) goto no_mem;
|
||||||
pCur->nullRow = 1;
|
pCur->nullRow = 1;
|
||||||
/* We always provide a key comparison function. If the table being
|
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, &pCur->pCursor);
|
||||||
** opened is of type INTKEY, the comparision function will be ignored. */
|
|
||||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag,
|
|
||||||
sqlite3VdbeRecordCompare, pOp->p4.p,
|
|
||||||
&pCur->pCursor);
|
|
||||||
if( pOp->p4type==P4_KEYINFO ){
|
if( pOp->p4type==P4_KEYINFO ){
|
||||||
pCur->pKeyInfo = pOp->p4.pKeyInfo;
|
pCur->pKeyInfo = pOp->p4.pKeyInfo;
|
||||||
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
|
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
|
||||||
@@ -2625,15 +2620,15 @@ case OP_OpenEphemeral: {
|
|||||||
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
assert( pgno==MASTER_ROOT+1 );
|
assert( pgno==MASTER_ROOT+1 );
|
||||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare,
|
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1,
|
||||||
pOp->p4.z, &pCx->pCursor);
|
(KeyInfo*)pOp->p4.z, &pCx->pCursor);
|
||||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||||
pCx->pKeyInfo->enc = ENC(p->db);
|
pCx->pKeyInfo->enc = ENC(p->db);
|
||||||
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
|
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
|
||||||
}
|
}
|
||||||
pCx->isTable = 0;
|
pCx->isTable = 0;
|
||||||
}else{
|
}else{
|
||||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor);
|
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, &pCx->pCursor);
|
||||||
pCx->isTable = 1;
|
pCx->isTable = 1;
|
||||||
pCx->pIncrKey = &pCx->bogusIncrKey;
|
pCx->pIncrKey = &pCx->bogusIncrKey;
|
||||||
}
|
}
|
||||||
|
@@ -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.126 2008/03/22 01:07:18 drh Exp $
|
** $Id: vdbe.h,v 1.127 2008/03/25 00:22:21 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_VDBE_H_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@@ -34,6 +34,7 @@ typedef struct Vdbe Vdbe;
|
|||||||
*/
|
*/
|
||||||
typedef struct VdbeFunc VdbeFunc;
|
typedef struct VdbeFunc VdbeFunc;
|
||||||
typedef struct Mem Mem;
|
typedef struct Mem Mem;
|
||||||
|
typedef struct VdbeParsedRecord VdbeParsedRecord;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A single instruction of the virtual machine has an opcode
|
** A single instruction of the virtual machine has an opcode
|
||||||
@@ -181,6 +182,11 @@ sqlite3 *sqlite3VdbeDb(Vdbe*);
|
|||||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
|
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
|
||||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||||
|
|
||||||
|
VdbeParsedRecord *sqlite3VdbeRecordParse(KeyInfo*,int,const void*,void*,int);
|
||||||
|
void sqlite3VdbeRecordUnparse(VdbeParsedRecord*);
|
||||||
|
int sqlite3VdbeRecordCompareParsed(int,const void*,VdbeParsedRecord*);
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||||
# define VdbeComment(X) sqlite3VdbeComment X
|
# define VdbeComment(X) sqlite3VdbeComment X
|
||||||
|
@@ -362,7 +362,6 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
|||||||
int sqlite3VdbeIdxKeyCompare(Cursor*,int,const unsigned char*,int*);
|
int sqlite3VdbeIdxKeyCompare(Cursor*,int,const unsigned char*,int*);
|
||||||
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
||||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||||
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
|
|
||||||
int sqlite3VdbeIdxRowidLen(const u8*);
|
int sqlite3VdbeIdxRowidLen(const u8*);
|
||||||
int sqlite3VdbeExec(Vdbe*);
|
int sqlite3VdbeExec(Vdbe*);
|
||||||
int sqlite3VdbeList(Vdbe*);
|
int sqlite3VdbeList(Vdbe*);
|
||||||
|
195
src/vdbeaux.c
195
src/vdbeaux.c
@@ -2130,6 +2130,7 @@ int sqlite3VdbeSerialGet(
|
|||||||
*/
|
*/
|
||||||
#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
|
#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
|
||||||
|
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
** This function compares the two table rows or index records specified by
|
** This function compares the two table rows or index records specified by
|
||||||
** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
|
** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
|
||||||
@@ -2216,6 +2217,190 @@ int sqlite3VdbeRecordCompare(
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of the following structure holds information about a
|
||||||
|
** single index record that has already been parsed out into individual
|
||||||
|
** values.
|
||||||
|
**
|
||||||
|
** A record is an object that contains one or more fields of data.
|
||||||
|
** Records are used to store the content of a table row and to store
|
||||||
|
** the key of an index. A blob encoding of a record is created by
|
||||||
|
** the OP_MakeRecord opcode of the VDBE and is disassemblied by the
|
||||||
|
** OP_Column opcode.
|
||||||
|
**
|
||||||
|
** This structure holds a record that has already been disassembled
|
||||||
|
** into its constitutent fields.
|
||||||
|
*/
|
||||||
|
struct VdbeParsedRecord {
|
||||||
|
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||||
|
u16 nField; /* Number of entries in apMem[] */
|
||||||
|
u8 needFree; /* True if memory obtained from sqlite3_malloc() */
|
||||||
|
u8 needDestroy; /* True if apMem[]s should be destroyed on close */
|
||||||
|
Mem *apMem[1]; /* Values */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Given the nKey-byte encoding of a record in pKey[], parse the
|
||||||
|
** record into a VdbeParsedRecord structure. Return a pointer to
|
||||||
|
** that structure.
|
||||||
|
**
|
||||||
|
** The calling function might provide szSpace bytes of memory
|
||||||
|
** space at pSpace. This space can be used to hold the returned
|
||||||
|
** VDbeParsedRecord structure if it is large enough. If it is
|
||||||
|
** not big enough, space is obtained from sqlite3_malloc().
|
||||||
|
**
|
||||||
|
** The returned structure should be closed by a call to
|
||||||
|
** sqlite3VdbeRecordUnparse().
|
||||||
|
*/
|
||||||
|
VdbeParsedRecord *sqlite3VdbeRecordParse(
|
||||||
|
KeyInfo *pKeyInfo, /* Information about the record format */
|
||||||
|
int nKey, /* Size of the binary record */
|
||||||
|
const void *pKey, /* The binary record */
|
||||||
|
void *pSpace, /* Space available to hold resulting object */
|
||||||
|
int szSpace /* Size of pSpace[] in bytes */
|
||||||
|
){
|
||||||
|
const unsigned char *aKey = (const unsigned char *)pKey;
|
||||||
|
VdbeParsedRecord *p;
|
||||||
|
int nByte;
|
||||||
|
int i, idx, d;
|
||||||
|
u32 szHdr;
|
||||||
|
Mem *pMem;
|
||||||
|
|
||||||
|
nByte = sizeof(*p) + sizeof(Mem*)*pKeyInfo->nField
|
||||||
|
+ sizeof(Mem)*(pKeyInfo->nField+1);
|
||||||
|
if( nByte>szSpace ){
|
||||||
|
p = sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
||||||
|
if( p==0 ) return 0;
|
||||||
|
p->needFree = 1;
|
||||||
|
}else{
|
||||||
|
p = pSpace;
|
||||||
|
p->needFree = 0;
|
||||||
|
}
|
||||||
|
p->pKeyInfo = pKeyInfo;
|
||||||
|
p->nField = pKeyInfo->nField + 1;
|
||||||
|
p->needDestroy = 1;
|
||||||
|
pMem = (Mem*)&p->apMem[pKeyInfo->nField+1];
|
||||||
|
idx = GetVarint(aKey, szHdr);
|
||||||
|
d = szHdr;
|
||||||
|
i = 0;
|
||||||
|
while( idx<szHdr && i<p->nField ){
|
||||||
|
u32 serial_type;
|
||||||
|
|
||||||
|
idx += GetVarint( aKey+idx, serial_type);
|
||||||
|
if( d>=nKey && sqlite3VdbeSerialTypeLen(serial_type)>0 ) break;
|
||||||
|
pMem->enc = pKeyInfo->enc;
|
||||||
|
pMem->db = pKeyInfo->db;
|
||||||
|
pMem->flags = 0;
|
||||||
|
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
|
||||||
|
p->apMem[i++] = pMem++;
|
||||||
|
}
|
||||||
|
p->nField = i;
|
||||||
|
return (void*)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine destroys a VdbeParsedRecord object
|
||||||
|
*/
|
||||||
|
void sqlite3VdbeRecordUnparse(VdbeParsedRecord *p){
|
||||||
|
if( p ){
|
||||||
|
if( p->needDestroy ){
|
||||||
|
int i;
|
||||||
|
for(i=0; i<p->nField; i++){
|
||||||
|
if( p->apMem[i]->flags & MEM_Dyn ){
|
||||||
|
sqlite3VdbeMemRelease(p->apMem[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( p->needFree ){
|
||||||
|
sqlite3_free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function compares the two table rows or index records
|
||||||
|
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
|
||||||
|
** or positive integer if {nKey1, pKey1} is less than, equal to or
|
||||||
|
** greater than pPKey2. The {nKey1, pKey1} key must be a blob
|
||||||
|
** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
|
||||||
|
** key must be a parsed key such as obtained from
|
||||||
|
** sqlite3VdbeParseRecord.
|
||||||
|
**
|
||||||
|
** Key1 and Key2 do not have to contain the same number of fields.
|
||||||
|
** But if the lengths differ, Key2 must be the shorter of the two.
|
||||||
|
**
|
||||||
|
** Historical note: In earlier versions of this routine both Key1
|
||||||
|
** and Key2 were blobs obtained from OP_MakeRecord. But we found
|
||||||
|
** that in typical use the same Key2 would be submitted multiple times
|
||||||
|
** in a row. So an optimization was added to parse the Key2 key
|
||||||
|
** separately and submit the parsed version. In this way, we avoid
|
||||||
|
** parsing the same Key2 multiple times in a row.
|
||||||
|
*/
|
||||||
|
int sqlite3VdbeRecordCompareParsed(
|
||||||
|
int nKey1, const void *pKey1,
|
||||||
|
VdbeParsedRecord *pPKey2
|
||||||
|
){
|
||||||
|
u32 d1; /* Offset into aKey[] of next data element */
|
||||||
|
u32 idx1; /* Offset into aKey[] of next header element */
|
||||||
|
u32 szHdr1; /* Number of bytes in header */
|
||||||
|
int i = 0;
|
||||||
|
int nField;
|
||||||
|
int rc = 0;
|
||||||
|
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
||||||
|
KeyInfo *pKeyInfo;
|
||||||
|
Mem mem1;
|
||||||
|
|
||||||
|
pKeyInfo = pPKey2->pKeyInfo;
|
||||||
|
mem1.enc = pKeyInfo->enc;
|
||||||
|
mem1.db = pKeyInfo->db;
|
||||||
|
mem1.flags = 0;
|
||||||
|
|
||||||
|
idx1 = GetVarint(aKey1, szHdr1);
|
||||||
|
d1 = szHdr1;
|
||||||
|
nField = pKeyInfo->nField;
|
||||||
|
while( idx1<szHdr1 && i<pPKey2->nField ){
|
||||||
|
u32 serial_type1;
|
||||||
|
|
||||||
|
/* Read the serial types for the next element in each key. */
|
||||||
|
idx1 += GetVarint( aKey1+idx1, serial_type1 );
|
||||||
|
if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
|
||||||
|
|
||||||
|
/* Extract the values to be compared.
|
||||||
|
*/
|
||||||
|
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
|
||||||
|
|
||||||
|
/* Do the comparison
|
||||||
|
*/
|
||||||
|
rc = sqlite3MemCompare(&mem1, pPKey2->apMem[i],
|
||||||
|
i<nField ? pKeyInfo->aColl[i] : 0);
|
||||||
|
if( mem1.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
|
||||||
|
if( rc!=0 ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One of the keys ran out of fields, but all the fields up to that point
|
||||||
|
** were equal. If the incrKey flag is true, then the second key is
|
||||||
|
** treated as larger.
|
||||||
|
*/
|
||||||
|
if( rc==0 ){
|
||||||
|
if( pKeyInfo->incrKey ){
|
||||||
|
rc = -1;
|
||||||
|
}else if( !pKeyInfo->prefixIsEqual ){
|
||||||
|
if( d1<nKey1 ){
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
|
||||||
|
&& pKeyInfo->aSortOrder[i] ){
|
||||||
|
rc = -rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The argument is an index entry composed using the OP_MakeRecord opcode.
|
** The argument is an index entry composed using the OP_MakeRecord opcode.
|
||||||
@@ -2285,6 +2470,8 @@ int sqlite3VdbeIdxKeyCompare(
|
|||||||
BtCursor *pCur = pC->pCursor;
|
BtCursor *pCur = pC->pCursor;
|
||||||
int lenRowid;
|
int lenRowid;
|
||||||
Mem m;
|
Mem m;
|
||||||
|
VdbeParsedRecord *pRec;
|
||||||
|
char zSpace[200];
|
||||||
|
|
||||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||||
if( nCellKey<=0 ){
|
if( nCellKey<=0 ){
|
||||||
@@ -2298,7 +2485,13 @@ int sqlite3VdbeIdxKeyCompare(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
|
lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
|
||||||
*res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
|
pRec = sqlite3VdbeRecordParse(pC->pKeyInfo, nKey, pKey,
|
||||||
|
zSpace, sizeof(zSpace));
|
||||||
|
if( pRec==0 ){
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
*res = sqlite3VdbeRecordCompareParsed(m.n-lenRowid, m.z, pRec);
|
||||||
|
sqlite3VdbeRecordUnparse(pRec);
|
||||||
sqlite3VdbeMemRelease(&m);
|
sqlite3VdbeMemRelease(&m);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
1066
test/btree.test
1066
test/btree.test
File diff suppressed because it is too large
Load Diff
502
test/btree2.test
502
test/btree2.test
@@ -1,502 +0,0 @@
|
|||||||
# 2001 September 15
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend
|
|
||||||
#
|
|
||||||
# $Id: btree2.test,v 1.15 2006/03/19 13:00:25 drh Exp $
|
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
if {[info commands btree_open]!=""} {
|
|
||||||
|
|
||||||
# Create a new database file containing no entries. The database should
|
|
||||||
# contain 5 tables:
|
|
||||||
#
|
|
||||||
# 2 The descriptor table
|
|
||||||
# 3 The foreground table
|
|
||||||
# 4 The background table
|
|
||||||
# 5 The long key table
|
|
||||||
# 6 The long data table
|
|
||||||
#
|
|
||||||
# An explanation for what all these tables are used for is provided below.
|
|
||||||
#
|
|
||||||
do_test btree2-1.1 {
|
|
||||||
expr srand(1)
|
|
||||||
file delete -force test2.bt
|
|
||||||
file delete -force test2.bt-journal
|
|
||||||
set ::b [btree_open test2.bt 2000 0]
|
|
||||||
btree_begin_transaction $::b
|
|
||||||
btree_create_table $::b 0
|
|
||||||
} {2}
|
|
||||||
do_test btree2-1.2 {
|
|
||||||
btree_create_table $::b 0
|
|
||||||
} {3}
|
|
||||||
do_test btree2-1.3 {
|
|
||||||
btree_create_table $::b 0
|
|
||||||
} {4}
|
|
||||||
do_test btree2-1.4 {
|
|
||||||
btree_create_table $::b 0
|
|
||||||
} {5}
|
|
||||||
do_test btree2-1.5 {
|
|
||||||
btree_create_table $::b 0
|
|
||||||
} {6}
|
|
||||||
do_test btree2-1.6 {
|
|
||||||
set ::c2 [btree_cursor $::b 2 1]
|
|
||||||
btree_insert $::c2 {one} {1}
|
|
||||||
btree_move_to $::c2 {one}
|
|
||||||
btree_delete $::c2
|
|
||||||
btree_close_cursor $::c2
|
|
||||||
btree_commit $::b
|
|
||||||
btree_integrity_check $::b 1 2 3 4 5 6
|
|
||||||
} {}
|
|
||||||
|
|
||||||
# This test module works by making lots of pseudo-random changes to a
|
|
||||||
# database while simultaneously maintaining an invariant on that database.
|
|
||||||
# Periodically, the script does a sanity check on the database and verifies
|
|
||||||
# that the invariant is satisfied.
|
|
||||||
#
|
|
||||||
# The invariant is as follows:
|
|
||||||
#
|
|
||||||
# 1. The descriptor table always contains 2 enters. An entry keyed by
|
|
||||||
# "N" is the number of elements in the foreground and background tables
|
|
||||||
# combined. The entry keyed by "L" is the number of digits in the keys
|
|
||||||
# for foreground and background tables.
|
|
||||||
#
|
|
||||||
# 2. The union of the foreground an background tables consists of N entries
|
|
||||||
# where each entry has an L-digit key. (Actually, some keys can be longer
|
|
||||||
# than L characters, but they always start with L digits.) The keys
|
|
||||||
# cover all integers between 1 and N. Whenever an entry is added to
|
|
||||||
# the foreground it is removed form the background and vice versa.
|
|
||||||
#
|
|
||||||
# 3. Some entries in the foreground and background tables have keys that
|
|
||||||
# begin with an L-digit number but are followed by additional characters.
|
|
||||||
# For each such entry there is a corresponding entry in the long key
|
|
||||||
# table. The long key table entry has a key which is just the L-digit
|
|
||||||
# number and data which is the length of the key in the foreground and
|
|
||||||
# background tables.
|
|
||||||
#
|
|
||||||
# 4. The data for both foreground and background entries is usually a
|
|
||||||
# short string. But some entries have long data strings. For each
|
|
||||||
# such entries there is an entry in the long data type. The key to
|
|
||||||
# long data table is an L-digit number. (The extension on long keys
|
|
||||||
# is omitted.) The data is the number of charaters in the data of the
|
|
||||||
# foreground or background entry.
|
|
||||||
#
|
|
||||||
# The following function builds a database that satisfies all of the above
|
|
||||||
# invariants.
|
|
||||||
#
|
|
||||||
proc build_db {N L} {
|
|
||||||
for {set i 2} {$i<=6} {incr i} {
|
|
||||||
catch {btree_close_cursor [set ::c$i]}
|
|
||||||
btree_clear_table $::b $i
|
|
||||||
set ::c$i [btree_cursor $::b $i 1]
|
|
||||||
}
|
|
||||||
btree_insert $::c2 N $N
|
|
||||||
btree_insert $::c2 L $L
|
|
||||||
set format %0${L}d
|
|
||||||
for {set i 1} {$i<=$N} {incr i} {
|
|
||||||
set key [format $format $i]
|
|
||||||
set data $key
|
|
||||||
btree_insert $::c3 $key $data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Given a base key number and a length, construct the full text of the key
|
|
||||||
# or data.
|
|
||||||
#
|
|
||||||
proc make_payload {keynum L len} {
|
|
||||||
set key [format %0${L}d $keynum]
|
|
||||||
set r $key
|
|
||||||
set i 1
|
|
||||||
while {[string length $r]<$len} {
|
|
||||||
append r " ($i) $key"
|
|
||||||
incr i
|
|
||||||
}
|
|
||||||
return [string range $r 0 [expr {$len-1}]]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Verify the invariants on the database. Return an empty string on
|
|
||||||
# success or an error message if something is amiss.
|
|
||||||
#
|
|
||||||
proc check_invariants {} {
|
|
||||||
set ck [btree_integrity_check $::b 1 2 3 4 5 6]
|
|
||||||
if {$ck!=""} {
|
|
||||||
puts "\n*** SANITY:\n$ck"
|
|
||||||
exit
|
|
||||||
return $ck
|
|
||||||
}
|
|
||||||
btree_move_to $::c3 {}
|
|
||||||
btree_move_to $::c4 {}
|
|
||||||
btree_move_to $::c2 N
|
|
||||||
set N [btree_data $::c2]
|
|
||||||
btree_move_to $::c2 L
|
|
||||||
set L [btree_data $::c2]
|
|
||||||
set LM1 [expr {$L-1}]
|
|
||||||
for {set i 1} {$i<=$N} {incr i} {
|
|
||||||
set key {}
|
|
||||||
if {![btree_eof $::c3]} {
|
|
||||||
set key [btree_key $::c3]
|
|
||||||
}
|
|
||||||
if {[scan $key %d k]<1} {set k 0}
|
|
||||||
if {$k!=$i} {
|
|
||||||
set key {}
|
|
||||||
if {![btree_eof $::c4]} {
|
|
||||||
set key [btree_key $::c4]
|
|
||||||
}
|
|
||||||
if {[scan $key %d k]<1} {set k 0}
|
|
||||||
if {$k!=$i} {
|
|
||||||
return "Key $i is missing from both foreground and background"
|
|
||||||
}
|
|
||||||
set data [btree_data $::c4]
|
|
||||||
btree_next $::c4
|
|
||||||
} else {
|
|
||||||
set data [btree_data $::c3]
|
|
||||||
btree_next $::c3
|
|
||||||
}
|
|
||||||
set skey [string range $key 0 $LM1]
|
|
||||||
if {[btree_move_to $::c5 $skey]==0} {
|
|
||||||
set keylen [btree_data $::c5]
|
|
||||||
} else {
|
|
||||||
set keylen $L
|
|
||||||
}
|
|
||||||
if {[string length $key]!=$keylen} {
|
|
||||||
return "Key $i is the wrong size.\
|
|
||||||
Is \"$key\" but should be \"[make_payload $k $L $keylen]\""
|
|
||||||
}
|
|
||||||
if {[make_payload $k $L $keylen]!=$key} {
|
|
||||||
return "Key $i has an invalid extension"
|
|
||||||
}
|
|
||||||
if {[btree_move_to $::c6 $skey]==0} {
|
|
||||||
set datalen [btree_data $::c6]
|
|
||||||
} else {
|
|
||||||
set datalen $L
|
|
||||||
}
|
|
||||||
if {[string length $data]!=$datalen} {
|
|
||||||
return "Data for $i is the wrong size.\
|
|
||||||
Is [string length $data] but should be $datalen"
|
|
||||||
}
|
|
||||||
if {[make_payload $k $L $datalen]!=$data} {
|
|
||||||
return "Entry $i has an incorrect data"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Look at all elements in both the foreground and background tables.
|
|
||||||
# Make sure the key is always the same as the prefix of the data.
|
|
||||||
#
|
|
||||||
# This routine was used for hunting bugs. It is not a part of standard
|
|
||||||
# tests.
|
|
||||||
#
|
|
||||||
proc check_data {n key} {
|
|
||||||
global c3 c4
|
|
||||||
incr n -1
|
|
||||||
foreach c [list $c3 $c4] {
|
|
||||||
btree_first $c ;# move_to $c $key
|
|
||||||
set cnt 0
|
|
||||||
while {![btree_eof $c]} {
|
|
||||||
set key [btree_key $c]
|
|
||||||
set data [btree_data $c]
|
|
||||||
if {[string range $key 0 $n] ne [string range $data 0 $n]} {
|
|
||||||
puts "key=[list $key] data=[list $data] n=$n"
|
|
||||||
puts "cursor info = [btree_cursor_info $c]"
|
|
||||||
btree_page_dump $::b [lindex [btree_cursor_info $c] 0]
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
btree_next $c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make random changes to the database such that each change preserves
|
|
||||||
# the invariants. The number of changes is $n*N where N is the parameter
|
|
||||||
# from the descriptor table. Each changes begins with a random key.
|
|
||||||
# the entry with that key is put in the foreground table with probability
|
|
||||||
# $I and it is put in background with probability (1.0-$I). It gets
|
|
||||||
# a long key with probability $K and long data with probability $D.
|
|
||||||
#
|
|
||||||
set chngcnt 0
|
|
||||||
proc random_changes {n I K D} {
|
|
||||||
global chngcnt
|
|
||||||
btree_move_to $::c2 N
|
|
||||||
set N [btree_data $::c2]
|
|
||||||
btree_move_to $::c2 L
|
|
||||||
set L [btree_data $::c2]
|
|
||||||
set LM1 [expr {$L-1}]
|
|
||||||
set total [expr {int($N*$n)}]
|
|
||||||
set format %0${L}d
|
|
||||||
for {set i 0} {$i<$total} {incr i} {
|
|
||||||
set k [expr {int(rand()*$N)+1}]
|
|
||||||
set insert [expr {rand()<=$I}]
|
|
||||||
set longkey [expr {rand()<=$K}]
|
|
||||||
set longdata [expr {rand()<=$D}]
|
|
||||||
if {$longkey} {
|
|
||||||
set x [expr {rand()}]
|
|
||||||
set keylen [expr {int($x*$x*$x*$x*3000)+10}]
|
|
||||||
} else {
|
|
||||||
set keylen $L
|
|
||||||
}
|
|
||||||
set key [make_payload $k $L $keylen]
|
|
||||||
if {$longdata} {
|
|
||||||
set x [expr {rand()}]
|
|
||||||
set datalen [expr {int($x*$x*$x*$x*3000)+10}]
|
|
||||||
} else {
|
|
||||||
set datalen $L
|
|
||||||
}
|
|
||||||
set data [make_payload $k $L $datalen]
|
|
||||||
set basekey [format $format $k]
|
|
||||||
if {[set c [btree_move_to $::c3 $basekey]]==0} {
|
|
||||||
btree_delete $::c3
|
|
||||||
} else {
|
|
||||||
if {$c<0} {btree_next $::c3}
|
|
||||||
if {![btree_eof $::c3]} {
|
|
||||||
if {[string match $basekey* [btree_key $::c3]]} {
|
|
||||||
btree_delete $::c3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if {[set c [btree_move_to $::c4 $basekey]]==0} {
|
|
||||||
btree_delete $::c4
|
|
||||||
} else {
|
|
||||||
if {$c<0} {btree_next $::c4}
|
|
||||||
if {![btree_eof $::c4]} {
|
|
||||||
if {[string match $basekey* [btree_key $::c4]]} {
|
|
||||||
btree_delete $::c4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set kx -1
|
|
||||||
if {![btree_eof $::c4]} {
|
|
||||||
if {[scan [btree_key $::c4] %d kx]<1} {set kx -1}
|
|
||||||
}
|
|
||||||
if {$kx==$k} {
|
|
||||||
btree_delete $::c4
|
|
||||||
}
|
|
||||||
# For debugging - change the "0" to "1" to integrity check after
|
|
||||||
# every change.
|
|
||||||
if 0 {
|
|
||||||
incr chngcnt
|
|
||||||
puts check----$chngcnt
|
|
||||||
set ck [btree_integrity_check $::b 1 2 3 4 5 6]
|
|
||||||
if {$ck!=""} {
|
|
||||||
puts "\nSANITY CHECK FAILED!\n$ck"
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if {$insert} {
|
|
||||||
btree_insert $::c3 $key $data
|
|
||||||
} else {
|
|
||||||
btree_insert $::c4 $key $data
|
|
||||||
}
|
|
||||||
if {$longkey} {
|
|
||||||
btree_insert $::c5 $basekey $keylen
|
|
||||||
} elseif {[btree_move_to $::c5 $basekey]==0} {
|
|
||||||
btree_delete $::c5
|
|
||||||
}
|
|
||||||
if {$longdata} {
|
|
||||||
btree_insert $::c6 $basekey $datalen
|
|
||||||
} elseif {[btree_move_to $::c6 $basekey]==0} {
|
|
||||||
btree_delete $::c6
|
|
||||||
}
|
|
||||||
# For debugging - change the "0" to "1" to integrity check after
|
|
||||||
# every change.
|
|
||||||
if 0 {
|
|
||||||
incr chngcnt
|
|
||||||
puts check----$chngcnt
|
|
||||||
set ck [btree_integrity_check $::b 1 2 3 4 5 6]
|
|
||||||
if {$ck!=""} {
|
|
||||||
puts "\nSANITY CHECK FAILED!\n$ck"
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set btree_trace 0
|
|
||||||
|
|
||||||
# Repeat this test sequence on database of various sizes
|
|
||||||
#
|
|
||||||
set testno 2
|
|
||||||
foreach {N L} {
|
|
||||||
10 2
|
|
||||||
50 2
|
|
||||||
200 3
|
|
||||||
2000 5
|
|
||||||
} {
|
|
||||||
puts "**** N=$N L=$L ****"
|
|
||||||
set hash [md5file test2.bt]
|
|
||||||
do_test btree2-$testno.1 [subst -nocommands {
|
|
||||||
set ::c2 [btree_cursor $::b 2 1]
|
|
||||||
set ::c3 [btree_cursor $::b 3 1]
|
|
||||||
set ::c4 [btree_cursor $::b 4 1]
|
|
||||||
set ::c5 [btree_cursor $::b 5 1]
|
|
||||||
set ::c6 [btree_cursor $::b 6 1]
|
|
||||||
btree_begin_transaction $::b
|
|
||||||
build_db $N $L
|
|
||||||
check_invariants
|
|
||||||
}] {}
|
|
||||||
do_test btree2-$testno.2 {
|
|
||||||
btree_close_cursor $::c2
|
|
||||||
btree_close_cursor $::c3
|
|
||||||
btree_close_cursor $::c4
|
|
||||||
btree_close_cursor $::c5
|
|
||||||
btree_close_cursor $::c6
|
|
||||||
btree_rollback $::b
|
|
||||||
md5file test2.bt
|
|
||||||
} $hash
|
|
||||||
do_test btree2-$testno.3 [subst -nocommands {
|
|
||||||
btree_begin_transaction $::b
|
|
||||||
set ::c2 [btree_cursor $::b 2 1]
|
|
||||||
set ::c3 [btree_cursor $::b 3 1]
|
|
||||||
set ::c4 [btree_cursor $::b 4 1]
|
|
||||||
set ::c5 [btree_cursor $::b 5 1]
|
|
||||||
set ::c6 [btree_cursor $::b 6 1]
|
|
||||||
build_db $N $L
|
|
||||||
check_invariants
|
|
||||||
}] {}
|
|
||||||
do_test btree2-$testno.4 {
|
|
||||||
btree_commit $::b
|
|
||||||
check_invariants
|
|
||||||
} {}
|
|
||||||
do_test btree2-$testno.5 {
|
|
||||||
lindex [btree_pager_stats $::b] 1
|
|
||||||
} {6}
|
|
||||||
do_test btree2-$testno.6 {
|
|
||||||
btree_cursor_info $::c2
|
|
||||||
btree_cursor_info $::c3
|
|
||||||
btree_cursor_info $::c4
|
|
||||||
btree_cursor_info $::c5
|
|
||||||
btree_cursor_info $::c6
|
|
||||||
btree_close_cursor $::c2
|
|
||||||
btree_close_cursor $::c3
|
|
||||||
btree_close_cursor $::c4
|
|
||||||
btree_close_cursor $::c5
|
|
||||||
btree_close_cursor $::c6
|
|
||||||
lindex [btree_pager_stats $::b] 1
|
|
||||||
} {0}
|
|
||||||
do_test btree2-$testno.7 {
|
|
||||||
btree_close $::b
|
|
||||||
} {}
|
|
||||||
|
|
||||||
# For each database size, run various changes tests.
|
|
||||||
#
|
|
||||||
set num2 1
|
|
||||||
foreach {n I K D} {
|
|
||||||
0.5 0.5 0.1 0.1
|
|
||||||
1.0 0.2 0.1 0.1
|
|
||||||
1.0 0.8 0.1 0.1
|
|
||||||
2.0 0.0 0.1 0.1
|
|
||||||
2.0 1.0 0.1 0.1
|
|
||||||
2.0 0.0 0.0 0.0
|
|
||||||
2.0 1.0 0.0 0.0
|
|
||||||
} {
|
|
||||||
set testid btree2-$testno.8.$num2
|
|
||||||
set hash [md5file test2.bt]
|
|
||||||
do_test $testid.0 {
|
|
||||||
set ::b [btree_open test2.bt 2000 0]
|
|
||||||
set ::c2 [btree_cursor $::b 2 1]
|
|
||||||
set ::c3 [btree_cursor $::b 3 1]
|
|
||||||
set ::c4 [btree_cursor $::b 4 1]
|
|
||||||
set ::c5 [btree_cursor $::b 5 1]
|
|
||||||
set ::c6 [btree_cursor $::b 6 1]
|
|
||||||
check_invariants
|
|
||||||
} {}
|
|
||||||
set cnt 6
|
|
||||||
for {set i 2} {$i<=6} {incr i} {
|
|
||||||
if {[lindex [btree_cursor_info [set ::c$i]] 0]!=$i} {incr cnt}
|
|
||||||
}
|
|
||||||
do_test $testid.1 {
|
|
||||||
btree_begin_transaction $::b
|
|
||||||
lindex [btree_pager_stats $::b] 1
|
|
||||||
} $cnt
|
|
||||||
do_test $testid.2 [subst {
|
|
||||||
random_changes $n $I $K $D
|
|
||||||
}] {}
|
|
||||||
do_test $testid.3 {
|
|
||||||
check_invariants
|
|
||||||
} {}
|
|
||||||
do_test $testid.4 {
|
|
||||||
btree_close_cursor $::c2
|
|
||||||
btree_close_cursor $::c3
|
|
||||||
btree_close_cursor $::c4
|
|
||||||
btree_close_cursor $::c5
|
|
||||||
btree_close_cursor $::c6
|
|
||||||
btree_rollback $::b
|
|
||||||
md5file test2.bt
|
|
||||||
} $hash
|
|
||||||
btree_begin_transaction $::b
|
|
||||||
set ::c2 [btree_cursor $::b 2 1]
|
|
||||||
set ::c3 [btree_cursor $::b 3 1]
|
|
||||||
set ::c4 [btree_cursor $::b 4 1]
|
|
||||||
set ::c5 [btree_cursor $::b 5 1]
|
|
||||||
set ::c6 [btree_cursor $::b 6 1]
|
|
||||||
do_test $testid.5 [subst {
|
|
||||||
random_changes $n $I $K $D
|
|
||||||
}] {}
|
|
||||||
do_test $testid.6 {
|
|
||||||
check_invariants
|
|
||||||
} {}
|
|
||||||
do_test $testid.7 {
|
|
||||||
btree_commit $::b
|
|
||||||
check_invariants
|
|
||||||
} {}
|
|
||||||
set hash [md5file test2.bt]
|
|
||||||
do_test $testid.8 {
|
|
||||||
btree_close_cursor $::c2
|
|
||||||
btree_close_cursor $::c3
|
|
||||||
btree_close_cursor $::c4
|
|
||||||
btree_close_cursor $::c5
|
|
||||||
btree_close_cursor $::c6
|
|
||||||
lindex [btree_pager_stats $::b] 1
|
|
||||||
} {0}
|
|
||||||
do_test $testid.9 {
|
|
||||||
btree_close $::b
|
|
||||||
set ::b [btree_open test2.bt 2000 0]
|
|
||||||
set ::c2 [btree_cursor $::b 2 1]
|
|
||||||
set ::c3 [btree_cursor $::b 3 1]
|
|
||||||
set ::c4 [btree_cursor $::b 4 1]
|
|
||||||
set ::c5 [btree_cursor $::b 5 1]
|
|
||||||
set ::c6 [btree_cursor $::b 6 1]
|
|
||||||
check_invariants
|
|
||||||
} {}
|
|
||||||
do_test $testid.10 {
|
|
||||||
btree_close_cursor $::c2
|
|
||||||
btree_close_cursor $::c3
|
|
||||||
btree_close_cursor $::c4
|
|
||||||
btree_close_cursor $::c5
|
|
||||||
btree_close_cursor $::c6
|
|
||||||
lindex [btree_pager_stats $::b] 1
|
|
||||||
} {0}
|
|
||||||
do_test $testid.11 {
|
|
||||||
btree_close $::b
|
|
||||||
} {}
|
|
||||||
incr num2
|
|
||||||
}
|
|
||||||
incr testno
|
|
||||||
set ::b [btree_open test2.bt 2000 0]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Testing is complete. Shut everything down.
|
|
||||||
#
|
|
||||||
do_test btree-999.1 {
|
|
||||||
lindex [btree_pager_stats $::b] 1
|
|
||||||
} {0}
|
|
||||||
do_test btree-999.2 {
|
|
||||||
btree_close $::b
|
|
||||||
} {}
|
|
||||||
do_test btree-999.3 {
|
|
||||||
file delete -force test2.bt
|
|
||||||
file exists test2.bt-journal
|
|
||||||
} {0}
|
|
||||||
|
|
||||||
} ;# end if( not mem: and has pager_open command );
|
|
||||||
|
|
||||||
finish_test
|
|
101
test/btree4.test
101
test/btree4.test
@@ -1,101 +0,0 @@
|
|||||||
# 2002 December 03
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend
|
|
||||||
#
|
|
||||||
# This file focuses on testing the sqliteBtreeNext() and
|
|
||||||
# sqliteBtreePrevious() procedures and making sure they are able
|
|
||||||
# to step through an entire table from either direction.
|
|
||||||
#
|
|
||||||
# $Id: btree4.test,v 1.2 2004/05/09 20:40:12 drh Exp $
|
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
if {[info commands btree_open]!=""} {
|
|
||||||
|
|
||||||
# Open a test database.
|
|
||||||
#
|
|
||||||
file delete -force test1.bt
|
|
||||||
file delete -force test1.bt-journal
|
|
||||||
set b1 [btree_open test1.bt 2000 0]
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
do_test btree4-0.1 {
|
|
||||||
btree_create_table $b1 0
|
|
||||||
} 2
|
|
||||||
|
|
||||||
set data {abcdefghijklmnopqrstuvwxyz0123456789}
|
|
||||||
append data $data
|
|
||||||
append data $data
|
|
||||||
append data $data
|
|
||||||
append data $data
|
|
||||||
|
|
||||||
foreach N {10 100 1000} {
|
|
||||||
btree_clear_table $::b1 2
|
|
||||||
set ::c1 [btree_cursor $::b1 2 1]
|
|
||||||
do_test btree4-$N.1 {
|
|
||||||
for {set i 1} {$i<=$N} {incr i} {
|
|
||||||
btree_insert $::c1 [format k-%05d $i] $::data-$i
|
|
||||||
}
|
|
||||||
btree_first $::c1
|
|
||||||
btree_key $::c1
|
|
||||||
} {k-00001}
|
|
||||||
do_test btree4-$N.2 {
|
|
||||||
btree_data $::c1
|
|
||||||
} $::data-1
|
|
||||||
for {set i 2} {$i<=$N} {incr i} {
|
|
||||||
do_test btree-$N.3.$i.1 {
|
|
||||||
btree_next $::c1
|
|
||||||
} 0
|
|
||||||
do_test btree-$N.3.$i.2 {
|
|
||||||
btree_key $::c1
|
|
||||||
} [format k-%05d $i]
|
|
||||||
do_test btree-$N.3.$i.3 {
|
|
||||||
btree_data $::c1
|
|
||||||
} $::data-$i
|
|
||||||
}
|
|
||||||
do_test btree4-$N.4 {
|
|
||||||
btree_next $::c1
|
|
||||||
} 1
|
|
||||||
do_test btree4-$N.5 {
|
|
||||||
btree_last $::c1
|
|
||||||
} 0
|
|
||||||
do_test btree4-$N.6 {
|
|
||||||
btree_key $::c1
|
|
||||||
} [format k-%05d $N]
|
|
||||||
do_test btree4-$N.7 {
|
|
||||||
btree_data $::c1
|
|
||||||
} $::data-$N
|
|
||||||
for {set i [expr {$N-1}]} {$i>=1} {incr i -1} {
|
|
||||||
do_test btree4-$N.8.$i.1 {
|
|
||||||
btree_prev $::c1
|
|
||||||
} 0
|
|
||||||
do_test btree4-$N.8.$i.2 {
|
|
||||||
btree_key $::c1
|
|
||||||
} [format k-%05d $i]
|
|
||||||
do_test btree4-$N.8.$i.3 {
|
|
||||||
btree_data $::c1
|
|
||||||
} $::data-$i
|
|
||||||
}
|
|
||||||
do_test btree4-$N.9 {
|
|
||||||
btree_prev $::c1
|
|
||||||
} 1
|
|
||||||
btree_close_cursor $::c1
|
|
||||||
}
|
|
||||||
|
|
||||||
btree_rollback $::b1
|
|
||||||
btree_pager_ref_dump $::b1
|
|
||||||
btree_close $::b1
|
|
||||||
|
|
||||||
} ;# end if( not mem: and has pager_open command );
|
|
||||||
|
|
||||||
finish_test
|
|
292
test/btree5.test
292
test/btree5.test
@@ -1,292 +0,0 @@
|
|||||||
# 2004 May 10
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend
|
|
||||||
#
|
|
||||||
# $Id: btree5.test,v 1.5 2004/05/14 12:17:46 drh Exp $
|
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
# Attempting to read table 1 of an empty file gives an SQLITE_EMPTY
|
|
||||||
# error.
|
|
||||||
#
|
|
||||||
do_test btree5-1.1 {
|
|
||||||
file delete -force test1.bt
|
|
||||||
file delete -force test1.bt-journal
|
|
||||||
set rc [catch {btree_open test1.bt 2000 0} ::b1]
|
|
||||||
} {0}
|
|
||||||
do_test btree5-1.2 {
|
|
||||||
set rc [catch {btree_cursor $::b1 1 0} ::c1]
|
|
||||||
} {1}
|
|
||||||
do_test btree5-1.3 {
|
|
||||||
set ::c1
|
|
||||||
} {SQLITE_EMPTY}
|
|
||||||
do_test btree5-1.4 {
|
|
||||||
set rc [catch {btree_cursor $::b1 1 1} ::c1]
|
|
||||||
} {1}
|
|
||||||
do_test btree5-1.5 {
|
|
||||||
set ::c1
|
|
||||||
} {SQLITE_EMPTY}
|
|
||||||
|
|
||||||
# Starting a transaction initializes the first page of the database
|
|
||||||
# and the error goes away.
|
|
||||||
#
|
|
||||||
do_test btree5-1.6 {
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
set rc [catch {btree_cursor $b1 1 0} c1]
|
|
||||||
} {0}
|
|
||||||
do_test btree5-1.7 {
|
|
||||||
btree_first $c1
|
|
||||||
} {1}
|
|
||||||
do_test btree5-1.8 {
|
|
||||||
btree_close_cursor $c1
|
|
||||||
btree_rollback $b1
|
|
||||||
set rc [catch {btree_cursor $b1 1 0} c1]
|
|
||||||
} {1}
|
|
||||||
do_test btree5-1.9 {
|
|
||||||
set c1
|
|
||||||
} {SQLITE_EMPTY}
|
|
||||||
do_test btree5-1.10 {
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
set rc [catch {btree_cursor $b1 1 0} c1]
|
|
||||||
} {0}
|
|
||||||
do_test btree5-1.11 {
|
|
||||||
btree_first $c1
|
|
||||||
} {1}
|
|
||||||
do_test btree5-1.12 {
|
|
||||||
btree_close_cursor $c1
|
|
||||||
btree_commit $b1
|
|
||||||
set rc [catch {btree_cursor $b1 1 0} c1]
|
|
||||||
} {0}
|
|
||||||
do_test btree5-1.13 {
|
|
||||||
btree_first $c1
|
|
||||||
} {1}
|
|
||||||
do_test btree5-1.14 {
|
|
||||||
btree_close_cursor $c1
|
|
||||||
btree_integrity_check $b1 1
|
|
||||||
} {}
|
|
||||||
|
|
||||||
# Insert many entries into table 1. This is designed to test the
|
|
||||||
# virtual-root logic that comes into play for page one. It is also
|
|
||||||
# a good test of INTKEY tables.
|
|
||||||
#
|
|
||||||
# Stagger the inserts. After the inserts complete, go back and do
|
|
||||||
# deletes. Stagger the deletes too. Repeat this several times.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Do N inserts into table 1 using random keys between 0 and 1000000
|
|
||||||
#
|
|
||||||
proc random_inserts {N} {
|
|
||||||
global c1
|
|
||||||
while {$N>0} {
|
|
||||||
set k [expr {int(rand()*1000000)}]
|
|
||||||
if {[btree_move_to $c1 $k]==0} continue; # entry already exists
|
|
||||||
btree_insert $c1 $k data-for-$k
|
|
||||||
incr N -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Do N delete from table 1
|
|
||||||
#
|
|
||||||
proc random_deletes {N} {
|
|
||||||
global c1
|
|
||||||
while {$N>0} {
|
|
||||||
set k [expr {int(rand()*1000000)}]
|
|
||||||
btree_move_to $c1 $k
|
|
||||||
btree_delete $c1
|
|
||||||
incr N -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make sure the table has exactly N entries. Make sure the data for
|
|
||||||
# each entry agrees with its key.
|
|
||||||
#
|
|
||||||
proc check_table {N} {
|
|
||||||
global c1
|
|
||||||
btree_first $c1
|
|
||||||
set cnt 0
|
|
||||||
while {![btree_eof $c1]} {
|
|
||||||
if {[set data [btree_data $c1]] ne "data-for-[btree_key $c1]"} {
|
|
||||||
return "wrong data for entry $cnt"
|
|
||||||
}
|
|
||||||
set n [string length $data]
|
|
||||||
set fdata1 [btree_fetch_data $c1 $n]
|
|
||||||
set fdata2 [btree_fetch_data $c1 -1]
|
|
||||||
if {$fdata1 ne "" && $fdata1 ne $data} {
|
|
||||||
return "DataFetch returned the wrong value with amt=$n"
|
|
||||||
}
|
|
||||||
if {$fdata1 ne $fdata2} {
|
|
||||||
return "DataFetch returned the wrong value when amt=-1"
|
|
||||||
}
|
|
||||||
if {$n>10} {
|
|
||||||
set fdata3 [btree_fetch_data $c1 10]
|
|
||||||
if {$fdata3 ne [string range $data 0 9]} {
|
|
||||||
return "DataFetch returned the wrong value when amt=10"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
incr cnt
|
|
||||||
btree_next $c1
|
|
||||||
}
|
|
||||||
if {$cnt!=$N} {
|
|
||||||
return "wrong number of entries"
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Initialize the database
|
|
||||||
#
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
set c1 [btree_cursor $b1 1 1]
|
|
||||||
set btree_trace 0
|
|
||||||
|
|
||||||
# Do the tests.
|
|
||||||
#
|
|
||||||
set cnt 0
|
|
||||||
for {set i 1} {$i<=100} {incr i} {
|
|
||||||
do_test btree5-2.$i.1 {
|
|
||||||
random_inserts 200
|
|
||||||
incr cnt 200
|
|
||||||
check_table $cnt
|
|
||||||
} {}
|
|
||||||
do_test btree5-2.$i.2 {
|
|
||||||
btree_integrity_check $b1 1
|
|
||||||
} {}
|
|
||||||
do_test btree5-2.$i.3 {
|
|
||||||
random_deletes 190
|
|
||||||
incr cnt -190
|
|
||||||
check_table $cnt
|
|
||||||
} {}
|
|
||||||
do_test btree5-2.$i.4 {
|
|
||||||
btree_integrity_check $b1 1
|
|
||||||
} {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#btree_tree_dump $b1 1
|
|
||||||
btree_close_cursor $c1
|
|
||||||
btree_commit $b1
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
|
|
||||||
# This procedure converts an integer into a variable-length text key.
|
|
||||||
# The conversion is reversible.
|
|
||||||
#
|
|
||||||
# The first two characters of the string are alphabetics derived from
|
|
||||||
# the least significant bits of the number. Because they are derived
|
|
||||||
# from least significant bits, the sort order of the resulting string
|
|
||||||
# is different from numeric order. After the alphabetic prefix comes
|
|
||||||
# the original number. A variable-length suffix follows. The length
|
|
||||||
# of the suffix is based on a hash of the original number.
|
|
||||||
#
|
|
||||||
proc num_to_key {n} {
|
|
||||||
global charset ncharset suffix
|
|
||||||
set c1 [string index $charset [expr {$n%$ncharset}]]
|
|
||||||
set c2 [string index $charset [expr {($n/$ncharset)%$ncharset}]]
|
|
||||||
set nsuf [expr {($n*211)%593}]
|
|
||||||
return $c1$c2-$n-[string range $suffix 0 $nsuf]
|
|
||||||
}
|
|
||||||
set charset {abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ}
|
|
||||||
set ncharset [string length $charset]
|
|
||||||
set suffix $charset$charset
|
|
||||||
while {[string length $suffix]<1000} {append suffix $suffix}
|
|
||||||
|
|
||||||
# This procedures extracts the original integer used to create
|
|
||||||
# a key by num_to_key
|
|
||||||
#
|
|
||||||
proc key_to_num {key} {
|
|
||||||
regexp {^..-([0-9]+)} $key all n
|
|
||||||
return $n
|
|
||||||
}
|
|
||||||
|
|
||||||
# Insert into table $tab keys corresponding to all values between
|
|
||||||
# $start and $end, inclusive.
|
|
||||||
#
|
|
||||||
proc insert_range {tab start end} {
|
|
||||||
for {set i $start} {$i<=$end} {incr i} {
|
|
||||||
btree_insert $tab [num_to_key $i] {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Delete from table $tab keys corresponding to all values between
|
|
||||||
# $start and $end, inclusive.
|
|
||||||
#
|
|
||||||
proc delete_range {tab start end} {
|
|
||||||
for {set i $start} {$i<=$end} {incr i} {
|
|
||||||
if {[btree_move_to $tab [num_to_key $i]]==0} {
|
|
||||||
btree_delete $tab
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make sure table $tab contains exactly those keys corresponding
|
|
||||||
# to values between $start and $end
|
|
||||||
#
|
|
||||||
proc check_range {tab start end} {
|
|
||||||
btree_first $tab
|
|
||||||
while {![btree_eof $tab]} {
|
|
||||||
set key [btree_key $tab]
|
|
||||||
set i [key_to_num $key]
|
|
||||||
if {[num_to_key $i] ne $key} {
|
|
||||||
return "malformed key: $key"
|
|
||||||
}
|
|
||||||
set got($i) 1
|
|
||||||
btree_next $tab
|
|
||||||
}
|
|
||||||
set all [lsort -integer [array names got]]
|
|
||||||
if {[llength $all]!=$end+1-$start} {
|
|
||||||
return "table contains wrong number of values"
|
|
||||||
}
|
|
||||||
if {[lindex $all 0]!=$start} {
|
|
||||||
return "wrong starting value"
|
|
||||||
}
|
|
||||||
if {[lindex $all end]!=$end} {
|
|
||||||
return "wrong ending value"
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create a zero-data table and test it out.
|
|
||||||
#
|
|
||||||
do_test btree5-3.1 {
|
|
||||||
set rc [catch {btree_create_table $b1 2} t2]
|
|
||||||
} {0}
|
|
||||||
do_test btree5-3.2 {
|
|
||||||
set rc [catch {btree_cursor $b1 $t2 1} c2]
|
|
||||||
} {0}
|
|
||||||
set start 1
|
|
||||||
set end 100
|
|
||||||
for {set i 1} {$i<=100} {incr i} {
|
|
||||||
do_test btree5-3.3.$i.1 {
|
|
||||||
insert_range $c2 $start $end
|
|
||||||
btree_integrity_check $b1 1 $t2
|
|
||||||
} {}
|
|
||||||
do_test btree5-3.3.$i.2 {
|
|
||||||
check_range $c2 $start $end
|
|
||||||
} {}
|
|
||||||
set nstart $start
|
|
||||||
incr nstart 89
|
|
||||||
do_test btree5-3.3.$i.3 {
|
|
||||||
delete_range $c2 $start $nstart
|
|
||||||
btree_integrity_check $b1 1 $t2
|
|
||||||
} {}
|
|
||||||
incr start 90
|
|
||||||
do_test btree5-3.3.$i.4 {
|
|
||||||
check_range $c2 $start $end
|
|
||||||
} {}
|
|
||||||
incr end 100
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btree_close_cursor $c2
|
|
||||||
btree_commit $b1
|
|
||||||
btree_close $b1
|
|
||||||
|
|
||||||
finish_test
|
|
128
test/btree6.test
128
test/btree6.test
@@ -1,128 +0,0 @@
|
|||||||
# 2004 May 10
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend - specifically
|
|
||||||
# the B+tree tables. B+trees store all data on the leaves rather
|
|
||||||
# that storing data with keys on interior nodes.
|
|
||||||
#
|
|
||||||
# $Id: btree6.test,v 1.4 2004/05/20 22:16:31 drh Exp $
|
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
|
|
||||||
# Insert many entries into the table that cursor $cur points to.
|
|
||||||
# The table should be an INTKEY table.
|
|
||||||
#
|
|
||||||
# Stagger the inserts. After the inserts complete, go back and do
|
|
||||||
# deletes. Stagger the deletes too. Repeat this several times.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Do N inserts into table $tab using random keys between 0 and 1000000
|
|
||||||
#
|
|
||||||
proc random_inserts {cur N} {
|
|
||||||
global inscnt
|
|
||||||
while {$N>0} {
|
|
||||||
set k [expr {int(rand()*1000000)}]
|
|
||||||
if {[btree_move_to $cur $k]==0} {
|
|
||||||
continue; # entry already exists
|
|
||||||
}
|
|
||||||
incr inscnt
|
|
||||||
btree_insert $cur $k data-for-$k
|
|
||||||
incr N -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set inscnt 0
|
|
||||||
|
|
||||||
# Do N delete from the table that $cur points to.
|
|
||||||
#
|
|
||||||
proc random_deletes {cur N} {
|
|
||||||
while {$N>0} {
|
|
||||||
set k [expr {int(rand()*1000000)}]
|
|
||||||
btree_move_to $cur $k
|
|
||||||
btree_delete $cur
|
|
||||||
incr N -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make sure the table that $cur points to has exactly N entries.
|
|
||||||
# Make sure the data for each entry agrees with its key.
|
|
||||||
#
|
|
||||||
proc check_table {cur N} {
|
|
||||||
btree_first $cur
|
|
||||||
set cnt 0
|
|
||||||
while {![btree_eof $cur]} {
|
|
||||||
if {[set data [btree_data $cur]] ne "data-for-[btree_key $cur]"} {
|
|
||||||
return "wrong data for entry $cnt"
|
|
||||||
}
|
|
||||||
set n [string length $data]
|
|
||||||
set fdata1 [btree_fetch_data $cur $n]
|
|
||||||
set fdata2 [btree_fetch_data $cur -1]
|
|
||||||
if {$fdata1 ne "" && $fdata1 ne $data} {
|
|
||||||
return "DataFetch returned the wrong value with amt=$n"
|
|
||||||
}
|
|
||||||
if {$fdata1 ne $fdata2} {
|
|
||||||
return "DataFetch returned the wrong value when amt=-1"
|
|
||||||
}
|
|
||||||
if {$n>10} {
|
|
||||||
set fdata3 [btree_fetch_data $cur 10]
|
|
||||||
if {$fdata3 ne [string range $data 0 9]} {
|
|
||||||
return "DataFetch returned the wrong value when amt=10"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
incr cnt
|
|
||||||
btree_next $cur
|
|
||||||
}
|
|
||||||
if {$cnt!=$N} {
|
|
||||||
return "wrong number of entries. Got $cnt. Looking for $N"
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Initialize the database
|
|
||||||
#
|
|
||||||
file delete -force test1.bt
|
|
||||||
file delete -force test1.bt-journal
|
|
||||||
set b1 [btree_open test1.bt 2000 0]
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
set tab [btree_create_table $b1 5]
|
|
||||||
set cur [btree_cursor $b1 $tab 1]
|
|
||||||
set btree_trace 0
|
|
||||||
expr srand(1)
|
|
||||||
|
|
||||||
# Do the tests.
|
|
||||||
#
|
|
||||||
set cnt 0
|
|
||||||
for {set i 1} {$i<=40} {incr i} {
|
|
||||||
do_test btree6-1.$i.1 {
|
|
||||||
random_inserts $cur 200
|
|
||||||
incr cnt 200
|
|
||||||
check_table $cur $cnt
|
|
||||||
} {}
|
|
||||||
do_test btree6-1.$i.2 {
|
|
||||||
btree_integrity_check $b1 1 $tab
|
|
||||||
} {}
|
|
||||||
do_test btree6-1.$i.3 {
|
|
||||||
random_deletes $cur 90
|
|
||||||
incr cnt -90
|
|
||||||
check_table $cur $cnt
|
|
||||||
} {}
|
|
||||||
do_test btree6-1.$i.4 {
|
|
||||||
btree_integrity_check $b1 1 $tab
|
|
||||||
} {}
|
|
||||||
}
|
|
||||||
|
|
||||||
btree_close_cursor $cur
|
|
||||||
btree_commit $b1
|
|
||||||
btree_close $b1
|
|
||||||
|
|
||||||
finish_test
|
|
@@ -1,50 +0,0 @@
|
|||||||
# 2004 Jun 4
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend.
|
|
||||||
#
|
|
||||||
# $Id: btree7.test,v 1.2 2004/11/04 14:47:13 drh Exp $
|
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
# Stress the balance routine by trying to create situations where
|
|
||||||
# 3 neighboring nodes split into 5.
|
|
||||||
#
|
|
||||||
set bigdata _123456789 ;# 10
|
|
||||||
append bigdata $bigdata ;# 20
|
|
||||||
append bigdata $bigdata ;# 40
|
|
||||||
append bigdata $bigdata ;# 80
|
|
||||||
append bigdata $bigdata ;# 160
|
|
||||||
append bigdata $bigdata ;# 320
|
|
||||||
append bigdata $bigdata ;# 640
|
|
||||||
set data450 [string range $bigdata 0 449]
|
|
||||||
do_test btree7-1.1 {
|
|
||||||
execsql "
|
|
||||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
|
|
||||||
INSERT INTO t1 VALUES(1, '$bigdata');
|
|
||||||
INSERT INTO t1 VALUES(2, '$bigdata');
|
|
||||||
INSERT INTO t1 VALUES(3, '$data450');
|
|
||||||
INSERT INTO t1 VALUES(5, '$data450');
|
|
||||||
INSERT INTO t1 VALUES(8, '$bigdata');
|
|
||||||
INSERT INTO t1 VALUES(9, '$bigdata');
|
|
||||||
"
|
|
||||||
} {}
|
|
||||||
integrity_check btree7-1.2
|
|
||||||
do_test btree7-1.3 {
|
|
||||||
execsql "
|
|
||||||
INSERT INTO t1 VALUES(4, '$bigdata');
|
|
||||||
"
|
|
||||||
} {}
|
|
||||||
integrity_check btree7-1.4
|
|
||||||
|
|
||||||
finish_test
|
|
@@ -1,43 +0,0 @@
|
|||||||
# 2005 August 2
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend.
|
|
||||||
#
|
|
||||||
# $Id: btree8.test,v 1.6 2005/08/02 17:13:12 drh Exp $
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
# Ticket #1346: If the table rooted on page 1 contains a single entry
|
|
||||||
# and that single entries has to flow out into another page because
|
|
||||||
# page 1 is 100-bytes smaller than most other pages, then you delete that
|
|
||||||
# one entry, everything should still work.
|
|
||||||
#
|
|
||||||
do_test btree8-1.1 {
|
|
||||||
execsql {
|
|
||||||
CREATE TABLE t1(x
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
);
|
|
||||||
DROP table t1;
|
|
||||||
}
|
|
||||||
} {}
|
|
||||||
integrity_check btree8-1.2
|
|
@@ -1,49 +0,0 @@
|
|||||||
# 2007 May 01
|
|
||||||
#
|
|
||||||
# The author disclaims copyright to this source code. In place of
|
|
||||||
# a legal notice, here is a blessing:
|
|
||||||
#
|
|
||||||
# May you do good and not evil.
|
|
||||||
# May you find forgiveness for yourself and forgive others.
|
|
||||||
# May you share freely, never taking more than you give.
|
|
||||||
#
|
|
||||||
#***********************************************************************
|
|
||||||
# This file implements regression tests for SQLite library. The
|
|
||||||
# focus of this script is btree database backend.
|
|
||||||
#
|
|
||||||
# $Id: btree9.test,v 1.1 2007/05/02 01:34:32 drh Exp $
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
|
||||||
source $testdir/tester.tcl
|
|
||||||
|
|
||||||
# The sqlite3BtreeInsert() API now has an additional "nZero" parameter
|
|
||||||
# which specifies the number of zero bytes to append to the end of the
|
|
||||||
# data. This feature allows large zero-filled BLOBs to be created without
|
|
||||||
# having to allocate a big chunk of memory to instantiate the blob.
|
|
||||||
#
|
|
||||||
# The following code tests the new feature.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Create the database
|
|
||||||
#
|
|
||||||
do_test btree9-1.1 {
|
|
||||||
file delete -force test1.bt
|
|
||||||
file delete -force test1.bt-journal
|
|
||||||
set b1 [btree_open test1.bt 2000 0]
|
|
||||||
btree_begin_transaction $b1
|
|
||||||
set t1 [btree_create_table $b1 5]
|
|
||||||
set c1 [btree_cursor $b1 $t1 1]
|
|
||||||
btree_insert $c1 1 data-for-1 20000
|
|
||||||
btree_move_to $c1 1
|
|
||||||
btree_key $c1
|
|
||||||
} {1}
|
|
||||||
do_test btree9-1.2 {
|
|
||||||
btree_payload_size $c1
|
|
||||||
} {20010}
|
|
||||||
|
|
||||||
|
|
||||||
btree_close_cursor $c1
|
|
||||||
btree_commit $b1
|
|
||||||
btree_close $b1
|
|
||||||
|
|
||||||
finish_test
|
|
@@ -6,7 +6,7 @@
|
|||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
# This file runs all tests.
|
# This file runs all tests.
|
||||||
#
|
#
|
||||||
# $Id: quick.test,v 1.72 2008/03/22 01:08:01 drh Exp $
|
# $Id: quick.test,v 1.73 2008/03/25 00:22:22 drh Exp $
|
||||||
|
|
||||||
proc lshift {lvar} {
|
proc lshift {lvar} {
|
||||||
upvar $lvar l
|
upvar $lvar l
|
||||||
@@ -39,11 +39,6 @@ set EXCLUDE {
|
|||||||
all.test
|
all.test
|
||||||
async.test
|
async.test
|
||||||
async2.test
|
async2.test
|
||||||
btree2.test
|
|
||||||
btree3.test
|
|
||||||
btree4.test
|
|
||||||
btree5.test
|
|
||||||
btree6.test
|
|
||||||
corrupt.test
|
corrupt.test
|
||||||
crash.test
|
crash.test
|
||||||
crash2.test
|
crash2.test
|
||||||
|
Reference in New Issue
Block a user