Remove the test/dbselftest.c program. In its place, add the ".selftest"
command to the CLI. The new CLI version is .selftest is slightly different in that it uses SHA3 hashing instead of SHA1, so the new is subtly incompatible with the old. FossilOrigin-Name: f4fcd46f08ba59d2a3e772cad98383129f648386
This commit is contained in:
parent
f8563c00b2
commit
fb546afb4d
@ -1185,11 +1185,6 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
|
||||
|
||||
DBSELFTEST_OPT += -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4
|
||||
|
||||
dbselftest$(TEXE): $(TOP)/test/dbselftest.c sqlite3.c
|
||||
$(LTLINK) $(DBSELFTEST_OPT) -o $@ $(TOP)/test/dbselftest.c sqlite3.c $(TLIBS)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
|
||||
|
||||
|
5
main.mk
5
main.mk
@ -479,8 +479,6 @@ FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
DBSELFTEST_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
DBSELFTEST_OPT += -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
@ -902,9 +900,6 @@ speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
kvtest$(EXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
dbselftest$(EXE): $(TOP)/test/dbselftest.c sqlite3.c
|
||||
$(TCCX) -I. $(DBSELFTEST_OPT) -o dbselftest$(EXE) $(TOP)/test/dbselftest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
|
||||
$(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \
|
||||
$(THREADLIB)
|
||||
|
17
manifest
17
manifest
@ -1,6 +1,6 @@
|
||||
C Fix\sthe\s".dump"\scommand\sto\scorrectly\sextract\stail\sdata\sfrom\scorrupt\nWITHOUT\sROWID\stables.
|
||||
D 2017-03-09T18:13:52.322
|
||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||
C Remove\sthe\stest/dbselftest.c\sprogram.\s\sIn\sits\splace,\sadd\sthe\s".selftest"\ncommand\sto\sthe\sCLI.\s\sThe\snew\sCLI\sversion\sis\s.selftest\sis\sslightly\sdifferent\nin\sthat\sit\suses\sSHA3\shashing\sinstead\sof\sSHA1,\sso\sthe\snew\sis\ssubtly\s\nincompatible\swith\sthe\sold.
|
||||
D 2017-03-09T22:00:33.842
|
||||
F Makefile.in 5f415e7867296d678fed2e6779aea10c1318b4bc
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
@ -323,7 +323,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 08e0b151abb46353c677ac4974b50c6077f85eee
|
||||
F main.mk 98f9e673437e28b17f86d07d0749021bb140c152
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@ -400,7 +400,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c d12f3539f80db38b09015561b569e0eb1c4b6c5f
|
||||
F src/shell.c f4a7169ddfff73ba1ab2f06a4e97bd6d569cb984
|
||||
F src/shell.c 2009654e24924b51a54afb925b49034f1c5460d4
|
||||
F src/sqlite.h.in 4d0c08f8640c586564a7032b259c5f69bf397850
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
|
||||
@ -643,7 +643,6 @@ F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbselftest.c b2e6cfac59066dbcb7334b66304bb15a5508dd42
|
||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
@ -1564,7 +1563,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 50eec5d9aa38fab1a85d788356ffdaf6c35d9ece
|
||||
R a2e2297f06f9d9483ad6626d70cfa2bc
|
||||
P 6c627e50622d8bcd25ec7d5503f3fafd725673a8
|
||||
R de6856f188fdc076241cbc67ee174b05
|
||||
U drh
|
||||
Z 704977d7ee0085e38c9f718cc949a370
|
||||
Z 85b6274077eac0b5500dd53648c9e848
|
||||
|
@ -1 +1 @@
|
||||
6c627e50622d8bcd25ec7d5503f3fafd725673a8
|
||||
f4fcd46f08ba59d2a3e772cad98383129f648386
|
161
src/shell.c
161
src/shell.c
@ -2054,6 +2054,49 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
return shell_callback(pArg, nArg, azArg, azCol, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the callback routine from sqlite3_exec() that appends all
|
||||
** output onto the end of a ShellText object.
|
||||
*/
|
||||
static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
|
||||
ShellText *p = (ShellText*)pArg;
|
||||
int i;
|
||||
if( p->n ) appendText(p, "|", 0);
|
||||
for(i=0; i<nArg; i++){
|
||||
if( i ) appendText(p, ",", 0);
|
||||
if( azArg[i] ) appendText(p, azArg[i], 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate an appropriate SELFTEST table in the main database.
|
||||
*/
|
||||
static void createSelftestTable(ShellState *p){
|
||||
sqlite3_exec(p->db,
|
||||
"CREATE TABLE selftest(\n"
|
||||
" tno INTEGER PRIMARY KEY,\n" /* Test number */
|
||||
" op TEXT,\n" /* Operator: memo run */
|
||||
" cmd TEXT,\n" /* Command text */
|
||||
" ans TEXT\n" /* Desired answer */
|
||||
");"
|
||||
"INSERT INTO selftest(op,cmd,ans)\n"
|
||||
" SELECT 'run',"
|
||||
" 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
|
||||
" printf('%w',name) || '\" NOT INDEXED'',224))',\n"
|
||||
" hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
|
||||
" FROM (\n"
|
||||
" SELECT name FROM sqlite_master\n"
|
||||
" WHERE type='table'\n"
|
||||
" AND name<>'selftest'\n"
|
||||
" AND coalesce(rootpage,0)>0\n"
|
||||
" )\n"
|
||||
" ORDER BY name;\n"
|
||||
"INSERT INTO selftest(op,cmd,ans)\n"
|
||||
" VALUES('run','PRAGMA integrity_check','ok');\n"
|
||||
,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set the destination table field of the ShellState structure to
|
||||
@ -5727,6 +5770,124 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
|
||||
int bIsInit = 0; /* True to initialize the SELFTEST table */
|
||||
int bVerbose = 0; /* Verbose output */
|
||||
int bSelftestExists; /* True if SELFTEST already exists */
|
||||
char **azTest = 0; /* Content of the SELFTEST table */
|
||||
int nRow = 0; /* Number of rows in the SELFTEST table */
|
||||
int nCol = 4; /* Number of columns in the SELFTEST table */
|
||||
int i; /* Loop counter */
|
||||
int nTest = 0; /* Number of tests runs */
|
||||
int nErr = 0; /* Number of errors seen */
|
||||
ShellText str; /* Answer for a query */
|
||||
static char *azDefaultTest[] = {
|
||||
0, 0, 0, 0,
|
||||
"0", "memo", "Missing SELFTEST table - default checks only", "",
|
||||
"1", "run", "PRAGMA integrity_check", "ok"
|
||||
};
|
||||
static const int nDefaultRow = 2;
|
||||
|
||||
open_db(p,0);
|
||||
for(i=1; i<nArg; i++){
|
||||
const char *z = azArg[i];
|
||||
if( z[0]=='-' && z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-init")==0 ){
|
||||
bIsInit = 1;
|
||||
}else
|
||||
if( strcmp(z,"-v")==0 ){
|
||||
bVerbose++;
|
||||
}else
|
||||
{
|
||||
utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
|
||||
azArg[i], azArg[0]);
|
||||
raw_printf(stderr, "Should be one of: --init -v\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
|
||||
!= SQLITE_OK ){
|
||||
bSelftestExists = 0;
|
||||
}else{
|
||||
bSelftestExists = 1;
|
||||
}
|
||||
if( bIsInit ){
|
||||
if( bSelftestExists ){
|
||||
raw_printf(stderr, "The selftest table already exists\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
createSelftestTable(p);
|
||||
bSelftestExists = 1;
|
||||
}
|
||||
if( bSelftestExists ){
|
||||
rc = sqlite3_get_table(p->db,
|
||||
"SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
|
||||
&azTest, &nRow, &nCol, 0);
|
||||
if( rc ){
|
||||
raw_printf(stderr, "Error querying the selftest table\n");
|
||||
rc = 1;
|
||||
sqlite3_free_table(azTest);
|
||||
goto meta_command_exit;
|
||||
}else if( nRow==0 ){
|
||||
sqlite3_free_table(azTest);
|
||||
azTest = azDefaultTest;
|
||||
nRow = nDefaultRow;
|
||||
}
|
||||
}else{
|
||||
azTest = azDefaultTest;
|
||||
nRow = nDefaultRow;
|
||||
}
|
||||
initText(&str);
|
||||
appendText(&str, "x", 0);
|
||||
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( bVerbose>0 ){
|
||||
char *zQuote = sqlite3_mprintf("%q", zSql);
|
||||
printf("%d: %s %s\n", tno, zOp, zSql);
|
||||
sqlite3_free(zQuote);
|
||||
}
|
||||
if( strcmp(zOp,"memo")==0 ){
|
||||
utf8_printf(p->out, "%s\n", zSql);
|
||||
}else
|
||||
if( strcmp(zOp,"run")==0 ){
|
||||
char *zErrMsg = 0;
|
||||
str.n = 0;
|
||||
str.z[0] = 0;
|
||||
rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
|
||||
nTest++;
|
||||
if( bVerbose ){
|
||||
utf8_printf(p->out, "Result: %s\n", str.z);
|
||||
}
|
||||
if( rc || zErrMsg ){
|
||||
nErr++;
|
||||
rc = 1;
|
||||
utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
}else if( strcmp(zAns,str.z)!=0 ){
|
||||
nErr++;
|
||||
rc = 1;
|
||||
utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
|
||||
utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
|
||||
}
|
||||
}else
|
||||
{
|
||||
utf8_printf(stderr,
|
||||
"Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeText(&str);
|
||||
if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
|
||||
utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
|
||||
}else
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
|
||||
if( nArg<2 || nArg>3 ){
|
||||
raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
|
||||
|
@ -1,786 +0,0 @@
|
||||
/*
|
||||
** 2017-02-07
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This program implements an SQLite database self-verification utility.
|
||||
** Usage:
|
||||
**
|
||||
** 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
|
||||
** end.
|
||||
**
|
||||
** The intent of this program is to have a set of test database files that
|
||||
** can be run using future versions of SQLite in order to verify that
|
||||
** legacy database files continue to be readable. In other words, the
|
||||
** intent is to confirm that there have been no breaking changes in the
|
||||
** file format. The program can also be used to verify that database files
|
||||
** are fully compatible between different architectures.
|
||||
**
|
||||
** The selftest table looks like this:
|
||||
**
|
||||
** CREATE TABLE selftest (
|
||||
** id INTEGER PRIMARY KEY, -- Run tests in ascending order
|
||||
** op TEXT, -- "test", "regexp", "print", etc.
|
||||
** cmdtxt TEXT, -- Usually the SQL to be run
|
||||
** expected TEXT -- Expected results
|
||||
** );
|
||||
**
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
static const char zHelp[] =
|
||||
"Usage: dbselftest [OPTIONS] DBFILE ...\n"
|
||||
"\n"
|
||||
" --init Create the selftest table\n"
|
||||
" -q Suppress most output. Errors only\n"
|
||||
" -v Show extra output\n"
|
||||
;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** The following code from ext/misc/sha1.c
|
||||
**
|
||||
** Context for the SHA1 hash
|
||||
*/
|
||||
typedef struct SHA1Context SHA1Context;
|
||||
struct SHA1Context {
|
||||
unsigned int state[5];
|
||||
unsigned int count[2];
|
||||
unsigned char buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
|
||||
/*
|
||||
* GCC by itself only generates left rotates. Use right rotates if
|
||||
* possible to be kinder to dinky implementations with iterative rotate
|
||||
* instructions.
|
||||
*/
|
||||
#define SHA_ROT(op, x, k) \
|
||||
({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
|
||||
#define rol(x,k) SHA_ROT("roll", x, k)
|
||||
#define ror(x,k) SHA_ROT("rorl", x, k)
|
||||
|
||||
#else
|
||||
/* Generic C equivalent */
|
||||
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
|
||||
#define rol(x,k) SHA_ROT(x,k,32-(k))
|
||||
#define ror(x,k) SHA_ROT(x,32-(k),k)
|
||||
#endif
|
||||
|
||||
|
||||
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
#define blk0be(i) block[i]
|
||||
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
|
||||
^block[(i+2)&15]^block[i&15],1))
|
||||
|
||||
/*
|
||||
* (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
|
||||
*
|
||||
* Rl0() for little-endian and Rb0() for big-endian. Endianness is
|
||||
* determined at run-time.
|
||||
*/
|
||||
#define Rl0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define Rb0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R1(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R2(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
|
||||
#define R3(v,w,x,y,z,i) \
|
||||
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
|
||||
#define R4(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
|
||||
|
||||
/*
|
||||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
|
||||
unsigned int qq[5]; /* a, b, c, d, e; */
|
||||
static int one = 1;
|
||||
unsigned int block[16];
|
||||
memcpy(block, buffer, 64);
|
||||
memcpy(qq,state,5*sizeof(unsigned int));
|
||||
|
||||
#define a qq[0]
|
||||
#define b qq[1]
|
||||
#define c qq[2]
|
||||
#define d qq[3]
|
||||
#define e qq[4]
|
||||
|
||||
/* Copy p->state[] to working vars */
|
||||
/*
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
*/
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
if( 1 == *(unsigned char*)&one ){
|
||||
Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
|
||||
Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
|
||||
Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
|
||||
Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
|
||||
}else{
|
||||
Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
|
||||
Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
|
||||
Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
|
||||
Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
|
||||
}
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
#undef a
|
||||
#undef b
|
||||
#undef c
|
||||
#undef d
|
||||
#undef e
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a SHA1 context */
|
||||
static void hash_init(SHA1Context *p){
|
||||
/* SHA1 initialization constants */
|
||||
p->state[0] = 0x67452301;
|
||||
p->state[1] = 0xEFCDAB89;
|
||||
p->state[2] = 0x98BADCFE;
|
||||
p->state[3] = 0x10325476;
|
||||
p->state[4] = 0xC3D2E1F0;
|
||||
p->count[0] = p->count[1] = 0;
|
||||
}
|
||||
|
||||
/* Add new content to the SHA1 hash */
|
||||
static void hash_step(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const unsigned char *data, /* Data to be added */
|
||||
unsigned int len /* Number of bytes in data */
|
||||
){
|
||||
unsigned int i, j;
|
||||
|
||||
j = p->count[0];
|
||||
if( (p->count[0] += len << 3) < j ){
|
||||
p->count[1] += (len>>29)+1;
|
||||
}
|
||||
j = (j >> 3) & 63;
|
||||
if( (j + len) > 63 ){
|
||||
(void)memcpy(&p->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(p->state, p->buffer);
|
||||
for(; i + 63 < len; i += 64){
|
||||
SHA1Transform(p->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}else{
|
||||
i = 0;
|
||||
}
|
||||
(void)memcpy(&p->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
/* Compute a string using sqlite3_vsnprintf() and hash it */
|
||||
static void hash_step_vformat(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
int n;
|
||||
char zBuf[50];
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zBuf);
|
||||
hash_step(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and compute the message digest. Render the
|
||||
** message digest as lower-case hexadecimal and put it into
|
||||
** zOut[]. zOut[] must be at least 41 bytes long. */
|
||||
static void hash_finish(
|
||||
SHA1Context *p, /* The SHA1 context to finish and render */
|
||||
char *zOut /* Store hexadecimal hash here */
|
||||
){
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
unsigned char digest[20];
|
||||
static const char zEncode[] = "0123456789abcdef";
|
||||
|
||||
for (i = 0; i < 8; i++){
|
||||
finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
hash_step(p, (const unsigned char *)"\200", 1);
|
||||
while ((p->count[0] & 504) != 448){
|
||||
hash_step(p, (const unsigned char *)"\0", 1);
|
||||
}
|
||||
hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++){
|
||||
digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
for(i=0; i<20; i++){
|
||||
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
|
||||
zOut[i*2+1] = zEncode[digest[i] & 0xf];
|
||||
}
|
||||
zOut[i*2]= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1(X) function.
|
||||
**
|
||||
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
|
||||
** argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** types of input, X is converted into a UTF-8 string and the string
|
||||
** is hash without the trailing 0x00 terminator. The hash of a NULL
|
||||
** value is NULL.
|
||||
*/
|
||||
static void sha1Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA1Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
hash_init(&cx);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
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.
|
||||
**
|
||||
** This function compiles and runs the SQL statement(s) given in the
|
||||
** argument. The results are hashed using SHA1 and that hash is returned.
|
||||
**
|
||||
** The original SQL text is included as part of the hash.
|
||||
**
|
||||
** The hash is not just a concatenation of the outputs. Each query
|
||||
** is delimited and each row and value within the query is delimited,
|
||||
** with all values being marked with their datatypes.
|
||||
*/
|
||||
static void sha1QueryFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
SHA1Context cx;
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( zSql==0 ) return;
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
|
||||
zSql, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
if( !sqlite3_stmt_readonly(pStmt) ){
|
||||
char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
sha1RunStatement(&cx, pStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
/* End of ext/misc/sha1.c
|
||||
******************************************************************************/
|
||||
|
||||
/* How much output to display */
|
||||
#define VOLUME_MIN 0
|
||||
#define VOLUME_OFF 0
|
||||
#define VOLUME_ERROR_ONLY 1
|
||||
#define VOLUME_LOW 2
|
||||
#define VOLUME_ECHO 3
|
||||
#define VOLUME_VERBOSE 4
|
||||
#define VOLUME_MAX 4
|
||||
|
||||
/* A string accumulator
|
||||
*/
|
||||
typedef struct Str {
|
||||
char *z; /* Accumulated text */
|
||||
int n; /* Bytes of z[] used so far */
|
||||
int nAlloc; /* Bytes allocated for z[] */
|
||||
} Str;
|
||||
|
||||
/* Append text to the Str object
|
||||
*/
|
||||
static void strAppend(Str *p, const char *z){
|
||||
int n = (int)strlen(z);
|
||||
if( p->n+n >= p->nAlloc ){
|
||||
p->nAlloc += p->n+n + 100;
|
||||
p->z = sqlite3_realloc(p->z, p->nAlloc);
|
||||
if( z==0 ){
|
||||
printf("Could not allocate %d bytes\n", p->nAlloc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
memcpy(p->z+p->n, z, n+1);
|
||||
p->n += n;
|
||||
}
|
||||
|
||||
/* This is an sqlite3_exec() callback that will capture all
|
||||
** output in a Str.
|
||||
**
|
||||
** Columns are separated by ",". Rows are separated by "|".
|
||||
*/
|
||||
static int execCallback(void *pStr, int argc, char **argv, char **colv){
|
||||
int i;
|
||||
Str *p = (Str*)pStr;
|
||||
if( p->n ) strAppend(p, "|");
|
||||
for(i=0; i<argc; i++){
|
||||
const char *z = (const char*)argv[i];
|
||||
if( z==0 ) z = "NULL";
|
||||
if( i>0 ) strAppend(p, ",");
|
||||
strAppend(p, z);
|
||||
}
|
||||
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 ORDER BY name";
|
||||
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 **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 */
|
||||
char *zErrMsg = 0; /* An error message return */
|
||||
char **azTest; /* Content of the selftest table */
|
||||
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];
|
||||
if( z[0]=='-' ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z, "-help")==0 ){
|
||||
printf("%s", zHelp);
|
||||
return 0;
|
||||
}else
|
||||
if( strcmp(z, "-init")==0 ){
|
||||
doInit = 1;
|
||||
}else
|
||||
if( strcmp(z, "-a")==0 ){
|
||||
if( eVolume>VOLUME_MIN) eVolume--;
|
||||
}else
|
||||
if( strcmp(z, "-v")==0 ){
|
||||
if( eVolume<VOLUME_MAX) eVolume++;
|
||||
}else
|
||||
{
|
||||
printf("unknown option: \"%s\"\nUse --help for more information\n",
|
||||
argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
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( nDb==0 ){
|
||||
printf("No databases specified. Use --help for more info\n");
|
||||
return 1;
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW ){
|
||||
printf("SQLite %s\n", sqlite3_sourceid());
|
||||
}
|
||||
memset(&str, 0, sizeof(str));
|
||||
strAppend(&str, "\n");
|
||||
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);
|
||||
}
|
||||
if( eVolume>=VOLUME_LOW || (nErr>0 && eVolume>=VOLUME_ERROR_ONLY) ){
|
||||
printf("%d errors out of %d tests on %d databases\n", nErr, nTest, nDb);
|
||||
}
|
||||
return nErr;
|
||||
}
|
Loading…
Reference in New Issue
Block a user