More BTree tests (CVS 233)
FossilOrigin-Name: 55c89bfdd35f1ad494618a451f9a1ed08502ae07
This commit is contained in:
parent
5eddca6cfc
commit
efc251da92
@ -84,7 +84,8 @@ SRC = \
|
||||
TESTSRC = \
|
||||
$(TOP)/src/test1.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
|
||||
# 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)
|
||||
D 2001-06-30T21:53:53
|
||||
C More\sBTree\stests\s(CVS\s233)
|
||||
D 2001-07-01T22:12:01
|
||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||
F Makefile.in 63bc9a6a39b7160ce8d2392ae74eb4ca4ca84c6e
|
||||
F Makefile.in df14e0f23d6946304d4681c24799d1ece965bf74
|
||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||
F VERSION 71874cb7e2a53c2bd22bb6affa7d223dd94a7a13
|
||||
F configure d2051345f49f7e48604423da26e086a745c86a47 x
|
||||
@ -12,7 +12,7 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
|
||||
F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e
|
||||
F notes/notes3.txt 985bf688b59f1f52bfe6e4b1f896efdeffac1432
|
||||
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
||||
F src/btree.c 26f04c3fc1bb5bc9ba598c373cba09acaf82d6ce
|
||||
F src/btree.c 7e39906a52592d3683552235c2a7d3782cc9e6f9
|
||||
F src/btree.h 987d80658ae67f0e4d8b849539c113d4f9a7e835
|
||||
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
||||
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
||||
@ -31,6 +31,7 @@ F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
|
||||
F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
|
||||
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
|
||||
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
|
||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||
F src/pager.c 3e864a3e6cdec6f000a343f793360b42714028d8
|
||||
F src/pager.h d85259a2fd59e39f976abfb2bf6703c6f810e993
|
||||
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
||||
@ -42,10 +43,10 @@ F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677
|
||||
F src/sqliteInt.h 47845c60e2e196b5409d774936a56700b1611f00
|
||||
F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
|
||||
F src/tclsqlite.c af29a45cb4c2244a6fd032568a22d26516472b2c
|
||||
F src/tclsqlite.c 7acb8887c44622214edb0dedeaab2593a3f86c62
|
||||
F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
|
||||
F src/test2.c 0183625225a860397b4fd3041aefb48f77e4630a
|
||||
F src/test3.c 6b5a099476ab96e7bca8bb6c48bc28700157a314
|
||||
F src/test3.c ad8ff3513c3deb2d3909eca0f94527017b6d2fe6
|
||||
F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
|
||||
F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
|
||||
F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
|
||||
@ -54,6 +55,7 @@ F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437
|
||||
F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f
|
||||
F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048
|
||||
F test/btree.test 2463425e01ef94ec123fdbfb0dcae33f5303d5b1
|
||||
F test/btree2.test 480e39c80109280cdfdbc305b77919c5eae69b2e
|
||||
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
|
||||
F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
|
||||
F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
|
||||
@ -108,7 +110,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
||||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||
P 2c9127943cd5a541613924d2df773c4e8df4c1a6
|
||||
R 28adcf006d91ae47e28b3894b3bf7acf
|
||||
P 42486880ed31318ef36a8831b959e9115b4fbac6
|
||||
R 453a76da442402a2188baa6e8a5a2ed6
|
||||
U drh
|
||||
Z a0a81713c9302268fb4ff7274344753c
|
||||
Z 41c451abad8201b164f89425654bbd84
|
||||
|
@ -1 +1 @@
|
||||
42486880ed31318ef36a8831b959e9115b4fbac6
|
||||
55c89bfdd35f1ad494618a451f9a1ed08502ae07
|
@ -21,7 +21,7 @@
|
||||
** 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.
|
||||
** 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);
|
||||
freePage(pBt, pChild, pgnoChild);
|
||||
sqlitepager_unref(pChild);
|
||||
}else{
|
||||
relinkCellList(pPage);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -2489,6 +2491,9 @@ char *sqliteBtreeSanityCheck(Btree *pBt, int *aRoot, int nRoot){
|
||||
SanityCheck sCheck;
|
||||
|
||||
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.pPager = pBt->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
|
||||
*/
|
||||
unlockBtree(pBt);
|
||||
if( nRef != *sqlitepager_stats(pBt->pPager) ){
|
||||
char zBuf[100];
|
||||
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
|
||||
**
|
||||
** $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 */
|
||||
|
||||
@ -512,9 +512,11 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
extern int Sqlitetest1_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest2_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest3_Init(Tcl_Interp*);
|
||||
extern int Md5_Init(Tcl_Interp*);
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest2_Init(interp);
|
||||
Sqlitetest3_Init(interp);
|
||||
Md5_Init(interp);
|
||||
}
|
||||
#endif
|
||||
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
|
||||
** 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 "pager.h"
|
||||
@ -256,6 +256,35 @@ static int btree_drop_table(
|
||||
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
|
||||
**
|
||||
@ -762,6 +791,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateCommand(interp, "btree_rollback", btree_rollback, 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_clear_table", btree_clear_table, 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_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
|
Loading…
Reference in New Issue
Block a user