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:
parent
f84ddc183d
commit
1e968a0cbf
38
manifest
38
manifest
@ -1,5 +1,5 @@
|
||||
C Improved\sdocumentation\sof\ssqlite3_blob_open().\s(CVS\s4910)
|
||||
D 2008-03-24T12:51:46
|
||||
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-25T00:22:21
|
||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||
F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -86,9 +86,9 @@ F src/attach.c bdc75e759ca25a16f4dc7fbdbc6d37ad2561bb24
|
||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||
F src/bitvec.c 49817d442e51e4123585f3cf3c2afc293a3c91e2
|
||||
F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2
|
||||
F src/btree.c 15424f41344ad96ab56a3322f5930cfb7a8ee24e
|
||||
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
|
||||
F src/btreeInt.h d7d2f4d9d7f2e72c455326d48b2b478b842a81f6
|
||||
F src/btree.c 984962aa403be49d79784f01cc9887d16cd841ed
|
||||
F src/btree.h ca065a5910e6dd3b91b88ff9d729450a8b8eda1f
|
||||
F src/btreeInt.h c2deca3e778e2a1e6196343b8087a868f4faa19a
|
||||
F src/build.c 31ed5af4e8ac40c30bb0f88d7fec75e72cc16e0e
|
||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||
@ -132,7 +132,7 @@ F src/pager.c 22241b59c80ca083a96816df434adb8c097afcd4
|
||||
F src/pager.h b1e2258f03878c14b06a95bfa362e8c5c9638170
|
||||
F src/parse.y b0ee84d94218046ea88c2a6561005710d127ca7d
|
||||
F src/pragma.c f64eed914518c28d1863356163dea1e6f58e28f2
|
||||
F src/prepare.c 1b71b5d43ba3d88f2d3c2a6d084f28ac209df956
|
||||
F src/prepare.c f7fc2eb7418dcaa63e22b66c5ecf478e658ecd8f
|
||||
F src/printf.c 05d2b44d7b5b80c8a4a09108ddad9c20e254370d
|
||||
F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a
|
||||
F src/select.c 35063b078beafe9aa35344a8ce039210920d7fea
|
||||
@ -146,7 +146,7 @@ F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a
|
||||
F src/tclsqlite.c d42912617d4734b8f9195416badf5b27e512ded2
|
||||
F src/test1.c 342a2628310fa709074d979e695a28a3bb570834
|
||||
F src/test2.c f0808cc643528b9620e4059ca9bda8346f526121
|
||||
F src/test3.c 5c7452038ab27aa698070799b10132f26cdd2a80
|
||||
F src/test3.c 9bf750645412effca0b2567b8b833e1e91377b47
|
||||
F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071
|
||||
F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4
|
||||
F src/test6.c 62281c0a9ac0265e579065942f7de4e080f8eb05
|
||||
@ -174,11 +174,11 @@ F src/update.c d2c59643af98f966c2a04d392463089b715ca18f
|
||||
F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4
|
||||
F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2
|
||||
F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30
|
||||
F src/vdbe.c 43b261f50be60c758430a9072f960715f2ff0852
|
||||
F src/vdbe.h 93acc03fe8002173cb6affad2bf5d5c5305ba229
|
||||
F src/vdbeInt.h 76c81d057a39813de0fda3cad1498655d53ec69d
|
||||
F src/vdbe.c d81771c67e67f9a25af1d53e5c22299becef1322
|
||||
F src/vdbe.h 0fef6798be121ed2b5a547a5cb85e0824ec3971f
|
||||
F src/vdbeInt.h 4bbec80d55d179ab8438ac9822416d9111638919
|
||||
F src/vdbeapi.c b9e9d7a58690c1e1ae66de7232edccf4793ad817
|
||||
F src/vdbeaux.c 82f3c8913e68b4928de28c3fa117464356d59df6
|
||||
F src/vdbeaux.c f3ee532bfdf191f0d2a8c4d1a50816cdd1a235d2
|
||||
F src/vdbeblob.c 63c750acc7b5012479f508c0e9627372a82cb65d
|
||||
F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736
|
||||
F src/vdbemem.c 67662aac917b627356262f9501591206db2a8845
|
||||
@ -215,14 +215,6 @@ F test/bind.test 261fd1603613e7f877a516d29f281c9d8c2ecf52
|
||||
F test/bindxfer.test 995d2cf8df61204d748cde6960443121c4ccd2e1
|
||||
F test/bitvec.test 62a512c3f7041d1df12558eb25990e5a19820571
|
||||
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/cache.test 3ff445c445742a7b6b9ba6e1d62a25263f9424b9
|
||||
F test/capi2.test cc64df7560a96f848f919ea2926c60acf639684b
|
||||
@ -419,7 +411,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test c3405535b418d454e8a52196a0fc592ec9eec58d
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
||||
F test/ptrchng.test 83150cb7b513e33cce90fdc68f4b1817551857c0
|
||||
F test/quick.test 037a953ccc4e5419c89528e7b93742db29bc3ec1
|
||||
F test/quick.test fcd8fb7aeee4b8bc7a5be56c25104f6f39258eb1
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
|
||||
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
||||
@ -625,7 +617,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P a807e7184b857414ce203af129ac1adf2012096c
|
||||
R 4101d535e06a9619e1c68b648b338bf6
|
||||
P 1ed695f560a58786f2a8467c601f281c67034fd4
|
||||
R 4b7a149e165aca7212e2405c0ae3196c
|
||||
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.
|
||||
**
|
||||
*************************************************************************
|
||||
** $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.
|
||||
** See the header comment on "btreeInt.h" for additional information.
|
||||
@ -2649,23 +2649,6 @@ int sqlite3BtreeRollbackStmt(Btree *p){
|
||||
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
|
||||
** 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
|
||||
** root page of a b-tree. If it is not, then the cursor acquired
|
||||
** 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(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
|
||||
void *pArg, /* First arg to xCompare() */
|
||||
BtCursor **ppCur /* Write new cursor here */
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||
BtCursor **ppCur /* Write new cursor here */
|
||||
){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
@ -2750,8 +2726,7 @@ static int btreeCursor(
|
||||
** variables, link the cursor into the BtShared list and set *ppCur (the
|
||||
** output argument to this function).
|
||||
*/
|
||||
pCur->xCompare = xCmp ? xCmp : dfltCompare;
|
||||
pCur->pArg = pArg;
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
pCur->pBtree = p;
|
||||
pCur->pBt = pBt;
|
||||
pCur->wrFlag = wrFlag;
|
||||
@ -2774,17 +2749,16 @@ create_cursor_exception:
|
||||
return rc;
|
||||
}
|
||||
int sqlite3BtreeCursor(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
|
||||
void *pArg, /* First arg to xCompare() */
|
||||
BtCursor **ppCur /* Write new cursor here */
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
||||
BtCursor **ppCur /* Write new cursor here */
|
||||
){
|
||||
int rc;
|
||||
sqlite3BtreeEnter(p);
|
||||
p->pBt->db = p->db;
|
||||
rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur);
|
||||
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, ppCur);
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
}
|
||||
@ -3578,8 +3552,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
**
|
||||
** For INTKEY tables, only the nKey parameter is used. pKey is
|
||||
** ignored. For other tables, nKey is the number of bytes of data
|
||||
** in pKey. The comparison function specified when the cursor was
|
||||
** created is used to compare keys.
|
||||
** in pKey.
|
||||
**
|
||||
** 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
|
||||
@ -3609,6 +3582,8 @@ int sqlite3BtreeMoveto(
|
||||
int *pRes /* Search result flag */
|
||||
){
|
||||
int rc;
|
||||
VdbeParsedRecord *pPKey;
|
||||
char aSpace[200];
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
@ -3623,6 +3598,13 @@ int sqlite3BtreeMoveto(
|
||||
assert( pCur->pPage->nCell==0 );
|
||||
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(;;){
|
||||
int lwr, upr;
|
||||
Pgno chldPg;
|
||||
@ -3631,7 +3613,8 @@ int sqlite3BtreeMoveto(
|
||||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
if( !pPage->intKey && pKey==0 ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
if( biasRight ){
|
||||
pCur->idx = upr;
|
||||
@ -3662,16 +3645,14 @@ int sqlite3BtreeMoveto(
|
||||
pCellKey = (void *)fetchPayload(pCur, &available, 0);
|
||||
nCellKey = pCur->info.nKey;
|
||||
if( available>=nCellKey ){
|
||||
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
|
||||
c = sqlite3VdbeRecordCompareParsed(nCellKey, pCellKey, pPKey);
|
||||
}else{
|
||||
pCellKey = sqlite3_malloc( nCellKey );
|
||||
if( pCellKey==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
|
||||
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
|
||||
c = sqlite3VdbeRecordCompareParsed(nCellKey, pCellKey, pPKey);
|
||||
sqlite3_free(pCellKey);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
if( rc ) goto moveto_finish;
|
||||
}
|
||||
}
|
||||
if( c==0 ){
|
||||
@ -3681,7 +3662,8 @@ int sqlite3BtreeMoveto(
|
||||
break;
|
||||
}else{
|
||||
if( pRes ) *pRes = 0;
|
||||
return SQLITE_OK;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
}
|
||||
}
|
||||
if( c<0 ){
|
||||
@ -3706,16 +3688,17 @@ int sqlite3BtreeMoveto(
|
||||
if( chldPg==0 ){
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
if( pRes ) *pRes = c;
|
||||
return SQLITE_OK;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->idx = lwr;
|
||||
pCur->info.nSize = 0;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
if( rc ) goto moveto_finish;
|
||||
}
|
||||
/* 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
|
||||
** 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_
|
||||
#define _BTREE_H_
|
||||
@ -128,12 +128,11 @@ int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
|
||||
void*, /* First argument to compare function */
|
||||
BtCursor **ppCursor /* Returned cursor */
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
struct KeyInfo*, /* First argument to compare function */
|
||||
BtCursor **ppCursor /* Returned cursor */
|
||||
);
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
|
@ -9,7 +9,7 @@
|
||||
** 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.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@ -435,8 +435,7 @@ struct BtCursor {
|
||||
Btree *pBtree; /* The Btree to which this cursor belongs */
|
||||
BtShared *pBt; /* The BtShared this cursor points to */
|
||||
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
|
||||
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
|
||||
void *pArg; /* First arg to xCompare() */
|
||||
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
MemPage *pPage; /* Page that contains the entry */
|
||||
int idx; /* Index of the entry in pPage->aCell[] */
|
||||
|
@ -13,7 +13,7 @@
|
||||
** interface, and routines that contribute to loading the database schema
|
||||
** 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 <ctype.h>
|
||||
@ -208,7 +208,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
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 ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
@ -446,7 +446,7 @@ static int schemaIsValid(sqlite3 *db){
|
||||
Btree *pBt;
|
||||
pBt = db->aDb[iDb].pBt;
|
||||
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 ){
|
||||
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&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
|
||||
** 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 "btreeInt.h"
|
||||
@ -712,7 +712,7 @@ static int btree_cursor(
|
||||
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
|
||||
if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
|
||||
sqlite3BtreeEnter(pBt);
|
||||
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur);
|
||||
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, &pCur);
|
||||
sqlite3BtreeLeave(pBt);
|
||||
if( rc ){
|
||||
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
|
||||
** 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 <ctype.h>
|
||||
@ -2054,9 +2054,8 @@ op_column_out:
|
||||
** 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
|
||||
** 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
|
||||
** sqlite3VdbeRecordCompare function will correctly compare two encoded
|
||||
** records. Refer to source code comments for the details of the record
|
||||
** the OP_Column opcode can decode the record later.
|
||||
** Refer to source code comments for the details of the record
|
||||
** format.
|
||||
**
|
||||
** 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);
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->nullRow = 1;
|
||||
/* We always provide a key comparison function. If the table being
|
||||
** opened is of type INTKEY, the comparision function will be ignored. */
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag,
|
||||
sqlite3VdbeRecordCompare, pOp->p4.p,
|
||||
&pCur->pCursor);
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, &pCur->pCursor);
|
||||
if( pOp->p4type==P4_KEYINFO ){
|
||||
pCur->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
|
||||
@ -2625,15 +2620,15 @@ case OP_OpenEphemeral: {
|
||||
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pgno==MASTER_ROOT+1 );
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare,
|
||||
pOp->p4.z, &pCx->pCursor);
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1,
|
||||
(KeyInfo*)pOp->p4.z, &pCx->pCursor);
|
||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
pCx->pKeyInfo->enc = ENC(p->db);
|
||||
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
|
||||
}
|
||||
pCx->isTable = 0;
|
||||
}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->pIncrKey = &pCx->bogusIncrKey;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** 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_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -34,6 +34,7 @@ typedef struct Vdbe Vdbe;
|
||||
*/
|
||||
typedef struct VdbeFunc VdbeFunc;
|
||||
typedef struct Mem Mem;
|
||||
typedef struct VdbeParsedRecord VdbeParsedRecord;
|
||||
|
||||
/*
|
||||
** 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 sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
|
||||
VdbeParsedRecord *sqlite3VdbeRecordParse(KeyInfo*,int,const void*,void*,int);
|
||||
void sqlite3VdbeRecordUnparse(VdbeParsedRecord*);
|
||||
int sqlite3VdbeRecordCompareParsed(int,const void*,VdbeParsedRecord*);
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
# 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 sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
|
||||
int sqlite3VdbeIdxRowidLen(const u8*);
|
||||
int sqlite3VdbeExec(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))
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** This function compares the two table rows or index records specified by
|
||||
** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
|
||||
@ -2216,6 +2217,190 @@ int sqlite3VdbeRecordCompare(
|
||||
|
||||
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.
|
||||
@ -2285,6 +2470,8 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
BtCursor *pCur = pC->pCursor;
|
||||
int lenRowid;
|
||||
Mem m;
|
||||
VdbeParsedRecord *pRec;
|
||||
char zSpace[200];
|
||||
|
||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
if( nCellKey<=0 ){
|
||||
@ -2298,7 +2485,13 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
return rc;
|
||||
}
|
||||
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);
|
||||
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.
|
||||
#
|
||||
# $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} {
|
||||
upvar $lvar l
|
||||
@ -39,11 +39,6 @@ set EXCLUDE {
|
||||
all.test
|
||||
async.test
|
||||
async2.test
|
||||
btree2.test
|
||||
btree3.test
|
||||
btree4.test
|
||||
btree5.test
|
||||
btree6.test
|
||||
corrupt.test
|
||||
crash.test
|
||||
crash2.test
|
||||
|
Loading…
Reference in New Issue
Block a user