The dbselftest utility now generates hashes in the selftest table with --init.
It also accepts multiple database files on the command-line. FossilOrigin-Name: e68829c9bbc69bf4a0dc057e0a6e977f2fac79be
This commit is contained in:
parent
18b20c981d
commit
cbc65e5f4f
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Omit\sfts5fault1.test\sfrom\sthe\sinmemory_journal\spermutation.
|
||||
D 2017-02-07T19:36:14.794
|
||||
C The\sdbselftest\sutility\snow\sgenerates\shashes\sin\sthe\sselftest\stable\swith\s--init.\nIt\salso\saccepts\smultiple\sdatabase\sfiles\son\sthe\scommand-line.
|
||||
D 2017-02-07T20:51:38.461
|
||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc ba953c8921fc7e18333f61898007206de7e23964
|
||||
@ -636,7 +636,7 @@ F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
||||
F test/date.test a6a5a48b90907bca9fbcc79a30be5a715c1ab2fc
|
||||
F test/dbfuzz.c 8cc2bdb818b4483a052f9f80f96be74cbd9a6e1d
|
||||
F test/dbselftest.c eeb95d09932b4dc79e5886bd8cf5d812e7d28d94
|
||||
F test/dbselftest.c 4bf86fe04dc2d0d58dabc5e6b7a06fa4ef7827ea
|
||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
@ -1555,7 +1555,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P be82d5ae20ba62a165bdc28766a8dc8049abcac6
|
||||
R 4c6aa653d353c19152ed7b2aaba4bc83
|
||||
U dan
|
||||
Z 450aa5587fc5eb1e148efd8100bf109e
|
||||
P cb1e83f9583bf93ce7583d9f5e97272e2d43cfb8
|
||||
R 64e5750ab44994d5b187d93e5c4a1318
|
||||
U drh
|
||||
Z f3a9d081d357071c2c4fc7a23224549e
|
||||
|
@ -1 +1 @@
|
||||
cb1e83f9583bf93ce7583d9f5e97272e2d43cfb8
|
||||
e68829c9bbc69bf4a0dc057e0a6e977f2fac79be
|
@ -13,7 +13,7 @@
|
||||
** This program implements an SQLite database self-verification utility.
|
||||
** Usage:
|
||||
**
|
||||
** dbselftest DATABASE
|
||||
** dbselftest DATABASE ...
|
||||
**
|
||||
** This program reads the "selftest" table in DATABASE, in rowid order,
|
||||
** and runs each of the tests described there, reporting results at the
|
||||
@ -44,7 +44,7 @@
|
||||
#include "sqlite3.h"
|
||||
|
||||
static const char zHelp[] =
|
||||
"Usage: dbselftest [OPTIONS] DBFILE\n"
|
||||
"Usage: dbselftest [OPTIONS] DBFILE ...\n"
|
||||
"\n"
|
||||
" --init Create the selftest table\n"
|
||||
" -q Suppress most output. Errors only\n"
|
||||
@ -294,6 +294,101 @@ static void sha1Func(
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Run a prepared statement and compute the SHA1 hash on the
|
||||
** result rows.
|
||||
*/
|
||||
static void sha1RunStatement(SHA1Context *pCtx, sqlite3_stmt *pStmt){
|
||||
int nCol = sqlite3_column_count(pStmt);
|
||||
const char *z = sqlite3_sql(pStmt);
|
||||
int n = (int)strlen(z);
|
||||
|
||||
hash_step_vformat(pCtx,"S%d:",n);
|
||||
hash_step(pCtx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int i;
|
||||
hash_step(pCtx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
hash_step(pCtx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
hash_step(pCtx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
hash_step(pCtx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(pCtx,"T%d:",n2);
|
||||
hash_step(pCtx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(pCtx,"B%d:",n2);
|
||||
hash_step(pCtx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run one or more statements of SQL. Compute a SHA1 hash of the output.
|
||||
*/
|
||||
static int sha1Exec(
|
||||
sqlite3 *db, /* Run against this database connection */
|
||||
const char *zSql, /* The SQL to be run */
|
||||
char *zOut /* Store the SHA1 hash as hexadecimal in this buffer */
|
||||
){
|
||||
sqlite3_stmt *pStmt = 0; /* A prepared statement */
|
||||
int rc; /* Result of an API call */
|
||||
SHA1Context cx; /* The SHA1 hash context */
|
||||
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1_query(SQL) function.
|
||||
**
|
||||
@ -314,11 +409,7 @@ static void sha1QueryFunc(
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int nCol; /* Number of columns in the result set */
|
||||
int i; /* Loop counter */
|
||||
int rc;
|
||||
int n;
|
||||
const char *z;
|
||||
SHA1Context cx;
|
||||
char zOut[44];
|
||||
|
||||
@ -342,66 +433,7 @@ static void sha1QueryFunc(
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
z = sqlite3_sql(pStmt);
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
hash_step(&cx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
hash_step(&cx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
hash_step(&cx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
hash_step(&cx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
hash_step(&cx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(&cx,"T%d:",n2);
|
||||
hash_step(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(&cx,"B%d:",n2);
|
||||
hash_step(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
@ -439,7 +471,7 @@ static void strAppend(Str *p, const char *z){
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
memcpy(p->z+n, z, n+1);
|
||||
memcpy(p->z+p->n, z, n+1);
|
||||
p->n += n;
|
||||
}
|
||||
|
||||
@ -461,9 +493,138 @@ static int execCallback(void *pStr, int argc, char **argv, char **colv){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL statement constructing using sqlite3_vmprintf().
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int runSql(sqlite3 *db, const char *zFormat, ...){
|
||||
char *zSql;
|
||||
char *zErr = 0;
|
||||
int rc;
|
||||
int nErr = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
printf("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
|
||||
if( rc || zErr ){
|
||||
printf("SQL error in [%s]: code=%d: %s\n", zSql, rc, zErr);
|
||||
nErr++;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a prepared statement using a formatted string.
|
||||
*/
|
||||
static sqlite3_stmt *prepareSql(sqlite3 *db, const char *zFormat, ...){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ){
|
||||
printf("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
printf("SQL error in [%s]: code=%d: %s\n", zSql, rc, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct the standard selftest configuration for the database.
|
||||
*/
|
||||
static int buildSelftestTable(sqlite3 *db){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int tno = 110;
|
||||
char *zSql;
|
||||
char zHash[50];
|
||||
|
||||
rc = runSql(db,
|
||||
"CREATE TABLE IF NOT EXISTS selftest(\n"
|
||||
" tno INTEGER PRIMARY KEY, -- test number\n"
|
||||
" op TEXT, -- what kind of test\n"
|
||||
" sql TEXT, -- SQL text for the test\n"
|
||||
" ans TEXT -- expected answer\n"
|
||||
");"
|
||||
"INSERT INTO selftest"
|
||||
" VALUES(100,'memo','Hashes generated using --init',NULL);"
|
||||
);
|
||||
if( rc ) return 1;
|
||||
tno = 110;
|
||||
zSql = "SELECT type,name,tbl_name,sql FROM sqlite_master";
|
||||
sha1Exec(db, zSql, zHash);
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'sha1',%Q,%Q)", tno, zSql, zHash);
|
||||
tno += 10;
|
||||
pStmt = prepareSql(db,
|
||||
"SELECT lower(name) FROM sqlite_master"
|
||||
" WHERE type='table' AND sql NOT GLOB 'CREATE VIRTUAL*'"
|
||||
" AND name<>'selftest'"
|
||||
" ORDER BY 1");
|
||||
if( pStmt==0 ) return 1;
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
zSql = sqlite3_mprintf("SELECT * FROM \"%w\" NOT INDEXED",
|
||||
sqlite3_column_text(pStmt, 0));
|
||||
if( zSql==0 ){
|
||||
printf("Of of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
sha1Exec(db, zSql, zHash);
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'sha1',%Q,%Q)", tno, zSql, zHash);
|
||||
tno += 10;
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) break;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( rc ) return 1;
|
||||
rc = runSql(db,
|
||||
"INSERT INTO selftest(tno,op,sql,ans)"
|
||||
" VALUES(%d,'run','PRAGMA integrity_check','ok');", tno);
|
||||
if( rc ) return 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the named table exists
|
||||
*/
|
||||
static int tableExists(sqlite3 *db, const char *zTab){
|
||||
return sqlite3_table_column_metadata(db, "main", zTab, 0, 0, 0, 0, 0, 0)
|
||||
== SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Default selftest table content, for use when there is no selftest table
|
||||
*/
|
||||
static char *azDefaultTest[] = {
|
||||
0, 0, 0, 0,
|
||||
"0", "memo", "Missing SELFTEST table - default checks only", "",
|
||||
"1", "run", "PRAGMA integrity_check", "ok"
|
||||
};
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int eVolume = VOLUME_LOW; /* How much output to display */
|
||||
const char *zDb = 0; /* Name of the database file */
|
||||
const char **azDb = 0; /* Name of the database file */
|
||||
int nDb = 0; /* Number of database files to check */
|
||||
int doInit = 0; /* True if --init is present */
|
||||
sqlite3 *db = 0; /* Open database connection */
|
||||
int rc; /* Return code from API calls */
|
||||
@ -472,7 +633,9 @@ int main(int argc, char **argv){
|
||||
int nRow = 0, nCol = 0; /* Rows and columns in azTest[] */
|
||||
int i; /* Loop counter */
|
||||
int nErr = 0; /* Number of errors */
|
||||
int iDb; /* Loop counter for databases */
|
||||
Str str; /* Result accumulator */
|
||||
int nTest = 0; /* Number of tests run */
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
@ -496,56 +659,18 @@ int main(int argc, char **argv){
|
||||
argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}else if( zDb!=0 ){
|
||||
printf("More than one database specified. Use --help for more info.\n");
|
||||
return 1;
|
||||
}else{
|
||||
zDb = argv[i];
|
||||
nDb++;
|
||||
azDb = sqlite3_realloc(azDb, nDb*sizeof(azDb[0]));
|
||||
if( azDb==0 ){
|
||||
printf("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
azDb[nDb-1] = argv[i];
|
||||
}
|
||||
}
|
||||
if( zDb==0 ){
|
||||
printf("No database specified. Use --help for more info\n");
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_open(zDb, &db);
|
||||
if( rc ){
|
||||
printf("Cannot open \"%s\": %s\n", zDb, sqlite3_errmsg(db));
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
|
||||
sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
|
||||
sha1QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc ){
|
||||
printf("Initialization error: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
if( doInit ){
|
||||
rc = sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS selftest(\n"
|
||||
" tno INTEGER PRIMARY KEY, -- test number\n"
|
||||
" op TEXT, -- what kind of test\n"
|
||||
" sql TEXT, -- SQL text for the test\n"
|
||||
" ans TEXT -- expected answer\n"
|
||||
");", 0, 0, &zErrMsg);
|
||||
if( rc || zErrMsg ){
|
||||
printf("CREATE TABLE selftest failed: %s\n", zErrMsg);
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( sqlite3_table_column_metadata(db,"main","selftest","sql",0,0,0,0,0) ){
|
||||
printf("No such table: selftest\nSee the --init option.\n");
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_get_table(db,
|
||||
"SELECT tno,op,sql,ans FROM selftest ORDRE BY tno",
|
||||
&azTest, &nRow, &nCol, &zErrMsg);
|
||||
if( rc || zErrMsg ){
|
||||
printf("Error querying selftest: %s\n", zErrMsg);
|
||||
if( nDb==0 ){
|
||||
printf("No databases specified. Use --help for more info\n");
|
||||
return 1;
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
@ -553,53 +678,109 @@ int main(int argc, char **argv){
|
||||
}
|
||||
memset(&str, 0, sizeof(str));
|
||||
strAppend(&str, "\n");
|
||||
for(i=1; i<=nRow; i++){
|
||||
int tno = atoi(azTest[i*nCol]);
|
||||
const char *zOp = azTest[i*nCol+1];
|
||||
const char *zSql = azTest[i*nCol+2];
|
||||
const char *zAns = azTest[i*nCol+3];
|
||||
|
||||
if( eVolume>=VOLUME_ECHO ){
|
||||
char *zQuote = sqlite3_mprintf("%q", zSql);
|
||||
printf("%d: %s %s\n", tno, zOp, zSql);
|
||||
sqlite3_free(zQuote);
|
||||
}
|
||||
if( strcmp(zOp,"memo")==0 ){
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("%s\n", zSql);
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"run")==0 ){
|
||||
str.n = 0;
|
||||
str.z[0] = 0;
|
||||
zErrMsg = 0;
|
||||
rc = sqlite3_exec(db, zSql, execCallback, &str, &zErrMsg);
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", str.z);
|
||||
}
|
||||
if( rc || zErrMsg ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
|
||||
}
|
||||
sqlite3_free(zErrMsg);
|
||||
}else if( strcmp(zAns,str.z)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, str.z);
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
printf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
|
||||
for(iDb=0; iDb<nDb; iDb++, sqlite3_close(db)){
|
||||
rc = sqlite3_open_v2(azDb[iDb], &db,
|
||||
doInit ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY, 0);
|
||||
if( rc ){
|
||||
printf("Cannot open \"%s\": %s\n", azDb[iDb], sqlite3_errmsg(db));
|
||||
return 1;
|
||||
}
|
||||
rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
|
||||
sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
|
||||
sha1QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc ){
|
||||
printf("Initialization error: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
if( doInit && !tableExists(db, "selftest") ){
|
||||
buildSelftestTable(db);
|
||||
}
|
||||
if( !tableExists(db, "selftest") ){
|
||||
azTest = azDefaultTest;
|
||||
nCol = 4;
|
||||
nRow = 2;
|
||||
}else{
|
||||
rc = sqlite3_get_table(db,
|
||||
"SELECT tno,op,sql,ans FROM selftest ORDER BY tno",
|
||||
&azTest, &nRow, &nCol, &zErrMsg);
|
||||
if( rc || zErrMsg ){
|
||||
printf("Error querying selftest: %s\n", zErrMsg);
|
||||
sqlite3_free_table(azTest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for(i=1; i<=nRow; i++){
|
||||
int tno = atoi(azTest[i*nCol]);
|
||||
const char *zOp = azTest[i*nCol+1];
|
||||
const char *zSql = azTest[i*nCol+2];
|
||||
const char *zAns = azTest[i*nCol+3];
|
||||
|
||||
if( eVolume>=VOLUME_ECHO ){
|
||||
char *zQuote = sqlite3_mprintf("%q", zSql);
|
||||
printf("%d: %s %s\n", tno, zOp, zSql);
|
||||
sqlite3_free(zQuote);
|
||||
}
|
||||
if( strcmp(zOp,"memo")==0 ){
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("%s: %s\n", azDb[iDb], zSql);
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"sha1")==0 ){
|
||||
char zOut[44];
|
||||
rc = sha1Exec(db, zSql, zOut);
|
||||
nTest++;
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", zOut);
|
||||
}
|
||||
if( rc ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, sqlite3_errmsg(db));
|
||||
}
|
||||
}else if( strcmp(zAns,zOut)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, zOut);
|
||||
}
|
||||
}
|
||||
}else
|
||||
if( strcmp(zOp,"run")==0 ){
|
||||
str.n = 0;
|
||||
str.z[0] = 0;
|
||||
zErrMsg = 0;
|
||||
rc = sqlite3_exec(db, zSql, execCallback, &str, &zErrMsg);
|
||||
nTest++;
|
||||
if( eVolume>=VOLUME_VERBOSE ){
|
||||
printf("Result: %s\n", str.z);
|
||||
}
|
||||
if( rc || zErrMsg ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
|
||||
}
|
||||
sqlite3_free(zErrMsg);
|
||||
}else if( strcmp(zAns,str.z)!=0 ){
|
||||
nErr++;
|
||||
if( eVolume>=VOLUME_ERROR_ONLY ){
|
||||
printf("%d: Expected: [%s]\n", tno, zAns);
|
||||
printf("%d: Got: [%s]\n", tno, str.z);
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
printf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
|
||||
}
|
||||
sqlite3_free_table(azTest);
|
||||
sqlite3_close(db);
|
||||
if( eVolume>=VOLUME_LOW || (nErr>0 && eVolume>=VOLUME_ERROR_ONLY) ){
|
||||
printf("%d errors out of %d tests\n", nErr, nRow);
|
||||
printf("%d errors out of %d tests on %d databases\n", nErr, nTest, nDb);
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user