1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Improved diagnostics for Bitvec: Add the sqlite3ShowBitvec() routine that

can be called from a debugger (only available with SQLITE_DEBUG).  Add new
output opcodes for sqlite3BitvecBuiltinTest().

FossilOrigin-Name: dea1e37fa67ada6efc1533b449d9eb22338d9e58eec8f89b48c38319c212c8f4
This commit is contained in:
drh
2025-06-10 16:02:29 +00:00
parent f091f423ad
commit 90ba0d4995
5 changed files with 128 additions and 12 deletions

View File

@@ -107,6 +107,7 @@ struct Bitvec {
} u;
};
/*
** Create a new bitmap object able to handle bits between 0 and iSize,
** inclusive. Return a pointer to the new object. Return NULL if
@@ -293,6 +294,52 @@ u32 sqlite3BitvecSize(Bitvec *p){
return p->iSize;
}
#ifdef SQLITE_DEBUG
/*
** Show the content of a Bitvec option and its children. Indent
** everything by n spaces. Add x to each bitvec value.
**
** From a debugger such as gdb, one can type:
**
** call sqlite3ShowBitvec(p)
**
** For some Bitvec p and see a recursive view of the Bitvec's content.
*/
static void showBitvec(Bitvec *p, int n, unsigned x){
int i;
if( p==0 ){
printf("NULL\n");
return;
}
printf("Bitvec 0x%p iSize=%d", p, p->iSize);
if( p->iSize<=BITVEC_NBIT ){
printf(" bitmap\n");
printf("%*s bits:", n, "");
for(i=1; i<=BITVEC_NBIT; i++){
if( sqlite3BitvecTest(p,i) ) printf(" %u", x+(unsigned)i);
}
printf("\n");
}else if( p->iDivisor==0 ){
printf(" hash with %d entries\n", p->nSet);
printf("%*s bits:", n, "");
for(i=0; i<BITVEC_NINT; i++){
if( p->u.aHash[i] ) printf(" %u", x+(unsigned)p->u.aHash[i]);
}
printf("\n");
}else{
printf(" sub-bitvec with iDivisor=%d\n", p->iDivisor);
for(i=0; i<BITVEC_NPTR; i++){
if( p->u.apSub[i]==0 ) continue;
printf("%*s apSub[%d]=", n, "", i);
showBitvec(p->u.apSub[i], n+4, i*p->iDivisor);
}
}
}
void sqlite3ShowBitvec(Bitvec *p){
showBitvec(p, 0, 0);
}
#endif
#ifndef SQLITE_UNTESTABLE
/*
** Let V[] be an array of unsigned characters sufficient to hold
@@ -304,6 +351,7 @@ u32 sqlite3BitvecSize(Bitvec *p){
#define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7))
#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
/*
** This routine runs an extensive test of the Bitvec code.
**
@@ -312,7 +360,7 @@ u32 sqlite3BitvecSize(Bitvec *p){
** 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
** There are opcodes numbered starting with 0. 0 is the
** "halt" opcode and causes the test to end.
**
** 0 Halt and return the number of errors
@@ -321,12 +369,16 @@ u32 sqlite3BitvecSize(Bitvec *p){
** 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
** 6 Invoice sqlite3ShowBitvec() on the Bitvec object so far
** 7 X Show compile-time parameters and the hash of X
**
** 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.
** confirm that error detection works. Opcodes 6 and greater are
** state output opcodes. Opcodes 6 and greater are no-ops unless
** SQLite has been compiled with SQLITE_DEBUG.
**
** At the conclusion of the test the linear array is compared
** against the Bitvec object. If there are any differences,
@@ -355,6 +407,26 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
/* Run the program */
pc = i = 0;
while( (op = aOp[pc])!=0 ){
if( op>=6 ){
#ifdef SQLITE_DEBUG
if( op==6 ){
sqlite3ShowBitvec(pBitvec);
}else if( op==7 ){
unsigned x = (unsigned)aOp[++pc];
printf("BITVEC_SZ = %d (%d by sizeof)\n",
BITVEC_SZ, (int)sizeof(Bitvec));
printf("BITVEC_USIZE = %d\n", (int)BITVEC_USIZE);
printf("BITVEC_NELEM = %d\n", (int)BITVEC_NELEM);
printf("BITVEC_NBIT = %d\n", (int)BITVEC_NBIT);
printf("BITVEC_NINT = %d\n", (int)BITVEC_NINT);
printf("BITVEC_MXHASH = %d\n", (int)BITVEC_MXHASH);
printf("BITVEC_NPTR = %d\n", (int)BITVEC_NPTR);
printf("hash(%u): %u\n", x, (unsigned)BITVEC_HASH(x));
}
#endif
pc++;
continue;
}
switch( op ){
case 1:
case 2:

View File

@@ -11590,7 +11590,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{"always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" },
{"assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" },
/*{"benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/
/*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/
{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "SIZE INT-ARRAY"},
{"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" },
{"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" },
{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"args..." },
@@ -11928,6 +11928,49 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_test_control(testctrl, &rc2);
break;
case SQLITE_TESTCTRL_BITVEC_TEST: {
/* Examples:
** .testctrl bitvec_test 100 6,1 -- Show BITVEC constants
** .testctrl bitvec_test 1000 1,12,7,3 -- Simple test
** ---- --------
** size of Bitvec -----^ ^--- aOp array. 0 added at end.
**
** See comments on sqlite3BitvecBuiltinTest() for more information
** about the aOp[] array.
*/
int iSize;
const char *zTestArg;
int nOp;
int ii, jj, x;
int *aOp;
if( nArg!=4 ){
sqlite3_fprintf(stderr,
"ERROR - should be: \".testctrl bitvec_test SIZE INT-ARRAY\"\n"
);
rc = 1;
goto meta_command_exit;
}
isOk = 3;
iSize = (int)integerValue(azArg[2]);
zTestArg = azArg[3];
nOp = (int)strlen(zTestArg)+1;
aOp = malloc( sizeof(int)*(nOp+1) );
shell_check_oom(aOp);
memset(aOp, 0, sizeof(int)*(nOp+1) );
for(ii = jj = x = 0; zTestArg[ii]!=0; ii++){
if( IsDigit(zTestArg[ii]) ){
x = x*10 + zTestArg[ii] - '0';
}else{
aOp[jj++] = x;
x = 0;
}
}
aOp[jj] = x;
x = sqlite3_test_control(testctrl, iSize, aOp);
sqlite3_fprintf(p->out, "result: %d\n", x);
free(aOp);
break;
}
case SQLITE_TESTCTRL_FAULT_INSTALL: {
int kk;
int bShowHelp = nArg<=2;

View File

@@ -4894,6 +4894,7 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
void sqlite3ShowWindow(const Window*);
void sqlite3ShowWinFunc(const Window*);
#endif
void sqlite3ShowBitvec(Bitvec*);
#endif
void sqlite3SetString(char **, sqlite3*, const char*);