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:
drh 2008-03-25 00:22:21 +00:00
parent f84ddc183d
commit 1e968a0cbf
20 changed files with 274 additions and 2344 deletions

View File

@ -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

View File

@ -1 +1 @@
1ed695f560a58786f2a8467c601f281c67034fd4
0e1d84f2f456e7680bb667266745b629ddf3605f

View File

@ -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;
}

View File

@ -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*);

View File

@ -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[] */

View File

@ -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 ){

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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*);

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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