mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
More BTree tests (CVS 233)
FossilOrigin-Name: 55c89bfdd35f1ad494618a451f9a1ed08502ae07
This commit is contained in:
@@ -84,7 +84,8 @@ SRC = \
|
|||||||
TESTSRC = \
|
TESTSRC = \
|
||||||
$(TOP)/src/test1.c \
|
$(TOP)/src/test1.c \
|
||||||
$(TOP)/src/test2.c \
|
$(TOP)/src/test2.c \
|
||||||
$(TOP)/src/test3.c
|
$(TOP)/src/test3.c \
|
||||||
|
$(TOP)/src/md5.c
|
||||||
|
|
||||||
# This is the default Makefile target. The objects listed here
|
# This is the default Makefile target. The objects listed here
|
||||||
# are what get build when you type just "make" with no arguments.
|
# are what get build when you type just "make" with no arguments.
|
||||||
|
20
manifest
20
manifest
@@ -1,7 +1,7 @@
|
|||||||
C Implemented\sthe\ssqliteBtreeSanityCheck()\stest\sfunction.\s(CVS\s232)
|
C More\sBTree\stests\s(CVS\s233)
|
||||||
D 2001-06-30T21:53:53
|
D 2001-07-01T22:12:01
|
||||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||||
F Makefile.in 63bc9a6a39b7160ce8d2392ae74eb4ca4ca84c6e
|
F Makefile.in df14e0f23d6946304d4681c24799d1ece965bf74
|
||||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||||
F VERSION 71874cb7e2a53c2bd22bb6affa7d223dd94a7a13
|
F VERSION 71874cb7e2a53c2bd22bb6affa7d223dd94a7a13
|
||||||
F configure d2051345f49f7e48604423da26e086a745c86a47 x
|
F configure d2051345f49f7e48604423da26e086a745c86a47 x
|
||||||
@@ -12,7 +12,7 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
|
|||||||
F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e
|
F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e
|
||||||
F notes/notes3.txt 985bf688b59f1f52bfe6e4b1f896efdeffac1432
|
F notes/notes3.txt 985bf688b59f1f52bfe6e4b1f896efdeffac1432
|
||||||
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
||||||
F src/btree.c 26f04c3fc1bb5bc9ba598c373cba09acaf82d6ce
|
F src/btree.c 7e39906a52592d3683552235c2a7d3782cc9e6f9
|
||||||
F src/btree.h 987d80658ae67f0e4d8b849539c113d4f9a7e835
|
F src/btree.h 987d80658ae67f0e4d8b849539c113d4f9a7e835
|
||||||
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
||||||
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
||||||
@@ -31,6 +31,7 @@ F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
|
|||||||
F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
|
F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
|
||||||
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
|
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
|
||||||
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
|
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
|
||||||
|
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||||
F src/pager.c 3e864a3e6cdec6f000a343f793360b42714028d8
|
F src/pager.c 3e864a3e6cdec6f000a343f793360b42714028d8
|
||||||
F src/pager.h d85259a2fd59e39f976abfb2bf6703c6f810e993
|
F src/pager.h d85259a2fd59e39f976abfb2bf6703c6f810e993
|
||||||
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
||||||
@@ -42,10 +43,10 @@ F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
|||||||
F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677
|
F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677
|
||||||
F src/sqliteInt.h 47845c60e2e196b5409d774936a56700b1611f00
|
F src/sqliteInt.h 47845c60e2e196b5409d774936a56700b1611f00
|
||||||
F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
|
F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
|
||||||
F src/tclsqlite.c af29a45cb4c2244a6fd032568a22d26516472b2c
|
F src/tclsqlite.c 7acb8887c44622214edb0dedeaab2593a3f86c62
|
||||||
F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
|
F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
|
||||||
F src/test2.c 0183625225a860397b4fd3041aefb48f77e4630a
|
F src/test2.c 0183625225a860397b4fd3041aefb48f77e4630a
|
||||||
F src/test3.c 6b5a099476ab96e7bca8bb6c48bc28700157a314
|
F src/test3.c ad8ff3513c3deb2d3909eca0f94527017b6d2fe6
|
||||||
F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
|
F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
|
||||||
F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
|
F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
|
||||||
F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
|
F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
|
||||||
@@ -54,6 +55,7 @@ F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437
|
|||||||
F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f
|
F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f
|
||||||
F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048
|
F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048
|
||||||
F test/btree.test 2463425e01ef94ec123fdbfb0dcae33f5303d5b1
|
F test/btree.test 2463425e01ef94ec123fdbfb0dcae33f5303d5b1
|
||||||
|
F test/btree2.test 480e39c80109280cdfdbc305b77919c5eae69b2e
|
||||||
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
|
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
|
||||||
F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
|
F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
|
||||||
F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
|
F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
|
||||||
@@ -108,7 +110,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
|||||||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||||
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
||||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||||
P 2c9127943cd5a541613924d2df773c4e8df4c1a6
|
P 42486880ed31318ef36a8831b959e9115b4fbac6
|
||||||
R 28adcf006d91ae47e28b3894b3bf7acf
|
R 453a76da442402a2188baa6e8a5a2ed6
|
||||||
U drh
|
U drh
|
||||||
Z a0a81713c9302268fb4ff7274344753c
|
Z 41c451abad8201b164f89425654bbd84
|
||||||
|
@@ -1 +1 @@
|
|||||||
42486880ed31318ef36a8831b959e9115b4fbac6
|
55c89bfdd35f1ad494618a451f9a1ed08502ae07
|
@@ -21,7 +21,7 @@
|
|||||||
** http://www.hwaci.com/drh/
|
** http://www.hwaci.com/drh/
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.18 2001/06/30 21:53:53 drh Exp $
|
** $Id: btree.c,v 1.19 2001/07/01 22:12:01 drh Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@@ -1666,6 +1666,8 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
|
|||||||
reparentChildPages(pBt->pPager, pPage);
|
reparentChildPages(pBt->pPager, pPage);
|
||||||
freePage(pBt, pChild, pgnoChild);
|
freePage(pBt, pChild, pgnoChild);
|
||||||
sqlitepager_unref(pChild);
|
sqlitepager_unref(pChild);
|
||||||
|
}else{
|
||||||
|
relinkCellList(pPage);
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -2489,6 +2491,9 @@ char *sqliteBtreeSanityCheck(Btree *pBt, int *aRoot, int nRoot){
|
|||||||
SanityCheck sCheck;
|
SanityCheck sCheck;
|
||||||
|
|
||||||
nRef = *sqlitepager_stats(pBt->pPager);
|
nRef = *sqlitepager_stats(pBt->pPager);
|
||||||
|
if( lockBtree(pBt)!=SQLITE_OK ){
|
||||||
|
return sqliteStrDup("Unable to acquire a read lock on the database");
|
||||||
|
}
|
||||||
sCheck.pBt = pBt;
|
sCheck.pBt = pBt;
|
||||||
sCheck.pPager = pBt->pPager;
|
sCheck.pPager = pBt->pPager;
|
||||||
sCheck.nPage = sqlitepager_pagecount(sCheck.pPager);
|
sCheck.nPage = sqlitepager_pagecount(sCheck.pPager);
|
||||||
@@ -2519,6 +2524,7 @@ char *sqliteBtreeSanityCheck(Btree *pBt, int *aRoot, int nRoot){
|
|||||||
|
|
||||||
/* Make sure this analysis did not leave any unref() pages
|
/* Make sure this analysis did not leave any unref() pages
|
||||||
*/
|
*/
|
||||||
|
unlockBtree(pBt);
|
||||||
if( nRef != *sqlitepager_stats(pBt->pPager) ){
|
if( nRef != *sqlitepager_stats(pBt->pPager) ){
|
||||||
char zBuf[100];
|
char zBuf[100];
|
||||||
sprintf(zBuf,
|
sprintf(zBuf,
|
||||||
|
352
src/md5.c
Normal file
352
src/md5.c
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
** SQLite uses this code for testing only. It is not a part of
|
||||||
|
** the SQLite library. This file implements two new TCL commands
|
||||||
|
** "md5" and "md5file" that compute md5 checksums on arbitrary text
|
||||||
|
** and on complete files. These commands are used by the "testfixture"
|
||||||
|
** program to help verify the correct operation of the SQLite library.
|
||||||
|
**
|
||||||
|
** The original use of these TCL commands was to test the ROLLBACK
|
||||||
|
** feature of SQLite. First compute the MD5-checksum of the database.
|
||||||
|
** Then make some changes but rollback the changes rather than commit
|
||||||
|
** them. Compute a second MD5-checksum of the file and verify that the
|
||||||
|
** two checksums are the same. Such is the original use of this code.
|
||||||
|
** New uses may have been added since this comment was written.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This code implements the MD5 message-digest algorithm.
|
||||||
|
* The algorithm is due to Ron Rivest. This code was
|
||||||
|
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||||
|
* This code is in the public domain; do with it what you wish.
|
||||||
|
*
|
||||||
|
* Equivalent code is available from RSA Data Security, Inc.
|
||||||
|
* This code has been tested against that, and is equivalent,
|
||||||
|
* except that you don't need to include two pages of legalese
|
||||||
|
* with every copy.
|
||||||
|
*
|
||||||
|
* To compute the message digest of a chunk of bytes, declare an
|
||||||
|
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||||
|
* needed on buffers full of bytes, and then call MD5Final, which
|
||||||
|
* will fill a supplied 16-byte array with the digest.
|
||||||
|
*/
|
||||||
|
#include <tcl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If compiled on a machine that doesn't have a 32-bit integer,
|
||||||
|
* you just set "uint32" to the appropriate datatype for an
|
||||||
|
* unsigned 32-bit integer. For example:
|
||||||
|
*
|
||||||
|
* cc -Duint32='unsigned long' md5.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef uint32
|
||||||
|
# define uint32 unsigned int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
uint32 buf[4];
|
||||||
|
uint32 bits[2];
|
||||||
|
unsigned char in[64];
|
||||||
|
};
|
||||||
|
typedef char MD5Context[88];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: this code is harmless on little-endian machines.
|
||||||
|
*/
|
||||||
|
static void byteReverse (unsigned char *buf, unsigned longs){
|
||||||
|
uint32 t;
|
||||||
|
do {
|
||||||
|
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
|
||||||
|
((unsigned)buf[1]<<8 | buf[0]);
|
||||||
|
*(uint32 *)buf = t;
|
||||||
|
buf += 4;
|
||||||
|
} while (--longs);
|
||||||
|
}
|
||||||
|
/* The four core functions - F1 is optimized somewhat */
|
||||||
|
|
||||||
|
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||||
|
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||||
|
#define F2(x, y, z) F1(z, x, y)
|
||||||
|
#define F3(x, y, z) (x ^ y ^ z)
|
||||||
|
#define F4(x, y, z) (y ^ (x | ~z))
|
||||||
|
|
||||||
|
/* This is the central step in the MD5 algorithm. */
|
||||||
|
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||||
|
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||||
|
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||||
|
* the data and converts bytes into longwords for this routine.
|
||||||
|
*/
|
||||||
|
static void MD5Transform(uint32 buf[4], const uint32 in[16]){
|
||||||
|
register uint32 a, b, c, d;
|
||||||
|
|
||||||
|
a = buf[0];
|
||||||
|
b = buf[1];
|
||||||
|
c = buf[2];
|
||||||
|
d = buf[3];
|
||||||
|
|
||||||
|
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||||
|
|
||||||
|
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||||
|
|
||||||
|
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||||
|
|
||||||
|
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||||
|
|
||||||
|
buf[0] += a;
|
||||||
|
buf[1] += b;
|
||||||
|
buf[2] += c;
|
||||||
|
buf[3] += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||||
|
* initialization constants.
|
||||||
|
*/
|
||||||
|
static void MD5Init(MD5Context *pCtx){
|
||||||
|
struct Context *ctx = (struct Context *)pCtx;
|
||||||
|
ctx->buf[0] = 0x67452301;
|
||||||
|
ctx->buf[1] = 0xefcdab89;
|
||||||
|
ctx->buf[2] = 0x98badcfe;
|
||||||
|
ctx->buf[3] = 0x10325476;
|
||||||
|
ctx->bits[0] = 0;
|
||||||
|
ctx->bits[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update context to reflect the concatenation of another buffer full
|
||||||
|
* of bytes.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
|
||||||
|
struct Context *ctx = (struct Context *)pCtx;
|
||||||
|
uint32 t;
|
||||||
|
|
||||||
|
/* Update bitcount */
|
||||||
|
|
||||||
|
t = ctx->bits[0];
|
||||||
|
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
|
||||||
|
ctx->bits[1]++; /* Carry from low to high */
|
||||||
|
ctx->bits[1] += len >> 29;
|
||||||
|
|
||||||
|
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||||
|
|
||||||
|
/* Handle any leading odd-sized chunks */
|
||||||
|
|
||||||
|
if ( t ) {
|
||||||
|
unsigned char *p = (unsigned char *)ctx->in + t;
|
||||||
|
|
||||||
|
t = 64-t;
|
||||||
|
if (len < t) {
|
||||||
|
memcpy(p, buf, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(p, buf, t);
|
||||||
|
byteReverse(ctx->in, 16);
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
buf += t;
|
||||||
|
len -= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process data in 64-byte chunks */
|
||||||
|
|
||||||
|
while (len >= 64) {
|
||||||
|
memcpy(ctx->in, buf, 64);
|
||||||
|
byteReverse(ctx->in, 16);
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
buf += 64;
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle any remaining bytes of data. */
|
||||||
|
|
||||||
|
memcpy(ctx->in, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||||
|
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||||
|
*/
|
||||||
|
static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
|
||||||
|
struct Context *ctx = (struct Context *)pCtx;
|
||||||
|
unsigned count;
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
/* Compute number of bytes mod 64 */
|
||||||
|
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||||
|
|
||||||
|
/* Set the first char of padding to 0x80. This is safe since there is
|
||||||
|
always at least one byte free */
|
||||||
|
p = ctx->in + count;
|
||||||
|
*p++ = 0x80;
|
||||||
|
|
||||||
|
/* Bytes of padding needed to make 64 bytes */
|
||||||
|
count = 64 - 1 - count;
|
||||||
|
|
||||||
|
/* Pad out to 56 mod 64 */
|
||||||
|
if (count < 8) {
|
||||||
|
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||||
|
memset(p, 0, count);
|
||||||
|
byteReverse(ctx->in, 16);
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
|
||||||
|
/* Now fill the next block with 56 bytes */
|
||||||
|
memset(ctx->in, 0, 56);
|
||||||
|
} else {
|
||||||
|
/* Pad block to 56 bytes */
|
||||||
|
memset(p, 0, count-8);
|
||||||
|
}
|
||||||
|
byteReverse(ctx->in, 14);
|
||||||
|
|
||||||
|
/* Append length in bits and transform */
|
||||||
|
((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
|
||||||
|
((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
|
||||||
|
|
||||||
|
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||||
|
byteReverse((unsigned char *)ctx->buf, 4);
|
||||||
|
memcpy(digest, ctx->buf, 16);
|
||||||
|
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert a digest into base-16. digest should be declared as
|
||||||
|
** "unsigned char digest[16]" in the calling function. The MD5
|
||||||
|
** digest is stored in the first 16 bytes. zBuf should
|
||||||
|
** be "char zBuf[33]".
|
||||||
|
*/
|
||||||
|
static void DigestToBase16(unsigned char *digest, char *zBuf){
|
||||||
|
static char const zEncode[] = "0123456789abcdef";
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for(j=i=0; i<16; i++){
|
||||||
|
int a = digest[i];
|
||||||
|
zBuf[j++] = zEncode[(a>>4)&0xf];
|
||||||
|
zBuf[j++] = zEncode[a & 0xf];
|
||||||
|
}
|
||||||
|
zBuf[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A TCL command for md5. The argument is the text to be hashed. The
|
||||||
|
** Result is the hash in base64.
|
||||||
|
*/
|
||||||
|
static int md5_cmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv){
|
||||||
|
MD5Context ctx;
|
||||||
|
unsigned char digest[16];
|
||||||
|
|
||||||
|
if( argc!=2 ){
|
||||||
|
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||||
|
" TEXT\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
MD5Init(&ctx);
|
||||||
|
MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
|
||||||
|
MD5Final(digest, &ctx);
|
||||||
|
DigestToBase16(digest, interp->result);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A TCL command to take the md5 hash of a file. The argument is the
|
||||||
|
** name of the file.
|
||||||
|
*/
|
||||||
|
static int md5file_cmd(ClientData cd, Tcl_Interp*interp, int argc, char **argv){
|
||||||
|
FILE *in;
|
||||||
|
MD5Context ctx;
|
||||||
|
unsigned char digest[16];
|
||||||
|
char zBuf[10240];
|
||||||
|
|
||||||
|
if( argc!=2 ){
|
||||||
|
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||||
|
" FILENAME\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
in = fopen(argv[1],"rb");
|
||||||
|
if( in==0 ){
|
||||||
|
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||||
|
"\" for reading", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
MD5Init(&ctx);
|
||||||
|
for(;;){
|
||||||
|
int n;
|
||||||
|
n = fread(zBuf, 1, sizeof(zBuf), in);
|
||||||
|
if( n<=0 ) break;
|
||||||
|
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
|
||||||
|
}
|
||||||
|
fclose(in);
|
||||||
|
MD5Final(digest, &ctx);
|
||||||
|
DigestToBase16(digest, interp->result);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Register the two TCL commands above with the TCL interpreter.
|
||||||
|
*/
|
||||||
|
int Md5_Init(Tcl_Interp *interp){
|
||||||
|
Tcl_CreateCommand(interp, "md5", md5_cmd, 0, 0);
|
||||||
|
Tcl_CreateCommand(interp, "md5file", md5file_cmd, 0, 0);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
@@ -23,7 +23,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** A TCL Interface to SQLite
|
** A TCL Interface to SQLite
|
||||||
**
|
**
|
||||||
** $Id: tclsqlite.c,v 1.19 2001/06/22 19:15:01 drh Exp $
|
** $Id: tclsqlite.c,v 1.20 2001/07/01 22:12:02 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||||
|
|
||||||
@@ -512,9 +512,11 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||||||
extern int Sqlitetest1_Init(Tcl_Interp*);
|
extern int Sqlitetest1_Init(Tcl_Interp*);
|
||||||
extern int Sqlitetest2_Init(Tcl_Interp*);
|
extern int Sqlitetest2_Init(Tcl_Interp*);
|
||||||
extern int Sqlitetest3_Init(Tcl_Interp*);
|
extern int Sqlitetest3_Init(Tcl_Interp*);
|
||||||
|
extern int Md5_Init(Tcl_Interp*);
|
||||||
Sqlitetest1_Init(interp);
|
Sqlitetest1_Init(interp);
|
||||||
Sqlitetest2_Init(interp);
|
Sqlitetest2_Init(interp);
|
||||||
Sqlitetest3_Init(interp);
|
Sqlitetest3_Init(interp);
|
||||||
|
Md5_Init(interp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( argc>=2 ){
|
if( argc>=2 ){
|
||||||
|
32
src/test3.c
32
src/test3.c
@@ -25,7 +25,7 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test3.c,v 1.5 2001/06/30 21:53:53 drh Exp $
|
** $Id: test3.c,v 1.6 2001/07/01 22:12:02 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@@ -256,6 +256,35 @@ static int btree_drop_table(
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: btree_clear_table ID TABLENUM
|
||||||
|
**
|
||||||
|
** Remove all entries from the given table but keep the table around.
|
||||||
|
*/
|
||||||
|
static int btree_clear_table(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
Btree *pBt;
|
||||||
|
int iTable;
|
||||||
|
int rc;
|
||||||
|
if( argc!=3 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" ID TABLENUM\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
|
||||||
|
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
|
||||||
|
rc = sqliteBtreeClearTable(pBt, iTable);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: btree_get_meta ID
|
** Usage: btree_get_meta ID
|
||||||
**
|
**
|
||||||
@@ -762,6 +791,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
|||||||
Tcl_CreateCommand(interp, "btree_rollback", btree_rollback, 0, 0);
|
Tcl_CreateCommand(interp, "btree_rollback", btree_rollback, 0, 0);
|
||||||
Tcl_CreateCommand(interp, "btree_create_table", btree_create_table, 0, 0);
|
Tcl_CreateCommand(interp, "btree_create_table", btree_create_table, 0, 0);
|
||||||
Tcl_CreateCommand(interp, "btree_drop_table", btree_drop_table, 0, 0);
|
Tcl_CreateCommand(interp, "btree_drop_table", btree_drop_table, 0, 0);
|
||||||
|
Tcl_CreateCommand(interp, "btree_clear_table", btree_clear_table, 0, 0);
|
||||||
Tcl_CreateCommand(interp, "btree_get_meta", btree_get_meta, 0, 0);
|
Tcl_CreateCommand(interp, "btree_get_meta", btree_get_meta, 0, 0);
|
||||||
Tcl_CreateCommand(interp, "btree_update_meta", btree_update_meta, 0, 0);
|
Tcl_CreateCommand(interp, "btree_update_meta", btree_update_meta, 0, 0);
|
||||||
Tcl_CreateCommand(interp, "btree_page_dump", btree_page_dump, 0, 0);
|
Tcl_CreateCommand(interp, "btree_page_dump", btree_page_dump, 0, 0);
|
||||||
|
385
test/btree2.test
Normal file
385
test/btree2.test
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
# Copyright (c) 1999, 2000 D. Richard Hipp
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public
|
||||||
|
# License along with this library; if not, write to the
|
||||||
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
# Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Author contact information:
|
||||||
|
# drh@hwaci.com
|
||||||
|
# http://www.hwaci.com/drh/
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this script is btree database backend
|
||||||
|
#
|
||||||
|
# $Id: btree2.test,v 1.1 2001/07/01 22:12:02 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
if {$dbprefix!="memory:" && [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 {
|
||||||
|
file delete -force test2.bt
|
||||||
|
file delete -force test2.bt-journal
|
||||||
|
set ::b [btree_open test2.bt]
|
||||||
|
btree_begin_transaction $::b
|
||||||
|
btree_create_table $::b
|
||||||
|
} {3}
|
||||||
|
do_test btree2-1.2 {
|
||||||
|
btree_create_table $::b
|
||||||
|
} {4}
|
||||||
|
do_test btree2-1.3 {
|
||||||
|
btree_create_table $::b
|
||||||
|
} {5}
|
||||||
|
do_test btree2-1.4 {
|
||||||
|
btree_create_table $::b
|
||||||
|
} {6}
|
||||||
|
do_test btree2-1.5 {
|
||||||
|
set ::c2 [btree_cursor $::b 2]
|
||||||
|
btree_insert $::c2 {one} {1}
|
||||||
|
btree_delete $::c2
|
||||||
|
btree_close_cursor $::c2
|
||||||
|
btree_commit $::b
|
||||||
|
btree_sanity_check $::b 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 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]
|
||||||
|
}
|
||||||
|
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 {} {
|
||||||
|
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 [btree_key $::c3]
|
||||||
|
scan $key %d k
|
||||||
|
if {$k!=$i} {
|
||||||
|
set key [btree_key $::c4]
|
||||||
|
scan $key %d k
|
||||||
|
if {$k!=$i} {
|
||||||
|
return "Key $i is missing from both foreground and backgroun"
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
proc random_changes {n I K D} {
|
||||||
|
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)}]
|
||||||
|
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)}]
|
||||||
|
} 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)}]
|
||||||
|
} else {
|
||||||
|
set datalen $L
|
||||||
|
}
|
||||||
|
set data [make_payload $k $L $datalen]
|
||||||
|
set basekey [format $format $k]
|
||||||
|
if {$insert} {
|
||||||
|
btree_move_to $::c4 $basekey
|
||||||
|
if {[scan [btree_key $::c4] %d kx]<1} {set kx -1}
|
||||||
|
if {$kx==$k} {
|
||||||
|
btree_delete $::c4
|
||||||
|
}
|
||||||
|
btree_insert $::c3 $key $data
|
||||||
|
} else {
|
||||||
|
btree_move_to $::c3 $basekey
|
||||||
|
if {[scan [btree_key $::c4] %d kx]<1} {set kx -1}
|
||||||
|
if {$kx==$k} {
|
||||||
|
btree_delete $::c3
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [btree_sanity_check $::b 2 3 4 5 6]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Repeat this test sequence on database of various sizes
|
||||||
|
#
|
||||||
|
set testno 2
|
||||||
|
foreach {N L} {
|
||||||
|
10 2
|
||||||
|
} {
|
||||||
|
puts "**** N=$N L=$L ****"
|
||||||
|
set hash [md5file test2.bt]
|
||||||
|
do_test btree2-$testno.1 [subst -nocommands {
|
||||||
|
set ::c2 [btree_cursor $::b 2]
|
||||||
|
set ::c3 [btree_cursor $::b 3]
|
||||||
|
set ::c4 [btree_cursor $::b 4]
|
||||||
|
set ::c5 [btree_cursor $::b 5]
|
||||||
|
set ::c6 [btree_cursor $::b 6]
|
||||||
|
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]
|
||||||
|
set ::c3 [btree_cursor $::b 3]
|
||||||
|
set ::c4 [btree_cursor $::b 4]
|
||||||
|
set ::c5 [btree_cursor $::b 5]
|
||||||
|
set ::c6 [btree_cursor $::b 6]
|
||||||
|
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_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
|
||||||
|
set ::b [btree_open test2.bt]
|
||||||
|
check_invariants
|
||||||
|
} {}
|
||||||
|
|
||||||
|
# For each database size, run various changes tests.
|
||||||
|
#
|
||||||
|
set num2 1
|
||||||
|
foreach {n I K D} {
|
||||||
|
0.5 0.5 0.5 0.5
|
||||||
|
} {
|
||||||
|
set testid btree2-$testno.8.$num2
|
||||||
|
do_test $testid.1 {
|
||||||
|
set ::c2 [btree_cursor $::b 2]
|
||||||
|
set ::c3 [btree_cursor $::b 3]
|
||||||
|
set ::c4 [btree_cursor $::b 4]
|
||||||
|
set ::c5 [btree_cursor $::b 5]
|
||||||
|
set ::c6 [btree_cursor $::b 6]
|
||||||
|
btree_begin_transaction $::b
|
||||||
|
lindex [btree_pager_stats $::b] 1
|
||||||
|
} {6}
|
||||||
|
set hash [md5file test2.bt]
|
||||||
|
do_test $testid.2 [subst -nocommands {
|
||||||
|
random_changes $n $I $K $D
|
||||||
|
check_invariants
|
||||||
|
}] {}
|
||||||
|
do_test $testid.3 {
|
||||||
|
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 $testid.4 [subst -nocommands {
|
||||||
|
btree_begin_transaction $::b
|
||||||
|
set ::c2 [btree_cursor $::b 2]
|
||||||
|
set ::c3 [btree_cursor $::b 3]
|
||||||
|
set ::c4 [btree_cursor $::b 4]
|
||||||
|
set ::c5 [btree_cursor $::b 5]
|
||||||
|
set ::c6 [btree_cursor $::b 6]
|
||||||
|
random_changes $n $I $K $D
|
||||||
|
check_invariants
|
||||||
|
}] {}
|
||||||
|
do_test $testid.5 {
|
||||||
|
btree_commit $::b
|
||||||
|
check_invariants
|
||||||
|
} {}
|
||||||
|
set hash [md5file test2.bt]
|
||||||
|
do_test $testid.6 {
|
||||||
|
btree_close_cursor $::c2
|
||||||
|
btree_close_cursor $::c3
|
||||||
|
btree_close_cursor $::c4
|
||||||
|
btree_close_cursor $::c5
|
||||||
|
btree_close_cursor $::c6
|
||||||
|
btree_close $::b
|
||||||
|
set ::b [btree_open test2.bt]
|
||||||
|
check_invariants
|
||||||
|
} {}
|
||||||
|
incr num2
|
||||||
|
}
|
||||||
|
incr testno
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
Reference in New Issue
Block a user