aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitvec.c127
-rw-r--r--src/fault.c6
-rw-r--r--src/main.c21
-rw-r--r--src/random.c6
-rw-r--r--src/sqlite.h.in3
-rw-r--r--src/sqliteInt.h5
-rw-r--r--src/test2.c120
-rw-r--r--src/test_config.c14
8 files changed, 183 insertions, 119 deletions
diff --git a/src/bitvec.c b/src/bitvec.c
index 7fa8a8aec..be8f4d6d1 100644
--- a/src/bitvec.c
+++ b/src/bitvec.c
@@ -32,14 +32,14 @@
** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database.
**
-** @(#) $Id: bitvec.c,v 1.2 2008/03/14 13:02:08 mlcreech Exp $
+** @(#) $Id: bitvec.c,v 1.3 2008/03/21 16:45:47 drh Exp $
*/
#include "sqliteInt.h"
#define BITVEC_SZ 512
/* Round the union size down to the nearest pointer boundary, since that's how
** it will be aligned within the Bitvec struct. */
-#define BITVEC_USIZE (((BITVEC_SZ-12)/sizeof(Bitvec *))*sizeof(Bitvec *))
+#define BITVEC_USIZE (((BITVEC_SZ-12)/sizeof(Bitvec*))*sizeof(Bitvec*))
#define BITVEC_NCHAR BITVEC_USIZE
#define BITVEC_NBIT (BITVEC_NCHAR*8)
#define BITVEC_NINT (BITVEC_USIZE/4)
@@ -101,9 +101,8 @@ Bitvec *sqlite3BitvecCreate(u32 iSize){
** i is out of range, then return false.
*/
int sqlite3BitvecTest(Bitvec *p, u32 i){
- assert( i>0 );
if( p==0 ) return 0;
- if( i>p->iSize ) return 0;
+ if( i>p->iSize || i==0 ) return 0;
if( p->iSize<=BITVEC_NBIT ){
i--;
return (p->u.aBitmap[i/8] & (1<<(i&7)))!=0;
@@ -130,6 +129,7 @@ int sqlite3BitvecTest(Bitvec *p, u32 i){
int sqlite3BitvecSet(Bitvec *p, u32 i){
u32 h;
assert( p!=0 );
+ assert( i>0 );
if( p->iSize<=BITVEC_NBIT ){
i--;
p->u.aBitmap[i/8] |= 1 << (i&7);
@@ -159,8 +159,8 @@ int sqlite3BitvecSet(Bitvec *p, u32 i){
memcpy(aiValues, p->u.aHash, sizeof(aiValues));
memset(p->u.apSub, 0, sizeof(p->u.apSub[0])*BITVEC_NPTR);
p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
- sqlite3BitvecSet(p, i);
- for(rc=j=0; j<BITVEC_NINT; j++){
+ rc = sqlite3BitvecSet(p, i);
+ for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
}
return rc;
@@ -175,6 +175,7 @@ int sqlite3BitvecSet(Bitvec *p, u32 i){
*/
void sqlite3BitvecClear(Bitvec *p, u32 i){
assert( p!=0 );
+ assert( i>0 );
if( p->iSize<=BITVEC_NBIT ){
i--;
p->u.aBitmap[i/8] &= ~(1 << (i&7));
@@ -191,7 +192,9 @@ void sqlite3BitvecClear(Bitvec *p, u32 i){
memset(p->u.aHash, 0, sizeof(p->u.aHash[0])*BITVEC_NINT);
p->nSet = 0;
for(j=0; j<BITVEC_NINT; j++){
- if( aiValues[j] && aiValues[j]!=i ) sqlite3BitvecSet(p, aiValues[j]);
+ if( aiValues[j] && aiValues[j]!=i ){
+ sqlite3BitvecSet(p, aiValues[j]);
+ }
}
}
}
@@ -209,3 +212,113 @@ void sqlite3BitvecDestroy(Bitvec *p){
}
sqlite3_free(p);
}
+
+#ifndef SQLITE_OMIT_BUILTIN_TEST
+/*
+** Let V[] be an array of unsigned characters sufficient to hold
+** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
+** Then the following macros can be used to set, clear, or test
+** individual bits within V.
+*/
+#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
+#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
+#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
+
+/*
+** This routine runs an extensive test of the Bitvec code.
+**
+** The input is an array of integers that acts as a program
+** to test the Bitvec. The integers are opcodes followed
+** by 0, 1, or 3 operands, depending on the opcode. Another
+** opcode follows immediately after the last operand.
+**
+** There are 6 opcodes numbered from 0 through 5. 0 is the
+** "halt" opcode and causes the test to end.
+**
+** 0 Halt and return the number of errors
+** 1 N S X Set N bits beginning with S and incrementing by X
+** 2 N S X Clear N bits beginning with S and incrementing by X
+** 3 N Set N randomly chosen bits
+** 4 N Clear N randomly chosen bits
+** 5 N S X Set N bits from S increment X in array only, not in bitvec
+**
+** The opcodes 1 through 4 perform set and clear operations are performed
+** on both a Bitvec object and on a linear array of bits obtained from malloc.
+** Opcode 5 works on the linear array only, not on the Bitvec.
+** Opcode 5 is used to deliberately induce a fault in order to
+** confirm that error detection works.
+**
+** At the conclusion of the test the linear array is compared
+** against the Bitvec object. If there are any differences,
+** an error is returned. If they are the same, zero is returned.
+**
+** If a memory allocation error occurs, return -1.
+*/
+int sqlite3BitvecBuiltinTest(int sz, int *aOp){
+ Bitvec *pBitvec = 0;
+ unsigned char *pV = 0;
+ int rc = -1;
+ int i, nx, pc, op;
+
+ /* Allocate the Bitvec to be tested and a linear array of
+ ** bits to act as the reference */
+ pBitvec = sqlite3BitvecCreate( sz );
+ pV = sqlite3_malloc( (sz+7)/8 + 1 );
+ if( pBitvec==0 || pV==0 ) goto bitvec_end;
+ memset(pV, 0, (sz+7)/8 + 1);
+
+ /* Run the program */
+ pc = 0;
+ while( (op = aOp[pc])!=0 ){
+ switch( op ){
+ case 1:
+ case 2:
+ case 5: {
+ nx = 4;
+ i = aOp[pc+2] - 1;
+ aOp[pc+2] += aOp[pc+3];
+ break;
+ }
+ case 3:
+ case 4:
+ default: {
+ nx = 2;
+ sqlite3_randomness(sizeof(i), &i);
+ break;
+ }
+ }
+ if( (--aOp[pc+1]) > 0 ) nx = 0;
+ pc += nx;
+ i = (i & 0x7fffffff)%sz;
+ if( (op & 1)!=0 ){
+ SETBIT(pV, (i+1));
+ if( op!=5 ){
+ if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end;
+ }
+ }else{
+ CLEARBIT(pV, (i+1));
+ sqlite3BitvecClear(pBitvec, i+1);
+ }
+ }
+
+ /* Test to make sure the linear array exactly matches the
+ ** Bitvec object. Start with the assumption that they do
+ ** match (rc==0). Change rc to non-zero if a discrepancy
+ ** is found.
+ */
+ rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1)
+ + sqlite3BitvecTest(pBitvec, 0);
+ for(i=1; i<=sz; i++){
+ if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){
+ rc = i;
+ break;
+ }
+ }
+
+ /* Free allocated structure */
+bitvec_end:
+ sqlite3_free(pV);
+ sqlite3BitvecDestroy(pBitvec);
+ return rc;
+}
+#endif /* SQLITE_OMIT_BUILTIN_TEST */
diff --git a/src/fault.c b/src/fault.c
index af7702ec9..7e183ed43 100644
--- a/src/fault.c
+++ b/src/fault.c
@@ -19,7 +19,7 @@
** allocation failures or I/O errors.
**
** The fault injector is omitted from the code if SQLite is
-** compiled with -DSQLITE_OMIT_TESTLOGIC=1. There is a very
+** compiled with -DSQLITE_OMIT_BUILTIN_TEST=1. There is a very
** small performance hit for leaving the fault injector in the code.
** Commerical products will probably want to omit the fault injector
** from production builds. But safety-critical systems who work
@@ -28,7 +28,7 @@
*/
#include "sqliteInt.h"
-#ifndef SQLITE_OMIT_TESTLOGIC
+#ifndef SQLITE_OMIT_BUILTIN_TEST
/*
** There can be various kinds of faults. For example, there can be
@@ -144,4 +144,4 @@ int sqlite3FaultStep(int id){
return 1;
}
-#endif /* SQLITE_OMIT_TESTLOGIC */
+#endif /* SQLITE_OMIT_BUILTIN_TEST */
diff --git a/src/main.c b/src/main.c
index 140e64a62..41b84c094 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.428 2008/03/20 18:00:49 drh Exp $
+** $Id: main.c,v 1.429 2008/03/21 16:45:47 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -1574,7 +1574,7 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
*/
int sqlite3_test_control(int op, ...){
int rc = 0;
-#ifndef SQLITE_OMIT_TESTLOGIC
+#ifndef SQLITE_OMIT_BUILTIN_TEST
va_list ap;
va_start(ap, op);
switch( op ){
@@ -1658,8 +1658,23 @@ int sqlite3_test_control(int op, ...){
sqlite3PrngResetState();
break;
}
+
+ /*
+ ** sqlite3_test_control(BITVEC_TEST, size, program)
+ **
+ ** Run a test against a Bitvec object of size. The program argument
+ ** is an array of integers that defines the test. Return -1 on a
+ ** memory allocation error, 0 on success, or non-zero for an error.
+ ** See the sqlite3BitvecBuiltinTest() for additional information.
+ */
+ case SQLITE_TESTCTRL_BITVEC_TEST: {
+ int sz = va_arg(ap, int);
+ int *aProg = va_arg(ap, int*);
+ rc = sqlite3BitvecBuiltinTest(sz, aProg);
+ break;
+ }
}
va_end(ap);
-#endif /* SQLITE_OMIT_TESTLOGIC */
+#endif /* SQLITE_OMIT_BUILTIN_TEST */
return rc;
}
diff --git a/src/random.c b/src/random.c
index 0c6591866..4b977f2b4 100644
--- a/src/random.c
+++ b/src/random.c
@@ -15,7 +15,7 @@
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
**
-** $Id: random.c,v 1.22 2008/03/19 14:15:35 drh Exp $
+** $Id: random.c,v 1.23 2008/03/21 16:45:47 drh Exp $
*/
#include "sqliteInt.h"
@@ -103,7 +103,7 @@ void sqlite3_randomness(int N, void *pBuf){
sqlite3_mutex_leave(mutex);
}
-#ifndef SQLITE_OMIT_TESTLOGIC
+#ifndef SQLITE_OMIT_BUILTIN_TEST
/*
** For testing purposes, we sometimes want to preserve the state of
** PRNG and restore the PRNG to its saved state at a later time.
@@ -120,4 +120,4 @@ void sqlite3PrngRestoreState(void){
void sqlite3PrngResetState(void){
sqlite3Prng.isInit = 0;
}
-#endif /* SQLITE_OMIT_TESTLOGIC */
+#endif /* SQLITE_OMIT_BUILTIN_TEST */
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 158c6e1e3..18d44d263 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
-** @(#) $Id: sqlite.h.in,v 1.298 2008/03/20 18:00:49 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.299 2008/03/21 16:45:47 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -5610,6 +5610,7 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7
+#define SQLITE_TESTCTRL_BITVEC_TEST 8
/*
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 8c7173b2f..8f6b5bdd6 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.678 2008/03/20 16:30:18 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.679 2008/03/21 16:45:47 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1790,6 +1790,7 @@ int sqlite3BitvecTest(Bitvec*, u32);
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32);
void sqlite3BitvecDestroy(Bitvec*);
+int sqlite3BitvecBuiltinTest(int,int*);
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
@@ -2084,7 +2085,7 @@ CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
** mechanism is disabled at compile-time then set up macros so that no
** unnecessary code is generated.
*/
-#ifndef SQLITE_OMIT_TESTLOGIC
+#ifndef SQLITE_OMIT_BUILTIN_TEST
void sqlite3FaultConfig(int,int,int);
int sqlite3FaultFailures(int);
int sqlite3FaultBenignFailures(int);
diff --git a/src/test2.c b/src/test2.c
index a8457efb3..68e9c65c0 100644
--- a/src/test2.c
+++ b/src/test2.c
@@ -13,12 +13,13 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test2.c,v 1.56 2008/03/20 11:04:21 danielk1977 Exp $
+** $Id: test2.c,v 1.57 2008/03/21 16:45:48 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
/*
** Interpret an SQLite error number
@@ -561,103 +562,40 @@ static int fake_big_file(
}
#endif
+
/*
-** sqlite3BitvecCreate SIZE
-** sqlite3BitvecTest POINTER N
-** sqlite3BitvecSet POINTER N
-** sqlite3BitvecClear POINTER N
-** sqlite3BitvecDestroy POINTER
+** sqlite3BitvecBuiltinTest SIZE PROGRAM
+**
+** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
+** See comments on sqlite3BitvecBuiltinTest() for additional information.
*/
-static int testBitvecCreate(
- void *NotUsed,
- Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
- int argc, /* Number of arguments */
- const char **argv /* Text of each argument */
-){
- int size;
- Bitvec *p;
- char zBuf[100];
- if( argc!=2 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"",
- (void*)0);
- }
- if( Tcl_GetInt(interp, argv[1], &size) ) return TCL_ERROR;
- p = sqlite3BitvecCreate(size);
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",p);
- Tcl_AppendResult(interp, zBuf, 0);
- return TCL_OK;
-}
-static int testBitvecTest(
- void *NotUsed,
- Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
- int argc, /* Number of arguments */
- const char **argv /* Text of each argument */
-){
- int N;
- Bitvec *p;
- char zBuf[100];
- if( argc!=3 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"",
- (void*)0);
- }
- p = (Bitvec*)sqlite3TextToPtr(argv[1]);
- if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR;
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3BitvecTest(p,N));
- Tcl_AppendResult(interp, zBuf, 0);
- return TCL_OK;
-}
-static int testBitvecSet(
- void *NotUsed,
- Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
- int argc, /* Number of arguments */
- const char **argv /* Text of each argument */
-){
- int N;
- Bitvec *p;
- char zBuf[100];
- if( argc!=3 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"",
- (void*)0);
- }
- p = (Bitvec*)sqlite3TextToPtr(argv[1]);
- if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR;
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3BitvecSet(p,N));
- Tcl_AppendResult(interp, zBuf, 0);
- return TCL_OK;
-}
-static int testBitvecClear(
+static int testBitvecBuiltinTest(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
- int N;
- Bitvec *p;
+ int sz, rc;
+ int nProg = 0;
+ int aProg[100];
+ const char *z;
if( argc!=3 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"",
- (void*)0);
- }
- p = (Bitvec*)sqlite3TextToPtr(argv[1]);
- if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR;
- sqlite3BitvecClear(p,N);
- return TCL_OK;
-}
-static int testBitvecDestroy(
- void *NotUsed,
- Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
- int argc, /* Number of arguments */
- const char **argv /* Text of each argument */
-){
- Bitvec *p;
- if( argc!=2 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR\"",
- (void*)0);
- }
- p = (Bitvec*)sqlite3TextToPtr(argv[1]);
- sqlite3BitvecDestroy(p);
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " SIZE PROGRAM\"", (void*)0);
+ }
+ if( Tcl_GetInt(interp, argv[1], &sz) ) return TCL_ERROR;
+ z = argv[2];
+ while( nProg<99 && *z ){
+ while( *z && !isdigit(*z) ){ z++; }
+ if( *z==0 ) break;
+ aProg[nProg++] = atoi(z);
+ while( isdigit(*z) ){ z++; }
+ }
+ aProg[nProg] = 0;
+ rc = sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
-
/*
** Register commands with the TCL interpreter.
@@ -693,11 +631,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
#ifndef SQLITE_OMIT_DISKIO
{ "fake_big_file", (Tcl_CmdProc*)fake_big_file },
#endif
- { "sqlite3BitvecCreate", (Tcl_CmdProc*)testBitvecCreate },
- { "sqlite3BitvecTest", (Tcl_CmdProc*)testBitvecTest },
- { "sqlite3BitvecSet", (Tcl_CmdProc*)testBitvecSet },
- { "sqlite3BitvecClear", (Tcl_CmdProc*)testBitvecClear },
- { "sqlite3BitvecDestroy", (Tcl_CmdProc*)testBitvecDestroy },
+ { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest},
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
diff --git a/src/test_config.c b/src/test_config.c
index adf6805e8..c396763d4 100644
--- a/src/test_config.c
+++ b/src/test_config.c
@@ -16,7 +16,7 @@
** The focus of this file is providing the TCL testing layer
** access to compile-time constants.
**
-** $Id: test_config.c,v 1.22 2008/03/20 14:03:29 drh Exp $
+** $Id: test_config.c,v 1.23 2008/03/21 16:45:48 drh Exp $
*/
#include "sqliteLimit.h"
@@ -135,6 +135,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "between_opt", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_OMIT_BUILTIN_TEST
+ Tcl_SetVar2(interp, "sqlite_options", "builtin_test", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "builtin_test", "1", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_BLOB_LITERAL
Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL_GLOBAL_ONLY);
#else
@@ -356,12 +362,6 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "tclvar", "1", TCL_GLOBAL_ONLY);
#endif
-#ifdef SQLITE_OMIT_TESTLOGIC
- Tcl_SetVar2(interp, "sqlite_options", "testlogic", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "testlogic", "1", TCL_GLOBAL_ONLY);
-#endif
-
rc = sqlite3_threadsafe();
#if SQLITE_THREADSAFE
Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "1", TCL_GLOBAL_ONLY);